From 08185548cc61e8549152634653cf182090d24ded Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 3 May 2021 20:13:22 +0200 Subject: [PATCH] :twisted_rightwards_arrows: merge develop --- single_include/nlohmann/json.hpp | 609 ++++++++++++++++++++----------- 1 file changed, 386 insertions(+), 223 deletions(-) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 4b5774f27..cc057a41c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -49,6 +49,7 @@ SOFTWARE. // #include +#include #include // #include @@ -2229,15 +2230,20 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif // C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) - #define JSON_HAS_CPP_20 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 #endif // disable documentation warnings on clang @@ -3166,6 +3172,18 @@ constexpr T static_const::value; } // namespace detail } // namespace nlohmann +// #include + + +namespace nlohmann +{ +namespace detail +{ +// dispatching helper struct +template struct identity_tag {}; +} // namespace detail +} // namespace nlohmann + // #include @@ -3483,8 +3501,7 @@ struct is_getable }; template -struct has_from_json < BasicJsonType, T, - enable_if_t < !is_basic_json::value >> +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> { using serializer = typename BasicJsonType::template json_serializer; @@ -3528,6 +3545,52 @@ struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> // is_ functions // /////////////////// +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B1 { }; +template +struct conjunction +: std::conditional, B1>::type {}; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + + template struct is_iterator_traits : std::false_type {}; @@ -3570,9 +3633,9 @@ struct is_compatible_object_type_impl < // macOS's is_constructible does not play well with nonesuch... static constexpr bool value = - std::is_constructible::value && - std::is_constructible::value; }; @@ -3593,10 +3656,10 @@ struct is_constructible_object_type_impl < using object_t = typename BasicJsonType::object_t; static constexpr bool value = - (std::is_default_constructible::value && + (is_default_constructible::value && (std::is_move_assignable::value || std::is_copy_assignable::value) && - (std::is_constructible::value && std::is_same < typename object_t::mapped_type, @@ -3624,7 +3687,7 @@ struct is_compatible_string_type_impl < value_type_t, CompatibleStringType>::value >> { static constexpr auto value = - std::is_constructible::value; + is_constructible::value; }; template @@ -3642,7 +3705,7 @@ struct is_constructible_string_type_impl < value_type_t, ConstructibleStringType>::value >> { static constexpr auto value = - std::is_constructible::value; }; @@ -3665,7 +3728,7 @@ struct is_compatible_array_type_impl < iterator_traits>::value >> { static constexpr bool value = - std::is_constructible::value; }; @@ -3688,7 +3751,7 @@ struct is_constructible_array_type_impl < BasicJsonType, ConstructibleArrayType, enable_if_t < !std::is_same::value&& - std::is_default_constructible::value&& + is_default_constructible::value&& (std::is_move_assignable::value || std::is_copy_assignable::value)&& is_detected::value&& @@ -3732,7 +3795,7 @@ struct is_compatible_integer_type_impl < using CompatibleLimits = std::numeric_limits; static constexpr auto value = - std::is_constructible::value && CompatibleLimits::is_integer && RealLimits::is_signed == CompatibleLimits::is_signed; @@ -3759,18 +3822,11 @@ template struct is_compatible_type : is_compatible_type_impl {}; -// https://en.cppreference.com/w/cpp/types/conjunction -template struct conjunction : std::true_type { }; -template struct conjunction : B1 { }; -template -struct conjunction -: std::conditional, B1>::type {}; - template struct is_constructible_tuple : std::false_type {}; template -struct is_constructible_tuple> : conjunction...> {}; +struct is_constructible_tuple> : conjunction...> {}; /// type to check if KeyType can be used as object key template @@ -3784,7 +3840,6 @@ struct is_key_type && !std::is_same::value && !std::is_same::value; }; - } // namespace detail } // namespace nlohmann @@ -3960,7 +4015,10 @@ auto from_json_array_impl(const BasicJsonType& j, std::array& arr, } } -template +template::value, + int> = 0> auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) -> decltype( arr.reserve(std::declval()), @@ -3981,7 +4039,10 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p arr = std::move(ret); } -template +template::value, + int> = 0> void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<0> /*unused*/) { @@ -4020,6 +4081,25 @@ void()) from_json_array_impl(j, arr, priority_tag<3> {}); } +template < typename BasicJsonType, typename T, std::size_t... Idx > +std::array from_json_inplace_array_impl(BasicJsonType&& j, + identity_tag> /*unused*/, index_sequence /*unused*/) +{ + return { { std::forward(j).at(Idx).template get()... } }; +} + +template < typename BasicJsonType, typename T, std::size_t N > +auto from_json(BasicJsonType&& j, identity_tag> tag) +-> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + + return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); +} + template void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) { @@ -4095,22 +4175,47 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) } } -template -void from_json(const BasicJsonType& j, std::pair& p) +template +std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence /*unused*/) { - p = {j.at(0).template get(), j.at(1).template get()}; + return std::make_tuple(std::forward(j).at(Idx).template get()...); } -template -void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence /*unused*/) +template < typename BasicJsonType, class A1, class A2 > +std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) { - t = std::make_tuple(j.at(Idx).template get::type>()...); + return {std::forward(j).at(0).template get(), + std::forward(j).at(1).template get()}; +} + +template +void from_json_tuple_impl(BasicJsonType&& j, std::pair& p, priority_tag<1> /*unused*/) +{ + p = from_json_tuple_impl(std::forward(j), identity_tag> {}, priority_tag<0> {}); } template -void from_json(const BasicJsonType& j, std::tuple& t) +std::tuple from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<2> /*unused*/) { - from_json_tuple_impl(j, t, index_sequence_for {}); + return from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +void from_json_tuple_impl(BasicJsonType&& j, std::tuple& t, priority_tag<3> /*unused*/) +{ + t = from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +auto from_json(BasicJsonType&& j, TupleRelated&& t) +-> decltype(from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + + return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); } template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, @@ -4156,11 +4261,11 @@ void from_json(const BasicJsonType& j, std::unordered_map - auto operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(from_json(j, val))) - -> decltype(from_json(j, val), void()) + auto operator()(const BasicJsonType& j, T&& val) const + noexcept(noexcept(from_json(j, std::forward(val)))) + -> decltype(from_json(j, std::forward(val))) { - return from_json(j, val); + return from_json(j, std::forward(val)); } }; } // namespace detail @@ -4745,11 +4850,15 @@ constexpr const auto& to_json = detail::static_const::value; } // namespace } // namespace nlohmann +// #include + +// #include + namespace nlohmann { -template +template struct adl_serializer { /*! @@ -4758,17 +4867,39 @@ struct adl_serializer This function is usually called by the `get()` function of the @ref basic_json class (either explicit or via conversion operators). + @note This function is chosen for default-constructible value types. + @param[in] j JSON value to read from @param[in,out] val value to write to */ - template - static auto from_json(BasicJsonType&& j, ValueType& val) noexcept( + template + static auto from_json(BasicJsonType && j, TargetType& val) noexcept( noexcept(::nlohmann::from_json(std::forward(j), val))) -> decltype(::nlohmann::from_json(std::forward(j), val), void()) { ::nlohmann::from_json(std::forward(j), val); } + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @note This function is chosen for value types which are not default-constructible. + + @param[in] j JSON value to read from + + @return copy of the JSON value, converted to @a ValueType + */ + template + static auto from_json(BasicJsonType && j) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) + -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) + { + return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); + } + /*! @brief convert any value type to a JSON value @@ -4778,15 +4909,14 @@ struct adl_serializer @param[in,out] j JSON value to write to @param[in] val value to read from */ - template - static auto to_json(BasicJsonType& j, ValueType&& val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward(val)))) - -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) + template + static auto to_json(BasicJsonType& j, TargetType && val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) { - ::nlohmann::to_json(j, std::forward(val)); + ::nlohmann::to_json(j, std::forward(val)); } }; - } // namespace nlohmann // #include @@ -6537,7 +6667,7 @@ class lexer : public lexer_base /*! @brief scan a string literal - This function scans a string according to Sect. 7 of RFC 7159. While + This function scans a string according to Sect. 7 of RFC 8259. While scanning, bytes are escaped and copied into buffer token_buffer. Then the function returns successfully, token_buffer is *not* null-terminated (as it may contain \0 bytes), and token_buffer.size() is the number of bytes in the @@ -7227,10 +7357,10 @@ class lexer : public lexer_base /*! @brief scan a number literal - This function scans a string according to Sect. 6 of RFC 7159. + This function scans a string according to Sect. 6 of RFC 8259. The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 7159. Starting in state "init", the + from the grammar described in RFC 8259. Starting in state "init", the input is read and used to determined the next state. Only state "done" accepts the number. State "error" is a trap state to model errors. In the table below, "anything" means any character but the ones listed before. @@ -17066,8 +17196,8 @@ The invariants are checked by member function assert_invariant(). @note ObjectType trick from https://stackoverflow.com/a/9860911 @endinternal -@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange -Format](http://rfc7159.net/rfc7159) +@see [RFC 8259: The JavaScript Object Notation (JSON) Data Interchange +Format](https://tools.ietf.org/html/rfc8259) @since version 1.0.0 @@ -17328,7 +17458,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /*! @brief a type for an object - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON objects as follows: > An object is an unordered collection of zero or more name/value pairs, > where a name is a string and a value is a string, number, boolean, null, > object, or array. @@ -17382,7 +17512,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Limits - [RFC 7159](http://rfc7159.net/rfc7159) specifies: + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the maximum depth of nesting. In this class, the object's limit of nesting is not explicitly constrained. @@ -17405,7 +17535,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default. Please note this behavior conforms to [RFC - 7159](http://rfc7159.net/rfc7159), because any order implements the + 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. */ using object_t = ObjectType An array is an ordered sequence of zero or more values. To store objects in C++, a type is defined by the template parameters @@ -17441,7 +17571,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Limits - [RFC 7159](http://rfc7159.net/rfc7159) specifies: + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the maximum depth of nesting. In this class, the array's limit of nesting is not explicitly constrained. @@ -17463,7 +17593,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /*! @brief a type for a string - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON strings as follows: > A string is a sequence of zero or more Unicode characters. To store objects in C++, a type is defined by the template parameter @@ -17490,7 +17620,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### String comparison - [RFC 7159](http://rfc7159.net/rfc7159) states: + [RFC 8259](https://tools.ietf.org/html/rfc8259) states: > Software implementations are typically required to test names of object > members for equality. Implementations that transform the textual > representation into sequences of Unicode code units and then perform the @@ -17516,7 +17646,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /*! @brief a type for a boolean - [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + [RFC 8259](https://tools.ietf.org/html/rfc8259) implicitly describes a boolean as a type which differentiates the two literals `true` and `false`. To store objects in C++, a type is defined by the template parameter @a @@ -17542,7 +17672,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /*! @brief a type for a number (integer) - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an @@ -17580,7 +17710,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Limits - [RFC 7159](http://rfc7159.net/rfc7159) specifies: + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the range and precision of numbers. When the default type is used, the maximal integer number that can be @@ -17591,7 +17721,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec will be automatically be stored as @ref number_unsigned_t or @ref number_float_t. - [RFC 7159](http://rfc7159.net/rfc7159) further states: + [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: > Note that when such software is used, numbers that are integers and are > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense > that implementations will agree exactly on their numeric values. @@ -17614,7 +17744,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /*! @brief a type for a number (unsigned) - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an @@ -17652,7 +17782,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Limits - [RFC 7159](http://rfc7159.net/rfc7159) specifies: + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the range and precision of numbers. When the default type is used, the maximal integer number that can be @@ -17662,7 +17792,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec deserialization, too large or small integer numbers will be automatically be stored as @ref number_integer_t or @ref number_float_t. - [RFC 7159](http://rfc7159.net/rfc7159) further states: + [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: > Note that when such software is used, numbers that are integers and are > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense > that implementations will agree exactly on their numeric values. @@ -17685,7 +17815,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /*! @brief a type for a number (floating-point) - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an @@ -17723,7 +17853,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Limits - [RFC 7159](http://rfc7159.net/rfc7159) states: + [RFC 8259](https://tools.ietf.org/html/rfc8259) states: > This specification allows implementations to set limits on the range and > precision of numbers accepted. Since software that implements IEEE > 754-2008 binary64 (double precision) numbers is generally available and @@ -18161,9 +18291,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec })); } JSON_CATCH(...) {} // LCOV_EXCL_LINE -#else - static_cast(check_parents); #endif + static_cast(check_parents); } void set_parents() @@ -19826,50 +19955,53 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @{ /*! - @brief get special-case overload + @brief get a pointer value (implicit) - This overloads avoids a lot of template boilerplate, it can be seen as the - identity method + Implicit pointer access to the internally stored JSON value. No copies are + made. - @tparam BasicJsonType == @ref basic_json + @warning Writing data to the pointee of the result yields an undefined + state. - @return a copy of *this + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. - @since version 2.1.0 + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 */ - template::type, basic_json_t>::value, - int> = 0> - basic_json get() const + template::value, int>::type = 0> + auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { - return *this; + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); } /*! - @brief get special-case overload - - This overloads converts the current @ref basic_json in a different - @ref basic_json type - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this, converted into @a BasicJsonType - - @complexity Depending on the implementation of the called `from_json()` - method. - - @since version 3.2.0 + @brief get a pointer value (implicit) + @copydoc get_ptr() */ - template < typename BasicJsonType, detail::enable_if_t < - !std::is_same::value&& - detail::is_basic_json::value, int > = 0 > - BasicJsonType get() const + template < typename PointerType, typename std::enable_if < + std::is_pointer::value&& + std::is_const::type>::value, int >::type = 0 > + constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { - return *this; + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); } + private: /*! @brief get a value (explicit) @@ -19893,7 +20025,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec - @ref json_serializer does not have a `from_json()` method of the form `ValueType from_json(const basic_json&)` - @tparam ValueTypeCV the provided value type @tparam ValueType the returned value type @return copy of the JSON value, converted to @a ValueType @@ -19909,23 +20040,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.1.0 */ - template < typename ValueTypeCV, typename ValueType = detail::uncvref_t, + template < typename ValueType, detail::enable_if_t < - !detail::is_basic_json::value && - detail::has_from_json::value && - !detail::has_non_default_from_json::value, + detail::is_default_constructible::value&& + detail::has_from_json::value, int > = 0 > - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), std::declval()))) + ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) { - // we cannot static_assert on ValueTypeCV being non-const, because - // there is support for get(), which is why we - // still need the uncvref - static_assert(!std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - static_assert(std::is_default_constructible::value, - "types must be DefaultConstructible when used with get()"); - ValueType ret{}; JSONSerializer::from_json(*this, ret); return ret; @@ -19942,7 +20064,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec The function is equivalent to executing @code {.cpp} - return JSONSerializer::from_json(*this); + return JSONSerializer::from_json(*this); @endcode This overloads is chosen if: @@ -19953,7 +20075,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @note If @ref json_serializer has both overloads of `from_json()`, this one is chosen. - @tparam ValueTypeCV the provided value type @tparam ValueType the returned value type @return copy of the JSON value, converted to @a ValueType @@ -19962,16 +20083,151 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.1.0 */ - template < typename ValueTypeCV, typename ValueType = detail::uncvref_t, - detail::enable_if_t < !std::is_same::value && - detail::has_non_default_from_json::value, - int > = 0 > - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval()))) + template < typename ValueType, + detail::enable_if_t < + detail::has_non_default_from_json::value, + int > = 0 > + ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) { + return JSONSerializer::from_json(*this); + } + + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @a BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.2.0 + */ + template < typename BasicJsonType, + detail::enable_if_t < + detail::is_basic_json::value, + int > = 0 > + BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const + { + return *this; + } + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::value, + int> = 0> + basic_json get_impl(detail::priority_tag<3> /*unused*/) const + { + return *this; + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, + int> = 0> + constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept + -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + public: + /*! + @brief get a (pointer) value (explicit) + + Performs explicit type conversion between the JSON value and a compatible value if required. + + - If the requested type is a pointer to the internally stored JSON value that pointer is returned. + No copies are made. + + - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible + from the current @ref basic_json. + + - Otherwise the value is converted by calling the @ref json_serializer `from_json()` + method. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @tparam ValueType if necessary + + @throw what @ref json_serializer `from_json()` method throws if conversion is required + + @since version 2.1.0 + */ + template < typename ValueTypeCV, typename ValueType = detail::uncvref_t> +#if defined(JSON_HAS_CPP_14) + constexpr +#endif + auto get() const noexcept( + noexcept(std::declval().template get_impl(detail::priority_tag<4> {}))) + -> decltype(std::declval().template get_impl(detail::priority_tag<4> {})) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref static_assert(!std::is_reference::value, "get() cannot be used with reference types, you might want to use get_ref()"); - return JSONSerializer::from_json(*this); + return get_impl(detail::priority_tag<4> {}); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa see @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); } /*! @@ -20044,101 +20300,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return v; } - - /*! - @brief get a pointer value (implicit) - - Implicit pointer access to the internally stored JSON value. No copies are - made. - - @warning Writing data to the pointee of the result yields an undefined - state. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. Enforced by a static - assertion. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get_ptr} - - @since version 1.0.0 - */ - template::value, int>::type = 0> - auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) - { - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a pointer value (implicit) - @copydoc get_ptr() - */ - template < typename PointerType, typename std::enable_if < - std::is_pointer::value&& - std::is_const::type>::value, int >::type = 0 > - constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) - { - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a pointer value (explicit) - - Explicit pointer access to the internally stored JSON value. No copies are - made. - - @warning The pointer becomes invalid if the underlying JSON object - changes. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} - - @sa see @ref get_ptr() for explicit pointer-member access - - @since version 1.0.0 - */ - template::value, int>::type = 0> - auto get() noexcept -> decltype(std::declval().template get_ptr()) - { - // delegate the call to get_ptr - return get_ptr(); - } - - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, int>::type = 0> - constexpr auto get() const noexcept -> decltype(std::declval().template get_ptr()) - { - // delegate the call to get_ptr - return get_ptr(); - } - /*! @brief get a reference value (implicit) @@ -25755,8 +25916,10 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef JSON_THROW #undef JSON_TRY #undef JSON_PRIVATE_UNLESS_TESTED +#undef JSON_HAS_CPP_11 #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 +#undef JSON_HAS_CPP_20 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT