5259 lines
		
	
	
		
			194 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			5259 lines
		
	
	
		
			194 KiB
		
	
	
	
		
			C++
		
	
	
	
| //     __ _____ _____ _____
 | |
| //  __|  |   __|     |   | |  JSON for Modern C++
 | |
| // |  |  |__   |  |  | | | |  version 3.11.3
 | |
| // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
 | |
| //
 | |
| // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| /****************************************************************************\
 | |
|  * Note on documentation: The source files contain links to the online      *
 | |
|  * documentation of the public API at https://json.nlohmann.me. This URL    *
 | |
|  * contains the most recent documentation and should also be applicable to  *
 | |
|  * previous versions; documentation for deprecated functions is not         *
 | |
|  * removed, but marked deprecated. See "Generate documentation" section in  *
 | |
|  * file docs/README.md.                                                     *
 | |
| \****************************************************************************/
 | |
| 
 | |
| #ifndef INCLUDE_NLOHMANN_JSON_HPP_
 | |
| #define INCLUDE_NLOHMANN_JSON_HPP_
 | |
| 
 | |
| #include <algorithm> // all_of, find, for_each
 | |
| #include <cstddef> // nullptr_t, ptrdiff_t, size_t
 | |
| #include <functional> // hash, less
 | |
| #include <initializer_list> // initializer_list
 | |
| #ifndef JSON_NO_IO
 | |
|     #include <iosfwd> // istream, ostream
 | |
| #endif  // JSON_NO_IO
 | |
| #include <iterator> // random_access_iterator_tag
 | |
| #include <memory> // unique_ptr
 | |
| #include <string> // string, stoi, to_string
 | |
| #include <utility> // declval, forward, move, pair, swap
 | |
| #include <vector> // vector
 | |
| 
 | |
| #include <nlohmann/adl_serializer.hpp>
 | |
| #include <nlohmann/byte_container_with_subtype.hpp>
 | |
| #include <nlohmann/detail/conversions/from_json.hpp>
 | |
| #include <nlohmann/detail/conversions/to_json.hpp>
 | |
| #include <nlohmann/detail/exceptions.hpp>
 | |
| #include <nlohmann/detail/hash.hpp>
 | |
| #include <nlohmann/detail/input/binary_reader.hpp>
 | |
| #include <nlohmann/detail/input/input_adapters.hpp>
 | |
| #include <nlohmann/detail/input/lexer.hpp>
 | |
| #include <nlohmann/detail/input/parser.hpp>
 | |
| #include <nlohmann/detail/iterators/internal_iterator.hpp>
 | |
| #include <nlohmann/detail/iterators/iter_impl.hpp>
 | |
| #include <nlohmann/detail/iterators/iteration_proxy.hpp>
 | |
| #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
 | |
| #include <nlohmann/detail/iterators/primitive_iterator.hpp>
 | |
| #include <nlohmann/detail/json_custom_base_class.hpp>
 | |
| #include <nlohmann/detail/json_pointer.hpp>
 | |
| #include <nlohmann/detail/json_ref.hpp>
 | |
| #include <nlohmann/detail/macro_scope.hpp>
 | |
| #include <nlohmann/detail/string_concat.hpp>
 | |
| #include <nlohmann/detail/string_escape.hpp>
 | |
| #include <nlohmann/detail/meta/cpp_future.hpp>
 | |
| #include <nlohmann/detail/meta/type_traits.hpp>
 | |
| #include <nlohmann/detail/output/binary_writer.hpp>
 | |
| #include <nlohmann/detail/output/output_adapters.hpp>
 | |
| #include <nlohmann/detail/output/serializer.hpp>
 | |
| #include <nlohmann/detail/value_t.hpp>
 | |
| #include <nlohmann/json_fwd.hpp>
 | |
| #include <nlohmann/ordered_map.hpp>
 | |
| 
 | |
| #if defined(JSON_HAS_CPP_17)
 | |
|     #if JSON_HAS_STATIC_RTTI
 | |
|         #include <any>
 | |
|     #endif
 | |
|     #include <string_view>
 | |
| #endif
 | |
| 
 | |
| /*!
 | |
| @brief namespace for Niels Lohmann
 | |
| @see https://github.com/nlohmann
 | |
| @since version 1.0.0
 | |
| */
 | |
| NLOHMANN_JSON_NAMESPACE_BEGIN
 | |
| 
 | |
| /*!
 | |
| @brief a class to store JSON values
 | |
| 
 | |
| @internal
 | |
| @invariant The member variables @a m_value and @a m_type have the following
 | |
| relationship:
 | |
| - If `m_type == value_t::object`, then `m_value.object != nullptr`.
 | |
| - If `m_type == value_t::array`, then `m_value.array != nullptr`.
 | |
| - If `m_type == value_t::string`, then `m_value.string != nullptr`.
 | |
| The invariants are checked by member function assert_invariant().
 | |
| 
 | |
| @note ObjectType trick from https://stackoverflow.com/a/9860911
 | |
| @endinternal
 | |
| 
 | |
| @since version 1.0.0
 | |
| 
 | |
| @nosubgrouping
 | |
| */
 | |
| NLOHMANN_BASIC_JSON_TPL_DECLARATION
 | |
| class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
 | |
|     : public ::nlohmann::detail::json_base_class<CustomBaseClass>
 | |
| {
 | |
|   private:
 | |
|     template<detail::value_t> friend struct detail::external_constructor;
 | |
| 
 | |
|     template<typename>
 | |
|     friend class ::nlohmann::json_pointer;
 | |
|     // can be restored when json_pointer backwards compatibility is removed
 | |
|     // friend ::nlohmann::json_pointer<StringType>;
 | |
| 
 | |
|     template<typename BasicJsonType, typename InputType>
 | |
|     friend class ::nlohmann::detail::parser;
 | |
|     friend ::nlohmann::detail::serializer<basic_json>;
 | |
|     template<typename BasicJsonType>
 | |
|     friend class ::nlohmann::detail::iter_impl;
 | |
|     template<typename BasicJsonType, typename CharType>
 | |
|     friend class ::nlohmann::detail::binary_writer;
 | |
|     template<typename BasicJsonType, typename InputType, typename SAX>
 | |
|     friend class ::nlohmann::detail::binary_reader;
 | |
|     template<typename BasicJsonType>
 | |
|     friend class ::nlohmann::detail::json_sax_dom_parser;
 | |
|     template<typename BasicJsonType>
 | |
|     friend class ::nlohmann::detail::json_sax_dom_callback_parser;
 | |
|     friend class ::nlohmann::detail::exception;
 | |
| 
 | |
|     /// workaround type for MSVC
 | |
|     using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
 | |
|     using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;
 | |
| 
 | |
|   JSON_PRIVATE_UNLESS_TESTED:
 | |
|     // convenience aliases for types residing in namespace detail;
 | |
|     using lexer = ::nlohmann::detail::lexer_base<basic_json>;
 | |
| 
 | |
|     template<typename InputAdapterType>
 | |
|     static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
 | |
|         InputAdapterType adapter,
 | |
|         detail::parser_callback_t<basic_json>cb = nullptr,
 | |
|         const bool allow_exceptions = true,
 | |
|         const bool ignore_comments = false
 | |
|     )
 | |
|     {
 | |
|         return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
 | |
|                 std::move(cb), allow_exceptions, ignore_comments);
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
 | |
|     template<typename BasicJsonType>
 | |
|     using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
 | |
|     template<typename BasicJsonType>
 | |
|     using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
 | |
|     template<typename Iterator>
 | |
|     using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
 | |
|     template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
 | |
| 
 | |
|     template<typename CharType>
 | |
|     using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
 | |
| 
 | |
|     template<typename InputType>
 | |
|     using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;
 | |
|     template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
 | |
| 
 | |
|   JSON_PRIVATE_UNLESS_TESTED:
 | |
|     using serializer = ::nlohmann::detail::serializer<basic_json>;
 | |
| 
 | |
|   public:
 | |
|     using value_t = detail::value_t;
 | |
|     /// JSON Pointer, see @ref nlohmann::json_pointer
 | |
|     using json_pointer = ::nlohmann::json_pointer<StringType>;
 | |
|     template<typename T, typename SFINAE>
 | |
|     using json_serializer = JSONSerializer<T, SFINAE>;
 | |
|     /// how to treat decoding errors
 | |
|     using error_handler_t = detail::error_handler_t;
 | |
|     /// how to treat CBOR tags
 | |
|     using cbor_tag_handler_t = detail::cbor_tag_handler_t;
 | |
|     /// helper type for initializer lists of basic_json values
 | |
|     using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
 | |
| 
 | |
|     using input_format_t = detail::input_format_t;
 | |
|     /// SAX interface type, see @ref nlohmann::json_sax
 | |
|     using json_sax_t = json_sax<basic_json>;
 | |
| 
 | |
|     ////////////////
 | |
|     // exceptions //
 | |
|     ////////////////
 | |
| 
 | |
|     /// @name exceptions
 | |
|     /// Classes to implement user-defined exceptions.
 | |
|     /// @{
 | |
| 
 | |
|     using exception = detail::exception;
 | |
|     using parse_error = detail::parse_error;
 | |
|     using invalid_iterator = detail::invalid_iterator;
 | |
|     using type_error = detail::type_error;
 | |
|     using out_of_range = detail::out_of_range;
 | |
|     using other_error = detail::other_error;
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     /////////////////////
 | |
|     // container types //
 | |
|     /////////////////////
 | |
| 
 | |
|     /// @name container types
 | |
|     /// The canonic container types to use @ref basic_json like any other STL
 | |
|     /// container.
 | |
|     /// @{
 | |
| 
 | |
|     /// the type of elements in a basic_json container
 | |
|     using value_type = basic_json;
 | |
| 
 | |
|     /// the type of an element reference
 | |
|     using reference = value_type&;
 | |
|     /// the type of an element const reference
 | |
|     using const_reference = const value_type&;
 | |
| 
 | |
|     /// a type to represent differences between iterators
 | |
|     using difference_type = std::ptrdiff_t;
 | |
|     /// a type to represent container sizes
 | |
|     using size_type = std::size_t;
 | |
| 
 | |
|     /// the allocator type
 | |
|     using allocator_type = AllocatorType<basic_json>;
 | |
| 
 | |
|     /// the type of an element pointer
 | |
|     using pointer = typename std::allocator_traits<allocator_type>::pointer;
 | |
|     /// the type of an element const pointer
 | |
|     using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
 | |
| 
 | |
|     /// an iterator for a basic_json container
 | |
|     using iterator = iter_impl<basic_json>;
 | |
|     /// a const iterator for a basic_json container
 | |
|     using const_iterator = iter_impl<const basic_json>;
 | |
|     /// a reverse iterator for a basic_json container
 | |
|     using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
 | |
|     /// a const reverse iterator for a basic_json container
 | |
|     using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     /// @brief returns the allocator associated with the container
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/
 | |
|     static allocator_type get_allocator()
 | |
|     {
 | |
|         return allocator_type();
 | |
|     }
 | |
| 
 | |
|     /// @brief returns version information on the library
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/meta/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json meta()
 | |
|     {
 | |
|         basic_json result;
 | |
| 
 | |
|         result["copyright"] = "(C) 2013-2023 Niels Lohmann";
 | |
|         result["name"] = "JSON for Modern C++";
 | |
|         result["url"] = "https://github.com/nlohmann/json";
 | |
|         result["version"]["string"] =
 | |
|             detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.',
 | |
|                            std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.',
 | |
|                            std::to_string(NLOHMANN_JSON_VERSION_PATCH));
 | |
|         result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
 | |
|         result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
 | |
|         result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
 | |
| 
 | |
| #ifdef _WIN32
 | |
|         result["platform"] = "win32";
 | |
| #elif defined __linux__
 | |
|         result["platform"] = "linux";
 | |
| #elif defined __APPLE__
 | |
|         result["platform"] = "apple";
 | |
| #elif defined __unix__
 | |
|         result["platform"] = "unix";
 | |
| #else
 | |
|         result["platform"] = "unknown";
 | |
| #endif
 | |
| 
 | |
| #if defined(__ICC) || defined(__INTEL_COMPILER)
 | |
|         result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
 | |
| #elif defined(__clang__)
 | |
|         result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
 | |
| #elif defined(__GNUC__) || defined(__GNUG__)
 | |
|         result["compiler"] = {{"family", "gcc"}, {"version", detail::concat(
 | |
|                     std::to_string(__GNUC__), '.',
 | |
|                     std::to_string(__GNUC_MINOR__), '.',
 | |
|                     std::to_string(__GNUC_PATCHLEVEL__))
 | |
|             }
 | |
|         };
 | |
| #elif defined(__HP_cc) || defined(__HP_aCC)
 | |
|         result["compiler"] = "hp"
 | |
| #elif defined(__IBMCPP__)
 | |
|         result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
 | |
| #elif defined(_MSC_VER)
 | |
|         result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
 | |
| #elif defined(__PGI)
 | |
|         result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
 | |
| #elif defined(__SUNPRO_CC)
 | |
|         result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
 | |
| #else
 | |
|         result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
 | |
| #endif
 | |
| 
 | |
| #if defined(_MSVC_LANG)
 | |
|         result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
 | |
| #elif defined(__cplusplus)
 | |
|         result["compiler"]["c++"] = std::to_string(__cplusplus);
 | |
| #else
 | |
|         result["compiler"]["c++"] = "unknown";
 | |
| #endif
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     ///////////////////////////
 | |
|     // JSON value data types //
 | |
|     ///////////////////////////
 | |
| 
 | |
|     /// @name JSON value data types
 | |
|     /// The data types to store a JSON value. These types are derived from
 | |
|     /// the template arguments passed to class @ref basic_json.
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief default object key comparator type
 | |
|     /// The actual object key comparator type (@ref object_comparator_t) may be
 | |
|     /// different.
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
 | |
| #if defined(JSON_HAS_CPP_14)
 | |
|     // use of transparent comparator avoids unnecessary repeated construction of temporaries
 | |
|     // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
 | |
|     using default_object_comparator_t = std::less<>;
 | |
| #else
 | |
|     using default_object_comparator_t = std::less<StringType>;
 | |
| #endif
 | |
| 
 | |
|     /// @brief a type for an object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/object_t/
 | |
|     using object_t = ObjectType<StringType,
 | |
|           basic_json,
 | |
|           default_object_comparator_t,
 | |
|           AllocatorType<std::pair<const StringType,
 | |
|           basic_json>>>;
 | |
| 
 | |
|     /// @brief a type for an array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/array_t/
 | |
|     using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
 | |
| 
 | |
|     /// @brief a type for a string
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/string_t/
 | |
|     using string_t = StringType;
 | |
| 
 | |
|     /// @brief a type for a boolean
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/
 | |
|     using boolean_t = BooleanType;
 | |
| 
 | |
|     /// @brief a type for a number (integer)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/
 | |
|     using number_integer_t = NumberIntegerType;
 | |
| 
 | |
|     /// @brief a type for a number (unsigned)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/
 | |
|     using number_unsigned_t = NumberUnsignedType;
 | |
| 
 | |
|     /// @brief a type for a number (floating-point)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/
 | |
|     using number_float_t = NumberFloatType;
 | |
| 
 | |
|     /// @brief a type for a packed binary type
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/binary_t/
 | |
|     using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
 | |
| 
 | |
|     /// @brief object key comparator type
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
 | |
|     using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|   private:
 | |
| 
 | |
|     /// helper for exception-safe object creation
 | |
|     template<typename T, typename... Args>
 | |
|     JSON_HEDLEY_RETURNS_NON_NULL
 | |
|     static T* create(Args&& ... args)
 | |
|     {
 | |
|         AllocatorType<T> alloc;
 | |
|         using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
 | |
| 
 | |
|         auto deleter = [&](T * obj)
 | |
|         {
 | |
|             AllocatorTraits::deallocate(alloc, obj, 1);
 | |
|         };
 | |
|         std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);
 | |
|         AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);
 | |
|         JSON_ASSERT(obj != nullptr);
 | |
|         return obj.release();
 | |
|     }
 | |
| 
 | |
|     ////////////////////////
 | |
|     // JSON value storage //
 | |
|     ////////////////////////
 | |
| 
 | |
|   JSON_PRIVATE_UNLESS_TESTED:
 | |
|     /*!
 | |
|     @brief a JSON value
 | |
| 
 | |
|     The actual storage for a JSON value of the @ref basic_json class. This
 | |
|     union combines the different storage types for the JSON value types
 | |
|     defined in @ref value_t.
 | |
| 
 | |
|     JSON type | value_t type    | used type
 | |
|     --------- | --------------- | ------------------------
 | |
|     object    | object          | pointer to @ref object_t
 | |
|     array     | array           | pointer to @ref array_t
 | |
|     string    | string          | pointer to @ref string_t
 | |
|     boolean   | boolean         | @ref boolean_t
 | |
|     number    | number_integer  | @ref number_integer_t
 | |
|     number    | number_unsigned | @ref number_unsigned_t
 | |
|     number    | number_float    | @ref number_float_t
 | |
|     binary    | binary          | pointer to @ref binary_t
 | |
|     null      | null            | *no value is stored*
 | |
| 
 | |
|     @note Variable-length types (objects, arrays, and strings) are stored as
 | |
|     pointers. The size of the union should not exceed 64 bits if the default
 | |
|     value types are used.
 | |
| 
 | |
|     @since version 1.0.0
 | |
|     */
 | |
|     union json_value
 | |
|     {
 | |
|         /// object (stored with pointer to save storage)
 | |
|         object_t* object;
 | |
|         /// array (stored with pointer to save storage)
 | |
|         array_t* array;
 | |
|         /// string (stored with pointer to save storage)
 | |
|         string_t* string;
 | |
|         /// binary (stored with pointer to save storage)
 | |
|         binary_t* binary;
 | |
|         /// boolean
 | |
|         boolean_t boolean;
 | |
|         /// number (integer)
 | |
|         number_integer_t number_integer;
 | |
|         /// number (unsigned integer)
 | |
|         number_unsigned_t number_unsigned;
 | |
|         /// number (floating-point)
 | |
|         number_float_t number_float;
 | |
| 
 | |
|         /// default constructor (for null values)
 | |
|         json_value() = default;
 | |
|         /// constructor for booleans
 | |
|         json_value(boolean_t v) noexcept : boolean(v) {}
 | |
|         /// constructor for numbers (integer)
 | |
|         json_value(number_integer_t v) noexcept : number_integer(v) {}
 | |
|         /// constructor for numbers (unsigned)
 | |
|         json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
 | |
|         /// constructor for numbers (floating-point)
 | |
|         json_value(number_float_t v) noexcept : number_float(v) {}
 | |
|         /// constructor for empty values of a given type
 | |
|         json_value(value_t t)
 | |
|         {
 | |
|             switch (t)
 | |
|             {
 | |
|                 case value_t::object:
 | |
|                 {
 | |
|                     object = create<object_t>();
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::array:
 | |
|                 {
 | |
|                     array = create<array_t>();
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::string:
 | |
|                 {
 | |
|                     string = create<string_t>("");
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::binary:
 | |
|                 {
 | |
|                     binary = create<binary_t>();
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::boolean:
 | |
|                 {
 | |
|                     boolean = static_cast<boolean_t>(false);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::number_integer:
 | |
|                 {
 | |
|                     number_integer = static_cast<number_integer_t>(0);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::number_unsigned:
 | |
|                 {
 | |
|                     number_unsigned = static_cast<number_unsigned_t>(0);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::number_float:
 | |
|                 {
 | |
|                     number_float = static_cast<number_float_t>(0.0);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::null:
 | |
|                 {
 | |
|                     object = nullptr;  // silence warning, see #821
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::discarded:
 | |
|                 default:
 | |
|                 {
 | |
|                     object = nullptr;  // silence warning, see #821
 | |
|                     if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
 | |
|                     {
 | |
|                         JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
 | |
|                     }
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// constructor for strings
 | |
|         json_value(const string_t& value) : string(create<string_t>(value)) {}
 | |
| 
 | |
|         /// constructor for rvalue strings
 | |
|         json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
 | |
| 
 | |
|         /// constructor for objects
 | |
|         json_value(const object_t& value) : object(create<object_t>(value)) {}
 | |
| 
 | |
|         /// constructor for rvalue objects
 | |
|         json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
 | |
| 
 | |
|         /// constructor for arrays
 | |
|         json_value(const array_t& value) : array(create<array_t>(value)) {}
 | |
| 
 | |
|         /// constructor for rvalue arrays
 | |
|         json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
 | |
| 
 | |
|         /// constructor for binary arrays
 | |
|         json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
 | |
| 
 | |
|         /// constructor for rvalue binary arrays
 | |
|         json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
 | |
| 
 | |
|         /// constructor for binary arrays (internal type)
 | |
|         json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
 | |
| 
 | |
|         /// constructor for rvalue binary arrays (internal type)
 | |
|         json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
 | |
| 
 | |
|         void destroy(value_t t)
 | |
|         {
 | |
|             if (
 | |
|                 (t == value_t::object && object == nullptr) ||
 | |
|                 (t == value_t::array && array == nullptr) ||
 | |
|                 (t == value_t::string && string == nullptr) ||
 | |
|                 (t == value_t::binary && binary == nullptr)
 | |
|             )
 | |
|             {
 | |
|                 //not initialized (e.g. due to exception in the ctor)
 | |
|                 return;
 | |
|             }
 | |
|             if (t == value_t::array || t == value_t::object)
 | |
|             {
 | |
|                 // flatten the current json_value to a heap-allocated stack
 | |
|                 std::vector<basic_json> stack;
 | |
| 
 | |
|                 // move the top-level items to stack
 | |
|                 if (t == value_t::array)
 | |
|                 {
 | |
|                     stack.reserve(array->size());
 | |
|                     std::move(array->begin(), array->end(), std::back_inserter(stack));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     stack.reserve(object->size());
 | |
|                     for (auto&& it : *object)
 | |
|                     {
 | |
|                         stack.push_back(std::move(it.second));
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 while (!stack.empty())
 | |
|                 {
 | |
|                     // move the last item to local variable to be processed
 | |
|                     basic_json current_item(std::move(stack.back()));
 | |
|                     stack.pop_back();
 | |
| 
 | |
|                     // if current_item is array/object, move
 | |
|                     // its children to the stack to be processed later
 | |
|                     if (current_item.is_array())
 | |
|                     {
 | |
|                         std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
 | |
| 
 | |
|                         current_item.m_data.m_value.array->clear();
 | |
|                     }
 | |
|                     else if (current_item.is_object())
 | |
|                     {
 | |
|                         for (auto&& it : *current_item.m_data.m_value.object)
 | |
|                         {
 | |
|                             stack.push_back(std::move(it.second));
 | |
|                         }
 | |
| 
 | |
|                         current_item.m_data.m_value.object->clear();
 | |
|                     }
 | |
| 
 | |
|                     // it's now safe that current_item get destructed
 | |
|                     // since it doesn't have any children
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             switch (t)
 | |
|             {
 | |
|                 case value_t::object:
 | |
|                 {
 | |
|                     AllocatorType<object_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::array:
 | |
|                 {
 | |
|                     AllocatorType<array_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::string:
 | |
|                 {
 | |
|                     AllocatorType<string_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::binary:
 | |
|                 {
 | |
|                     AllocatorType<binary_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::null:
 | |
|                 case value_t::boolean:
 | |
|                 case value_t::number_integer:
 | |
|                 case value_t::number_unsigned:
 | |
|                 case value_t::number_float:
 | |
|                 case value_t::discarded:
 | |
|                 default:
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     };
 | |
| 
 | |
|   private:
 | |
|     /*!
 | |
|     @brief checks the class invariants
 | |
| 
 | |
|     This function asserts the class invariants. It needs to be called at the
 | |
|     end of every constructor to make sure that created objects respect the
 | |
|     invariant. Furthermore, it has to be called each time the type of a JSON
 | |
|     value is changed, because the invariant expresses a relationship between
 | |
|     @a m_type and @a m_value.
 | |
| 
 | |
|     Furthermore, the parent relation is checked for arrays and objects: If
 | |
|     @a check_parents true and the value is an array or object, then the
 | |
|     container's elements must have the current value as parent.
 | |
| 
 | |
|     @param[in] check_parents  whether the parent relation should be checked.
 | |
|                The value is true by default and should only be set to false
 | |
|                during destruction of objects when the invariant does not
 | |
|                need to hold.
 | |
|     */
 | |
|     void assert_invariant(bool check_parents = true) const noexcept
 | |
|     {
 | |
|         JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr);
 | |
|         JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr);
 | |
|         JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr);
 | |
|         JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr);
 | |
| 
 | |
| #if JSON_DIAGNOSTICS
 | |
|         JSON_TRY
 | |
|         {
 | |
|             // cppcheck-suppress assertWithSideEffect
 | |
|             JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
 | |
|             {
 | |
|                 return j.m_parent == this;
 | |
|             }));
 | |
|         }
 | |
|         JSON_CATCH(...) {} // LCOV_EXCL_LINE
 | |
| #endif
 | |
|         static_cast<void>(check_parents);
 | |
|     }
 | |
| 
 | |
|     void set_parents()
 | |
|     {
 | |
| #if JSON_DIAGNOSTICS
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 for (auto& element : *m_data.m_value.array)
 | |
|                 {
 | |
|                     element.m_parent = this;
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 for (auto& element : *m_data.m_value.object)
 | |
|                 {
 | |
|                     element.second.m_parent = this;
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::string:
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::number_float:
 | |
|             case value_t::binary:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|                 break;
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)
 | |
|     {
 | |
| #if JSON_DIAGNOSTICS
 | |
|         for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)
 | |
|         {
 | |
|             (it + i)->m_parent = this;
 | |
|         }
 | |
| #else
 | |
|         static_cast<void>(count_set_parents);
 | |
| #endif
 | |
|         return it;
 | |
|     }
 | |
| 
 | |
|     reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1))
 | |
|     {
 | |
| #if JSON_DIAGNOSTICS
 | |
|         if (old_capacity != static_cast<std::size_t>(-1))
 | |
|         {
 | |
|             // see https://github.com/nlohmann/json/issues/2838
 | |
|             JSON_ASSERT(type() == value_t::array);
 | |
|             if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
 | |
|             {
 | |
|                 // capacity has changed: update all parents
 | |
|                 set_parents();
 | |
|                 return j;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // ordered_json uses a vector internally, so pointers could have
 | |
|         // been invalidated; see https://github.com/nlohmann/json/issues/2962
 | |
| #ifdef JSON_HEDLEY_MSVC_VERSION
 | |
| #pragma warning(push )
 | |
| #pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
 | |
| #endif
 | |
|         if (detail::is_ordered_map<object_t>::value)
 | |
|         {
 | |
|             set_parents();
 | |
|             return j;
 | |
|         }
 | |
| #ifdef JSON_HEDLEY_MSVC_VERSION
 | |
| #pragma warning( pop )
 | |
| #endif
 | |
| 
 | |
|         j.m_parent = this;
 | |
| #else
 | |
|         static_cast<void>(j);
 | |
|         static_cast<void>(old_capacity);
 | |
| #endif
 | |
|         return j;
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     //////////////////////////
 | |
|     // JSON parser callback //
 | |
|     //////////////////////////
 | |
| 
 | |
|     /// @brief parser event types
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/
 | |
|     using parse_event_t = detail::parse_event_t;
 | |
| 
 | |
|     /// @brief per-element parser callback type
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/
 | |
|     using parser_callback_t = detail::parser_callback_t<basic_json>;
 | |
| 
 | |
|     //////////////////
 | |
|     // constructors //
 | |
|     //////////////////
 | |
| 
 | |
|     /// @name constructors and destructors
 | |
|     /// Constructors of class @ref basic_json, copy/move constructor, copy
 | |
|     /// assignment, static functions creating objects, and the destructor.
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief create an empty value with a given type
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     basic_json(const value_t v)
 | |
|         : m_data(v)
 | |
|     {
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief create a null object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)
 | |
|         : basic_json(value_t::null)
 | |
|     {
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from compatible types
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     template < typename CompatibleType,
 | |
|                typename U = detail::uncvref_t<CompatibleType>,
 | |
|                detail::enable_if_t <
 | |
|                    !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
 | |
|     basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
 | |
|                 JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
 | |
|                                            std::forward<CompatibleType>(val))))
 | |
|     {
 | |
|         JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an existing one
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     template < typename BasicJsonType,
 | |
|                detail::enable_if_t <
 | |
|                    detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
 | |
|     basic_json(const BasicJsonType& val)
 | |
|     {
 | |
|         using other_boolean_t = typename BasicJsonType::boolean_t;
 | |
|         using other_number_float_t = typename BasicJsonType::number_float_t;
 | |
|         using other_number_integer_t = typename BasicJsonType::number_integer_t;
 | |
|         using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
 | |
|         using other_string_t = typename BasicJsonType::string_t;
 | |
|         using other_object_t = typename BasicJsonType::object_t;
 | |
|         using other_array_t = typename BasicJsonType::array_t;
 | |
|         using other_binary_t = typename BasicJsonType::binary_t;
 | |
| 
 | |
|         switch (val.type())
 | |
|         {
 | |
|             case value_t::boolean:
 | |
|                 JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
 | |
|                 break;
 | |
|             case value_t::number_float:
 | |
|                 JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
 | |
|                 break;
 | |
|             case value_t::number_integer:
 | |
|                 JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
 | |
|                 break;
 | |
|             case value_t::number_unsigned:
 | |
|                 JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
 | |
|                 break;
 | |
|             case value_t::string:
 | |
|                 JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
 | |
|                 break;
 | |
|             case value_t::object:
 | |
|                 JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
 | |
|                 break;
 | |
|             case value_t::array:
 | |
|                 JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
 | |
|                 break;
 | |
|             case value_t::binary:
 | |
|                 JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
 | |
|                 break;
 | |
|             case value_t::null:
 | |
|                 *this = nullptr;
 | |
|                 break;
 | |
|             case value_t::discarded:
 | |
|                 m_data.m_type = value_t::discarded;
 | |
|                 break;
 | |
|             default:            // LCOV_EXCL_LINE
 | |
|                 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
 | |
|         }
 | |
|         JSON_ASSERT(m_data.m_type == val.type());
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief create a container (array or object) from an initializer list
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     basic_json(initializer_list_t init,
 | |
|                bool type_deduction = true,
 | |
|                value_t manual_type = value_t::array)
 | |
|     {
 | |
|         // check if each element is an array with two elements whose first
 | |
|         // element is a string
 | |
|         bool is_an_object = std::all_of(init.begin(), init.end(),
 | |
|                                         [](const detail::json_ref<basic_json>& element_ref)
 | |
|         {
 | |
|             // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int;
 | |
|             // (many string types can be constructed from 0 via its null-pointer guise, so we get a
 | |
|             // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows)
 | |
|             return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string();
 | |
|         });
 | |
| 
 | |
|         // adjust type if type deduction is not wanted
 | |
|         if (!type_deduction)
 | |
|         {
 | |
|             // if array is wanted, do not create an object though possible
 | |
|             if (manual_type == value_t::array)
 | |
|             {
 | |
|                 is_an_object = false;
 | |
|             }
 | |
| 
 | |
|             // if object is wanted but impossible, throw an exception
 | |
|             if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
 | |
|             {
 | |
|                 JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (is_an_object)
 | |
|         {
 | |
|             // the initializer list is a list of pairs -> create object
 | |
|             m_data.m_type = value_t::object;
 | |
|             m_data.m_value = value_t::object;
 | |
| 
 | |
|             for (auto& element_ref : init)
 | |
|             {
 | |
|                 auto element = element_ref.moved_or_copied();
 | |
|                 m_data.m_value.object->emplace(
 | |
|                     std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)),
 | |
|                     std::move((*element.m_data.m_value.array)[1]));
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // the initializer list describes an array -> create array
 | |
|             m_data.m_type = value_t::array;
 | |
|             m_data.m_value.array = create<array_t>(init.begin(), init.end());
 | |
|         }
 | |
| 
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief explicitly create a binary array (without subtype)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/binary/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json binary(const typename binary_t::container_type& init)
 | |
|     {
 | |
|         auto res = basic_json();
 | |
|         res.m_data.m_type = value_t::binary;
 | |
|         res.m_data.m_value = init;
 | |
|         return res;
 | |
|     }
 | |
| 
 | |
|     /// @brief explicitly create a binary array (with subtype)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/binary/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
 | |
|     {
 | |
|         auto res = basic_json();
 | |
|         res.m_data.m_type = value_t::binary;
 | |
|         res.m_data.m_value = binary_t(init, subtype);
 | |
|         return res;
 | |
|     }
 | |
| 
 | |
|     /// @brief explicitly create a binary array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/binary/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json binary(typename binary_t::container_type&& init)
 | |
|     {
 | |
|         auto res = basic_json();
 | |
|         res.m_data.m_type = value_t::binary;
 | |
|         res.m_data.m_value = std::move(init);
 | |
|         return res;
 | |
|     }
 | |
| 
 | |
|     /// @brief explicitly create a binary array (with subtype)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/binary/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
 | |
|     {
 | |
|         auto res = basic_json();
 | |
|         res.m_data.m_type = value_t::binary;
 | |
|         res.m_data.m_value = binary_t(std::move(init), subtype);
 | |
|         return res;
 | |
|     }
 | |
| 
 | |
|     /// @brief explicitly create an array from an initializer list
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/array/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json array(initializer_list_t init = {})
 | |
|     {
 | |
|         return basic_json(init, false, value_t::array);
 | |
|     }
 | |
| 
 | |
|     /// @brief explicitly create an object from an initializer list
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/object/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json object(initializer_list_t init = {})
 | |
|     {
 | |
|         return basic_json(init, false, value_t::object);
 | |
|     }
 | |
| 
 | |
|     /// @brief construct an array with count copies of given value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     basic_json(size_type cnt, const basic_json& val):
 | |
|         m_data{cnt, val}
 | |
|     {
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief construct a JSON container given an iterator range
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     template < class InputIT, typename std::enable_if <
 | |
|                    std::is_same<InputIT, typename basic_json_t::iterator>::value ||
 | |
|                    std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
 | |
|     basic_json(InputIT first, InputIT last)
 | |
|     {
 | |
|         JSON_ASSERT(first.m_object != nullptr);
 | |
|         JSON_ASSERT(last.m_object != nullptr);
 | |
| 
 | |
|         // make sure iterator fits the current value
 | |
|         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
 | |
|         }
 | |
| 
 | |
|         // copy type from first iterator
 | |
|         m_data.m_type = first.m_object->m_data.m_type;
 | |
| 
 | |
|         // check if iterator range is complete for primitive values
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_float:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::string:
 | |
|             {
 | |
|                 if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
 | |
|                                          || !last.m_it.primitive_iterator.is_end()))
 | |
|                 {
 | |
|                     JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::object:
 | |
|             case value_t::array:
 | |
|             case value_t::binary:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::number_integer:
 | |
|             {
 | |
|                 m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::number_unsigned:
 | |
|             {
 | |
|                 m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::number_float:
 | |
|             {
 | |
|                 m_data.m_value.number_float = first.m_object->m_data.m_value.number_float;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::boolean:
 | |
|             {
 | |
|                 m_data.m_value.boolean = first.m_object->m_data.m_value.boolean;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::string:
 | |
|             {
 | |
|                 m_data.m_value = *first.m_object->m_data.m_value.string;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 m_data.m_value.object = create<object_t>(first.m_it.object_iterator,
 | |
|                                         last.m_it.object_iterator);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 m_data.m_value.array = create<array_t>(first.m_it.array_iterator,
 | |
|                                                        last.m_it.array_iterator);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::binary:
 | |
|             {
 | |
|                 m_data.m_value = *first.m_object->m_data.m_value.binary;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|                 JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
 | |
|         }
 | |
| 
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     ///////////////////////////////////////
 | |
|     // other constructors and destructor //
 | |
|     ///////////////////////////////////////
 | |
| 
 | |
|     template<typename JsonRef,
 | |
|              detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
 | |
|                                  std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
 | |
|     basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
 | |
| 
 | |
|     /// @brief copy constructor
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     basic_json(const basic_json& other)
 | |
|         : json_base_class_t(other)
 | |
|     {
 | |
|         m_data.m_type = other.m_data.m_type;
 | |
|         // check of passed value is valid
 | |
|         other.assert_invariant();
 | |
| 
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 m_data.m_value = *other.m_data.m_value.object;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 m_data.m_value = *other.m_data.m_value.array;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::string:
 | |
|             {
 | |
|                 m_data.m_value = *other.m_data.m_value.string;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::boolean:
 | |
|             {
 | |
|                 m_data.m_value = other.m_data.m_value.boolean;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::number_integer:
 | |
|             {
 | |
|                 m_data.m_value = other.m_data.m_value.number_integer;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::number_unsigned:
 | |
|             {
 | |
|                 m_data.m_value = other.m_data.m_value.number_unsigned;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::number_float:
 | |
|             {
 | |
|                 m_data.m_value = other.m_data.m_value.number_float;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::binary:
 | |
|             {
 | |
|                 m_data.m_value = *other.m_data.m_value.binary;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief move constructor
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
 | |
|     basic_json(basic_json&& other) noexcept
 | |
|         : json_base_class_t(std::forward<json_base_class_t>(other)),
 | |
|           m_data(std::move(other.m_data))
 | |
|     {
 | |
|         // check that passed value is valid
 | |
|         other.assert_invariant(false);
 | |
| 
 | |
|         // invalidate payload
 | |
|         other.m_data.m_type = value_t::null;
 | |
|         other.m_data.m_value = {};
 | |
| 
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief copy assignment
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator=/
 | |
|     basic_json& operator=(basic_json other) noexcept (
 | |
|         std::is_nothrow_move_constructible<value_t>::value&&
 | |
|         std::is_nothrow_move_assignable<value_t>::value&&
 | |
|         std::is_nothrow_move_constructible<json_value>::value&&
 | |
|         std::is_nothrow_move_assignable<json_value>::value&&
 | |
|         std::is_nothrow_move_assignable<json_base_class_t>::value
 | |
|     )
 | |
|     {
 | |
|         // check that passed value is valid
 | |
|         other.assert_invariant();
 | |
| 
 | |
|         using std::swap;
 | |
|         swap(m_data.m_type, other.m_data.m_type);
 | |
|         swap(m_data.m_value, other.m_data.m_value);
 | |
|         json_base_class_t::operator=(std::move(other));
 | |
| 
 | |
|         set_parents();
 | |
|         assert_invariant();
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     /// @brief destructor
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/
 | |
|     ~basic_json() noexcept
 | |
|     {
 | |
|         assert_invariant(false);
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|   public:
 | |
|     ///////////////////////
 | |
|     // object inspection //
 | |
|     ///////////////////////
 | |
| 
 | |
|     /// @name object inspection
 | |
|     /// Functions to inspect the type of a JSON value.
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief serialization
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/dump/
 | |
|     string_t dump(const int indent = -1,
 | |
|                   const char indent_char = ' ',
 | |
|                   const bool ensure_ascii = false,
 | |
|                   const error_handler_t error_handler = error_handler_t::strict) const
 | |
|     {
 | |
|         string_t result;
 | |
|         serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
 | |
| 
 | |
|         if (indent >= 0)
 | |
|         {
 | |
|             s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             s.dump(*this, false, ensure_ascii, 0);
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief return the type of the JSON value (explicit)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/type/
 | |
|     constexpr value_t type() const noexcept
 | |
|     {
 | |
|         return m_data.m_type;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether type is primitive
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
 | |
|     constexpr bool is_primitive() const noexcept
 | |
|     {
 | |
|         return is_null() || is_string() || is_boolean() || is_number() || is_binary();
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether type is structured
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
 | |
|     constexpr bool is_structured() const noexcept
 | |
|     {
 | |
|         return is_array() || is_object();
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is null
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_null/
 | |
|     constexpr bool is_null() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::null;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is a boolean
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
 | |
|     constexpr bool is_boolean() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::boolean;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is a number
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_number/
 | |
|     constexpr bool is_number() const noexcept
 | |
|     {
 | |
|         return is_number_integer() || is_number_float();
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is an integer number
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
 | |
|     constexpr bool is_number_integer() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is an unsigned integer number
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
 | |
|     constexpr bool is_number_unsigned() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::number_unsigned;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is a floating-point number
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
 | |
|     constexpr bool is_number_float() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::number_float;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is an object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_object/
 | |
|     constexpr bool is_object() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::object;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is an array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_array/
 | |
|     constexpr bool is_array() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::array;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is a string
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_string/
 | |
|     constexpr bool is_string() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::string;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is a binary array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
 | |
|     constexpr bool is_binary() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::binary;
 | |
|     }
 | |
| 
 | |
|     /// @brief return whether value is discarded
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
 | |
|     constexpr bool is_discarded() const noexcept
 | |
|     {
 | |
|         return m_data.m_type == value_t::discarded;
 | |
|     }
 | |
| 
 | |
|     /// @brief return the type of the JSON value (implicit)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/
 | |
|     constexpr operator value_t() const noexcept
 | |
|     {
 | |
|         return m_data.m_type;
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|   private:
 | |
|     //////////////////
 | |
|     // value access //
 | |
|     //////////////////
 | |
| 
 | |
|     /// get a boolean (explicit)
 | |
|     boolean_t get_impl(boolean_t* /*unused*/) const
 | |
|     {
 | |
|         if (JSON_HEDLEY_LIKELY(is_boolean()))
 | |
|         {
 | |
|             return m_data.m_value.boolean;
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (object)
 | |
|     object_t* get_impl_ptr(object_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_object() ? m_data.m_value.object : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (object)
 | |
|     constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_object() ? m_data.m_value.object : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (array)
 | |
|     array_t* get_impl_ptr(array_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_array() ? m_data.m_value.array : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (array)
 | |
|     constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_array() ? m_data.m_value.array : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (string)
 | |
|     string_t* get_impl_ptr(string_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_string() ? m_data.m_value.string : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (string)
 | |
|     constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_string() ? m_data.m_value.string : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (boolean)
 | |
|     boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_boolean() ? &m_data.m_value.boolean : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (boolean)
 | |
|     constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_boolean() ? &m_data.m_value.boolean : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (integer number)
 | |
|     number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (integer number)
 | |
|     constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (unsigned number)
 | |
|     number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (unsigned number)
 | |
|     constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (floating-point number)
 | |
|     number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_number_float() ? &m_data.m_value.number_float : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (floating-point number)
 | |
|     constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_number_float() ? &m_data.m_value.number_float : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (binary)
 | |
|     binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
 | |
|     {
 | |
|         return is_binary() ? m_data.m_value.binary : nullptr;
 | |
|     }
 | |
| 
 | |
|     /// get a pointer to the value (binary)
 | |
|     constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
 | |
|     {
 | |
|         return is_binary() ? m_data.m_value.binary : nullptr;
 | |
|     }
 | |
| 
 | |
|     /*!
 | |
|     @brief helper function to implement get_ref()
 | |
| 
 | |
|     This function helps to implement get_ref() without code duplication for
 | |
|     const and non-const overloads
 | |
| 
 | |
|     @tparam ThisType will be deduced as `basic_json` or `const basic_json`
 | |
| 
 | |
|     @throw type_error.303 if ReferenceType does not match underlying value
 | |
|     type of the current JSON
 | |
|     */
 | |
|     template<typename ReferenceType, typename ThisType>
 | |
|     static ReferenceType get_ref_impl(ThisType& obj)
 | |
|     {
 | |
|         // delegate the call to get_ptr<>()
 | |
|         auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
 | |
| 
 | |
|         if (JSON_HEDLEY_LIKELY(ptr != nullptr))
 | |
|         {
 | |
|             return *ptr;
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     /// @name value access
 | |
|     /// Direct access to the stored value of a JSON value.
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief get a pointer value (implicit)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
 | |
|     template<typename PointerType, typename std::enable_if<
 | |
|                  std::is_pointer<PointerType>::value, int>::type = 0>
 | |
|     auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
 | |
|     {
 | |
|         // delegate the call to get_impl_ptr<>()
 | |
|         return get_impl_ptr(static_cast<PointerType>(nullptr));
 | |
|     }
 | |
| 
 | |
|     /// @brief get a pointer value (implicit)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
 | |
|     template < typename PointerType, typename std::enable_if <
 | |
|                    std::is_pointer<PointerType>::value&&
 | |
|                    std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
 | |
|     constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
 | |
|     {
 | |
|         // delegate the call to get_impl_ptr<>() const
 | |
|         return get_impl_ptr(static_cast<PointerType>(nullptr));
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     /*!
 | |
|     @brief get a value (explicit)
 | |
| 
 | |
|     Explicit type conversion between the JSON value and a compatible value
 | |
|     which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
 | |
|     and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
 | |
|     The value is converted by calling the @ref json_serializer<ValueType>
 | |
|     `from_json()` method.
 | |
| 
 | |
|     The function is equivalent to executing
 | |
|     @code {.cpp}
 | |
|     ValueType ret;
 | |
|     JSONSerializer<ValueType>::from_json(*this, ret);
 | |
|     return ret;
 | |
|     @endcode
 | |
| 
 | |
|     This overloads is chosen if:
 | |
|     - @a ValueType is not @ref basic_json,
 | |
|     - @ref json_serializer<ValueType> has a `from_json()` method of the form
 | |
|       `void from_json(const basic_json&, ValueType&)`, and
 | |
|     - @ref json_serializer<ValueType> does not have a `from_json()` method of
 | |
|       the form `ValueType from_json(const basic_json&)`
 | |
| 
 | |
|     @tparam ValueType the returned value type
 | |
| 
 | |
|     @return copy of the JSON value, converted to @a ValueType
 | |
| 
 | |
|     @throw what @ref json_serializer<ValueType> `from_json()` method throws
 | |
| 
 | |
|     @liveexample{The example below shows several conversions from JSON values
 | |
|     to other types. There a few things to note: (1) Floating-point numbers can
 | |
|     be converted to integers\, (2) A JSON array can be converted to a standard
 | |
|     `std::vector<short>`\, (3) A JSON object can be converted to C++
 | |
|     associative containers such as `std::unordered_map<std::string\,
 | |
|     json>`.,get__ValueType_const}
 | |
| 
 | |
|     @since version 2.1.0
 | |
|     */
 | |
|     template < typename ValueType,
 | |
|                detail::enable_if_t <
 | |
|                    detail::is_default_constructible<ValueType>::value&&
 | |
|                    detail::has_from_json<basic_json_t, ValueType>::value,
 | |
|                    int > = 0 >
 | |
|     ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
 | |
|                 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
 | |
|     {
 | |
|         auto ret = ValueType();
 | |
|         JSONSerializer<ValueType>::from_json(*this, ret);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     /*!
 | |
|     @brief get a value (explicit); special case
 | |
| 
 | |
|     Explicit type conversion between the JSON value and a compatible value
 | |
|     which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
 | |
|     and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
 | |
|     The value is converted by calling the @ref json_serializer<ValueType>
 | |
|     `from_json()` method.
 | |
| 
 | |
|     The function is equivalent to executing
 | |
|     @code {.cpp}
 | |
|     return JSONSerializer<ValueType>::from_json(*this);
 | |
|     @endcode
 | |
| 
 | |
|     This overloads is chosen if:
 | |
|     - @a ValueType is not @ref basic_json and
 | |
|     - @ref json_serializer<ValueType> has a `from_json()` method of the form
 | |
|       `ValueType from_json(const basic_json&)`
 | |
| 
 | |
|     @note If @ref json_serializer<ValueType> has both overloads of
 | |
|     `from_json()`, this one is chosen.
 | |
| 
 | |
|     @tparam ValueType the returned value type
 | |
| 
 | |
|     @return copy of the JSON value, converted to @a ValueType
 | |
| 
 | |
|     @throw what @ref json_serializer<ValueType> `from_json()` method throws
 | |
| 
 | |
|     @since version 2.1.0
 | |
|     */
 | |
|     template < typename ValueType,
 | |
|                detail::enable_if_t <
 | |
|                    detail::has_non_default_from_json<basic_json_t, ValueType>::value,
 | |
|                    int > = 0 >
 | |
|     ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
 | |
|                 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
 | |
|     {
 | |
|         return JSONSerializer<ValueType>::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<BasicJsonType>::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<typename BasicJsonType,
 | |
|              detail::enable_if_t<
 | |
|                  std::is_same<BasicJsonType, basic_json_t>::value,
 | |
|                  int> = 0>
 | |
|     basic_json get_impl(detail::priority_tag<3> /*unused*/) const
 | |
|     {
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     /*!
 | |
|     @brief get a pointer value (explicit)
 | |
|     @copydoc get()
 | |
|     */
 | |
|     template<typename PointerType,
 | |
|              detail::enable_if_t<
 | |
|                  std::is_pointer<PointerType>::value,
 | |
|                  int> = 0>
 | |
|     constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
 | |
|     -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
 | |
|     {
 | |
|         // delegate the call to get_ptr
 | |
|         return get_ptr<PointerType>();
 | |
|     }
 | |
| 
 | |
|   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<ValueType> `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<ValueType> `from_json()` method throws if conversion is required
 | |
| 
 | |
|     @since version 2.1.0
 | |
|     */
 | |
|     template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
 | |
| #if defined(JSON_HAS_CPP_14)
 | |
|     constexpr
 | |
| #endif
 | |
|     auto get() const noexcept(
 | |
|     noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))
 | |
|     -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
 | |
|     {
 | |
|         // we cannot static_assert on ValueTypeCV being non-const, because
 | |
|         // there is support for get<const basic_json_t>(), which is why we
 | |
|         // still need the uncvref
 | |
|         static_assert(!std::is_reference<ValueTypeCV>::value,
 | |
|                       "get() cannot be used with reference types, you might want to use get_ref()");
 | |
|         return get_impl<ValueType>(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<typename PointerType, typename std::enable_if<
 | |
|                  std::is_pointer<PointerType>::value, int>::type = 0>
 | |
|     auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
 | |
|     {
 | |
|         // delegate the call to get_ptr
 | |
|         return get_ptr<PointerType>();
 | |
|     }
 | |
| 
 | |
|     /// @brief get a value (explicit)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_to/
 | |
|     template < typename ValueType,
 | |
|                detail::enable_if_t <
 | |
|                    !detail::is_basic_json<ValueType>::value&&
 | |
|                    detail::has_from_json<basic_json_t, ValueType>::value,
 | |
|                    int > = 0 >
 | |
|     ValueType & get_to(ValueType& v) const noexcept(noexcept(
 | |
|                 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
 | |
|     {
 | |
|         JSONSerializer<ValueType>::from_json(*this, v);
 | |
|         return v;
 | |
|     }
 | |
| 
 | |
|     // specialization to allow calling get_to with a basic_json value
 | |
|     // see https://github.com/nlohmann/json/issues/2175
 | |
|     template<typename ValueType,
 | |
|              detail::enable_if_t <
 | |
|                  detail::is_basic_json<ValueType>::value,
 | |
|                  int> = 0>
 | |
|     ValueType & get_to(ValueType& v) const
 | |
|     {
 | |
|         v = *this;
 | |
|         return v;
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         typename T, std::size_t N,
 | |
|         typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
 | |
|         detail::enable_if_t <
 | |
|             detail::has_from_json<basic_json_t, Array>::value, int > = 0 >
 | |
|     Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
 | |
|     noexcept(noexcept(JSONSerializer<Array>::from_json(
 | |
|                           std::declval<const basic_json_t&>(), v)))
 | |
|     {
 | |
|         JSONSerializer<Array>::from_json(*this, v);
 | |
|         return v;
 | |
|     }
 | |
| 
 | |
|     /// @brief get a reference value (implicit)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
 | |
|     template<typename ReferenceType, typename std::enable_if<
 | |
|                  std::is_reference<ReferenceType>::value, int>::type = 0>
 | |
|     ReferenceType get_ref()
 | |
|     {
 | |
|         // delegate call to get_ref_impl
 | |
|         return get_ref_impl<ReferenceType>(*this);
 | |
|     }
 | |
| 
 | |
|     /// @brief get a reference value (implicit)
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
 | |
|     template < typename ReferenceType, typename std::enable_if <
 | |
|                    std::is_reference<ReferenceType>::value&&
 | |
|                    std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
 | |
|     ReferenceType get_ref() const
 | |
|     {
 | |
|         // delegate call to get_ref_impl
 | |
|         return get_ref_impl<ReferenceType>(*this);
 | |
|     }
 | |
| 
 | |
|     /*!
 | |
|     @brief get a value (implicit)
 | |
| 
 | |
|     Implicit type conversion between the JSON value and a compatible value.
 | |
|     The call is realized by calling @ref get() const.
 | |
| 
 | |
|     @tparam ValueType non-pointer type compatible to the JSON value, for
 | |
|     instance `int` for JSON integer numbers, `bool` for JSON booleans, or
 | |
|     `std::vector` types for JSON arrays. The character type of @ref string_t
 | |
|     as well as an initializer list of this type is excluded to avoid
 | |
|     ambiguities as these types implicitly convert to `std::string`.
 | |
| 
 | |
|     @return copy of the JSON value, converted to type @a ValueType
 | |
| 
 | |
|     @throw type_error.302 in case passed type @a ValueType is incompatible
 | |
|     to the JSON value type (e.g., the JSON value is of type boolean, but a
 | |
|     string is requested); see example below
 | |
| 
 | |
|     @complexity Linear in the size of the JSON value.
 | |
| 
 | |
|     @liveexample{The example below shows several conversions from JSON values
 | |
|     to other types. There a few things to note: (1) Floating-point numbers can
 | |
|     be converted to integers\, (2) A JSON array can be converted to a standard
 | |
|     `std::vector<short>`\, (3) A JSON object can be converted to C++
 | |
|     associative containers such as `std::unordered_map<std::string\,
 | |
|     json>`.,operator__ValueType}
 | |
| 
 | |
|     @since version 1.0.0
 | |
|     */
 | |
|     template < typename ValueType, typename std::enable_if <
 | |
|                    detail::conjunction <
 | |
|                        detail::negation<std::is_pointer<ValueType>>,
 | |
|                        detail::negation<std::is_same<ValueType, std::nullptr_t>>,
 | |
|                        detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
 | |
|                                         detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
 | |
|                                         detail::negation<detail::is_basic_json<ValueType>>,
 | |
|                                         detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,
 | |
| #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
 | |
|                                                 detail::negation<std::is_same<ValueType, std::string_view>>,
 | |
| #endif
 | |
| #if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI
 | |
|                                                 detail::negation<std::is_same<ValueType, std::any>>,
 | |
| #endif
 | |
|                                                 detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
 | |
|                                                 >::value, int >::type = 0 >
 | |
|                                         JSON_EXPLICIT operator ValueType() const
 | |
|     {
 | |
|         // delegate the call to get<>() const
 | |
|         return get<ValueType>();
 | |
|     }
 | |
| 
 | |
|     /// @brief get a binary value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
 | |
|     binary_t& get_binary()
 | |
|     {
 | |
|         if (!is_binary())
 | |
|         {
 | |
|             JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         return *get_ptr<binary_t*>();
 | |
|     }
 | |
| 
 | |
|     /// @brief get a binary value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
 | |
|     const binary_t& get_binary() const
 | |
|     {
 | |
|         if (!is_binary())
 | |
|         {
 | |
|             JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         return *get_ptr<const binary_t*>();
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     ////////////////////
 | |
|     // element access //
 | |
|     ////////////////////
 | |
| 
 | |
|     /// @name element access
 | |
|     /// Access to the JSON value.
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief access specified array element with bounds checking
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     reference at(size_type idx)
 | |
|     {
 | |
|         // at only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             JSON_TRY
 | |
|             {
 | |
|                 return set_parent(m_data.m_value.array->at(idx));
 | |
|             }
 | |
|             JSON_CATCH (std::out_of_range&)
 | |
|             {
 | |
|                 // create better exception explanation
 | |
|                 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified array element with bounds checking
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     const_reference at(size_type idx) const
 | |
|     {
 | |
|         // at only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             JSON_TRY
 | |
|             {
 | |
|                 return m_data.m_value.array->at(idx);
 | |
|             }
 | |
|             JSON_CATCH (std::out_of_range&)
 | |
|             {
 | |
|                 // create better exception explanation
 | |
|                 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element with bounds checking
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     reference at(const typename object_t::key_type& key)
 | |
|     {
 | |
|         // at only works for objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         auto it = m_data.m_value.object->find(key);
 | |
|         if (it == m_data.m_value.object->end())
 | |
|         {
 | |
|             JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
 | |
|         }
 | |
|         return set_parent(it->second);
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element with bounds checking
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
 | |
|     reference at(KeyType && key)
 | |
|     {
 | |
|         // at only works for objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
 | |
|         if (it == m_data.m_value.object->end())
 | |
|         {
 | |
|             JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
 | |
|         }
 | |
|         return set_parent(it->second);
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element with bounds checking
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     const_reference at(const typename object_t::key_type& key) const
 | |
|     {
 | |
|         // at only works for objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         auto it = m_data.m_value.object->find(key);
 | |
|         if (it == m_data.m_value.object->end())
 | |
|         {
 | |
|             JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
 | |
|         }
 | |
|         return it->second;
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element with bounds checking
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
 | |
|     const_reference at(KeyType && key) const
 | |
|     {
 | |
|         // at only works for objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
 | |
|         if (it == m_data.m_value.object->end())
 | |
|         {
 | |
|             JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
 | |
|         }
 | |
|         return it->second;
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified array element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     reference operator[](size_type idx)
 | |
|     {
 | |
|         // implicitly convert null value to an empty array
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::array;
 | |
|             m_data.m_value.array = create<array_t>();
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // operator[] only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             // fill up array with null values if given idx is outside range
 | |
|             if (idx >= m_data.m_value.array->size())
 | |
|             {
 | |
| #if JSON_DIAGNOSTICS
 | |
|                 // remember array size & capacity before resizing
 | |
|                 const auto old_size = m_data.m_value.array->size();
 | |
|                 const auto old_capacity = m_data.m_value.array->capacity();
 | |
| #endif
 | |
|                 m_data.m_value.array->resize(idx + 1);
 | |
| 
 | |
| #if JSON_DIAGNOSTICS
 | |
|                 if (JSON_HEDLEY_UNLIKELY(m_data.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_data.m_value.array->operator[](idx);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified array element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     const_reference operator[](size_type idx) const
 | |
|     {
 | |
|         // const operator[] only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             return m_data.m_value.array->operator[](idx);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     reference operator[](typename object_t::key_type key)
 | |
|     {
 | |
|         // implicitly convert null value to an empty object
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::object;
 | |
|             m_data.m_value.object = create<object_t>();
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // operator[] only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             auto result = m_data.m_value.object->emplace(std::move(key), nullptr);
 | |
|             return set_parent(result.first->second);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     const_reference operator[](const typename object_t::key_type& key) const
 | |
|     {
 | |
|         // const operator[] only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             auto it = m_data.m_value.object->find(key);
 | |
|             JSON_ASSERT(it != m_data.m_value.object->end());
 | |
|             return it->second;
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
 | |
|     // (they seemingly cannot be constrained to resolve the ambiguity)
 | |
|     template<typename T>
 | |
|     reference operator[](T* key)
 | |
|     {
 | |
|         return operator[](typename object_t::key_type(key));
 | |
|     }
 | |
| 
 | |
|     template<typename T>
 | |
|     const_reference operator[](T* key) const
 | |
|     {
 | |
|         return operator[](typename object_t::key_type(key));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
 | |
|     reference operator[](KeyType && key)
 | |
|     {
 | |
|         // implicitly convert null value to an empty object
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::object;
 | |
|             m_data.m_value.object = create<object_t>();
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // operator[] only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
 | |
|             return set_parent(result.first->second);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
 | |
|     const_reference operator[](KeyType && key) const
 | |
|     {
 | |
|         // const operator[] only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
 | |
|             JSON_ASSERT(it != m_data.m_value.object->end());
 | |
|             return it->second;
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     template<typename KeyType>
 | |
|     using is_comparable_with_object_key = detail::is_comparable <
 | |
|         object_comparator_t, const typename object_t::key_type&, KeyType >;
 | |
| 
 | |
|     template<typename ValueType>
 | |
|     using value_return_type = std::conditional <
 | |
|         detail::is_c_string_uncvref<ValueType>::value,
 | |
|         string_t, typename std::decay<ValueType>::type >;
 | |
| 
 | |
|   public:
 | |
|     /// @brief access specified object element with default value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/value/
 | |
|     template < class ValueType, detail::enable_if_t <
 | |
|                    !detail::is_transparent<object_comparator_t>::value
 | |
|                    && detail::is_getable<basic_json_t, ValueType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
 | |
|     {
 | |
|         // value only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             // if key is found, return value and given default value otherwise
 | |
|             const auto it = find(key);
 | |
|             if (it != end())
 | |
|             {
 | |
|                 return it->template get<ValueType>();
 | |
|             }
 | |
| 
 | |
|             return default_value;
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element with default value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/value/
 | |
|     template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
 | |
|                detail::enable_if_t <
 | |
|                    !detail::is_transparent<object_comparator_t>::value
 | |
|                    && detail::is_getable<basic_json_t, ReturnType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
 | |
|     {
 | |
|         // value only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             // if key is found, return value and given default value otherwise
 | |
|             const auto it = find(key);
 | |
|             if (it != end())
 | |
|             {
 | |
|                 return it->template get<ReturnType>();
 | |
|             }
 | |
| 
 | |
|             return std::forward<ValueType>(default_value);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element with default value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/value/
 | |
|     template < class ValueType, class KeyType, detail::enable_if_t <
 | |
|                    detail::is_transparent<object_comparator_t>::value
 | |
|                    && !detail::is_json_pointer<KeyType>::value
 | |
|                    && is_comparable_with_object_key<KeyType>::value
 | |
|                    && detail::is_getable<basic_json_t, ValueType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     ValueType value(KeyType && key, const ValueType& default_value) const
 | |
|     {
 | |
|         // value only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             // if key is found, return value and given default value otherwise
 | |
|             const auto it = find(std::forward<KeyType>(key));
 | |
|             if (it != end())
 | |
|             {
 | |
|                 return it->template get<ValueType>();
 | |
|             }
 | |
| 
 | |
|             return default_value;
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element via JSON Pointer with default value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/value/
 | |
|     template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
 | |
|                detail::enable_if_t <
 | |
|                    detail::is_transparent<object_comparator_t>::value
 | |
|                    && !detail::is_json_pointer<KeyType>::value
 | |
|                    && is_comparable_with_object_key<KeyType>::value
 | |
|                    && detail::is_getable<basic_json_t, ReturnType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     ReturnType value(KeyType && key, ValueType && default_value) const
 | |
|     {
 | |
|         // value only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             // if key is found, return value and given default value otherwise
 | |
|             const auto it = find(std::forward<KeyType>(key));
 | |
|             if (it != end())
 | |
|             {
 | |
|                 return it->template get<ReturnType>();
 | |
|             }
 | |
| 
 | |
|             return std::forward<ValueType>(default_value);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element via JSON Pointer with default value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/value/
 | |
|     template < class ValueType, detail::enable_if_t <
 | |
|                    detail::is_getable<basic_json_t, ValueType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     ValueType value(const json_pointer& ptr, const ValueType& default_value) const
 | |
|     {
 | |
|         // value only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             // if pointer resolves a value, return it or use default value
 | |
|             JSON_TRY
 | |
|             {
 | |
|                 return ptr.get_checked(this).template get<ValueType>();
 | |
|             }
 | |
|             JSON_INTERNAL_CATCH (out_of_range&)
 | |
|             {
 | |
|                 return default_value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified object element via JSON Pointer with default value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/value/
 | |
|     template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
 | |
|                detail::enable_if_t <
 | |
|                    detail::is_getable<basic_json_t, ReturnType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     ReturnType value(const json_pointer& ptr, ValueType && default_value) const
 | |
|     {
 | |
|         // value only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             // if pointer resolves a value, return it or use default value
 | |
|             JSON_TRY
 | |
|             {
 | |
|                 return ptr.get_checked(this).template get<ReturnType>();
 | |
|             }
 | |
|             JSON_INTERNAL_CATCH (out_of_range&)
 | |
|             {
 | |
|                 return std::forward<ValueType>(default_value);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     template < class ValueType, class BasicJsonType, detail::enable_if_t <
 | |
|                    detail::is_basic_json<BasicJsonType>::value
 | |
|                    && detail::is_getable<basic_json_t, ValueType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
 | |
|     ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
 | |
|     {
 | |
|         return value(ptr.convert(), default_value);
 | |
|     }
 | |
| 
 | |
|     template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
 | |
|                detail::enable_if_t <
 | |
|                    detail::is_basic_json<BasicJsonType>::value
 | |
|                    && detail::is_getable<basic_json_t, ReturnType>::value
 | |
|                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
 | |
|     ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
 | |
|     {
 | |
|         return value(ptr.convert(), std::forward<ValueType>(default_value));
 | |
|     }
 | |
| 
 | |
|     /// @brief access the first element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/front/
 | |
|     reference front()
 | |
|     {
 | |
|         return *begin();
 | |
|     }
 | |
| 
 | |
|     /// @brief access the first element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/front/
 | |
|     const_reference front() const
 | |
|     {
 | |
|         return *cbegin();
 | |
|     }
 | |
| 
 | |
|     /// @brief access the last element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/back/
 | |
|     reference back()
 | |
|     {
 | |
|         auto tmp = end();
 | |
|         --tmp;
 | |
|         return *tmp;
 | |
|     }
 | |
| 
 | |
|     /// @brief access the last element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/back/
 | |
|     const_reference back() const
 | |
|     {
 | |
|         auto tmp = cend();
 | |
|         --tmp;
 | |
|         return *tmp;
 | |
|     }
 | |
| 
 | |
|     /// @brief remove element given an iterator
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/erase/
 | |
|     template < class IteratorType, detail::enable_if_t <
 | |
|                    std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
 | |
|                    std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
 | |
|     IteratorType erase(IteratorType pos)
 | |
|     {
 | |
|         // make sure iterator fits the current value
 | |
|         if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
 | |
|         }
 | |
| 
 | |
|         IteratorType result = end();
 | |
| 
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_float:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::string:
 | |
|             case value_t::binary:
 | |
|             {
 | |
|                 if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
 | |
|                 {
 | |
|                     JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
 | |
|                 }
 | |
| 
 | |
|                 if (is_string())
 | |
|                 {
 | |
|                     AllocatorType<string_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
 | |
|                     m_data.m_value.string = nullptr;
 | |
|                 }
 | |
|                 else if (is_binary())
 | |
|                 {
 | |
|                     AllocatorType<binary_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
 | |
|                     m_data.m_value.binary = nullptr;
 | |
|                 }
 | |
| 
 | |
|                 m_data.m_type = value_t::null;
 | |
|                 assert_invariant();
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|                 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief remove elements given an iterator range
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/erase/
 | |
|     template < class IteratorType, detail::enable_if_t <
 | |
|                    std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
 | |
|                    std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
 | |
|     IteratorType erase(IteratorType first, IteratorType last)
 | |
|     {
 | |
|         // make sure iterator fits the current value
 | |
|         if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
 | |
|         }
 | |
| 
 | |
|         IteratorType result = end();
 | |
| 
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_float:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::string:
 | |
|             case value_t::binary:
 | |
|             {
 | |
|                 if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
 | |
|                                        || !last.m_it.primitive_iterator.is_end()))
 | |
|                 {
 | |
|                     JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
 | |
|                 }
 | |
| 
 | |
|                 if (is_string())
 | |
|                 {
 | |
|                     AllocatorType<string_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
 | |
|                     m_data.m_value.string = nullptr;
 | |
|                 }
 | |
|                 else if (is_binary())
 | |
|                 {
 | |
|                     AllocatorType<binary_t> alloc;
 | |
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
 | |
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
 | |
|                     m_data.m_value.binary = nullptr;
 | |
|                 }
 | |
| 
 | |
|                 m_data.m_type = value_t::null;
 | |
|                 assert_invariant();
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator,
 | |
|                                               last.m_it.object_iterator);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator,
 | |
|                                              last.m_it.array_iterator);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|                 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     template < typename KeyType, detail::enable_if_t <
 | |
|                    detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
 | |
|     size_type erase_internal(KeyType && key)
 | |
|     {
 | |
|         // this erase only works for objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         return m_data.m_value.object->erase(std::forward<KeyType>(key));
 | |
|     }
 | |
| 
 | |
|     template < typename KeyType, detail::enable_if_t <
 | |
|                    !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
 | |
|     size_type erase_internal(KeyType && key)
 | |
|     {
 | |
|         // this erase only works for objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
 | |
|         if (it != m_data.m_value.object->end())
 | |
|         {
 | |
|             m_data.m_value.object->erase(it);
 | |
|             return 1;
 | |
|         }
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|   public:
 | |
| 
 | |
|     /// @brief remove element from a JSON object given a key
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/erase/
 | |
|     size_type erase(const typename object_t::key_type& key)
 | |
|     {
 | |
|         // the indirection via erase_internal() is added to avoid making this
 | |
|         // function a template and thus de-rank it during overload resolution
 | |
|         return erase_internal(key);
 | |
|     }
 | |
| 
 | |
|     /// @brief remove element from a JSON object given a key
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/erase/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
 | |
|     size_type erase(KeyType && key)
 | |
|     {
 | |
|         return erase_internal(std::forward<KeyType>(key));
 | |
|     }
 | |
| 
 | |
|     /// @brief remove element from a JSON array given an index
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/erase/
 | |
|     void erase(const size_type idx)
 | |
|     {
 | |
|         // this erase only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             if (JSON_HEDLEY_UNLIKELY(idx >= size()))
 | |
|             {
 | |
|                 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
 | |
|             }
 | |
| 
 | |
|             m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     ////////////
 | |
|     // lookup //
 | |
|     ////////////
 | |
| 
 | |
|     /// @name lookup
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief find an element in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/find/
 | |
|     iterator find(const typename object_t::key_type& key)
 | |
|     {
 | |
|         auto result = end();
 | |
| 
 | |
|         if (is_object())
 | |
|         {
 | |
|             result.m_it.object_iterator = m_data.m_value.object->find(key);
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief find an element in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/find/
 | |
|     const_iterator find(const typename object_t::key_type& key) const
 | |
|     {
 | |
|         auto result = cend();
 | |
| 
 | |
|         if (is_object())
 | |
|         {
 | |
|             result.m_it.object_iterator = m_data.m_value.object->find(key);
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief find an element in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/find/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
 | |
|     iterator find(KeyType && key)
 | |
|     {
 | |
|         auto result = end();
 | |
| 
 | |
|         if (is_object())
 | |
|         {
 | |
|             result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief find an element in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/find/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
 | |
|     const_iterator find(KeyType && key) const
 | |
|     {
 | |
|         auto result = cend();
 | |
| 
 | |
|         if (is_object())
 | |
|         {
 | |
|             result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief returns the number of occurrences of a key in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/count/
 | |
|     size_type count(const typename object_t::key_type& key) const
 | |
|     {
 | |
|         // return 0 for all nonobject types
 | |
|         return is_object() ? m_data.m_value.object->count(key) : 0;
 | |
|     }
 | |
| 
 | |
|     /// @brief returns the number of occurrences of a key in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/count/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
 | |
|     size_type count(KeyType && key) const
 | |
|     {
 | |
|         // return 0 for all nonobject types
 | |
|         return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
 | |
|     }
 | |
| 
 | |
|     /// @brief check the existence of an element in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/contains/
 | |
|     bool contains(const typename object_t::key_type& key) const
 | |
|     {
 | |
|         return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
 | |
|     }
 | |
| 
 | |
|     /// @brief check the existence of an element in a JSON object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/contains/
 | |
|     template<class KeyType, detail::enable_if_t<
 | |
|                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
 | |
|     bool contains(KeyType && key) const
 | |
|     {
 | |
|         return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
 | |
|     }
 | |
| 
 | |
|     /// @brief check the existence of an element in a JSON object given a JSON pointer
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/contains/
 | |
|     bool contains(const json_pointer& ptr) const
 | |
|     {
 | |
|         return ptr.contains(this);
 | |
|     }
 | |
| 
 | |
|     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
 | |
|     bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
 | |
|     {
 | |
|         return ptr.contains(this);
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     ///////////////
 | |
|     // iterators //
 | |
|     ///////////////
 | |
| 
 | |
|     /// @name iterators
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief returns an iterator to the first element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/begin/
 | |
|     iterator begin() noexcept
 | |
|     {
 | |
|         iterator result(this);
 | |
|         result.set_begin();
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to the first element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/begin/
 | |
|     const_iterator begin() const noexcept
 | |
|     {
 | |
|         return cbegin();
 | |
|     }
 | |
| 
 | |
|     /// @brief returns a const iterator to the first element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/cbegin/
 | |
|     const_iterator cbegin() const noexcept
 | |
|     {
 | |
|         const_iterator result(this);
 | |
|         result.set_begin();
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to one past the last element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/end/
 | |
|     iterator end() noexcept
 | |
|     {
 | |
|         iterator result(this);
 | |
|         result.set_end();
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to one past the last element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/end/
 | |
|     const_iterator end() const noexcept
 | |
|     {
 | |
|         return cend();
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to one past the last element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/cend/
 | |
|     const_iterator cend() const noexcept
 | |
|     {
 | |
|         const_iterator result(this);
 | |
|         result.set_end();
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to the reverse-beginning
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
 | |
|     reverse_iterator rbegin() noexcept
 | |
|     {
 | |
|         return reverse_iterator(end());
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to the reverse-beginning
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
 | |
|     const_reverse_iterator rbegin() const noexcept
 | |
|     {
 | |
|         return crbegin();
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to the reverse-end
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/rend/
 | |
|     reverse_iterator rend() noexcept
 | |
|     {
 | |
|         return reverse_iterator(begin());
 | |
|     }
 | |
| 
 | |
|     /// @brief returns an iterator to the reverse-end
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/rend/
 | |
|     const_reverse_iterator rend() const noexcept
 | |
|     {
 | |
|         return crend();
 | |
|     }
 | |
| 
 | |
|     /// @brief returns a const reverse iterator to the last element
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/crbegin/
 | |
|     const_reverse_iterator crbegin() const noexcept
 | |
|     {
 | |
|         return const_reverse_iterator(cend());
 | |
|     }
 | |
| 
 | |
|     /// @brief returns a const reverse iterator to one before the first
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/crend/
 | |
|     const_reverse_iterator crend() const noexcept
 | |
|     {
 | |
|         return const_reverse_iterator(cbegin());
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     /// @brief wrapper to access iterator member functions in range-based for
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/items/
 | |
|     /// @deprecated This function is deprecated since 3.1.0 and will be removed in
 | |
|     ///             version 4.0.0 of the library. Please use @ref items() instead;
 | |
|     ///             that is, replace `json::iterator_wrapper(j)` with `j.items()`.
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
 | |
|     static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
 | |
|     {
 | |
|         return ref.items();
 | |
|     }
 | |
| 
 | |
|     /// @brief wrapper to access iterator member functions in range-based for
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/items/
 | |
|     /// @deprecated This function is deprecated since 3.1.0 and will be removed in
 | |
|     ///         version 4.0.0 of the library. Please use @ref items() instead;
 | |
|     ///         that is, replace `json::iterator_wrapper(j)` with `j.items()`.
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
 | |
|     static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
 | |
|     {
 | |
|         return ref.items();
 | |
|     }
 | |
| 
 | |
|     /// @brief helper to access iterator member functions in range-based for
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/items/
 | |
|     iteration_proxy<iterator> items() noexcept
 | |
|     {
 | |
|         return iteration_proxy<iterator>(*this);
 | |
|     }
 | |
| 
 | |
|     /// @brief helper to access iterator member functions in range-based for
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/items/
 | |
|     iteration_proxy<const_iterator> items() const noexcept
 | |
|     {
 | |
|         return iteration_proxy<const_iterator>(*this);
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     //////////////
 | |
|     // capacity //
 | |
|     //////////////
 | |
| 
 | |
|     /// @name capacity
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief checks whether the container is empty.
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/empty/
 | |
|     bool empty() const noexcept
 | |
|     {
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::null:
 | |
|             {
 | |
|                 // null values are empty
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 // delegate call to array_t::empty()
 | |
|                 return m_data.m_value.array->empty();
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 // delegate call to object_t::empty()
 | |
|                 return m_data.m_value.object->empty();
 | |
|             }
 | |
| 
 | |
|             case value_t::string:
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::number_float:
 | |
|             case value_t::binary:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|             {
 | |
|                 // all other types are nonempty
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief returns the number of elements
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/size/
 | |
|     size_type size() const noexcept
 | |
|     {
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::null:
 | |
|             {
 | |
|                 // null values are empty
 | |
|                 return 0;
 | |
|             }
 | |
| 
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 // delegate call to array_t::size()
 | |
|                 return m_data.m_value.array->size();
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 // delegate call to object_t::size()
 | |
|                 return m_data.m_value.object->size();
 | |
|             }
 | |
| 
 | |
|             case value_t::string:
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::number_float:
 | |
|             case value_t::binary:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|             {
 | |
|                 // all other types have size 1
 | |
|                 return 1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief returns the maximum possible number of elements
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/max_size/
 | |
|     size_type max_size() const noexcept
 | |
|     {
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 // delegate call to array_t::max_size()
 | |
|                 return m_data.m_value.array->max_size();
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 // delegate call to object_t::max_size()
 | |
|                 return m_data.m_value.object->max_size();
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::string:
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::number_float:
 | |
|             case value_t::binary:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|             {
 | |
|                 // all other types have max_size() == size()
 | |
|                 return size();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     ///////////////
 | |
|     // modifiers //
 | |
|     ///////////////
 | |
| 
 | |
|     /// @name modifiers
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief clears the contents
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/clear/
 | |
|     void clear() noexcept
 | |
|     {
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::number_integer:
 | |
|             {
 | |
|                 m_data.m_value.number_integer = 0;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::number_unsigned:
 | |
|             {
 | |
|                 m_data.m_value.number_unsigned = 0;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::number_float:
 | |
|             {
 | |
|                 m_data.m_value.number_float = 0.0;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::boolean:
 | |
|             {
 | |
|                 m_data.m_value.boolean = false;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::string:
 | |
|             {
 | |
|                 m_data.m_value.string->clear();
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::binary:
 | |
|             {
 | |
|                 m_data.m_value.binary->clear();
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 m_data.m_value.array->clear();
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 m_data.m_value.object->clear();
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
 | |
|     void push_back(basic_json&& val)
 | |
|     {
 | |
|         // push_back only works for null objects or arrays
 | |
|         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // transform null object into an array
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::array;
 | |
|             m_data.m_value = value_t::array;
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // add element to array (move semantics)
 | |
|         const auto old_capacity = m_data.m_value.array->capacity();
 | |
|         m_data.m_value.array->push_back(std::move(val));
 | |
|         set_parent(m_data.m_value.array->back(), old_capacity);
 | |
|         // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
 | |
|     reference operator+=(basic_json&& val)
 | |
|     {
 | |
|         push_back(std::move(val));
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
 | |
|     void push_back(const basic_json& val)
 | |
|     {
 | |
|         // push_back only works for null objects or arrays
 | |
|         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // transform null object into an array
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::array;
 | |
|             m_data.m_value = value_t::array;
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // add element to array
 | |
|         const auto old_capacity = m_data.m_value.array->capacity();
 | |
|         m_data.m_value.array->push_back(val);
 | |
|         set_parent(m_data.m_value.array->back(), old_capacity);
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
 | |
|     reference operator+=(const basic_json& val)
 | |
|     {
 | |
|         push_back(val);
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
 | |
|     void push_back(const typename object_t::value_type& val)
 | |
|     {
 | |
|         // push_back only works for null objects or objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // transform null object into an object
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::object;
 | |
|             m_data.m_value = value_t::object;
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // add element to object
 | |
|         auto res = m_data.m_value.object->insert(val);
 | |
|         set_parent(res.first->second);
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
 | |
|     reference operator+=(const typename object_t::value_type& val)
 | |
|     {
 | |
|         push_back(val);
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
 | |
|     void push_back(initializer_list_t init)
 | |
|     {
 | |
|         if (is_object() && init.size() == 2 && (*init.begin())->is_string())
 | |
|         {
 | |
|             basic_json&& key = init.begin()->moved_or_copied();
 | |
|             push_back(typename object_t::value_type(
 | |
|                           std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             push_back(basic_json(init));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
 | |
|     reference operator+=(initializer_list_t init)
 | |
|     {
 | |
|         push_back(init);
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/
 | |
|     template<class... Args>
 | |
|     reference emplace_back(Args&& ... args)
 | |
|     {
 | |
|         // emplace_back only works for null objects or arrays
 | |
|         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // transform null object into an array
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::array;
 | |
|             m_data.m_value = value_t::array;
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // add element to array (perfect forwarding)
 | |
|         const auto old_capacity = m_data.m_value.array->capacity();
 | |
|         m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
 | |
|         return set_parent(m_data.m_value.array->back(), old_capacity);
 | |
|     }
 | |
| 
 | |
|     /// @brief add an object to an object if key does not exist
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/emplace/
 | |
|     template<class... Args>
 | |
|     std::pair<iterator, bool> emplace(Args&& ... args)
 | |
|     {
 | |
|         // emplace only works for null objects or arrays
 | |
|         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // transform null object into an object
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::object;
 | |
|             m_data.m_value = value_t::object;
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         // add element to array (perfect forwarding)
 | |
|         auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);
 | |
|         set_parent(res.first->second);
 | |
| 
 | |
|         // create result iterator and set iterator to the result of emplace
 | |
|         auto it = begin();
 | |
|         it.m_it.object_iterator = res.first;
 | |
| 
 | |
|         // return pair of iterator and boolean
 | |
|         return {it, res.second};
 | |
|     }
 | |
| 
 | |
|     /// Helper for insertion of an iterator
 | |
|     /// @note: This uses std::distance to support GCC 4.8,
 | |
|     ///        see https://github.com/nlohmann/json/pull/1257
 | |
|     template<typename... Args>
 | |
|     iterator insert_iterator(const_iterator pos, Args&& ... args)
 | |
|     {
 | |
|         iterator result(this);
 | |
|         JSON_ASSERT(m_data.m_value.array != nullptr);
 | |
| 
 | |
|         auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator);
 | |
|         m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
 | |
|         result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos;
 | |
| 
 | |
|         // This could have been written as:
 | |
|         // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val);
 | |
|         // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
 | |
| 
 | |
|         set_parents();
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief inserts element into array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/insert/
 | |
|     iterator insert(const_iterator pos, const basic_json& val)
 | |
|     {
 | |
|         // insert only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             // check if iterator pos fits to this JSON value
 | |
|             if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
 | |
|             {
 | |
|                 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
 | |
|             }
 | |
| 
 | |
|             // insert to array and return iterator
 | |
|             return insert_iterator(pos, val);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief inserts element into array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/insert/
 | |
|     iterator insert(const_iterator pos, basic_json&& val)
 | |
|     {
 | |
|         return insert(pos, val);
 | |
|     }
 | |
| 
 | |
|     /// @brief inserts copies of element into array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/insert/
 | |
|     iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
 | |
|     {
 | |
|         // insert only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             // check if iterator pos fits to this JSON value
 | |
|             if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
 | |
|             {
 | |
|                 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
 | |
|             }
 | |
| 
 | |
|             // insert to array and return iterator
 | |
|             return insert_iterator(pos, cnt, val);
 | |
|         }
 | |
| 
 | |
|         JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
 | |
|     }
 | |
| 
 | |
|     /// @brief inserts range of elements into array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/insert/
 | |
|     iterator insert(const_iterator pos, const_iterator first, const_iterator last)
 | |
|     {
 | |
|         // insert only works for arrays
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_array()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // check if iterator pos fits to this JSON value
 | |
|         if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
 | |
|         }
 | |
| 
 | |
|         // check if range iterators belong to the same JSON object
 | |
|         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
 | |
|         }
 | |
| 
 | |
|         if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
 | |
|         }
 | |
| 
 | |
|         // insert to array and return iterator
 | |
|         return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
 | |
|     }
 | |
| 
 | |
|     /// @brief inserts elements from initializer list into array
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/insert/
 | |
|     iterator insert(const_iterator pos, initializer_list_t ilist)
 | |
|     {
 | |
|         // insert only works for arrays
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_array()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // check if iterator pos fits to this JSON value
 | |
|         if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
 | |
|         }
 | |
| 
 | |
|         // insert to array and return iterator
 | |
|         return insert_iterator(pos, ilist.begin(), ilist.end());
 | |
|     }
 | |
| 
 | |
|     /// @brief inserts range of elements into object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/insert/
 | |
|     void insert(const_iterator first, const_iterator last)
 | |
|     {
 | |
|         // insert only works for objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // check if range iterators belong to the same JSON object
 | |
|         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
 | |
|         }
 | |
| 
 | |
|         // passed iterators must belong to objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
 | |
|         }
 | |
| 
 | |
|         m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
 | |
|     }
 | |
| 
 | |
|     /// @brief updates a JSON object from another object, overwriting existing keys
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/update/
 | |
|     void update(const_reference j, bool merge_objects = false)
 | |
|     {
 | |
|         update(j.begin(), j.end(), merge_objects);
 | |
|     }
 | |
| 
 | |
|     /// @brief updates a JSON object from another object, overwriting existing keys
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/update/
 | |
|     void update(const_iterator first, const_iterator last, bool merge_objects = false)
 | |
|     {
 | |
|         // implicitly convert null value to an empty object
 | |
|         if (is_null())
 | |
|         {
 | |
|             m_data.m_type = value_t::object;
 | |
|             m_data.m_value.object = create<object_t>();
 | |
|             assert_invariant();
 | |
|         }
 | |
| 
 | |
|         if (JSON_HEDLEY_UNLIKELY(!is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
 | |
|         }
 | |
| 
 | |
|         // check if range iterators belong to the same JSON object
 | |
|         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
 | |
|         {
 | |
|             JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
 | |
|         }
 | |
| 
 | |
|         // passed iterators must belong to objects
 | |
|         if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
 | |
|         {
 | |
|             JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
 | |
|         }
 | |
| 
 | |
|         for (auto it = first; it != last; ++it)
 | |
|         {
 | |
|             if (merge_objects && it.value().is_object())
 | |
|             {
 | |
|                 auto it2 = m_data.m_value.object->find(it.key());
 | |
|                 if (it2 != m_data.m_value.object->end())
 | |
|                 {
 | |
|                     it2->second.update(it.value(), true);
 | |
|                     continue;
 | |
|                 }
 | |
|             }
 | |
|             m_data.m_value.object->operator[](it.key()) = it.value();
 | |
| #if JSON_DIAGNOSTICS
 | |
|             m_data.m_value.object->operator[](it.key()).m_parent = this;
 | |
| #endif
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief exchanges the values
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/swap/
 | |
|     void swap(reference other) noexcept (
 | |
|         std::is_nothrow_move_constructible<value_t>::value&&
 | |
|         std::is_nothrow_move_assignable<value_t>::value&&
 | |
|         std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
 | |
|         std::is_nothrow_move_assignable<json_value>::value
 | |
|     )
 | |
|     {
 | |
|         std::swap(m_data.m_type, other.m_data.m_type);
 | |
|         std::swap(m_data.m_value, other.m_data.m_value);
 | |
| 
 | |
|         set_parents();
 | |
|         other.set_parents();
 | |
|         assert_invariant();
 | |
|     }
 | |
| 
 | |
|     /// @brief exchanges the values
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/swap/
 | |
|     friend void swap(reference left, reference right) noexcept (
 | |
|         std::is_nothrow_move_constructible<value_t>::value&&
 | |
|         std::is_nothrow_move_assignable<value_t>::value&&
 | |
|         std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
 | |
|         std::is_nothrow_move_assignable<json_value>::value
 | |
|     )
 | |
|     {
 | |
|         left.swap(right);
 | |
|     }
 | |
| 
 | |
|     /// @brief exchanges the values
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/swap/
 | |
|     void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
 | |
|     {
 | |
|         // swap only works for arrays
 | |
|         if (JSON_HEDLEY_LIKELY(is_array()))
 | |
|         {
 | |
|             using std::swap;
 | |
|             swap(*(m_data.m_value.array), other);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief exchanges the values
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/swap/
 | |
|     void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
 | |
|     {
 | |
|         // swap only works for objects
 | |
|         if (JSON_HEDLEY_LIKELY(is_object()))
 | |
|         {
 | |
|             using std::swap;
 | |
|             swap(*(m_data.m_value.object), other);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief exchanges the values
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/swap/
 | |
|     void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
 | |
|     {
 | |
|         // swap only works for strings
 | |
|         if (JSON_HEDLEY_LIKELY(is_string()))
 | |
|         {
 | |
|             using std::swap;
 | |
|             swap(*(m_data.m_value.string), other);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief exchanges the values
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/swap/
 | |
|     void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
 | |
|     {
 | |
|         // swap only works for strings
 | |
|         if (JSON_HEDLEY_LIKELY(is_binary()))
 | |
|         {
 | |
|             using std::swap;
 | |
|             swap(*(m_data.m_value.binary), other);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief exchanges the values
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/swap/
 | |
|     void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)
 | |
|     {
 | |
|         // swap only works for strings
 | |
|         if (JSON_HEDLEY_LIKELY(is_binary()))
 | |
|         {
 | |
|             using std::swap;
 | |
|             swap(*(m_data.m_value.binary), other);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     //////////////////////////////////////////
 | |
|     // lexicographical comparison operators //
 | |
|     //////////////////////////////////////////
 | |
| 
 | |
|     /// @name lexicographical comparison operators
 | |
|     /// @{
 | |
| 
 | |
|     // note parentheses around operands are necessary; see
 | |
|     // https://github.com/nlohmann/json/issues/1530
 | |
| #define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result)                       \
 | |
|     const auto lhs_type = lhs.type();                                                                    \
 | |
|     const auto rhs_type = rhs.type();                                                                    \
 | |
|     \
 | |
|     if (lhs_type == rhs_type) /* NOLINT(readability/braces) */                                           \
 | |
|     {                                                                                                    \
 | |
|         switch (lhs_type)                                                                                \
 | |
|         {                                                                                                \
 | |
|             case value_t::array:                                                                         \
 | |
|                 return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array);                                     \
 | |
|                 \
 | |
|             case value_t::object:                                                                        \
 | |
|                 return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object);                                   \
 | |
|                 \
 | |
|             case value_t::null:                                                                          \
 | |
|                 return (null_result);                                                                    \
 | |
|                 \
 | |
|             case value_t::string:                                                                        \
 | |
|                 return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string);                                   \
 | |
|                 \
 | |
|             case value_t::boolean:                                                                       \
 | |
|                 return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean);                                   \
 | |
|                 \
 | |
|             case value_t::number_integer:                                                                \
 | |
|                 return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer);                     \
 | |
|                 \
 | |
|             case value_t::number_unsigned:                                                               \
 | |
|                 return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned);                   \
 | |
|                 \
 | |
|             case value_t::number_float:                                                                  \
 | |
|                 return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float);                         \
 | |
|                 \
 | |
|             case value_t::binary:                                                                        \
 | |
|                 return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary);                                   \
 | |
|                 \
 | |
|             case value_t::discarded:                                                                     \
 | |
|             default:                                                                                     \
 | |
|                 return (unordered_result);                                                               \
 | |
|         }                                                                                                \
 | |
|     }                                                                                                    \
 | |
|     else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)                   \
 | |
|     {                                                                                                    \
 | |
|         return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float;      \
 | |
|     }                                                                                                    \
 | |
|     else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)                   \
 | |
|     {                                                                                                    \
 | |
|         return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer);      \
 | |
|     }                                                                                                    \
 | |
|     else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)                  \
 | |
|     {                                                                                                    \
 | |
|         return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float;     \
 | |
|     }                                                                                                    \
 | |
|     else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)                  \
 | |
|     {                                                                                                    \
 | |
|         return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned);     \
 | |
|     }                                                                                                    \
 | |
|     else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)                \
 | |
|     {                                                                                                    \
 | |
|         return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
 | |
|     }                                                                                                    \
 | |
|     else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)                \
 | |
|     {                                                                                                    \
 | |
|         return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
 | |
|     }                                                                                                    \
 | |
|     else if(compares_unordered(lhs, rhs))\
 | |
|     {\
 | |
|         return (unordered_result);\
 | |
|     }\
 | |
|     \
 | |
|     return (default_result);
 | |
| 
 | |
|   JSON_PRIVATE_UNLESS_TESTED:
 | |
|     // returns true if:
 | |
|     // - any operand is NaN and the other operand is of number type
 | |
|     // - any operand is discarded
 | |
|     // in legacy mode, discarded values are considered ordered if
 | |
|     // an operation is computed as an odd number of inverses of others
 | |
|     static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
 | |
|     {
 | |
|         if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number())
 | |
|                 || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number()))
 | |
|         {
 | |
|             return true;
 | |
|         }
 | |
| #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
 | |
|         return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
 | |
| #else
 | |
|         static_cast<void>(inverse);
 | |
|         return lhs.is_discarded() || rhs.is_discarded();
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
 | |
|     {
 | |
|         return compares_unordered(*this, rhs, inverse);
 | |
|     }
 | |
| 
 | |
|   public:
 | |
| #if JSON_HAS_THREE_WAY_COMPARISON
 | |
|     /// @brief comparison: equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
 | |
|     bool operator==(const_reference rhs) const noexcept
 | |
|     {
 | |
| #ifdef __GNUC__
 | |
| #pragma GCC diagnostic push
 | |
| #pragma GCC diagnostic ignored "-Wfloat-equal"
 | |
| #endif
 | |
|         const_reference lhs = *this;
 | |
|         JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
 | |
| #ifdef __GNUC__
 | |
| #pragma GCC diagnostic pop
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
 | |
|     template<typename ScalarType>
 | |
|     requires std::is_scalar_v<ScalarType>
 | |
|     bool operator==(ScalarType rhs) const noexcept
 | |
|     {
 | |
|         return *this == basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: not equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
 | |
|     bool operator!=(const_reference rhs) const noexcept
 | |
|     {
 | |
|         if (compares_unordered(rhs, true))
 | |
|         {
 | |
|             return false;
 | |
|         }
 | |
|         return !operator==(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: 3-way
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
 | |
|     std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
 | |
|     {
 | |
|         const_reference lhs = *this;
 | |
|         // default_result is used if we cannot compare values. In that case,
 | |
|         // we compare types.
 | |
|         JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
 | |
|                                 std::partial_ordering::equivalent,
 | |
|                                 std::partial_ordering::unordered,
 | |
|                                 lhs_type <=> rhs_type) // *NOPAD*
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: 3-way
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
 | |
|     template<typename ScalarType>
 | |
|     requires std::is_scalar_v<ScalarType>
 | |
|     std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
 | |
|     {
 | |
|         return *this <=> basic_json(rhs); // *NOPAD*
 | |
|     }
 | |
| 
 | |
| #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
 | |
|     // all operators that are computed as an odd number of inverses of others
 | |
|     // need to be overloaded to emulate the legacy comparison behavior
 | |
| 
 | |
|     /// @brief comparison: less than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
 | |
|     bool operator<=(const_reference rhs) const noexcept
 | |
|     {
 | |
|         if (compares_unordered(rhs, true))
 | |
|         {
 | |
|             return false;
 | |
|         }
 | |
|         return !(rhs < *this);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: less than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
 | |
|     template<typename ScalarType>
 | |
|     requires std::is_scalar_v<ScalarType>
 | |
|     bool operator<=(ScalarType rhs) const noexcept
 | |
|     {
 | |
|         return *this <= basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
 | |
|     bool operator>=(const_reference rhs) const noexcept
 | |
|     {
 | |
|         if (compares_unordered(rhs, true))
 | |
|         {
 | |
|             return false;
 | |
|         }
 | |
|         return !(*this < rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
 | |
|     template<typename ScalarType>
 | |
|     requires std::is_scalar_v<ScalarType>
 | |
|     bool operator>=(ScalarType rhs) const noexcept
 | |
|     {
 | |
|         return *this >= basic_json(rhs);
 | |
|     }
 | |
| #endif
 | |
| #else
 | |
|     /// @brief comparison: equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
 | |
|     friend bool operator==(const_reference lhs, const_reference rhs) noexcept
 | |
|     {
 | |
| #ifdef __GNUC__
 | |
| #pragma GCC diagnostic push
 | |
| #pragma GCC diagnostic ignored "-Wfloat-equal"
 | |
| #endif
 | |
|         JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
 | |
| #ifdef __GNUC__
 | |
| #pragma GCC diagnostic pop
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator==(const_reference lhs, ScalarType rhs) noexcept
 | |
|     {
 | |
|         return lhs == basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator==(ScalarType lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         return basic_json(lhs) == rhs;
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: not equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
 | |
|     friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         if (compares_unordered(lhs, rhs, true))
 | |
|         {
 | |
|             return false;
 | |
|         }
 | |
|         return !(lhs == rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: not equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept
 | |
|     {
 | |
|         return lhs != basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: not equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         return basic_json(lhs) != rhs;
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: less than
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
 | |
|     friend bool operator<(const_reference lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         // default_result is used if we cannot compare values. In that case,
 | |
|         // we compare types. Note we have to call the operator explicitly,
 | |
|         // because MSVC has problems otherwise.
 | |
|         JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: less than
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator<(const_reference lhs, ScalarType rhs) noexcept
 | |
|     {
 | |
|         return lhs < basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: less than
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator<(ScalarType lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         return basic_json(lhs) < rhs;
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: less than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
 | |
|     friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         if (compares_unordered(lhs, rhs, true))
 | |
|         {
 | |
|             return false;
 | |
|         }
 | |
|         return !(rhs < lhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: less than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept
 | |
|     {
 | |
|         return lhs <= basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: less than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         return basic_json(lhs) <= rhs;
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
 | |
|     friend bool operator>(const_reference lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         // double inverse
 | |
|         if (compares_unordered(lhs, rhs))
 | |
|         {
 | |
|             return false;
 | |
|         }
 | |
|         return !(lhs <= rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator>(const_reference lhs, ScalarType rhs) noexcept
 | |
|     {
 | |
|         return lhs > basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator>(ScalarType lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         return basic_json(lhs) > rhs;
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
 | |
|     friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         if (compares_unordered(lhs, rhs, true))
 | |
|         {
 | |
|             return false;
 | |
|         }
 | |
|         return !(lhs < rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept
 | |
|     {
 | |
|         return lhs >= basic_json(rhs);
 | |
|     }
 | |
| 
 | |
|     /// @brief comparison: greater than or equal
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
 | |
|     template<typename ScalarType, typename std::enable_if<
 | |
|                  std::is_scalar<ScalarType>::value, int>::type = 0>
 | |
|     friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
 | |
|     {
 | |
|         return basic_json(lhs) >= rhs;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #undef JSON_IMPLEMENT_OPERATOR
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     ///////////////////
 | |
|     // serialization //
 | |
|     ///////////////////
 | |
| 
 | |
|     /// @name serialization
 | |
|     /// @{
 | |
| #ifndef JSON_NO_IO
 | |
|     /// @brief serialize to stream
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
 | |
|     friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
 | |
|     {
 | |
|         // read width member and use it as indentation parameter if nonzero
 | |
|         const bool pretty_print = o.width() > 0;
 | |
|         const auto indentation = pretty_print ? o.width() : 0;
 | |
| 
 | |
|         // reset width to 0 for subsequent calls to this stream
 | |
|         o.width(0);
 | |
| 
 | |
|         // do the actual serialization
 | |
|         serializer s(detail::output_adapter<char>(o), o.fill());
 | |
|         s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
 | |
|         return o;
 | |
|     }
 | |
| 
 | |
|     /// @brief serialize to stream
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
 | |
|     /// @deprecated This function is deprecated since 3.0.0 and will be removed in
 | |
|     ///             version 4.0.0 of the library. Please use
 | |
|     ///             operator<<(std::ostream&, const basic_json&) instead; that is,
 | |
|     ///             replace calls like `j >> o;` with `o << j;`.
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
 | |
|     friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
 | |
|     {
 | |
|         return o << j;
 | |
|     }
 | |
| #endif  // JSON_NO_IO
 | |
|     /// @}
 | |
| 
 | |
|     /////////////////////
 | |
|     // deserialization //
 | |
|     /////////////////////
 | |
| 
 | |
|     /// @name deserialization
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief deserialize from a compatible input
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/parse/
 | |
|     template<typename InputType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json parse(InputType&& i,
 | |
|                             const parser_callback_t cb = nullptr,
 | |
|                             const bool allow_exceptions = true,
 | |
|                             const bool ignore_comments = false)
 | |
|     {
 | |
|         basic_json result;
 | |
|         parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief deserialize from a pair of character iterators
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/parse/
 | |
|     template<typename IteratorType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json parse(IteratorType first,
 | |
|                             IteratorType last,
 | |
|                             const parser_callback_t cb = nullptr,
 | |
|                             const bool allow_exceptions = true,
 | |
|                             const bool ignore_comments = false)
 | |
|     {
 | |
|         basic_json result;
 | |
|         parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
 | |
|     static basic_json parse(detail::span_input_adapter&& i,
 | |
|                             const parser_callback_t cb = nullptr,
 | |
|                             const bool allow_exceptions = true,
 | |
|                             const bool ignore_comments = false)
 | |
|     {
 | |
|         basic_json result;
 | |
|         parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief check if the input is valid JSON
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/accept/
 | |
|     template<typename InputType>
 | |
|     static bool accept(InputType&& i,
 | |
|                        const bool ignore_comments = false)
 | |
|     {
 | |
|         return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
 | |
|     }
 | |
| 
 | |
|     /// @brief check if the input is valid JSON
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/accept/
 | |
|     template<typename IteratorType>
 | |
|     static bool accept(IteratorType first, IteratorType last,
 | |
|                        const bool ignore_comments = false)
 | |
|     {
 | |
|         return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
 | |
|     }
 | |
| 
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
 | |
|     static bool accept(detail::span_input_adapter&& i,
 | |
|                        const bool ignore_comments = false)
 | |
|     {
 | |
|         return parser(i.get(), nullptr, false, ignore_comments).accept(true);
 | |
|     }
 | |
| 
 | |
|     /// @brief generate SAX events
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
 | |
|     template <typename InputType, typename SAX>
 | |
|     JSON_HEDLEY_NON_NULL(2)
 | |
|     static bool sax_parse(InputType&& i, SAX* sax,
 | |
|                           input_format_t format = input_format_t::json,
 | |
|                           const bool strict = true,
 | |
|                           const bool ignore_comments = false)
 | |
|     {
 | |
|         auto ia = detail::input_adapter(std::forward<InputType>(i));
 | |
|         return format == input_format_t::json
 | |
|                ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
 | |
|                : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
 | |
|     }
 | |
| 
 | |
|     /// @brief generate SAX events
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
 | |
|     template<class IteratorType, class SAX>
 | |
|     JSON_HEDLEY_NON_NULL(3)
 | |
|     static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
 | |
|                           input_format_t format = input_format_t::json,
 | |
|                           const bool strict = true,
 | |
|                           const bool ignore_comments = false)
 | |
|     {
 | |
|         auto ia = detail::input_adapter(std::move(first), std::move(last));
 | |
|         return format == input_format_t::json
 | |
|                ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
 | |
|                : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
 | |
|     }
 | |
| 
 | |
|     /// @brief generate SAX events
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
 | |
|     /// @deprecated This function is deprecated since 3.8.0 and will be removed in
 | |
|     ///             version 4.0.0 of the library. Please use
 | |
|     ///             sax_parse(ptr, ptr + len) instead.
 | |
|     template <typename SAX>
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
 | |
|     JSON_HEDLEY_NON_NULL(2)
 | |
|     static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
 | |
|                           input_format_t format = input_format_t::json,
 | |
|                           const bool strict = true,
 | |
|                           const bool ignore_comments = false)
 | |
|     {
 | |
|         auto ia = i.get();
 | |
|         return format == input_format_t::json
 | |
|                // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
 | |
|                ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
 | |
|                // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
 | |
|                : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
 | |
|     }
 | |
| #ifndef JSON_NO_IO
 | |
|     /// @brief deserialize from stream
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
 | |
|     /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
 | |
|     ///             version 4.0.0 of the library. Please use
 | |
|     ///             operator>>(std::istream&, basic_json&) instead; that is,
 | |
|     ///             replace calls like `j << i;` with `i >> j;`.
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
 | |
|     friend std::istream& operator<<(basic_json& j, std::istream& i)
 | |
|     {
 | |
|         return operator>>(i, j);
 | |
|     }
 | |
| 
 | |
|     /// @brief deserialize from stream
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
 | |
|     friend std::istream& operator>>(std::istream& i, basic_json& j)
 | |
|     {
 | |
|         parser(detail::input_adapter(i)).parse(false, j);
 | |
|         return i;
 | |
|     }
 | |
| #endif  // JSON_NO_IO
 | |
|     /// @}
 | |
| 
 | |
|     ///////////////////////////
 | |
|     // convenience functions //
 | |
|     ///////////////////////////
 | |
| 
 | |
|     /// @brief return the type as string
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/type_name/
 | |
|     JSON_HEDLEY_RETURNS_NON_NULL
 | |
|     const char* type_name() const noexcept
 | |
|     {
 | |
|         switch (m_data.m_type)
 | |
|         {
 | |
|             case value_t::null:
 | |
|                 return "null";
 | |
|             case value_t::object:
 | |
|                 return "object";
 | |
|             case value_t::array:
 | |
|                 return "array";
 | |
|             case value_t::string:
 | |
|                 return "string";
 | |
|             case value_t::boolean:
 | |
|                 return "boolean";
 | |
|             case value_t::binary:
 | |
|                 return "binary";
 | |
|             case value_t::discarded:
 | |
|                 return "discarded";
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::number_float:
 | |
|             default:
 | |
|                 return "number";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   JSON_PRIVATE_UNLESS_TESTED:
 | |
|     //////////////////////
 | |
|     // member variables //
 | |
|     //////////////////////
 | |
| 
 | |
|     struct data
 | |
|     {
 | |
|         /// the type of the current element
 | |
|         value_t m_type = value_t::null;
 | |
| 
 | |
|         /// the value of the current element
 | |
|         json_value m_value = {};
 | |
| 
 | |
|         data(const value_t v)
 | |
|             : m_type(v), m_value(v)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         data(size_type cnt, const basic_json& val)
 | |
|             : m_type(value_t::array)
 | |
|         {
 | |
|             m_value.array = create<array_t>(cnt, val);
 | |
|         }
 | |
| 
 | |
|         data() noexcept = default;
 | |
|         data(data&&) noexcept = default;
 | |
|         data(const data&) noexcept = delete;
 | |
|         data& operator=(data&&) noexcept = delete;
 | |
|         data& operator=(const data&) noexcept = delete;
 | |
| 
 | |
|         ~data() noexcept
 | |
|         {
 | |
|             m_value.destroy(m_type);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     data m_data = {};
 | |
| 
 | |
| #if JSON_DIAGNOSTICS
 | |
|     /// a pointer to a parent value (for debugging purposes)
 | |
|     basic_json* m_parent = nullptr;
 | |
| #endif
 | |
| 
 | |
|     //////////////////////////////////////////
 | |
|     // binary serialization/deserialization //
 | |
|     //////////////////////////////////////////
 | |
| 
 | |
|     /// @name binary serialization/deserialization support
 | |
|     /// @{
 | |
| 
 | |
|   public:
 | |
|     /// @brief create a CBOR serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
 | |
|     static std::vector<std::uint8_t> to_cbor(const basic_json& j)
 | |
|     {
 | |
|         std::vector<std::uint8_t> result;
 | |
|         to_cbor(j, result);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief create a CBOR serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
 | |
|     static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)
 | |
|     {
 | |
|         binary_writer<std::uint8_t>(o).write_cbor(j);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a CBOR serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
 | |
|     static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
 | |
|     {
 | |
|         binary_writer<char>(o).write_cbor(j);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a MessagePack serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
 | |
|     static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
 | |
|     {
 | |
|         std::vector<std::uint8_t> result;
 | |
|         to_msgpack(j, result);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief create a MessagePack serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
 | |
|     static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)
 | |
|     {
 | |
|         binary_writer<std::uint8_t>(o).write_msgpack(j);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a MessagePack serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
 | |
|     static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
 | |
|     {
 | |
|         binary_writer<char>(o).write_msgpack(j);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a UBJSON serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
 | |
|     static std::vector<std::uint8_t> to_ubjson(const basic_json& j,
 | |
|             const bool use_size = false,
 | |
|             const bool use_type = false)
 | |
|     {
 | |
|         std::vector<std::uint8_t> result;
 | |
|         to_ubjson(j, result, use_size, use_type);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief create a UBJSON serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
 | |
|     static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,
 | |
|                           const bool use_size = false, const bool use_type = false)
 | |
|     {
 | |
|         binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a UBJSON serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
 | |
|     static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
 | |
|                           const bool use_size = false, const bool use_type = false)
 | |
|     {
 | |
|         binary_writer<char>(o).write_ubjson(j, use_size, use_type);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a BJData serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
 | |
|     static std::vector<std::uint8_t> to_bjdata(const basic_json& j,
 | |
|             const bool use_size = false,
 | |
|             const bool use_type = false)
 | |
|     {
 | |
|         std::vector<std::uint8_t> result;
 | |
|         to_bjdata(j, result, use_size, use_type);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief create a BJData serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
 | |
|     static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o,
 | |
|                           const bool use_size = false, const bool use_type = false)
 | |
|     {
 | |
|         binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a BJData serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
 | |
|     static void to_bjdata(const basic_json& j, detail::output_adapter<char> o,
 | |
|                           const bool use_size = false, const bool use_type = false)
 | |
|     {
 | |
|         binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a BSON serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
 | |
|     static std::vector<std::uint8_t> to_bson(const basic_json& j)
 | |
|     {
 | |
|         std::vector<std::uint8_t> result;
 | |
|         to_bson(j, result);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief create a BSON serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
 | |
|     static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)
 | |
|     {
 | |
|         binary_writer<std::uint8_t>(o).write_bson(j);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a BSON serialization of a given JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
 | |
|     static void to_bson(const basic_json& j, detail::output_adapter<char> o)
 | |
|     {
 | |
|         binary_writer<char>(o).write_bson(j);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in CBOR format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
 | |
|     template<typename InputType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_cbor(InputType&& i,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true,
 | |
|                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::forward<InputType>(i));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in CBOR format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
 | |
|     template<typename IteratorType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_cbor(IteratorType first, IteratorType last,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true,
 | |
|                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::move(first), std::move(last));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     template<typename T>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
 | |
|     static basic_json from_cbor(const T* ptr, std::size_t len,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true,
 | |
|                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
 | |
|     {
 | |
|         return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
 | |
|     }
 | |
| 
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
 | |
|     static basic_json from_cbor(detail::span_input_adapter&& i,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true,
 | |
|                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = i.get();
 | |
|         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in MessagePack format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
 | |
|     template<typename InputType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_msgpack(InputType&& i,
 | |
|                                    const bool strict = true,
 | |
|                                    const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::forward<InputType>(i));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in MessagePack format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
 | |
|     template<typename IteratorType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_msgpack(IteratorType first, IteratorType last,
 | |
|                                    const bool strict = true,
 | |
|                                    const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::move(first), std::move(last));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     template<typename T>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
 | |
|     static basic_json from_msgpack(const T* ptr, std::size_t len,
 | |
|                                    const bool strict = true,
 | |
|                                    const bool allow_exceptions = true)
 | |
|     {
 | |
|         return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
 | |
|     }
 | |
| 
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
 | |
|     static basic_json from_msgpack(detail::span_input_adapter&& i,
 | |
|                                    const bool strict = true,
 | |
|                                    const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = i.get();
 | |
|         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in UBJSON format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
 | |
|     template<typename InputType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_ubjson(InputType&& i,
 | |
|                                   const bool strict = true,
 | |
|                                   const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::forward<InputType>(i));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in UBJSON format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
 | |
|     template<typename IteratorType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_ubjson(IteratorType first, IteratorType last,
 | |
|                                   const bool strict = true,
 | |
|                                   const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::move(first), std::move(last));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     template<typename T>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
 | |
|     static basic_json from_ubjson(const T* ptr, std::size_t len,
 | |
|                                   const bool strict = true,
 | |
|                                   const bool allow_exceptions = true)
 | |
|     {
 | |
|         return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
 | |
|     }
 | |
| 
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
 | |
|     static basic_json from_ubjson(detail::span_input_adapter&& i,
 | |
|                                   const bool strict = true,
 | |
|                                   const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = i.get();
 | |
|         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in BJData format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
 | |
|     template<typename InputType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_bjdata(InputType&& i,
 | |
|                                   const bool strict = true,
 | |
|                                   const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::forward<InputType>(i));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in BJData format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
 | |
|     template<typename IteratorType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_bjdata(IteratorType first, IteratorType last,
 | |
|                                   const bool strict = true,
 | |
|                                   const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::move(first), std::move(last));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in BSON format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
 | |
|     template<typename InputType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_bson(InputType&& i,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::forward<InputType>(i));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     /// @brief create a JSON value from an input in BSON format
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
 | |
|     template<typename IteratorType>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json from_bson(IteratorType first, IteratorType last,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = detail::input_adapter(std::move(first), std::move(last));
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
| 
 | |
|     template<typename T>
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
 | |
|     static basic_json from_bson(const T* ptr, std::size_t len,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true)
 | |
|     {
 | |
|         return from_bson(ptr, ptr + len, strict, allow_exceptions);
 | |
|     }
 | |
| 
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
 | |
|     static basic_json from_bson(detail::span_input_adapter&& i,
 | |
|                                 const bool strict = true,
 | |
|                                 const bool allow_exceptions = true)
 | |
|     {
 | |
|         basic_json result;
 | |
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
 | |
|         auto ia = i.get();
 | |
|         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
 | |
|         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
 | |
|         return res ? result : basic_json(value_t::discarded);
 | |
|     }
 | |
|     /// @}
 | |
| 
 | |
|     //////////////////////////
 | |
|     // JSON Pointer support //
 | |
|     //////////////////////////
 | |
| 
 | |
|     /// @name JSON Pointer functions
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief access specified element via JSON Pointer
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     reference operator[](const json_pointer& ptr)
 | |
|     {
 | |
|         return ptr.get_unchecked(this);
 | |
|     }
 | |
| 
 | |
|     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
 | |
|     reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
 | |
|     {
 | |
|         return ptr.get_unchecked(this);
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified element via JSON Pointer
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
 | |
|     const_reference operator[](const json_pointer& ptr) const
 | |
|     {
 | |
|         return ptr.get_unchecked(this);
 | |
|     }
 | |
| 
 | |
|     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
 | |
|     const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
 | |
|     {
 | |
|         return ptr.get_unchecked(this);
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified element via JSON Pointer
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     reference at(const json_pointer& ptr)
 | |
|     {
 | |
|         return ptr.get_checked(this);
 | |
|     }
 | |
| 
 | |
|     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
 | |
|     reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
 | |
|     {
 | |
|         return ptr.get_checked(this);
 | |
|     }
 | |
| 
 | |
|     /// @brief access specified element via JSON Pointer
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/at/
 | |
|     const_reference at(const json_pointer& ptr) const
 | |
|     {
 | |
|         return ptr.get_checked(this);
 | |
|     }
 | |
| 
 | |
|     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
 | |
|     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
 | |
|     const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
 | |
|     {
 | |
|         return ptr.get_checked(this);
 | |
|     }
 | |
| 
 | |
|     /// @brief return flattened JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/flatten/
 | |
|     basic_json flatten() const
 | |
|     {
 | |
|         basic_json result(value_t::object);
 | |
|         json_pointer::flatten("", *this, result);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief unflatten a previously flattened JSON value
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/unflatten/
 | |
|     basic_json unflatten() const
 | |
|     {
 | |
|         return json_pointer::unflatten(*this);
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| 
 | |
|     //////////////////////////
 | |
|     // JSON Patch functions //
 | |
|     //////////////////////////
 | |
| 
 | |
|     /// @name JSON Patch functions
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief applies a JSON patch in-place without copying the object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/patch/
 | |
|     void patch_inplace(const basic_json& json_patch)
 | |
|     {
 | |
|         basic_json& result = *this;
 | |
|         // the valid JSON Patch operations
 | |
|         enum class patch_operations {add, remove, replace, move, copy, test, invalid};
 | |
| 
 | |
|         const auto get_op = [](const std::string & op)
 | |
|         {
 | |
|             if (op == "add")
 | |
|             {
 | |
|                 return patch_operations::add;
 | |
|             }
 | |
|             if (op == "remove")
 | |
|             {
 | |
|                 return patch_operations::remove;
 | |
|             }
 | |
|             if (op == "replace")
 | |
|             {
 | |
|                 return patch_operations::replace;
 | |
|             }
 | |
|             if (op == "move")
 | |
|             {
 | |
|                 return patch_operations::move;
 | |
|             }
 | |
|             if (op == "copy")
 | |
|             {
 | |
|                 return patch_operations::copy;
 | |
|             }
 | |
|             if (op == "test")
 | |
|             {
 | |
|                 return patch_operations::test;
 | |
|             }
 | |
| 
 | |
|             return patch_operations::invalid;
 | |
|         };
 | |
| 
 | |
|         // wrapper for "add" operation; add value at ptr
 | |
|         const auto operation_add = [&result](json_pointer & ptr, basic_json val)
 | |
|         {
 | |
|             // adding to the root of the target document means replacing it
 | |
|             if (ptr.empty())
 | |
|             {
 | |
|                 result = val;
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             // make sure the top element of the pointer exists
 | |
|             json_pointer const top_pointer = ptr.top();
 | |
|             if (top_pointer != ptr)
 | |
|             {
 | |
|                 result.at(top_pointer);
 | |
|             }
 | |
| 
 | |
|             // get reference to parent of JSON pointer ptr
 | |
|             const auto last_path = ptr.back();
 | |
|             ptr.pop_back();
 | |
|             // parent must exist when performing patch add per RFC6902 specs
 | |
|             basic_json& parent = result.at(ptr);
 | |
| 
 | |
|             switch (parent.m_data.m_type)
 | |
|             {
 | |
|                 case value_t::null:
 | |
|                 case value_t::object:
 | |
|                 {
 | |
|                     // use operator[] to add value
 | |
|                     parent[last_path] = val;
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case value_t::array:
 | |
|                 {
 | |
|                     if (last_path == "-")
 | |
|                     {
 | |
|                         // special case: append to back
 | |
|                         parent.push_back(val);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         const auto idx = json_pointer::template array_index<basic_json_t>(last_path);
 | |
|                         if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
 | |
|                         {
 | |
|                             // avoid undefined behavior
 | |
|                             JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
 | |
|                         }
 | |
| 
 | |
|                         // default case: insert add offset
 | |
|                         parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
 | |
|                     }
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 // if there exists a parent it cannot be primitive
 | |
|                 case value_t::string: // LCOV_EXCL_LINE
 | |
|                 case value_t::boolean: // LCOV_EXCL_LINE
 | |
|                 case value_t::number_integer: // LCOV_EXCL_LINE
 | |
|                 case value_t::number_unsigned: // LCOV_EXCL_LINE
 | |
|                 case value_t::number_float: // LCOV_EXCL_LINE
 | |
|                 case value_t::binary: // LCOV_EXCL_LINE
 | |
|                 case value_t::discarded: // LCOV_EXCL_LINE
 | |
|                 default:            // LCOV_EXCL_LINE
 | |
|                     JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         // wrapper for "remove" operation; remove value at ptr
 | |
|         const auto operation_remove = [this, & result](json_pointer & ptr)
 | |
|         {
 | |
|             // get reference to parent of JSON pointer ptr
 | |
|             const auto last_path = ptr.back();
 | |
|             ptr.pop_back();
 | |
|             basic_json& parent = result.at(ptr);
 | |
| 
 | |
|             // remove child
 | |
|             if (parent.is_object())
 | |
|             {
 | |
|                 // perform range check
 | |
|                 auto it = parent.find(last_path);
 | |
|                 if (JSON_HEDLEY_LIKELY(it != parent.end()))
 | |
|                 {
 | |
|                     parent.erase(it);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
 | |
|                 }
 | |
|             }
 | |
|             else if (parent.is_array())
 | |
|             {
 | |
|                 // note erase performs range check
 | |
|                 parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         // type check: top level value must be an array
 | |
|         if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
 | |
|         {
 | |
|             JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
 | |
|         }
 | |
| 
 | |
|         // iterate and apply the operations
 | |
|         for (const auto& val : json_patch)
 | |
|         {
 | |
|             // wrapper to get a value for an operation
 | |
|             const auto get_value = [&val](const std::string & op,
 | |
|                                           const std::string & member,
 | |
|                                           bool string_type) -> basic_json &
 | |
|             {
 | |
|                 // find value
 | |
|                 auto it = val.m_data.m_value.object->find(member);
 | |
| 
 | |
|                 // context-sensitive error message
 | |
|                 const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable)
 | |
| 
 | |
|                 // check if desired value is present
 | |
|                 if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
 | |
|                 {
 | |
|                     // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
 | |
|                     JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
 | |
|                 }
 | |
| 
 | |
|                 // check if result is of type string
 | |
|                 if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
 | |
|                 {
 | |
|                     // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
 | |
|                     JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
 | |
|                 }
 | |
| 
 | |
|                 // no error: return value
 | |
|                 return it->second;
 | |
|             };
 | |
| 
 | |
|             // type check: every element of the array must be an object
 | |
|             if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
 | |
|             {
 | |
|                 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
 | |
|             }
 | |
| 
 | |
|             // collect mandatory members
 | |
|             const auto op = get_value("op", "op", true).template get<std::string>();
 | |
|             const auto path = get_value(op, "path", true).template get<std::string>();
 | |
|             json_pointer ptr(path);
 | |
| 
 | |
|             switch (get_op(op))
 | |
|             {
 | |
|                 case patch_operations::add:
 | |
|                 {
 | |
|                     operation_add(ptr, get_value("add", "value", false));
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case patch_operations::remove:
 | |
|                 {
 | |
|                     operation_remove(ptr);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case patch_operations::replace:
 | |
|                 {
 | |
|                     // the "path" location must exist - use at()
 | |
|                     result.at(ptr) = get_value("replace", "value", false);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case patch_operations::move:
 | |
|                 {
 | |
|                     const auto from_path = get_value("move", "from", true).template get<std::string>();
 | |
|                     json_pointer from_ptr(from_path);
 | |
| 
 | |
|                     // the "from" location must exist - use at()
 | |
|                     basic_json const v = result.at(from_ptr);
 | |
| 
 | |
|                     // The move operation is functionally identical to a
 | |
|                     // "remove" operation on the "from" location, followed
 | |
|                     // immediately by an "add" operation at the target
 | |
|                     // location with the value that was just removed.
 | |
|                     operation_remove(from_ptr);
 | |
|                     operation_add(ptr, v);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case patch_operations::copy:
 | |
|                 {
 | |
|                     const auto from_path = get_value("copy", "from", true).template get<std::string>();
 | |
|                     const json_pointer from_ptr(from_path);
 | |
| 
 | |
|                     // the "from" location must exist - use at()
 | |
|                     basic_json const v = result.at(from_ptr);
 | |
| 
 | |
|                     // The copy is functionally identical to an "add"
 | |
|                     // operation at the target location using the value
 | |
|                     // specified in the "from" member.
 | |
|                     operation_add(ptr, v);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case patch_operations::test:
 | |
|                 {
 | |
|                     bool success = false;
 | |
|                     JSON_TRY
 | |
|                     {
 | |
|                         // check if "value" matches the one at "path"
 | |
|                         // the "path" location must exist - use at()
 | |
|                         success = (result.at(ptr) == get_value("test", "value", false));
 | |
|                     }
 | |
|                     JSON_INTERNAL_CATCH (out_of_range&)
 | |
|                     {
 | |
|                         // ignore out of range errors: success remains false
 | |
|                     }
 | |
| 
 | |
|                     // throw an exception if test fails
 | |
|                     if (JSON_HEDLEY_UNLIKELY(!success))
 | |
|                     {
 | |
|                         JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
 | |
|                     }
 | |
| 
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 case patch_operations::invalid:
 | |
|                 default:
 | |
|                 {
 | |
|                     // op must be "add", "remove", "replace", "move", "copy", or
 | |
|                     // "test"
 | |
|                     JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @brief applies a JSON patch to a copy of the current object
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/patch/
 | |
|     basic_json patch(const basic_json& json_patch) const
 | |
|     {
 | |
|         basic_json result = *this;
 | |
|         result.patch_inplace(json_patch);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     /// @brief creates a diff as a JSON patch
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/diff/
 | |
|     JSON_HEDLEY_WARN_UNUSED_RESULT
 | |
|     static basic_json diff(const basic_json& source, const basic_json& target,
 | |
|                            const std::string& path = "")
 | |
|     {
 | |
|         // the patch
 | |
|         basic_json result(value_t::array);
 | |
| 
 | |
|         // if the values are the same, return empty patch
 | |
|         if (source == target)
 | |
|         {
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         if (source.type() != target.type())
 | |
|         {
 | |
|             // different types: replace value
 | |
|             result.push_back(
 | |
|             {
 | |
|                 {"op", "replace"}, {"path", path}, {"value", target}
 | |
|             });
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         switch (source.type())
 | |
|         {
 | |
|             case value_t::array:
 | |
|             {
 | |
|                 // first pass: traverse common elements
 | |
|                 std::size_t i = 0;
 | |
|                 while (i < source.size() && i < target.size())
 | |
|                 {
 | |
|                     // recursive call to compare array values at index i
 | |
|                     auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i)));
 | |
|                     result.insert(result.end(), temp_diff.begin(), temp_diff.end());
 | |
|                     ++i;
 | |
|                 }
 | |
| 
 | |
|                 // We now reached the end of at least one array
 | |
|                 // in a second pass, traverse the remaining elements
 | |
| 
 | |
|                 // remove my remaining elements
 | |
|                 const auto end_index = static_cast<difference_type>(result.size());
 | |
|                 while (i < source.size())
 | |
|                 {
 | |
|                     // add operations in reverse order to avoid invalid
 | |
|                     // indices
 | |
|                     result.insert(result.begin() + end_index, object(
 | |
|                     {
 | |
|                         {"op", "remove"},
 | |
|                         {"path", detail::concat(path, '/', std::to_string(i))}
 | |
|                     }));
 | |
|                     ++i;
 | |
|                 }
 | |
| 
 | |
|                 // add other remaining elements
 | |
|                 while (i < target.size())
 | |
|                 {
 | |
|                     result.push_back(
 | |
|                     {
 | |
|                         {"op", "add"},
 | |
|                         {"path", detail::concat(path, "/-")},
 | |
|                         {"value", target[i]}
 | |
|                     });
 | |
|                     ++i;
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::object:
 | |
|             {
 | |
|                 // first pass: traverse this object's elements
 | |
|                 for (auto it = source.cbegin(); it != source.cend(); ++it)
 | |
|                 {
 | |
|                     // escape the key name to be used in a JSON patch
 | |
|                     const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
 | |
| 
 | |
|                     if (target.find(it.key()) != target.end())
 | |
|                     {
 | |
|                         // recursive call to compare object values at key it
 | |
|                         auto temp_diff = diff(it.value(), target[it.key()], path_key);
 | |
|                         result.insert(result.end(), temp_diff.begin(), temp_diff.end());
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         // found a key that is not in o -> remove it
 | |
|                         result.push_back(object(
 | |
|                         {
 | |
|                             {"op", "remove"}, {"path", path_key}
 | |
|                         }));
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 // second pass: traverse other object's elements
 | |
|                 for (auto it = target.cbegin(); it != target.cend(); ++it)
 | |
|                 {
 | |
|                     if (source.find(it.key()) == source.end())
 | |
|                     {
 | |
|                         // found a key that is not in this -> add it
 | |
|                         const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
 | |
|                         result.push_back(
 | |
|                         {
 | |
|                             {"op", "add"}, {"path", path_key},
 | |
|                             {"value", it.value()}
 | |
|                         });
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             case value_t::null:
 | |
|             case value_t::string:
 | |
|             case value_t::boolean:
 | |
|             case value_t::number_integer:
 | |
|             case value_t::number_unsigned:
 | |
|             case value_t::number_float:
 | |
|             case value_t::binary:
 | |
|             case value_t::discarded:
 | |
|             default:
 | |
|             {
 | |
|                 // both primitive type: replace value
 | |
|                 result.push_back(
 | |
|                 {
 | |
|                     {"op", "replace"}, {"path", path}, {"value", target}
 | |
|                 });
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
|     /// @}
 | |
| 
 | |
|     ////////////////////////////////
 | |
|     // JSON Merge Patch functions //
 | |
|     ////////////////////////////////
 | |
| 
 | |
|     /// @name JSON Merge Patch functions
 | |
|     /// @{
 | |
| 
 | |
|     /// @brief applies a JSON Merge Patch
 | |
|     /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/
 | |
|     void merge_patch(const basic_json& apply_patch)
 | |
|     {
 | |
|         if (apply_patch.is_object())
 | |
|         {
 | |
|             if (!is_object())
 | |
|             {
 | |
|                 *this = object();
 | |
|             }
 | |
|             for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
 | |
|             {
 | |
|                 if (it.value().is_null())
 | |
|                 {
 | |
|                     erase(it.key());
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     operator[](it.key()).merge_patch(it.value());
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             *this = apply_patch;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @}
 | |
| };
 | |
| 
 | |
| /// @brief user-defined to_string function for JSON values
 | |
| /// @sa https://json.nlohmann.me/api/basic_json/to_string/
 | |
| NLOHMANN_BASIC_JSON_TPL_DECLARATION
 | |
| std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
 | |
| {
 | |
|     return j.dump();
 | |
| }
 | |
| 
 | |
| inline namespace literals
 | |
| {
 | |
| inline namespace json_literals
 | |
| {
 | |
| 
 | |
| /// @brief user-defined string literal for JSON values
 | |
| /// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/
 | |
| JSON_HEDLEY_NON_NULL(1)
 | |
| #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
 | |
|     inline nlohmann::json operator ""_json(const char* s, std::size_t n)
 | |
| #else
 | |
|     inline nlohmann::json operator "" _json(const char* s, std::size_t n)
 | |
| #endif
 | |
| {
 | |
|     return nlohmann::json::parse(s, s + n);
 | |
| }
 | |
| 
 | |
| /// @brief user-defined string literal for JSON pointer
 | |
| /// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/
 | |
| JSON_HEDLEY_NON_NULL(1)
 | |
| #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
 | |
|     inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n)
 | |
| #else
 | |
|     inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
 | |
| #endif
 | |
| {
 | |
|     return nlohmann::json::json_pointer(std::string(s, n));
 | |
| }
 | |
| 
 | |
| }  // namespace json_literals
 | |
| }  // namespace literals
 | |
| NLOHMANN_JSON_NAMESPACE_END
 | |
| 
 | |
| ///////////////////////
 | |
| // nonmember support //
 | |
| ///////////////////////
 | |
| 
 | |
| namespace std // NOLINT(cert-dcl58-cpp)
 | |
| {
 | |
| 
 | |
| /// @brief hash value for JSON objects
 | |
| /// @sa https://json.nlohmann.me/api/basic_json/std_hash/
 | |
| NLOHMANN_BASIC_JSON_TPL_DECLARATION
 | |
| struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)
 | |
| {
 | |
|     std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
 | |
|     {
 | |
|         return nlohmann::detail::hash(j);
 | |
|     }
 | |
| };
 | |
| 
 | |
| // specialization for std::less<value_t>
 | |
| template<>
 | |
| struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679
 | |
| {
 | |
|     /*!
 | |
|     @brief compare two value_t enum values
 | |
|     @since version 3.0.0
 | |
|     */
 | |
|     bool operator()(::nlohmann::detail::value_t lhs,
 | |
|                     ::nlohmann::detail::value_t rhs) const noexcept
 | |
|     {
 | |
| #if JSON_HAS_THREE_WAY_COMPARISON
 | |
|         return std::is_lt(lhs <=> rhs); // *NOPAD*
 | |
| #else
 | |
|         return ::nlohmann::detail::operator<(lhs, rhs);
 | |
| #endif
 | |
|     }
 | |
| };
 | |
| 
 | |
| // C++20 prohibit function specialization in the std namespace.
 | |
| #ifndef JSON_HAS_CPP_20
 | |
| 
 | |
| /// @brief exchanges the values of two JSON objects
 | |
| /// @sa https://json.nlohmann.me/api/basic_json/std_swap/
 | |
| NLOHMANN_BASIC_JSON_TPL_DECLARATION
 | |
| inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept(  // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp)
 | |
|     is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&&                          // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
 | |
|     is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
 | |
| {
 | |
|     j1.swap(j2);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| }  // namespace std
 | |
| 
 | |
| #if JSON_USE_GLOBAL_UDLS
 | |
|     #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
 | |
|         using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
 | |
|         using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
 | |
|     #else
 | |
|         using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
 | |
|         using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
 | |
|     #endif
 | |
| #endif
 | |
| 
 | |
| #include <nlohmann/detail/macro_unscope.hpp>
 | |
| 
 | |
| #endif  // INCLUDE_NLOHMANN_JSON_HPP_
 |