diff --git a/README.md b/README.md index 0f102ef3f1ba4e822fe97bdd7f6317741d50425c..6284668c2d5369927e7d3fe80e3a1cc0ceac6af0 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ include(FetchContent) FetchContent_Declare(json GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent - GIT_TAG v3.10.2) + GIT_TAG v3.10.3) FetchContent_GetProperties(json) if(NOT json_POPULATED) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 8959265daeaab16d3145c1fd95d317101b9395e0..25c6983b0420075a37df2a3ea66923b7fc977f88 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.10.2 +| | |__ | | | | | | version 3.10.3 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -32,7 +32,7 @@ SOFTWARE. #define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MINOR 10 -#define NLOHMANN_JSON_VERSION_PATCH 2 +#define NLOHMANN_JSON_VERSION_PATCH 3 #include <algorithm> // all_of, find, for_each #include <cstddef> // nullptr_t, ptrdiff_t, size_t @@ -167,7 +167,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept // #include <nlohmann/detail/macro_scope.hpp> -#include <utility> // pair +#include <utility> // declval, pair // #include <nlohmann/thirdparty/hedley/hedley.hpp> @@ -2214,6 +2214,83 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ +// #include <nlohmann/detail/meta/detected.hpp> + + +#include <type_traits> + +// #include <nlohmann/detail/meta/void_t.hpp> + + +namespace nlohmann +{ +namespace detail +{ +template<typename ...Ts> struct make_void +{ + using type = void; +}; +template<typename ...Ts> using void_t = typename make_void<Ts...>::type; +} // namespace detail +} // namespace nlohmann + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template<class Default, + class AlwaysVoid, + template<class...> class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template<class Default, template<class...> class Op, class... Args> +struct detector<Default, void_t<Op<Args...>>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op<Args...>; +}; + +template<template<class...> class Op, class... Args> +using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; + +template<template<class...> class Op, class... Args> +struct is_detected_lazy : is_detected<Op, Args...> { }; + +template<template<class...> class Op, class... Args> +using detected_t = typename detector<nonesuch, void, Op, Args...>::type; + +template<class Default, template<class...> class Op, class... Args> +using detected_or = detector<Default, void, Op, Args...>; + +template<class Default, template<class...> class Op, class... Args> +using detected_or_t = typename detected_or<Default, Op, Args...>::type; + +template<class Expected, template<class...> class Op, class... Args> +using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; + +template<class To, template<class...> class Op, class... Args> +using is_detected_convertible = + std::is_convertible<detected_t<Op, Args...>, To>; +} // namespace detail +} // namespace nlohmann + // This file contains all internal macro definitions // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them @@ -2504,6 +2581,45 @@ JSON_HEDLEY_DIAGNOSTIC_POP inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template<typename... T> \ + using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template<typename... T> \ + std_name##_tag std_name(T&&...); \ + \ + template<typename... T> \ + using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ + \ + template<typename... T> \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template<typename... T> \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \ + { \ + } + #ifndef JSON_USE_IMPLICIT_CONVERSIONS #define JSON_USE_IMPLICIT_CONVERSIONS 1 #endif @@ -3207,6 +3323,9 @@ template <class T> struct identity_tag {}; #include <utility> // declval #include <tuple> // tuple +// #include <nlohmann/detail/macro_scope.hpp> + + // #include <nlohmann/detail/iterators/iterator_traits.hpp> @@ -3214,19 +3333,6 @@ template <class T> struct identity_tag {}; // #include <nlohmann/detail/meta/void_t.hpp> - -namespace nlohmann -{ -namespace detail -{ -template<typename ...Ts> struct make_void -{ - using type = void; -}; -template<typename ...Ts> using void_t = typename make_void<Ts...>::type; -} // namespace detail -} // namespace nlohmann - // #include <nlohmann/detail/meta/cpp_future.hpp> @@ -3275,73 +3381,31 @@ struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> } // namespace detail } // namespace nlohmann -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/detected.hpp> - +// #include <nlohmann/detail/meta/call_std/begin.hpp> -#include <type_traits> -// #include <nlohmann/detail/meta/void_t.hpp> +// #include <nlohmann/detail/macro_scope.hpp> -// https://en.cppreference.com/w/cpp/experimental/is_detected namespace nlohmann { -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - nonesuch(nonesuch const&&) = delete; - void operator=(nonesuch const&) = delete; - void operator=(nonesuch&&) = delete; -}; - -template<class Default, - class AlwaysVoid, - template<class...> class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template<class Default, template<class...> class Op, class... Args> -struct detector<Default, void_t<Op<Args...>>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op<Args...>; -}; +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); +} // namespace nlohmann -template<template<class...> class Op, class... Args> -using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; +// #include <nlohmann/detail/meta/call_std/end.hpp> -template<template<class...> class Op, class... Args> -struct is_detected_lazy : is_detected<Op, Args...> { }; -template<template<class...> class Op, class... Args> -using detected_t = typename detector<nonesuch, void, Op, Args...>::type; +// #include <nlohmann/detail/macro_scope.hpp> -template<class Default, template<class...> class Op, class... Args> -using detected_or = detector<Default, void, Op, Args...>; -template<class Default, template<class...> class Op, class... Args> -using detected_or_t = typename detected_or<Default, Op, Args...>::type; +namespace nlohmann +{ +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); +} // namespace nlohmann -template<class Expected, template<class...> class Op, class... Args> -using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; +// #include <nlohmann/detail/meta/cpp_future.hpp> -template<class To, template<class...> class Op, class... Args> -using is_detected_convertible = - std::is_convertible<detected_t<Op, Args...>, To>; -} // namespace detail -} // namespace nlohmann +// #include <nlohmann/detail/meta/detected.hpp> // #include <nlohmann/json_fwd.hpp> #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ @@ -3492,9 +3556,6 @@ using reference_t = typename T::reference; template<typename T> using iterator_category_t = typename T::iterator_category; -template<typename T> -using iterator_t = typename T::iterator; - template<typename T, typename... Args> using to_json_function = decltype(T::to_json(std::declval<Args>()...)); @@ -3630,6 +3691,31 @@ struct is_iterator_traits<iterator_traits<T>> is_detected<reference_t, traits>::value; }; +template<typename T> +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference<T>::type; + + using iterator = detected_t<result_of_begin, t_ref>; + using sentinel = detected_t<result_of_end, t_ref>; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits<iterator_traits<iterator>>::value; + + public: + static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin; +}; + +template<typename R> +using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>; + +template<typename T> +using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>; + // The following implementation of is_complete_type is taken from // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ // and is written by Xiang Fan who agreed to using it in this library. @@ -3704,8 +3790,9 @@ struct is_compatible_string_type_impl : std::false_type {}; template<typename BasicJsonType, typename CompatibleStringType> struct is_compatible_string_type_impl < BasicJsonType, CompatibleStringType, - enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type, - value_type_t, CompatibleStringType>::value >> + enable_if_t<is_detected_convertible<typename BasicJsonType::string_t::value_type, + range_value_t, + CompatibleStringType>::value >> { static constexpr auto value = is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; @@ -3740,17 +3827,13 @@ struct is_compatible_array_type_impl : std::false_type {}; template<typename BasicJsonType, typename CompatibleArrayType> struct is_compatible_array_type_impl < BasicJsonType, CompatibleArrayType, - enable_if_t < is_detected<value_type_t, CompatibleArrayType>::value&& + enable_if_t < is_detected<iterator_t, CompatibleArrayType>::value&& -// This is needed because json_reverse_iterator has a ::iterator type... -// Therefore it is detected as a CompatibleArrayType. -// The real fix would be to have an Iterable concept. - !is_iterator_traits < - iterator_traits<CompatibleArrayType >>::value >> + is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value >> { static constexpr bool value = is_constructible<BasicJsonType, - typename CompatibleArrayType::value_type>::value; + range_value_t<CompatibleArrayType>>::value; }; template<typename BasicJsonType, typename CompatibleArrayType> @@ -3772,28 +3855,26 @@ struct is_constructible_array_type_impl < BasicJsonType, ConstructibleArrayType, enable_if_t < !std::is_same<ConstructibleArrayType, typename BasicJsonType::value_type>::value&& + !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&& is_default_constructible<ConstructibleArrayType>::value&& (std::is_move_assignable<ConstructibleArrayType>::value || std::is_copy_assignable<ConstructibleArrayType>::value)&& -is_detected<value_type_t, ConstructibleArrayType>::value&& is_detected<iterator_t, ConstructibleArrayType>::value&& +is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& +is_detected<range_value_t, ConstructibleArrayType>::value&& is_complete_type < -detected_t<value_type_t, ConstructibleArrayType >>::value >> +detected_t<range_value_t, ConstructibleArrayType >>::value >> { + using value_type = range_value_t<ConstructibleArrayType>; + static constexpr bool value = - // This is needed because json_reverse_iterator has a ::iterator type, - // furthermore, std::back_insert_iterator (and other iterators) have a - // base class `iterator`... Therefore it is detected as a - // ConstructibleArrayType. The real fix would be to have an Iterable - // concept. - !is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value && - - (std::is_same<typename ConstructibleArrayType::value_type, - typename BasicJsonType::array_t::value_type>::value || - has_from_json<BasicJsonType, - typename ConstructibleArrayType::value_type>::value || - has_non_default_from_json < - BasicJsonType, typename ConstructibleArrayType::value_type >::value); + std::is_same<value_type, + typename BasicJsonType::array_t::value_type>::value || + has_from_json<BasicJsonType, + value_type>::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; }; template<typename BasicJsonType, typename ConstructibleArrayType> @@ -13485,11 +13566,11 @@ template<typename CharType> using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>; /// output adapter for byte vectors -template<typename CharType> +template<typename CharType, typename AllocatorType = std::allocator<CharType>> class output_vector_adapter : public output_adapter_protocol<CharType> { public: - explicit output_vector_adapter(std::vector<CharType>& vec) noexcept + explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept : v(vec) {} @@ -13505,7 +13586,7 @@ class output_vector_adapter : public output_adapter_protocol<CharType> } private: - std::vector<CharType>& v; + std::vector<CharType, AllocatorType>& v; }; #ifndef JSON_NO_IO @@ -13562,8 +13643,9 @@ template<typename CharType, typename StringType = std::basic_string<CharType>> class output_adapter { public: - output_adapter(std::vector<CharType>& vec) - : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {} + template<typename AllocatorType = std::allocator<CharType>> + output_adapter(std::vector<CharType, AllocatorType>& vec) + : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {} #ifndef JSON_NO_IO output_adapter(std::basic_ostream<CharType>& s) @@ -18470,7 +18552,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.2", basic_json())); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.3", basic_json())); // LCOV_EXCL_LINE } break; } @@ -21100,15 +21182,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (idx >= m_value.array->size()) { #if JSON_DIAGNOSTICS - // remember array size before resizing - const auto previous_size = m_value.array->size(); + // remember array size & capacity before resizing + const auto old_size = m_value.array->size(); + const auto old_capacity = m_value.array->capacity(); #endif m_value.array->resize(idx + 1); #if JSON_DIAGNOSTICS - // set parent for values added above - set_parents(begin() + static_cast<typename iterator::difference_type>(previous_size), static_cast<typename iterator::difference_type>(idx + 1 - previous_size)); + if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) + { + // capacity has changed: update all parents + set_parents(); + } + else + { + // set parent for values added above + set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size)); + } #endif + assert_invariant(); } return m_value.array->operator[](idx); @@ -23414,6 +23506,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = j.cbegin(); it != j.cend(); ++it) { m_value.object->operator[](it.key()) = it.value(); +#if JSON_DIAGNOSTICS + m_value.object->operator[](it.key()).m_parent = this; +#endif } } @@ -23474,6 +23569,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec for (auto it = first; it != last; ++it) { m_value.object->operator[](it.key()) = it.value(); +#if JSON_DIAGNOSTICS + m_value.object->operator[](it.key()).m_parent = this; +#endif } } @@ -26482,6 +26580,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT +#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL // #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>