• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++
3 // |  |  |__   |  |  | | | |  version 3.11.3
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 /****************************************************************************\
10  * Note on documentation: The source files contain links to the online      *
11  * documentation of the public API at https://json.nlohmann.me. This URL    *
12  * contains the most recent documentation and should also be applicable to  *
13  * previous versions; documentation for deprecated functions is not         *
14  * removed, but marked deprecated. See "Generate documentation" section in  *
15  * file docs/README.md.                                                     *
16 \****************************************************************************/
17 
18 #ifndef INCLUDE_NLOHMANN_JSON_HPP_
19 #define INCLUDE_NLOHMANN_JSON_HPP_
20 
21 #include <algorithm> // all_of, find, for_each
22 #include <cstddef> // nullptr_t, ptrdiff_t, size_t
23 #include <functional> // hash, less
24 #include <initializer_list> // initializer_list
25 #ifndef JSON_NO_IO
26     #include <iosfwd> // istream, ostream
27 #endif  // JSON_NO_IO
28 #include <iterator> // random_access_iterator_tag
29 #include <memory> // unique_ptr
30 #include <string> // string, stoi, to_string
31 #include <utility> // declval, forward, move, pair, swap
32 #include <vector> // vector
33 
34 #include <nlohmann/adl_serializer.hpp>
35 #include <nlohmann/byte_container_with_subtype.hpp>
36 #include <nlohmann/detail/conversions/from_json.hpp>
37 #include <nlohmann/detail/conversions/to_json.hpp>
38 #include <nlohmann/detail/exceptions.hpp>
39 #include <nlohmann/detail/hash.hpp>
40 #include <nlohmann/detail/input/binary_reader.hpp>
41 #include <nlohmann/detail/input/input_adapters.hpp>
42 #include <nlohmann/detail/input/lexer.hpp>
43 #include <nlohmann/detail/input/parser.hpp>
44 #include <nlohmann/detail/iterators/internal_iterator.hpp>
45 #include <nlohmann/detail/iterators/iter_impl.hpp>
46 #include <nlohmann/detail/iterators/iteration_proxy.hpp>
47 #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
48 #include <nlohmann/detail/iterators/primitive_iterator.hpp>
49 #include <nlohmann/detail/json_custom_base_class.hpp>
50 #include <nlohmann/detail/json_pointer.hpp>
51 #include <nlohmann/detail/json_ref.hpp>
52 #include <nlohmann/detail/macro_scope.hpp>
53 #include <nlohmann/detail/string_concat.hpp>
54 #include <nlohmann/detail/string_escape.hpp>
55 #include <nlohmann/detail/meta/cpp_future.hpp>
56 #include <nlohmann/detail/meta/type_traits.hpp>
57 #include <nlohmann/detail/output/binary_writer.hpp>
58 #include <nlohmann/detail/output/output_adapters.hpp>
59 #include <nlohmann/detail/output/serializer.hpp>
60 #include <nlohmann/detail/value_t.hpp>
61 #include <nlohmann/json_fwd.hpp>
62 #include <nlohmann/ordered_map.hpp>
63 
64 #if defined(JSON_HAS_CPP_17)
65     #if JSON_HAS_STATIC_RTTI
66         #include <any>
67     #endif
68     #include <string_view>
69 #endif
70 
71 /*!
72 @brief namespace for Niels Lohmann
73 @see https://github.com/nlohmann
74 @since version 1.0.0
75 */
76 NLOHMANN_JSON_NAMESPACE_BEGIN
77 
78 /*!
79 @brief a class to store JSON values
80 
81 @internal
82 @invariant The member variables @a m_value and @a m_type have the following
83 relationship:
84 - If `m_type == value_t::object`, then `m_value.object != nullptr`.
85 - If `m_type == value_t::array`, then `m_value.array != nullptr`.
86 - If `m_type == value_t::string`, then `m_value.string != nullptr`.
87 The invariants are checked by member function assert_invariant().
88 
89 @note ObjectType trick from https://stackoverflow.com/a/9860911
90 @endinternal
91 
92 @since version 1.0.0
93 
94 @nosubgrouping
95 */
96 NLOHMANN_BASIC_JSON_TPL_DECLARATION
97 class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
98     : public ::nlohmann::detail::json_base_class<CustomBaseClass>
99 {
100   private:
101     template<detail::value_t> friend struct detail::external_constructor;
102 
103     template<typename>
104     friend class ::nlohmann::json_pointer;
105     // can be restored when json_pointer backwards compatibility is removed
106     // friend ::nlohmann::json_pointer<StringType>;
107 
108     template<typename BasicJsonType, typename InputType>
109     friend class ::nlohmann::detail::parser;
110     friend ::nlohmann::detail::serializer<basic_json>;
111     template<typename BasicJsonType>
112     friend class ::nlohmann::detail::iter_impl;
113     template<typename BasicJsonType, typename CharType>
114     friend class ::nlohmann::detail::binary_writer;
115     template<typename BasicJsonType, typename InputType, typename SAX>
116     friend class ::nlohmann::detail::binary_reader;
117     template<typename BasicJsonType>
118     friend class ::nlohmann::detail::json_sax_dom_parser;
119     template<typename BasicJsonType>
120     friend class ::nlohmann::detail::json_sax_dom_callback_parser;
121     friend class ::nlohmann::detail::exception;
122 
123     /// workaround type for MSVC
124     using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
125     using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;
126 
127   JSON_PRIVATE_UNLESS_TESTED:
128     // convenience aliases for types residing in namespace detail;
129     using lexer = ::nlohmann::detail::lexer_base<basic_json>;
130 
131     template<typename InputAdapterType>
parser(InputAdapterType adapter,detail::parser_callback_t<basic_json> cb=nullptr,const bool allow_exceptions=true,const bool ignore_comments=false)132     static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
133         InputAdapterType adapter,
134         detail::parser_callback_t<basic_json>cb = nullptr,
135         const bool allow_exceptions = true,
136         const bool ignore_comments = false
137     )
138     {
139         return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
140                 std::move(cb), allow_exceptions, ignore_comments);
141     }
142 
143   private:
144     using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
145     template<typename BasicJsonType>
146     using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
147     template<typename BasicJsonType>
148     using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
149     template<typename Iterator>
150     using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
151     template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
152 
153     template<typename CharType>
154     using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
155 
156     template<typename InputType>
157     using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;
158     template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
159 
160   JSON_PRIVATE_UNLESS_TESTED:
161     using serializer = ::nlohmann::detail::serializer<basic_json>;
162 
163   public:
164     using value_t = detail::value_t;
165     /// JSON Pointer, see @ref nlohmann::json_pointer
166     using json_pointer = ::nlohmann::json_pointer<StringType>;
167     template<typename T, typename SFINAE>
168     using json_serializer = JSONSerializer<T, SFINAE>;
169     /// how to treat decoding errors
170     using error_handler_t = detail::error_handler_t;
171     /// how to treat CBOR tags
172     using cbor_tag_handler_t = detail::cbor_tag_handler_t;
173     /// helper type for initializer lists of basic_json values
174     using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
175 
176     using input_format_t = detail::input_format_t;
177     /// SAX interface type, see @ref nlohmann::json_sax
178     using json_sax_t = json_sax<basic_json>;
179 
180     ////////////////
181     // exceptions //
182     ////////////////
183 
184     /// @name exceptions
185     /// Classes to implement user-defined exceptions.
186     /// @{
187 
188     using exception = detail::exception;
189     using parse_error = detail::parse_error;
190     using invalid_iterator = detail::invalid_iterator;
191     using type_error = detail::type_error;
192     using out_of_range = detail::out_of_range;
193     using other_error = detail::other_error;
194 
195     /// @}
196 
197     /////////////////////
198     // container types //
199     /////////////////////
200 
201     /// @name container types
202     /// The canonic container types to use @ref basic_json like any other STL
203     /// container.
204     /// @{
205 
206     /// the type of elements in a basic_json container
207     using value_type = basic_json;
208 
209     /// the type of an element reference
210     using reference = value_type&;
211     /// the type of an element const reference
212     using const_reference = const value_type&;
213 
214     /// a type to represent differences between iterators
215     using difference_type = std::ptrdiff_t;
216     /// a type to represent container sizes
217     using size_type = std::size_t;
218 
219     /// the allocator type
220     using allocator_type = AllocatorType<basic_json>;
221 
222     /// the type of an element pointer
223     using pointer = typename std::allocator_traits<allocator_type>::pointer;
224     /// the type of an element const pointer
225     using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
226 
227     /// an iterator for a basic_json container
228     using iterator = iter_impl<basic_json>;
229     /// a const iterator for a basic_json container
230     using const_iterator = iter_impl<const basic_json>;
231     /// a reverse iterator for a basic_json container
232     using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
233     /// a const reverse iterator for a basic_json container
234     using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
235 
236     /// @}
237 
238     /// @brief returns the allocator associated with the container
239     /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/
get_allocator()240     static allocator_type get_allocator()
241     {
242         return allocator_type();
243     }
244 
245     /// @brief returns version information on the library
246     /// @sa https://json.nlohmann.me/api/basic_json/meta/
247     JSON_HEDLEY_WARN_UNUSED_RESULT
meta()248     static basic_json meta()
249     {
250         basic_json result;
251 
252         result["copyright"] = "(C) 2013-2023 Niels Lohmann";
253         result["name"] = "JSON for Modern C++";
254         result["url"] = "https://github.com/nlohmann/json";
255         result["version"]["string"] =
256             detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.',
257                            std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.',
258                            std::to_string(NLOHMANN_JSON_VERSION_PATCH));
259         result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
260         result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
261         result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
262 
263 #ifdef _WIN32
264         result["platform"] = "win32";
265 #elif defined __linux__
266         result["platform"] = "linux";
267 #elif defined __APPLE__
268         result["platform"] = "apple";
269 #elif defined __unix__
270         result["platform"] = "unix";
271 #else
272         result["platform"] = "unknown";
273 #endif
274 
275 #if defined(__ICC) || defined(__INTEL_COMPILER)
276         result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
277 #elif defined(__clang__)
278         result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
279 #elif defined(__GNUC__) || defined(__GNUG__)
280         result["compiler"] = {{"family", "gcc"}, {"version", detail::concat(
281                     std::to_string(__GNUC__), '.',
282                     std::to_string(__GNUC_MINOR__), '.',
283                     std::to_string(__GNUC_PATCHLEVEL__))
284             }
285         };
286 #elif defined(__HP_cc) || defined(__HP_aCC)
287         result["compiler"] = "hp"
288 #elif defined(__IBMCPP__)
289         result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
290 #elif defined(_MSC_VER)
291         result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
292 #elif defined(__PGI)
293         result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
294 #elif defined(__SUNPRO_CC)
295         result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
296 #else
297         result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
298 #endif
299 
300 #if defined(_MSVC_LANG)
301         result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
302 #elif defined(__cplusplus)
303         result["compiler"]["c++"] = std::to_string(__cplusplus);
304 #else
305         result["compiler"]["c++"] = "unknown";
306 #endif
307         return result;
308     }
309 
310     ///////////////////////////
311     // JSON value data types //
312     ///////////////////////////
313 
314     /// @name JSON value data types
315     /// The data types to store a JSON value. These types are derived from
316     /// the template arguments passed to class @ref basic_json.
317     /// @{
318 
319     /// @brief default object key comparator type
320     /// The actual object key comparator type (@ref object_comparator_t) may be
321     /// different.
322     /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
323 #if defined(JSON_HAS_CPP_14)
324     // use of transparent comparator avoids unnecessary repeated construction of temporaries
325     // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
326     using default_object_comparator_t = std::less<>;
327 #else
328     using default_object_comparator_t = std::less<StringType>;
329 #endif
330 
331     /// @brief a type for an object
332     /// @sa https://json.nlohmann.me/api/basic_json/object_t/
333     using object_t = ObjectType<StringType,
334           basic_json,
335           default_object_comparator_t,
336           AllocatorType<std::pair<const StringType,
337           basic_json>>>;
338 
339     /// @brief a type for an array
340     /// @sa https://json.nlohmann.me/api/basic_json/array_t/
341     using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
342 
343     /// @brief a type for a string
344     /// @sa https://json.nlohmann.me/api/basic_json/string_t/
345     using string_t = StringType;
346 
347     /// @brief a type for a boolean
348     /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/
349     using boolean_t = BooleanType;
350 
351     /// @brief a type for a number (integer)
352     /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/
353     using number_integer_t = NumberIntegerType;
354 
355     /// @brief a type for a number (unsigned)
356     /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/
357     using number_unsigned_t = NumberUnsignedType;
358 
359     /// @brief a type for a number (floating-point)
360     /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/
361     using number_float_t = NumberFloatType;
362 
363     /// @brief a type for a packed binary type
364     /// @sa https://json.nlohmann.me/api/basic_json/binary_t/
365     using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
366 
367     /// @brief object key comparator type
368     /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
369     using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
370 
371     /// @}
372 
373   private:
374 
375     /// helper for exception-safe object creation
376     template<typename T, typename... Args>
377     JSON_HEDLEY_RETURNS_NON_NULL
create(Args &&...args)378     static T* create(Args&& ... args)
379     {
380         AllocatorType<T> alloc;
381         using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
382 
383         auto deleter = [&](T * obj)
384         {
385             AllocatorTraits::deallocate(alloc, obj, 1);
386         };
387         std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);
388         AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);
389         JSON_ASSERT(obj != nullptr);
390         return obj.release();
391     }
392 
393     ////////////////////////
394     // JSON value storage //
395     ////////////////////////
396 
397   JSON_PRIVATE_UNLESS_TESTED:
398     /*!
399     @brief a JSON value
400 
401     The actual storage for a JSON value of the @ref basic_json class. This
402     union combines the different storage types for the JSON value types
403     defined in @ref value_t.
404 
405     JSON type | value_t type    | used type
406     --------- | --------------- | ------------------------
407     object    | object          | pointer to @ref object_t
408     array     | array           | pointer to @ref array_t
409     string    | string          | pointer to @ref string_t
410     boolean   | boolean         | @ref boolean_t
411     number    | number_integer  | @ref number_integer_t
412     number    | number_unsigned | @ref number_unsigned_t
413     number    | number_float    | @ref number_float_t
414     binary    | binary          | pointer to @ref binary_t
415     null      | null            | *no value is stored*
416 
417     @note Variable-length types (objects, arrays, and strings) are stored as
418     pointers. The size of the union should not exceed 64 bits if the default
419     value types are used.
420 
421     @since version 1.0.0
422     */
423     union json_value
424     {
425         /// object (stored with pointer to save storage)
426         object_t* object;
427         /// array (stored with pointer to save storage)
428         array_t* array;
429         /// string (stored with pointer to save storage)
430         string_t* string;
431         /// binary (stored with pointer to save storage)
432         binary_t* binary;
433         /// boolean
434         boolean_t boolean;
435         /// number (integer)
436         number_integer_t number_integer;
437         /// number (unsigned integer)
438         number_unsigned_t number_unsigned;
439         /// number (floating-point)
440         number_float_t number_float;
441 
442         /// default constructor (for null values)
443         json_value() = default;
444         /// constructor for booleans
json_value(boolean_t v)445         json_value(boolean_t v) noexcept : boolean(v) {}
446         /// constructor for numbers (integer)
json_value(number_integer_t v)447         json_value(number_integer_t v) noexcept : number_integer(v) {}
448         /// constructor for numbers (unsigned)
json_value(number_unsigned_t v)449         json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
450         /// constructor for numbers (floating-point)
json_value(number_float_t v)451         json_value(number_float_t v) noexcept : number_float(v) {}
452         /// constructor for empty values of a given type
json_value(value_t t)453         json_value(value_t t)
454         {
455             switch (t)
456             {
457                 case value_t::object:
458                 {
459                     object = create<object_t>();
460                     break;
461                 }
462 
463                 case value_t::array:
464                 {
465                     array = create<array_t>();
466                     break;
467                 }
468 
469                 case value_t::string:
470                 {
471                     string = create<string_t>("");
472                     break;
473                 }
474 
475                 case value_t::binary:
476                 {
477                     binary = create<binary_t>();
478                     break;
479                 }
480 
481                 case value_t::boolean:
482                 {
483                     boolean = static_cast<boolean_t>(false);
484                     break;
485                 }
486 
487                 case value_t::number_integer:
488                 {
489                     number_integer = static_cast<number_integer_t>(0);
490                     break;
491                 }
492 
493                 case value_t::number_unsigned:
494                 {
495                     number_unsigned = static_cast<number_unsigned_t>(0);
496                     break;
497                 }
498 
499                 case value_t::number_float:
500                 {
501                     number_float = static_cast<number_float_t>(0.0);
502                     break;
503                 }
504 
505                 case value_t::null:
506                 {
507                     object = nullptr;  // silence warning, see #821
508                     break;
509                 }
510 
511                 case value_t::discarded:
512                 default:
513                 {
514                     object = nullptr;  // silence warning, see #821
515                     if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
516                     {
517                         JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
518                     }
519                     break;
520                 }
521             }
522         }
523 
524         /// constructor for strings
json_value(const string_t & value)525         json_value(const string_t& value) : string(create<string_t>(value)) {}
526 
527         /// constructor for rvalue strings
json_value(string_t && value)528         json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
529 
530         /// constructor for objects
json_value(const object_t & value)531         json_value(const object_t& value) : object(create<object_t>(value)) {}
532 
533         /// constructor for rvalue objects
json_value(object_t && value)534         json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
535 
536         /// constructor for arrays
json_value(const array_t & value)537         json_value(const array_t& value) : array(create<array_t>(value)) {}
538 
539         /// constructor for rvalue arrays
json_value(array_t && value)540         json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
541 
542         /// constructor for binary arrays
json_value(const typename binary_t::container_type & value)543         json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
544 
545         /// constructor for rvalue binary arrays
json_value(typename binary_t::container_type && value)546         json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
547 
548         /// constructor for binary arrays (internal type)
json_value(const binary_t & value)549         json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
550 
551         /// constructor for rvalue binary arrays (internal type)
json_value(binary_t && value)552         json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
553 
destroy(value_t t)554         void destroy(value_t t)
555         {
556             if (
557                 (t == value_t::object && object == nullptr) ||
558                 (t == value_t::array && array == nullptr) ||
559                 (t == value_t::string && string == nullptr) ||
560                 (t == value_t::binary && binary == nullptr)
561             )
562             {
563                 //not initialized (e.g. due to exception in the ctor)
564                 return;
565             }
566             if (t == value_t::array || t == value_t::object)
567             {
568                 // flatten the current json_value to a heap-allocated stack
569                 std::vector<basic_json> stack;
570 
571                 // move the top-level items to stack
572                 if (t == value_t::array)
573                 {
574                     stack.reserve(array->size());
575                     std::move(array->begin(), array->end(), std::back_inserter(stack));
576                 }
577                 else
578                 {
579                     stack.reserve(object->size());
580                     for (auto&& it : *object)
581                     {
582                         stack.push_back(std::move(it.second));
583                     }
584                 }
585 
586                 while (!stack.empty())
587                 {
588                     // move the last item to local variable to be processed
589                     basic_json current_item(std::move(stack.back()));
590                     stack.pop_back();
591 
592                     // if current_item is array/object, move
593                     // its children to the stack to be processed later
594                     if (current_item.is_array())
595                     {
596                         std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
597 
598                         current_item.m_data.m_value.array->clear();
599                     }
600                     else if (current_item.is_object())
601                     {
602                         for (auto&& it : *current_item.m_data.m_value.object)
603                         {
604                             stack.push_back(std::move(it.second));
605                         }
606 
607                         current_item.m_data.m_value.object->clear();
608                     }
609 
610                     // it's now safe that current_item get destructed
611                     // since it doesn't have any children
612                 }
613             }
614 
615             switch (t)
616             {
617                 case value_t::object:
618                 {
619                     AllocatorType<object_t> alloc;
620                     std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
621                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
622                     break;
623                 }
624 
625                 case value_t::array:
626                 {
627                     AllocatorType<array_t> alloc;
628                     std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
629                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
630                     break;
631                 }
632 
633                 case value_t::string:
634                 {
635                     AllocatorType<string_t> alloc;
636                     std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
637                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
638                     break;
639                 }
640 
641                 case value_t::binary:
642                 {
643                     AllocatorType<binary_t> alloc;
644                     std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
645                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
646                     break;
647                 }
648 
649                 case value_t::null:
650                 case value_t::boolean:
651                 case value_t::number_integer:
652                 case value_t::number_unsigned:
653                 case value_t::number_float:
654                 case value_t::discarded:
655                 default:
656                 {
657                     break;
658                 }
659             }
660         }
661     };
662 
663   private:
664     /*!
665     @brief checks the class invariants
666 
667     This function asserts the class invariants. It needs to be called at the
668     end of every constructor to make sure that created objects respect the
669     invariant. Furthermore, it has to be called each time the type of a JSON
670     value is changed, because the invariant expresses a relationship between
671     @a m_type and @a m_value.
672 
673     Furthermore, the parent relation is checked for arrays and objects: If
674     @a check_parents true and the value is an array or object, then the
675     container's elements must have the current value as parent.
676 
677     @param[in] check_parents  whether the parent relation should be checked.
678                The value is true by default and should only be set to false
679                during destruction of objects when the invariant does not
680                need to hold.
681     */
assert_invariant(bool check_parents=true) const682     void assert_invariant(bool check_parents = true) const noexcept
683     {
684         JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr);
685         JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr);
686         JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr);
687         JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr);
688 
689 #if JSON_DIAGNOSTICS
690         JSON_TRY
691         {
692             // cppcheck-suppress assertWithSideEffect
693             JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
694             {
695                 return j.m_parent == this;
696             }));
697         }
698         JSON_CATCH(...) {} // LCOV_EXCL_LINE
699 #endif
700         static_cast<void>(check_parents);
701     }
702 
set_parents()703     void set_parents()
704     {
705 #if JSON_DIAGNOSTICS
706         switch (m_data.m_type)
707         {
708             case value_t::array:
709             {
710                 for (auto& element : *m_data.m_value.array)
711                 {
712                     element.m_parent = this;
713                 }
714                 break;
715             }
716 
717             case value_t::object:
718             {
719                 for (auto& element : *m_data.m_value.object)
720                 {
721                     element.second.m_parent = this;
722                 }
723                 break;
724             }
725 
726             case value_t::null:
727             case value_t::string:
728             case value_t::boolean:
729             case value_t::number_integer:
730             case value_t::number_unsigned:
731             case value_t::number_float:
732             case value_t::binary:
733             case value_t::discarded:
734             default:
735                 break;
736         }
737 #endif
738     }
739 
set_parents(iterator it,typename iterator::difference_type count_set_parents)740     iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)
741     {
742 #if JSON_DIAGNOSTICS
743         for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)
744         {
745             (it + i)->m_parent = this;
746         }
747 #else
748         static_cast<void>(count_set_parents);
749 #endif
750         return it;
751     }
752 
set_parent(reference j,std::size_t old_capacity=static_cast<std::size_t> (-1))753     reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1))
754     {
755 #if JSON_DIAGNOSTICS
756         if (old_capacity != static_cast<std::size_t>(-1))
757         {
758             // see https://github.com/nlohmann/json/issues/2838
759             JSON_ASSERT(type() == value_t::array);
760             if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
761             {
762                 // capacity has changed: update all parents
763                 set_parents();
764                 return j;
765             }
766         }
767 
768         // ordered_json uses a vector internally, so pointers could have
769         // been invalidated; see https://github.com/nlohmann/json/issues/2962
770 #ifdef JSON_HEDLEY_MSVC_VERSION
771 #pragma warning(push )
772 #pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
773 #endif
774         if (detail::is_ordered_map<object_t>::value)
775         {
776             set_parents();
777             return j;
778         }
779 #ifdef JSON_HEDLEY_MSVC_VERSION
780 #pragma warning( pop )
781 #endif
782 
783         j.m_parent = this;
784 #else
785         static_cast<void>(j);
786         static_cast<void>(old_capacity);
787 #endif
788         return j;
789     }
790 
791   public:
792     //////////////////////////
793     // JSON parser callback //
794     //////////////////////////
795 
796     /// @brief parser event types
797     /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/
798     using parse_event_t = detail::parse_event_t;
799 
800     /// @brief per-element parser callback type
801     /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/
802     using parser_callback_t = detail::parser_callback_t<basic_json>;
803 
804     //////////////////
805     // constructors //
806     //////////////////
807 
808     /// @name constructors and destructors
809     /// Constructors of class @ref basic_json, copy/move constructor, copy
810     /// assignment, static functions creating objects, and the destructor.
811     /// @{
812 
813     /// @brief create an empty value with a given type
814     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(const value_t v)815     basic_json(const value_t v)
816         : m_data(v)
817     {
818         assert_invariant();
819     }
820 
821     /// @brief create a null object
822     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(std::nullptr_t=nullptr)823     basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)
824         : basic_json(value_t::null)
825     {
826         assert_invariant();
827     }
828 
829     /// @brief create a JSON value from compatible types
830     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
831     template < typename CompatibleType,
832                typename U = detail::uncvref_t<CompatibleType>,
833                detail::enable_if_t <
834                    !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
basic_json(CompatibleType && val)835     basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
836                 JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
837                                            std::forward<CompatibleType>(val))))
838     {
839         JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
840         set_parents();
841         assert_invariant();
842     }
843 
844     /// @brief create a JSON value from an existing one
845     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
846     template < typename BasicJsonType,
847                detail::enable_if_t <
848                    detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
basic_json(const BasicJsonType & val)849     basic_json(const BasicJsonType& val)
850     {
851         using other_boolean_t = typename BasicJsonType::boolean_t;
852         using other_number_float_t = typename BasicJsonType::number_float_t;
853         using other_number_integer_t = typename BasicJsonType::number_integer_t;
854         using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
855         using other_string_t = typename BasicJsonType::string_t;
856         using other_object_t = typename BasicJsonType::object_t;
857         using other_array_t = typename BasicJsonType::array_t;
858         using other_binary_t = typename BasicJsonType::binary_t;
859 
860         switch (val.type())
861         {
862             case value_t::boolean:
863                 JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
864                 break;
865             case value_t::number_float:
866                 JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
867                 break;
868             case value_t::number_integer:
869                 JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
870                 break;
871             case value_t::number_unsigned:
872                 JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
873                 break;
874             case value_t::string:
875                 JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
876                 break;
877             case value_t::object:
878                 JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
879                 break;
880             case value_t::array:
881                 JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
882                 break;
883             case value_t::binary:
884                 JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
885                 break;
886             case value_t::null:
887                 *this = nullptr;
888                 break;
889             case value_t::discarded:
890                 m_data.m_type = value_t::discarded;
891                 break;
892             default:            // LCOV_EXCL_LINE
893                 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
894         }
895         JSON_ASSERT(m_data.m_type == val.type());
896         set_parents();
897         assert_invariant();
898     }
899 
900     /// @brief create a container (array or object) from an initializer list
901     /// @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)902     basic_json(initializer_list_t init,
903                bool type_deduction = true,
904                value_t manual_type = value_t::array)
905     {
906         // check if each element is an array with two elements whose first
907         // element is a string
908         bool is_an_object = std::all_of(init.begin(), init.end(),
909                                         [](const detail::json_ref<basic_json>& element_ref)
910         {
911             // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int;
912             // (many string types can be constructed from 0 via its null-pointer guise, so we get a
913             // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows)
914             return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string();
915         });
916 
917         // adjust type if type deduction is not wanted
918         if (!type_deduction)
919         {
920             // if array is wanted, do not create an object though possible
921             if (manual_type == value_t::array)
922             {
923                 is_an_object = false;
924             }
925 
926             // if object is wanted but impossible, throw an exception
927             if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
928             {
929                 JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
930             }
931         }
932 
933         if (is_an_object)
934         {
935             // the initializer list is a list of pairs -> create object
936             m_data.m_type = value_t::object;
937             m_data.m_value = value_t::object;
938 
939             for (auto& element_ref : init)
940             {
941                 auto element = element_ref.moved_or_copied();
942                 m_data.m_value.object->emplace(
943                     std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)),
944                     std::move((*element.m_data.m_value.array)[1]));
945             }
946         }
947         else
948         {
949             // the initializer list describes an array -> create array
950             m_data.m_type = value_t::array;
951             m_data.m_value.array = create<array_t>(init.begin(), init.end());
952         }
953 
954         set_parents();
955         assert_invariant();
956     }
957 
958     /// @brief explicitly create a binary array (without subtype)
959     /// @sa https://json.nlohmann.me/api/basic_json/binary/
960     JSON_HEDLEY_WARN_UNUSED_RESULT
binary(const typename binary_t::container_type & init)961     static basic_json binary(const typename binary_t::container_type& init)
962     {
963         auto res = basic_json();
964         res.m_data.m_type = value_t::binary;
965         res.m_data.m_value = init;
966         return res;
967     }
968 
969     /// @brief explicitly create a binary array (with subtype)
970     /// @sa https://json.nlohmann.me/api/basic_json/binary/
971     JSON_HEDLEY_WARN_UNUSED_RESULT
binary(const typename binary_t::container_type & init,typename binary_t::subtype_type subtype)972     static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
973     {
974         auto res = basic_json();
975         res.m_data.m_type = value_t::binary;
976         res.m_data.m_value = binary_t(init, subtype);
977         return res;
978     }
979 
980     /// @brief explicitly create a binary array
981     /// @sa https://json.nlohmann.me/api/basic_json/binary/
982     JSON_HEDLEY_WARN_UNUSED_RESULT
binary(typename binary_t::container_type && init)983     static basic_json binary(typename binary_t::container_type&& init)
984     {
985         auto res = basic_json();
986         res.m_data.m_type = value_t::binary;
987         res.m_data.m_value = std::move(init);
988         return res;
989     }
990 
991     /// @brief explicitly create a binary array (with subtype)
992     /// @sa https://json.nlohmann.me/api/basic_json/binary/
993     JSON_HEDLEY_WARN_UNUSED_RESULT
binary(typename binary_t::container_type && init,typename binary_t::subtype_type subtype)994     static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
995     {
996         auto res = basic_json();
997         res.m_data.m_type = value_t::binary;
998         res.m_data.m_value = binary_t(std::move(init), subtype);
999         return res;
1000     }
1001 
1002     /// @brief explicitly create an array from an initializer list
1003     /// @sa https://json.nlohmann.me/api/basic_json/array/
1004     JSON_HEDLEY_WARN_UNUSED_RESULT
array(initializer_list_t init={})1005     static basic_json array(initializer_list_t init = {})
1006     {
1007         return basic_json(init, false, value_t::array);
1008     }
1009 
1010     /// @brief explicitly create an object from an initializer list
1011     /// @sa https://json.nlohmann.me/api/basic_json/object/
1012     JSON_HEDLEY_WARN_UNUSED_RESULT
object(initializer_list_t init={})1013     static basic_json object(initializer_list_t init = {})
1014     {
1015         return basic_json(init, false, value_t::object);
1016     }
1017 
1018     /// @brief construct an array with count copies of given value
1019     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(size_type cnt,const basic_json & val)1020     basic_json(size_type cnt, const basic_json& val):
1021         m_data{cnt, val}
1022     {
1023         set_parents();
1024         assert_invariant();
1025     }
1026 
1027     /// @brief construct a JSON container given an iterator range
1028     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
1029     template < class InputIT, typename std::enable_if <
1030                    std::is_same<InputIT, typename basic_json_t::iterator>::value ||
1031                    std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
basic_json(InputIT first,InputIT last)1032     basic_json(InputIT first, InputIT last)
1033     {
1034         JSON_ASSERT(first.m_object != nullptr);
1035         JSON_ASSERT(last.m_object != nullptr);
1036 
1037         // make sure iterator fits the current value
1038         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
1039         {
1040             JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
1041         }
1042 
1043         // copy type from first iterator
1044         m_data.m_type = first.m_object->m_data.m_type;
1045 
1046         // check if iterator range is complete for primitive values
1047         switch (m_data.m_type)
1048         {
1049             case value_t::boolean:
1050             case value_t::number_float:
1051             case value_t::number_integer:
1052             case value_t::number_unsigned:
1053             case value_t::string:
1054             {
1055                 if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
1056                                          || !last.m_it.primitive_iterator.is_end()))
1057                 {
1058                     JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
1059                 }
1060                 break;
1061             }
1062 
1063             case value_t::null:
1064             case value_t::object:
1065             case value_t::array:
1066             case value_t::binary:
1067             case value_t::discarded:
1068             default:
1069                 break;
1070         }
1071 
1072         switch (m_data.m_type)
1073         {
1074             case value_t::number_integer:
1075             {
1076                 m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer;
1077                 break;
1078             }
1079 
1080             case value_t::number_unsigned:
1081             {
1082                 m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned;
1083                 break;
1084             }
1085 
1086             case value_t::number_float:
1087             {
1088                 m_data.m_value.number_float = first.m_object->m_data.m_value.number_float;
1089                 break;
1090             }
1091 
1092             case value_t::boolean:
1093             {
1094                 m_data.m_value.boolean = first.m_object->m_data.m_value.boolean;
1095                 break;
1096             }
1097 
1098             case value_t::string:
1099             {
1100                 m_data.m_value = *first.m_object->m_data.m_value.string;
1101                 break;
1102             }
1103 
1104             case value_t::object:
1105             {
1106                 m_data.m_value.object = create<object_t>(first.m_it.object_iterator,
1107                                         last.m_it.object_iterator);
1108                 break;
1109             }
1110 
1111             case value_t::array:
1112             {
1113                 m_data.m_value.array = create<array_t>(first.m_it.array_iterator,
1114                                                        last.m_it.array_iterator);
1115                 break;
1116             }
1117 
1118             case value_t::binary:
1119             {
1120                 m_data.m_value = *first.m_object->m_data.m_value.binary;
1121                 break;
1122             }
1123 
1124             case value_t::null:
1125             case value_t::discarded:
1126             default:
1127                 JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
1128         }
1129 
1130         set_parents();
1131         assert_invariant();
1132     }
1133 
1134     ///////////////////////////////////////
1135     // other constructors and destructor //
1136     ///////////////////////////////////////
1137 
1138     template<typename JsonRef,
1139              detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
1140                                  std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
basic_json(const JsonRef & ref)1141     basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
1142 
1143     /// @brief copy constructor
1144     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(const basic_json & other)1145     basic_json(const basic_json& other)
1146         : json_base_class_t(other)
1147     {
1148         m_data.m_type = other.m_data.m_type;
1149         // check of passed value is valid
1150         other.assert_invariant();
1151 
1152         switch (m_data.m_type)
1153         {
1154             case value_t::object:
1155             {
1156                 m_data.m_value = *other.m_data.m_value.object;
1157                 break;
1158             }
1159 
1160             case value_t::array:
1161             {
1162                 m_data.m_value = *other.m_data.m_value.array;
1163                 break;
1164             }
1165 
1166             case value_t::string:
1167             {
1168                 m_data.m_value = *other.m_data.m_value.string;
1169                 break;
1170             }
1171 
1172             case value_t::boolean:
1173             {
1174                 m_data.m_value = other.m_data.m_value.boolean;
1175                 break;
1176             }
1177 
1178             case value_t::number_integer:
1179             {
1180                 m_data.m_value = other.m_data.m_value.number_integer;
1181                 break;
1182             }
1183 
1184             case value_t::number_unsigned:
1185             {
1186                 m_data.m_value = other.m_data.m_value.number_unsigned;
1187                 break;
1188             }
1189 
1190             case value_t::number_float:
1191             {
1192                 m_data.m_value = other.m_data.m_value.number_float;
1193                 break;
1194             }
1195 
1196             case value_t::binary:
1197             {
1198                 m_data.m_value = *other.m_data.m_value.binary;
1199                 break;
1200             }
1201 
1202             case value_t::null:
1203             case value_t::discarded:
1204             default:
1205                 break;
1206         }
1207 
1208         set_parents();
1209         assert_invariant();
1210     }
1211 
1212     /// @brief move constructor
1213     /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(basic_json && other)1214     basic_json(basic_json&& other) noexcept
1215         : json_base_class_t(std::forward<json_base_class_t>(other)),
1216           m_data(std::move(other.m_data))
1217     {
1218         // check that passed value is valid
1219         other.assert_invariant(false);
1220 
1221         // invalidate payload
1222         other.m_data.m_type = value_t::null;
1223         other.m_data.m_value = {};
1224 
1225         set_parents();
1226         assert_invariant();
1227     }
1228 
1229     /// @brief copy assignment
1230     /// @sa https://json.nlohmann.me/api/basic_json/operator=/
operator =(basic_json other)1231     basic_json& operator=(basic_json other) noexcept (
1232         std::is_nothrow_move_constructible<value_t>::value&&
1233         std::is_nothrow_move_assignable<value_t>::value&&
1234         std::is_nothrow_move_constructible<json_value>::value&&
1235         std::is_nothrow_move_assignable<json_value>::value&&
1236         std::is_nothrow_move_assignable<json_base_class_t>::value
1237     )
1238     {
1239         // check that passed value is valid
1240         other.assert_invariant();
1241 
1242         using std::swap;
1243         swap(m_data.m_type, other.m_data.m_type);
1244         swap(m_data.m_value, other.m_data.m_value);
1245         json_base_class_t::operator=(std::move(other));
1246 
1247         set_parents();
1248         assert_invariant();
1249         return *this;
1250     }
1251 
1252     /// @brief destructor
1253     /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/
~basic_json()1254     ~basic_json() noexcept
1255     {
1256         assert_invariant(false);
1257     }
1258 
1259     /// @}
1260 
1261   public:
1262     ///////////////////////
1263     // object inspection //
1264     ///////////////////////
1265 
1266     /// @name object inspection
1267     /// Functions to inspect the type of a JSON value.
1268     /// @{
1269 
1270     /// @brief serialization
1271     /// @sa https://json.nlohmann.me/api/basic_json/dump/
dump(const int indent=-1,const char indent_char=' ',const bool ensure_ascii=false,const error_handler_t error_handler=error_handler_t::strict) const1272     string_t dump(const int indent = -1,
1273                   const char indent_char = ' ',
1274                   const bool ensure_ascii = false,
1275                   const error_handler_t error_handler = error_handler_t::strict) const
1276     {
1277         string_t result;
1278         serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
1279 
1280         if (indent >= 0)
1281         {
1282             s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
1283         }
1284         else
1285         {
1286             s.dump(*this, false, ensure_ascii, 0);
1287         }
1288 
1289         return result;
1290     }
1291 
1292     /// @brief return the type of the JSON value (explicit)
1293     /// @sa https://json.nlohmann.me/api/basic_json/type/
type() const1294     constexpr value_t type() const noexcept
1295     {
1296         return m_data.m_type;
1297     }
1298 
1299     /// @brief return whether type is primitive
1300     /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
is_primitive() const1301     constexpr bool is_primitive() const noexcept
1302     {
1303         return is_null() || is_string() || is_boolean() || is_number() || is_binary();
1304     }
1305 
1306     /// @brief return whether type is structured
1307     /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
is_structured() const1308     constexpr bool is_structured() const noexcept
1309     {
1310         return is_array() || is_object();
1311     }
1312 
1313     /// @brief return whether value is null
1314     /// @sa https://json.nlohmann.me/api/basic_json/is_null/
is_null() const1315     constexpr bool is_null() const noexcept
1316     {
1317         return m_data.m_type == value_t::null;
1318     }
1319 
1320     /// @brief return whether value is a boolean
1321     /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
is_boolean() const1322     constexpr bool is_boolean() const noexcept
1323     {
1324         return m_data.m_type == value_t::boolean;
1325     }
1326 
1327     /// @brief return whether value is a number
1328     /// @sa https://json.nlohmann.me/api/basic_json/is_number/
is_number() const1329     constexpr bool is_number() const noexcept
1330     {
1331         return is_number_integer() || is_number_float();
1332     }
1333 
1334     /// @brief return whether value is an integer number
1335     /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
is_number_integer() const1336     constexpr bool is_number_integer() const noexcept
1337     {
1338         return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
1339     }
1340 
1341     /// @brief return whether value is an unsigned integer number
1342     /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
is_number_unsigned() const1343     constexpr bool is_number_unsigned() const noexcept
1344     {
1345         return m_data.m_type == value_t::number_unsigned;
1346     }
1347 
1348     /// @brief return whether value is a floating-point number
1349     /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
is_number_float() const1350     constexpr bool is_number_float() const noexcept
1351     {
1352         return m_data.m_type == value_t::number_float;
1353     }
1354 
1355     /// @brief return whether value is an object
1356     /// @sa https://json.nlohmann.me/api/basic_json/is_object/
is_object() const1357     constexpr bool is_object() const noexcept
1358     {
1359         return m_data.m_type == value_t::object;
1360     }
1361 
1362     /// @brief return whether value is an array
1363     /// @sa https://json.nlohmann.me/api/basic_json/is_array/
is_array() const1364     constexpr bool is_array() const noexcept
1365     {
1366         return m_data.m_type == value_t::array;
1367     }
1368 
1369     /// @brief return whether value is a string
1370     /// @sa https://json.nlohmann.me/api/basic_json/is_string/
is_string() const1371     constexpr bool is_string() const noexcept
1372     {
1373         return m_data.m_type == value_t::string;
1374     }
1375 
1376     /// @brief return whether value is a binary array
1377     /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
is_binary() const1378     constexpr bool is_binary() const noexcept
1379     {
1380         return m_data.m_type == value_t::binary;
1381     }
1382 
1383     /// @brief return whether value is discarded
1384     /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
is_discarded() const1385     constexpr bool is_discarded() const noexcept
1386     {
1387         return m_data.m_type == value_t::discarded;
1388     }
1389 
1390     /// @brief return the type of the JSON value (implicit)
1391     /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/
operator value_t() const1392     constexpr operator value_t() const noexcept
1393     {
1394         return m_data.m_type;
1395     }
1396 
1397     /// @}
1398 
1399   private:
1400     //////////////////
1401     // value access //
1402     //////////////////
1403 
1404     /// get a boolean (explicit)
get_impl(boolean_t *) const1405     boolean_t get_impl(boolean_t* /*unused*/) const
1406     {
1407         if (JSON_HEDLEY_LIKELY(is_boolean()))
1408         {
1409             return m_data.m_value.boolean;
1410         }
1411 
1412         JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
1413     }
1414 
1415     /// get a pointer to the value (object)
get_impl_ptr(object_t *)1416     object_t* get_impl_ptr(object_t* /*unused*/) noexcept
1417     {
1418         return is_object() ? m_data.m_value.object : nullptr;
1419     }
1420 
1421     /// get a pointer to the value (object)
get_impl_ptr(const object_t *) const1422     constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
1423     {
1424         return is_object() ? m_data.m_value.object : nullptr;
1425     }
1426 
1427     /// get a pointer to the value (array)
get_impl_ptr(array_t *)1428     array_t* get_impl_ptr(array_t* /*unused*/) noexcept
1429     {
1430         return is_array() ? m_data.m_value.array : nullptr;
1431     }
1432 
1433     /// get a pointer to the value (array)
get_impl_ptr(const array_t *) const1434     constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
1435     {
1436         return is_array() ? m_data.m_value.array : nullptr;
1437     }
1438 
1439     /// get a pointer to the value (string)
get_impl_ptr(string_t *)1440     string_t* get_impl_ptr(string_t* /*unused*/) noexcept
1441     {
1442         return is_string() ? m_data.m_value.string : nullptr;
1443     }
1444 
1445     /// get a pointer to the value (string)
get_impl_ptr(const string_t *) const1446     constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
1447     {
1448         return is_string() ? m_data.m_value.string : nullptr;
1449     }
1450 
1451     /// get a pointer to the value (boolean)
get_impl_ptr(boolean_t *)1452     boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
1453     {
1454         return is_boolean() ? &m_data.m_value.boolean : nullptr;
1455     }
1456 
1457     /// get a pointer to the value (boolean)
get_impl_ptr(const boolean_t *) const1458     constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
1459     {
1460         return is_boolean() ? &m_data.m_value.boolean : nullptr;
1461     }
1462 
1463     /// get a pointer to the value (integer number)
get_impl_ptr(number_integer_t *)1464     number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
1465     {
1466         return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
1467     }
1468 
1469     /// get a pointer to the value (integer number)
get_impl_ptr(const number_integer_t *) const1470     constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
1471     {
1472         return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
1473     }
1474 
1475     /// get a pointer to the value (unsigned number)
get_impl_ptr(number_unsigned_t *)1476     number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
1477     {
1478         return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
1479     }
1480 
1481     /// get a pointer to the value (unsigned number)
get_impl_ptr(const number_unsigned_t *) const1482     constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
1483     {
1484         return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
1485     }
1486 
1487     /// get a pointer to the value (floating-point number)
get_impl_ptr(number_float_t *)1488     number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
1489     {
1490         return is_number_float() ? &m_data.m_value.number_float : nullptr;
1491     }
1492 
1493     /// get a pointer to the value (floating-point number)
get_impl_ptr(const number_float_t *) const1494     constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
1495     {
1496         return is_number_float() ? &m_data.m_value.number_float : nullptr;
1497     }
1498 
1499     /// get a pointer to the value (binary)
get_impl_ptr(binary_t *)1500     binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
1501     {
1502         return is_binary() ? m_data.m_value.binary : nullptr;
1503     }
1504 
1505     /// get a pointer to the value (binary)
get_impl_ptr(const binary_t *) const1506     constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
1507     {
1508         return is_binary() ? m_data.m_value.binary : nullptr;
1509     }
1510 
1511     /*!
1512     @brief helper function to implement get_ref()
1513 
1514     This function helps to implement get_ref() without code duplication for
1515     const and non-const overloads
1516 
1517     @tparam ThisType will be deduced as `basic_json` or `const basic_json`
1518 
1519     @throw type_error.303 if ReferenceType does not match underlying value
1520     type of the current JSON
1521     */
1522     template<typename ReferenceType, typename ThisType>
get_ref_impl(ThisType & obj)1523     static ReferenceType get_ref_impl(ThisType& obj)
1524     {
1525         // delegate the call to get_ptr<>()
1526         auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
1527 
1528         if (JSON_HEDLEY_LIKELY(ptr != nullptr))
1529         {
1530             return *ptr;
1531         }
1532 
1533         JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
1534     }
1535 
1536   public:
1537     /// @name value access
1538     /// Direct access to the stored value of a JSON value.
1539     /// @{
1540 
1541     /// @brief get a pointer value (implicit)
1542     /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
1543     template<typename PointerType, typename std::enable_if<
1544                  std::is_pointer<PointerType>::value, int>::type = 0>
get_ptr()1545     auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
1546     {
1547         // delegate the call to get_impl_ptr<>()
1548         return get_impl_ptr(static_cast<PointerType>(nullptr));
1549     }
1550 
1551     /// @brief get a pointer value (implicit)
1552     /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
1553     template < typename PointerType, typename std::enable_if <
1554                    std::is_pointer<PointerType>::value&&
1555                    std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
get_ptr() const1556     constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
1557     {
1558         // delegate the call to get_impl_ptr<>() const
1559         return get_impl_ptr(static_cast<PointerType>(nullptr));
1560     }
1561 
1562   private:
1563     /*!
1564     @brief get a value (explicit)
1565 
1566     Explicit type conversion between the JSON value and a compatible value
1567     which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
1568     and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
1569     The value is converted by calling the @ref json_serializer<ValueType>
1570     `from_json()` method.
1571 
1572     The function is equivalent to executing
1573     @code {.cpp}
1574     ValueType ret;
1575     JSONSerializer<ValueType>::from_json(*this, ret);
1576     return ret;
1577     @endcode
1578 
1579     This overloads is chosen if:
1580     - @a ValueType is not @ref basic_json,
1581     - @ref json_serializer<ValueType> has a `from_json()` method of the form
1582       `void from_json(const basic_json&, ValueType&)`, and
1583     - @ref json_serializer<ValueType> does not have a `from_json()` method of
1584       the form `ValueType from_json(const basic_json&)`
1585 
1586     @tparam ValueType the returned value type
1587 
1588     @return copy of the JSON value, converted to @a ValueType
1589 
1590     @throw what @ref json_serializer<ValueType> `from_json()` method throws
1591 
1592     @liveexample{The example below shows several conversions from JSON values
1593     to other types. There a few things to note: (1) Floating-point numbers can
1594     be converted to integers\, (2) A JSON array can be converted to a standard
1595     `std::vector<short>`\, (3) A JSON object can be converted to C++
1596     associative containers such as `std::unordered_map<std::string\,
1597     json>`.,get__ValueType_const}
1598 
1599     @since version 2.1.0
1600     */
1601     template < typename ValueType,
1602                detail::enable_if_t <
1603                    detail::is_default_constructible<ValueType>::value&&
1604                    detail::has_from_json<basic_json_t, ValueType>::value,
1605                    int > = 0 >
get_impl(detail::priority_tag<0>) const1606     ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
1607                 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
1608     {
1609         auto ret = ValueType();
1610         JSONSerializer<ValueType>::from_json(*this, ret);
1611         return ret;
1612     }
1613 
1614     /*!
1615     @brief get a value (explicit); special case
1616 
1617     Explicit type conversion between the JSON value and a compatible value
1618     which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
1619     and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
1620     The value is converted by calling the @ref json_serializer<ValueType>
1621     `from_json()` method.
1622 
1623     The function is equivalent to executing
1624     @code {.cpp}
1625     return JSONSerializer<ValueType>::from_json(*this);
1626     @endcode
1627 
1628     This overloads is chosen if:
1629     - @a ValueType is not @ref basic_json and
1630     - @ref json_serializer<ValueType> has a `from_json()` method of the form
1631       `ValueType from_json(const basic_json&)`
1632 
1633     @note If @ref json_serializer<ValueType> has both overloads of
1634     `from_json()`, this one is chosen.
1635 
1636     @tparam ValueType the returned value type
1637 
1638     @return copy of the JSON value, converted to @a ValueType
1639 
1640     @throw what @ref json_serializer<ValueType> `from_json()` method throws
1641 
1642     @since version 2.1.0
1643     */
1644     template < typename ValueType,
1645                detail::enable_if_t <
1646                    detail::has_non_default_from_json<basic_json_t, ValueType>::value,
1647                    int > = 0 >
get_impl(detail::priority_tag<1>) const1648     ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
1649                 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
1650     {
1651         return JSONSerializer<ValueType>::from_json(*this);
1652     }
1653 
1654     /*!
1655     @brief get special-case overload
1656 
1657     This overloads converts the current @ref basic_json in a different
1658     @ref basic_json type
1659 
1660     @tparam BasicJsonType == @ref basic_json
1661 
1662     @return a copy of *this, converted into @a BasicJsonType
1663 
1664     @complexity Depending on the implementation of the called `from_json()`
1665                 method.
1666 
1667     @since version 3.2.0
1668     */
1669     template < typename BasicJsonType,
1670                detail::enable_if_t <
1671                    detail::is_basic_json<BasicJsonType>::value,
1672                    int > = 0 >
get_impl(detail::priority_tag<2>) const1673     BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
1674     {
1675         return *this;
1676     }
1677 
1678     /*!
1679     @brief get special-case overload
1680 
1681     This overloads avoids a lot of template boilerplate, it can be seen as the
1682     identity method
1683 
1684     @tparam BasicJsonType == @ref basic_json
1685 
1686     @return a copy of *this
1687 
1688     @complexity Constant.
1689 
1690     @since version 2.1.0
1691     */
1692     template<typename BasicJsonType,
1693              detail::enable_if_t<
1694                  std::is_same<BasicJsonType, basic_json_t>::value,
1695                  int> = 0>
get_impl(detail::priority_tag<3>) const1696     basic_json get_impl(detail::priority_tag<3> /*unused*/) const
1697     {
1698         return *this;
1699     }
1700 
1701     /*!
1702     @brief get a pointer value (explicit)
1703     @copydoc get()
1704     */
1705     template<typename PointerType,
1706              detail::enable_if_t<
1707                  std::is_pointer<PointerType>::value,
1708                  int> = 0>
get_impl(detail::priority_tag<4>) const1709     constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
1710     -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
1711     {
1712         // delegate the call to get_ptr
1713         return get_ptr<PointerType>();
1714     }
1715 
1716   public:
1717     /*!
1718     @brief get a (pointer) value (explicit)
1719 
1720     Performs explicit type conversion between the JSON value and a compatible value if required.
1721 
1722     - If the requested type is a pointer to the internally stored JSON value that pointer is returned.
1723     No copies are made.
1724 
1725     - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible
1726     from the current @ref basic_json.
1727 
1728     - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()`
1729     method.
1730 
1731     @tparam ValueTypeCV the provided value type
1732     @tparam ValueType the returned value type
1733 
1734     @return copy of the JSON value, converted to @tparam ValueType if necessary
1735 
1736     @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
1737 
1738     @since version 2.1.0
1739     */
1740     template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
1741 #if defined(JSON_HAS_CPP_14)
1742     constexpr
1743 #endif
get() const1744     auto get() const noexcept(
1745     noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))
1746     -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
1747     {
1748         // we cannot static_assert on ValueTypeCV being non-const, because
1749         // there is support for get<const basic_json_t>(), which is why we
1750         // still need the uncvref
1751         static_assert(!std::is_reference<ValueTypeCV>::value,
1752                       "get() cannot be used with reference types, you might want to use get_ref()");
1753         return get_impl<ValueType>(detail::priority_tag<4> {});
1754     }
1755 
1756     /*!
1757     @brief get a pointer value (explicit)
1758 
1759     Explicit pointer access to the internally stored JSON value. No copies are
1760     made.
1761 
1762     @warning The pointer becomes invalid if the underlying JSON object
1763     changes.
1764 
1765     @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
1766     object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
1767     @ref number_unsigned_t, or @ref number_float_t.
1768 
1769     @return pointer to the internally stored JSON value if the requested
1770     pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
1771 
1772     @complexity Constant.
1773 
1774     @liveexample{The example below shows how pointers to internal values of a
1775     JSON value can be requested. Note that no type conversions are made and a
1776     `nullptr` is returned if the value and the requested pointer type does not
1777     match.,get__PointerType}
1778 
1779     @sa see @ref get_ptr() for explicit pointer-member access
1780 
1781     @since version 1.0.0
1782     */
1783     template<typename PointerType, typename std::enable_if<
1784                  std::is_pointer<PointerType>::value, int>::type = 0>
get()1785     auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
1786     {
1787         // delegate the call to get_ptr
1788         return get_ptr<PointerType>();
1789     }
1790 
1791     /// @brief get a value (explicit)
1792     /// @sa https://json.nlohmann.me/api/basic_json/get_to/
1793     template < typename ValueType,
1794                detail::enable_if_t <
1795                    !detail::is_basic_json<ValueType>::value&&
1796                    detail::has_from_json<basic_json_t, ValueType>::value,
1797                    int > = 0 >
get_to(ValueType & v) const1798     ValueType & get_to(ValueType& v) const noexcept(noexcept(
1799                 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
1800     {
1801         JSONSerializer<ValueType>::from_json(*this, v);
1802         return v;
1803     }
1804 
1805     // specialization to allow calling get_to with a basic_json value
1806     // see https://github.com/nlohmann/json/issues/2175
1807     template<typename ValueType,
1808              detail::enable_if_t <
1809                  detail::is_basic_json<ValueType>::value,
1810                  int> = 0>
get_to(ValueType & v) const1811     ValueType & get_to(ValueType& v) const
1812     {
1813         v = *this;
1814         return v;
1815     }
1816 
1817     template <
1818         typename T, std::size_t N,
1819         typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
1820         detail::enable_if_t <
1821             detail::has_from_json<basic_json_t, Array>::value, int > = 0 >
get_to(T (& v)[N]) const1822     Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
1823     noexcept(noexcept(JSONSerializer<Array>::from_json(
1824                           std::declval<const basic_json_t&>(), v)))
1825     {
1826         JSONSerializer<Array>::from_json(*this, v);
1827         return v;
1828     }
1829 
1830     /// @brief get a reference value (implicit)
1831     /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
1832     template<typename ReferenceType, typename std::enable_if<
1833                  std::is_reference<ReferenceType>::value, int>::type = 0>
get_ref()1834     ReferenceType get_ref()
1835     {
1836         // delegate call to get_ref_impl
1837         return get_ref_impl<ReferenceType>(*this);
1838     }
1839 
1840     /// @brief get a reference value (implicit)
1841     /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
1842     template < typename ReferenceType, typename std::enable_if <
1843                    std::is_reference<ReferenceType>::value&&
1844                    std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
get_ref() const1845     ReferenceType get_ref() const
1846     {
1847         // delegate call to get_ref_impl
1848         return get_ref_impl<ReferenceType>(*this);
1849     }
1850 
1851     /*!
1852     @brief get a value (implicit)
1853 
1854     Implicit type conversion between the JSON value and a compatible value.
1855     The call is realized by calling @ref get() const.
1856 
1857     @tparam ValueType non-pointer type compatible to the JSON value, for
1858     instance `int` for JSON integer numbers, `bool` for JSON booleans, or
1859     `std::vector` types for JSON arrays. The character type of @ref string_t
1860     as well as an initializer list of this type is excluded to avoid
1861     ambiguities as these types implicitly convert to `std::string`.
1862 
1863     @return copy of the JSON value, converted to type @a ValueType
1864 
1865     @throw type_error.302 in case passed type @a ValueType is incompatible
1866     to the JSON value type (e.g., the JSON value is of type boolean, but a
1867     string is requested); see example below
1868 
1869     @complexity Linear in the size of the JSON value.
1870 
1871     @liveexample{The example below shows several conversions from JSON values
1872     to other types. There a few things to note: (1) Floating-point numbers can
1873     be converted to integers\, (2) A JSON array can be converted to a standard
1874     `std::vector<short>`\, (3) A JSON object can be converted to C++
1875     associative containers such as `std::unordered_map<std::string\,
1876     json>`.,operator__ValueType}
1877 
1878     @since version 1.0.0
1879     */
1880     template < typename ValueType, typename std::enable_if <
1881                    detail::conjunction <
1882                        detail::negation<std::is_pointer<ValueType>>,
1883                        detail::negation<std::is_same<ValueType, std::nullptr_t>>,
1884                        detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
1885                                         detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
1886                                         detail::negation<detail::is_basic_json<ValueType>>,
1887                                         detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,
1888 #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
1889                                                 detail::negation<std::is_same<ValueType, std::string_view>>,
1890 #endif
1891 #if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI
1892                                                 detail::negation<std::is_same<ValueType, std::any>>,
1893 #endif
1894                                                 detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
1895                                                 >::value, int >::type = 0 >
operator ValueType() const1896                                         JSON_EXPLICIT operator ValueType() const
1897     {
1898         // delegate the call to get<>() const
1899         return get<ValueType>();
1900     }
1901 
1902     /// @brief get a binary value
1903     /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
get_binary()1904     binary_t& get_binary()
1905     {
1906         if (!is_binary())
1907         {
1908             JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
1909         }
1910 
1911         return *get_ptr<binary_t*>();
1912     }
1913 
1914     /// @brief get a binary value
1915     /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
get_binary() const1916     const binary_t& get_binary() const
1917     {
1918         if (!is_binary())
1919         {
1920             JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
1921         }
1922 
1923         return *get_ptr<const binary_t*>();
1924     }
1925 
1926     /// @}
1927 
1928     ////////////////////
1929     // element access //
1930     ////////////////////
1931 
1932     /// @name element access
1933     /// Access to the JSON value.
1934     /// @{
1935 
1936     /// @brief access specified array element with bounds checking
1937     /// @sa https://json.nlohmann.me/api/basic_json/at/
at(size_type idx)1938     reference at(size_type idx)
1939     {
1940         // at only works for arrays
1941         if (JSON_HEDLEY_LIKELY(is_array()))
1942         {
1943             JSON_TRY
1944             {
1945                 return set_parent(m_data.m_value.array->at(idx));
1946             }
1947             JSON_CATCH (std::out_of_range&)
1948             {
1949                 // create better exception explanation
1950                 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
1951             }
1952         }
1953         else
1954         {
1955             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
1956         }
1957     }
1958 
1959     /// @brief access specified array element with bounds checking
1960     /// @sa https://json.nlohmann.me/api/basic_json/at/
at(size_type idx) const1961     const_reference at(size_type idx) const
1962     {
1963         // at only works for arrays
1964         if (JSON_HEDLEY_LIKELY(is_array()))
1965         {
1966             JSON_TRY
1967             {
1968                 return m_data.m_value.array->at(idx);
1969             }
1970             JSON_CATCH (std::out_of_range&)
1971             {
1972                 // create better exception explanation
1973                 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
1974             }
1975         }
1976         else
1977         {
1978             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
1979         }
1980     }
1981 
1982     /// @brief access specified object element with bounds checking
1983     /// @sa https://json.nlohmann.me/api/basic_json/at/
at(const typename object_t::key_type & key)1984     reference at(const typename object_t::key_type& key)
1985     {
1986         // at only works for objects
1987         if (JSON_HEDLEY_UNLIKELY(!is_object()))
1988         {
1989             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
1990         }
1991 
1992         auto it = m_data.m_value.object->find(key);
1993         if (it == m_data.m_value.object->end())
1994         {
1995             JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
1996         }
1997         return set_parent(it->second);
1998     }
1999 
2000     /// @brief access specified object element with bounds checking
2001     /// @sa https://json.nlohmann.me/api/basic_json/at/
2002     template<class KeyType, detail::enable_if_t<
2003                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
at(KeyType && key)2004     reference at(KeyType && key)
2005     {
2006         // at only works for objects
2007         if (JSON_HEDLEY_UNLIKELY(!is_object()))
2008         {
2009             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
2010         }
2011 
2012         auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
2013         if (it == m_data.m_value.object->end())
2014         {
2015             JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
2016         }
2017         return set_parent(it->second);
2018     }
2019 
2020     /// @brief access specified object element with bounds checking
2021     /// @sa https://json.nlohmann.me/api/basic_json/at/
at(const typename object_t::key_type & key) const2022     const_reference at(const typename object_t::key_type& key) const
2023     {
2024         // at only works for objects
2025         if (JSON_HEDLEY_UNLIKELY(!is_object()))
2026         {
2027             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
2028         }
2029 
2030         auto it = m_data.m_value.object->find(key);
2031         if (it == m_data.m_value.object->end())
2032         {
2033             JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
2034         }
2035         return it->second;
2036     }
2037 
2038     /// @brief access specified object element with bounds checking
2039     /// @sa https://json.nlohmann.me/api/basic_json/at/
2040     template<class KeyType, detail::enable_if_t<
2041                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
at(KeyType && key) const2042     const_reference at(KeyType && key) const
2043     {
2044         // at only works for objects
2045         if (JSON_HEDLEY_UNLIKELY(!is_object()))
2046         {
2047             JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
2048         }
2049 
2050         auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
2051         if (it == m_data.m_value.object->end())
2052         {
2053             JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
2054         }
2055         return it->second;
2056     }
2057 
2058     /// @brief access specified array element
2059     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
operator [](size_type idx)2060     reference operator[](size_type idx)
2061     {
2062         // implicitly convert null value to an empty array
2063         if (is_null())
2064         {
2065             m_data.m_type = value_t::array;
2066             m_data.m_value.array = create<array_t>();
2067             assert_invariant();
2068         }
2069 
2070         // operator[] only works for arrays
2071         if (JSON_HEDLEY_LIKELY(is_array()))
2072         {
2073             // fill up array with null values if given idx is outside range
2074             if (idx >= m_data.m_value.array->size())
2075             {
2076 #if JSON_DIAGNOSTICS
2077                 // remember array size & capacity before resizing
2078                 const auto old_size = m_data.m_value.array->size();
2079                 const auto old_capacity = m_data.m_value.array->capacity();
2080 #endif
2081                 m_data.m_value.array->resize(idx + 1);
2082 
2083 #if JSON_DIAGNOSTICS
2084                 if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
2085                 {
2086                     // capacity has changed: update all parents
2087                     set_parents();
2088                 }
2089                 else
2090                 {
2091                     // set parent for values added above
2092                     set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));
2093                 }
2094 #endif
2095                 assert_invariant();
2096             }
2097 
2098             return m_data.m_value.array->operator[](idx);
2099         }
2100 
2101         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
2102     }
2103 
2104     /// @brief access specified array element
2105     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
operator [](size_type idx) const2106     const_reference operator[](size_type idx) const
2107     {
2108         // const operator[] only works for arrays
2109         if (JSON_HEDLEY_LIKELY(is_array()))
2110         {
2111             return m_data.m_value.array->operator[](idx);
2112         }
2113 
2114         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
2115     }
2116 
2117     /// @brief access specified object element
2118     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
operator [](typename object_t::key_type key)2119     reference operator[](typename object_t::key_type key)
2120     {
2121         // implicitly convert null value to an empty object
2122         if (is_null())
2123         {
2124             m_data.m_type = value_t::object;
2125             m_data.m_value.object = create<object_t>();
2126             assert_invariant();
2127         }
2128 
2129         // operator[] only works for objects
2130         if (JSON_HEDLEY_LIKELY(is_object()))
2131         {
2132             auto result = m_data.m_value.object->emplace(std::move(key), nullptr);
2133             return set_parent(result.first->second);
2134         }
2135 
2136         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
2137     }
2138 
2139     /// @brief access specified object element
2140     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
operator [](const typename object_t::key_type & key) const2141     const_reference operator[](const typename object_t::key_type& key) const
2142     {
2143         // const operator[] only works for objects
2144         if (JSON_HEDLEY_LIKELY(is_object()))
2145         {
2146             auto it = m_data.m_value.object->find(key);
2147             JSON_ASSERT(it != m_data.m_value.object->end());
2148             return it->second;
2149         }
2150 
2151         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
2152     }
2153 
2154     // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
2155     // (they seemingly cannot be constrained to resolve the ambiguity)
2156     template<typename T>
operator [](T * key)2157     reference operator[](T* key)
2158     {
2159         return operator[](typename object_t::key_type(key));
2160     }
2161 
2162     template<typename T>
operator [](T * key) const2163     const_reference operator[](T* key) const
2164     {
2165         return operator[](typename object_t::key_type(key));
2166     }
2167 
2168     /// @brief access specified object element
2169     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2170     template<class KeyType, detail::enable_if_t<
2171                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
operator [](KeyType && key)2172     reference operator[](KeyType && key)
2173     {
2174         // implicitly convert null value to an empty object
2175         if (is_null())
2176         {
2177             m_data.m_type = value_t::object;
2178             m_data.m_value.object = create<object_t>();
2179             assert_invariant();
2180         }
2181 
2182         // operator[] only works for objects
2183         if (JSON_HEDLEY_LIKELY(is_object()))
2184         {
2185             auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
2186             return set_parent(result.first->second);
2187         }
2188 
2189         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
2190     }
2191 
2192     /// @brief access specified object element
2193     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2194     template<class KeyType, detail::enable_if_t<
2195                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
operator [](KeyType && key) const2196     const_reference operator[](KeyType && key) const
2197     {
2198         // const operator[] only works for objects
2199         if (JSON_HEDLEY_LIKELY(is_object()))
2200         {
2201             auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
2202             JSON_ASSERT(it != m_data.m_value.object->end());
2203             return it->second;
2204         }
2205 
2206         JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
2207     }
2208 
2209   private:
2210     template<typename KeyType>
2211     using is_comparable_with_object_key = detail::is_comparable <
2212         object_comparator_t, const typename object_t::key_type&, KeyType >;
2213 
2214     template<typename ValueType>
2215     using value_return_type = std::conditional <
2216         detail::is_c_string_uncvref<ValueType>::value,
2217         string_t, typename std::decay<ValueType>::type >;
2218 
2219   public:
2220     /// @brief access specified object element with default value
2221     /// @sa https://json.nlohmann.me/api/basic_json/value/
2222     template < class ValueType, detail::enable_if_t <
2223                    !detail::is_transparent<object_comparator_t>::value
2224                    && detail::is_getable<basic_json_t, ValueType>::value
2225                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
value(const typename object_t::key_type & key,const ValueType & default_value) const2226     ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
2227     {
2228         // value only works for objects
2229         if (JSON_HEDLEY_LIKELY(is_object()))
2230         {
2231             // if key is found, return value and given default value otherwise
2232             const auto it = find(key);
2233             if (it != end())
2234             {
2235                 return it->template get<ValueType>();
2236             }
2237 
2238             return default_value;
2239         }
2240 
2241         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
2242     }
2243 
2244     /// @brief access specified object element with default value
2245     /// @sa https://json.nlohmann.me/api/basic_json/value/
2246     template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
2247                detail::enable_if_t <
2248                    !detail::is_transparent<object_comparator_t>::value
2249                    && detail::is_getable<basic_json_t, ReturnType>::value
2250                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
value(const typename object_t::key_type & key,ValueType && default_value) const2251     ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
2252     {
2253         // value only works for objects
2254         if (JSON_HEDLEY_LIKELY(is_object()))
2255         {
2256             // if key is found, return value and given default value otherwise
2257             const auto it = find(key);
2258             if (it != end())
2259             {
2260                 return it->template get<ReturnType>();
2261             }
2262 
2263             return std::forward<ValueType>(default_value);
2264         }
2265 
2266         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
2267     }
2268 
2269     /// @brief access specified object element with default value
2270     /// @sa https://json.nlohmann.me/api/basic_json/value/
2271     template < class ValueType, class KeyType, detail::enable_if_t <
2272                    detail::is_transparent<object_comparator_t>::value
2273                    && !detail::is_json_pointer<KeyType>::value
2274                    && is_comparable_with_object_key<KeyType>::value
2275                    && detail::is_getable<basic_json_t, ValueType>::value
2276                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
value(KeyType && key,const ValueType & default_value) const2277     ValueType value(KeyType && key, const ValueType& default_value) const
2278     {
2279         // value only works for objects
2280         if (JSON_HEDLEY_LIKELY(is_object()))
2281         {
2282             // if key is found, return value and given default value otherwise
2283             const auto it = find(std::forward<KeyType>(key));
2284             if (it != end())
2285             {
2286                 return it->template get<ValueType>();
2287             }
2288 
2289             return default_value;
2290         }
2291 
2292         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
2293     }
2294 
2295     /// @brief access specified object element via JSON Pointer with default value
2296     /// @sa https://json.nlohmann.me/api/basic_json/value/
2297     template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
2298                detail::enable_if_t <
2299                    detail::is_transparent<object_comparator_t>::value
2300                    && !detail::is_json_pointer<KeyType>::value
2301                    && is_comparable_with_object_key<KeyType>::value
2302                    && detail::is_getable<basic_json_t, ReturnType>::value
2303                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
value(KeyType && key,ValueType && default_value) const2304     ReturnType value(KeyType && key, ValueType && default_value) const
2305     {
2306         // value only works for objects
2307         if (JSON_HEDLEY_LIKELY(is_object()))
2308         {
2309             // if key is found, return value and given default value otherwise
2310             const auto it = find(std::forward<KeyType>(key));
2311             if (it != end())
2312             {
2313                 return it->template get<ReturnType>();
2314             }
2315 
2316             return std::forward<ValueType>(default_value);
2317         }
2318 
2319         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
2320     }
2321 
2322     /// @brief access specified object element via JSON Pointer with default value
2323     /// @sa https://json.nlohmann.me/api/basic_json/value/
2324     template < class ValueType, detail::enable_if_t <
2325                    detail::is_getable<basic_json_t, ValueType>::value
2326                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
value(const json_pointer & ptr,const ValueType & default_value) const2327     ValueType value(const json_pointer& ptr, const ValueType& default_value) const
2328     {
2329         // value only works for objects
2330         if (JSON_HEDLEY_LIKELY(is_object()))
2331         {
2332             // if pointer resolves a value, return it or use default value
2333             JSON_TRY
2334             {
2335                 return ptr.get_checked(this).template get<ValueType>();
2336             }
2337             JSON_INTERNAL_CATCH (out_of_range&)
2338             {
2339                 return default_value;
2340             }
2341         }
2342 
2343         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
2344     }
2345 
2346     /// @brief access specified object element via JSON Pointer with default value
2347     /// @sa https://json.nlohmann.me/api/basic_json/value/
2348     template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
2349                detail::enable_if_t <
2350                    detail::is_getable<basic_json_t, ReturnType>::value
2351                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
value(const json_pointer & ptr,ValueType && default_value) const2352     ReturnType value(const json_pointer& ptr, ValueType && default_value) const
2353     {
2354         // value only works for objects
2355         if (JSON_HEDLEY_LIKELY(is_object()))
2356         {
2357             // if pointer resolves a value, return it or use default value
2358             JSON_TRY
2359             {
2360                 return ptr.get_checked(this).template get<ReturnType>();
2361             }
2362             JSON_INTERNAL_CATCH (out_of_range&)
2363             {
2364                 return std::forward<ValueType>(default_value);
2365             }
2366         }
2367 
2368         JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
2369     }
2370 
2371     template < class ValueType, class BasicJsonType, detail::enable_if_t <
2372                    detail::is_basic_json<BasicJsonType>::value
2373                    && detail::is_getable<basic_json_t, ValueType>::value
2374                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2375     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
value(const::nlohmann::json_pointer<BasicJsonType> & ptr,const ValueType & default_value) const2376     ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
2377     {
2378         return value(ptr.convert(), default_value);
2379     }
2380 
2381     template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
2382                detail::enable_if_t <
2383                    detail::is_basic_json<BasicJsonType>::value
2384                    && detail::is_getable<basic_json_t, ReturnType>::value
2385                    && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2386     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
value(const::nlohmann::json_pointer<BasicJsonType> & ptr,ValueType && default_value) const2387     ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
2388     {
2389         return value(ptr.convert(), std::forward<ValueType>(default_value));
2390     }
2391 
2392     /// @brief access the first element
2393     /// @sa https://json.nlohmann.me/api/basic_json/front/
front()2394     reference front()
2395     {
2396         return *begin();
2397     }
2398 
2399     /// @brief access the first element
2400     /// @sa https://json.nlohmann.me/api/basic_json/front/
front() const2401     const_reference front() const
2402     {
2403         return *cbegin();
2404     }
2405 
2406     /// @brief access the last element
2407     /// @sa https://json.nlohmann.me/api/basic_json/back/
back()2408     reference back()
2409     {
2410         auto tmp = end();
2411         --tmp;
2412         return *tmp;
2413     }
2414 
2415     /// @brief access the last element
2416     /// @sa https://json.nlohmann.me/api/basic_json/back/
back() const2417     const_reference back() const
2418     {
2419         auto tmp = cend();
2420         --tmp;
2421         return *tmp;
2422     }
2423 
2424     /// @brief remove element given an iterator
2425     /// @sa https://json.nlohmann.me/api/basic_json/erase/
2426     template < class IteratorType, detail::enable_if_t <
2427                    std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
2428                    std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
erase(IteratorType pos)2429     IteratorType erase(IteratorType pos)
2430     {
2431         // make sure iterator fits the current value
2432         if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
2433         {
2434             JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
2435         }
2436 
2437         IteratorType result = end();
2438 
2439         switch (m_data.m_type)
2440         {
2441             case value_t::boolean:
2442             case value_t::number_float:
2443             case value_t::number_integer:
2444             case value_t::number_unsigned:
2445             case value_t::string:
2446             case value_t::binary:
2447             {
2448                 if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
2449                 {
2450                     JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
2451                 }
2452 
2453                 if (is_string())
2454                 {
2455                     AllocatorType<string_t> alloc;
2456                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
2457                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
2458                     m_data.m_value.string = nullptr;
2459                 }
2460                 else if (is_binary())
2461                 {
2462                     AllocatorType<binary_t> alloc;
2463                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
2464                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
2465                     m_data.m_value.binary = nullptr;
2466                 }
2467 
2468                 m_data.m_type = value_t::null;
2469                 assert_invariant();
2470                 break;
2471             }
2472 
2473             case value_t::object:
2474             {
2475                 result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);
2476                 break;
2477             }
2478 
2479             case value_t::array:
2480             {
2481                 result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator);
2482                 break;
2483             }
2484 
2485             case value_t::null:
2486             case value_t::discarded:
2487             default:
2488                 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
2489         }
2490 
2491         return result;
2492     }
2493 
2494     /// @brief remove elements given an iterator range
2495     /// @sa https://json.nlohmann.me/api/basic_json/erase/
2496     template < class IteratorType, detail::enable_if_t <
2497                    std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
2498                    std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
erase(IteratorType first,IteratorType last)2499     IteratorType erase(IteratorType first, IteratorType last)
2500     {
2501         // make sure iterator fits the current value
2502         if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
2503         {
2504             JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
2505         }
2506 
2507         IteratorType result = end();
2508 
2509         switch (m_data.m_type)
2510         {
2511             case value_t::boolean:
2512             case value_t::number_float:
2513             case value_t::number_integer:
2514             case value_t::number_unsigned:
2515             case value_t::string:
2516             case value_t::binary:
2517             {
2518                 if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
2519                                        || !last.m_it.primitive_iterator.is_end()))
2520                 {
2521                     JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
2522                 }
2523 
2524                 if (is_string())
2525                 {
2526                     AllocatorType<string_t> alloc;
2527                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
2528                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
2529                     m_data.m_value.string = nullptr;
2530                 }
2531                 else if (is_binary())
2532                 {
2533                     AllocatorType<binary_t> alloc;
2534                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
2535                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
2536                     m_data.m_value.binary = nullptr;
2537                 }
2538 
2539                 m_data.m_type = value_t::null;
2540                 assert_invariant();
2541                 break;
2542             }
2543 
2544             case value_t::object:
2545             {
2546                 result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator,
2547                                               last.m_it.object_iterator);
2548                 break;
2549             }
2550 
2551             case value_t::array:
2552             {
2553                 result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator,
2554                                              last.m_it.array_iterator);
2555                 break;
2556             }
2557 
2558             case value_t::null:
2559             case value_t::discarded:
2560             default:
2561                 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
2562         }
2563 
2564         return result;
2565     }
2566 
2567   private:
2568     template < typename KeyType, detail::enable_if_t <
2569                    detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
erase_internal(KeyType && key)2570     size_type erase_internal(KeyType && key)
2571     {
2572         // this erase only works for objects
2573         if (JSON_HEDLEY_UNLIKELY(!is_object()))
2574         {
2575             JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
2576         }
2577 
2578         return m_data.m_value.object->erase(std::forward<KeyType>(key));
2579     }
2580 
2581     template < typename KeyType, detail::enable_if_t <
2582                    !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
erase_internal(KeyType && key)2583     size_type erase_internal(KeyType && key)
2584     {
2585         // this erase only works for objects
2586         if (JSON_HEDLEY_UNLIKELY(!is_object()))
2587         {
2588             JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
2589         }
2590 
2591         const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
2592         if (it != m_data.m_value.object->end())
2593         {
2594             m_data.m_value.object->erase(it);
2595             return 1;
2596         }
2597         return 0;
2598     }
2599 
2600   public:
2601 
2602     /// @brief remove element from a JSON object given a key
2603     /// @sa https://json.nlohmann.me/api/basic_json/erase/
erase(const typename object_t::key_type & key)2604     size_type erase(const typename object_t::key_type& key)
2605     {
2606         // the indirection via erase_internal() is added to avoid making this
2607         // function a template and thus de-rank it during overload resolution
2608         return erase_internal(key);
2609     }
2610 
2611     /// @brief remove element from a JSON object given a key
2612     /// @sa https://json.nlohmann.me/api/basic_json/erase/
2613     template<class KeyType, detail::enable_if_t<
2614                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
erase(KeyType && key)2615     size_type erase(KeyType && key)
2616     {
2617         return erase_internal(std::forward<KeyType>(key));
2618     }
2619 
2620     /// @brief remove element from a JSON array given an index
2621     /// @sa https://json.nlohmann.me/api/basic_json/erase/
erase(const size_type idx)2622     void erase(const size_type idx)
2623     {
2624         // this erase only works for arrays
2625         if (JSON_HEDLEY_LIKELY(is_array()))
2626         {
2627             if (JSON_HEDLEY_UNLIKELY(idx >= size()))
2628             {
2629                 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
2630             }
2631 
2632             m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
2633         }
2634         else
2635         {
2636             JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
2637         }
2638     }
2639 
2640     /// @}
2641 
2642     ////////////
2643     // lookup //
2644     ////////////
2645 
2646     /// @name lookup
2647     /// @{
2648 
2649     /// @brief find an element in a JSON object
2650     /// @sa https://json.nlohmann.me/api/basic_json/find/
find(const typename object_t::key_type & key)2651     iterator find(const typename object_t::key_type& key)
2652     {
2653         auto result = end();
2654 
2655         if (is_object())
2656         {
2657             result.m_it.object_iterator = m_data.m_value.object->find(key);
2658         }
2659 
2660         return result;
2661     }
2662 
2663     /// @brief find an element in a JSON object
2664     /// @sa https://json.nlohmann.me/api/basic_json/find/
find(const typename object_t::key_type & key) const2665     const_iterator find(const typename object_t::key_type& key) const
2666     {
2667         auto result = cend();
2668 
2669         if (is_object())
2670         {
2671             result.m_it.object_iterator = m_data.m_value.object->find(key);
2672         }
2673 
2674         return result;
2675     }
2676 
2677     /// @brief find an element in a JSON object
2678     /// @sa https://json.nlohmann.me/api/basic_json/find/
2679     template<class KeyType, detail::enable_if_t<
2680                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
find(KeyType && key)2681     iterator find(KeyType && key)
2682     {
2683         auto result = end();
2684 
2685         if (is_object())
2686         {
2687             result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
2688         }
2689 
2690         return result;
2691     }
2692 
2693     /// @brief find an element in a JSON object
2694     /// @sa https://json.nlohmann.me/api/basic_json/find/
2695     template<class KeyType, detail::enable_if_t<
2696                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
find(KeyType && key) const2697     const_iterator find(KeyType && key) const
2698     {
2699         auto result = cend();
2700 
2701         if (is_object())
2702         {
2703             result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
2704         }
2705 
2706         return result;
2707     }
2708 
2709     /// @brief returns the number of occurrences of a key in a JSON object
2710     /// @sa https://json.nlohmann.me/api/basic_json/count/
count(const typename object_t::key_type & key) const2711     size_type count(const typename object_t::key_type& key) const
2712     {
2713         // return 0 for all nonobject types
2714         return is_object() ? m_data.m_value.object->count(key) : 0;
2715     }
2716 
2717     /// @brief returns the number of occurrences of a key in a JSON object
2718     /// @sa https://json.nlohmann.me/api/basic_json/count/
2719     template<class KeyType, detail::enable_if_t<
2720                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
count(KeyType && key) const2721     size_type count(KeyType && key) const
2722     {
2723         // return 0 for all nonobject types
2724         return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
2725     }
2726 
2727     /// @brief check the existence of an element in a JSON object
2728     /// @sa https://json.nlohmann.me/api/basic_json/contains/
contains(const typename object_t::key_type & key) const2729     bool contains(const typename object_t::key_type& key) const
2730     {
2731         return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
2732     }
2733 
2734     /// @brief check the existence of an element in a JSON object
2735     /// @sa https://json.nlohmann.me/api/basic_json/contains/
2736     template<class KeyType, detail::enable_if_t<
2737                  detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
contains(KeyType && key) const2738     bool contains(KeyType && key) const
2739     {
2740         return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
2741     }
2742 
2743     /// @brief check the existence of an element in a JSON object given a JSON pointer
2744     /// @sa https://json.nlohmann.me/api/basic_json/contains/
contains(const json_pointer & ptr) const2745     bool contains(const json_pointer& ptr) const
2746     {
2747         return ptr.contains(this);
2748     }
2749 
2750     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
2751     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
contains(const typename::nlohmann::json_pointer<BasicJsonType> & ptr) const2752     bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
2753     {
2754         return ptr.contains(this);
2755     }
2756 
2757     /// @}
2758 
2759     ///////////////
2760     // iterators //
2761     ///////////////
2762 
2763     /// @name iterators
2764     /// @{
2765 
2766     /// @brief returns an iterator to the first element
2767     /// @sa https://json.nlohmann.me/api/basic_json/begin/
begin()2768     iterator begin() noexcept
2769     {
2770         iterator result(this);
2771         result.set_begin();
2772         return result;
2773     }
2774 
2775     /// @brief returns an iterator to the first element
2776     /// @sa https://json.nlohmann.me/api/basic_json/begin/
begin() const2777     const_iterator begin() const noexcept
2778     {
2779         return cbegin();
2780     }
2781 
2782     /// @brief returns a const iterator to the first element
2783     /// @sa https://json.nlohmann.me/api/basic_json/cbegin/
cbegin() const2784     const_iterator cbegin() const noexcept
2785     {
2786         const_iterator result(this);
2787         result.set_begin();
2788         return result;
2789     }
2790 
2791     /// @brief returns an iterator to one past the last element
2792     /// @sa https://json.nlohmann.me/api/basic_json/end/
end()2793     iterator end() noexcept
2794     {
2795         iterator result(this);
2796         result.set_end();
2797         return result;
2798     }
2799 
2800     /// @brief returns an iterator to one past the last element
2801     /// @sa https://json.nlohmann.me/api/basic_json/end/
end() const2802     const_iterator end() const noexcept
2803     {
2804         return cend();
2805     }
2806 
2807     /// @brief returns an iterator to one past the last element
2808     /// @sa https://json.nlohmann.me/api/basic_json/cend/
cend() const2809     const_iterator cend() const noexcept
2810     {
2811         const_iterator result(this);
2812         result.set_end();
2813         return result;
2814     }
2815 
2816     /// @brief returns an iterator to the reverse-beginning
2817     /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
rbegin()2818     reverse_iterator rbegin() noexcept
2819     {
2820         return reverse_iterator(end());
2821     }
2822 
2823     /// @brief returns an iterator to the reverse-beginning
2824     /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
rbegin() const2825     const_reverse_iterator rbegin() const noexcept
2826     {
2827         return crbegin();
2828     }
2829 
2830     /// @brief returns an iterator to the reverse-end
2831     /// @sa https://json.nlohmann.me/api/basic_json/rend/
rend()2832     reverse_iterator rend() noexcept
2833     {
2834         return reverse_iterator(begin());
2835     }
2836 
2837     /// @brief returns an iterator to the reverse-end
2838     /// @sa https://json.nlohmann.me/api/basic_json/rend/
rend() const2839     const_reverse_iterator rend() const noexcept
2840     {
2841         return crend();
2842     }
2843 
2844     /// @brief returns a const reverse iterator to the last element
2845     /// @sa https://json.nlohmann.me/api/basic_json/crbegin/
crbegin() const2846     const_reverse_iterator crbegin() const noexcept
2847     {
2848         return const_reverse_iterator(cend());
2849     }
2850 
2851     /// @brief returns a const reverse iterator to one before the first
2852     /// @sa https://json.nlohmann.me/api/basic_json/crend/
crend() const2853     const_reverse_iterator crend() const noexcept
2854     {
2855         return const_reverse_iterator(cbegin());
2856     }
2857 
2858   public:
2859     /// @brief wrapper to access iterator member functions in range-based for
2860     /// @sa https://json.nlohmann.me/api/basic_json/items/
2861     /// @deprecated This function is deprecated since 3.1.0 and will be removed in
2862     ///             version 4.0.0 of the library. Please use @ref items() instead;
2863     ///             that is, replace `json::iterator_wrapper(j)` with `j.items()`.
items()2864     JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
2865     static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
2866     {
2867         return ref.items();
2868     }
2869 
2870     /// @brief wrapper to access iterator member functions in range-based for
2871     /// @sa https://json.nlohmann.me/api/basic_json/items/
2872     /// @deprecated This function is deprecated since 3.1.0 and will be removed in
2873     ///         version 4.0.0 of the library. Please use @ref items() instead;
2874     ///         that is, replace `json::iterator_wrapper(j)` with `j.items()`.
items()2875     JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
2876     static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
2877     {
2878         return ref.items();
2879     }
2880 
2881     /// @brief helper to access iterator member functions in range-based for
2882     /// @sa https://json.nlohmann.me/api/basic_json/items/
items()2883     iteration_proxy<iterator> items() noexcept
2884     {
2885         return iteration_proxy<iterator>(*this);
2886     }
2887 
2888     /// @brief helper to access iterator member functions in range-based for
2889     /// @sa https://json.nlohmann.me/api/basic_json/items/
items() const2890     iteration_proxy<const_iterator> items() const noexcept
2891     {
2892         return iteration_proxy<const_iterator>(*this);
2893     }
2894 
2895     /// @}
2896 
2897     //////////////
2898     // capacity //
2899     //////////////
2900 
2901     /// @name capacity
2902     /// @{
2903 
2904     /// @brief checks whether the container is empty.
2905     /// @sa https://json.nlohmann.me/api/basic_json/empty/
empty() const2906     bool empty() const noexcept
2907     {
2908         switch (m_data.m_type)
2909         {
2910             case value_t::null:
2911             {
2912                 // null values are empty
2913                 return true;
2914             }
2915 
2916             case value_t::array:
2917             {
2918                 // delegate call to array_t::empty()
2919                 return m_data.m_value.array->empty();
2920             }
2921 
2922             case value_t::object:
2923             {
2924                 // delegate call to object_t::empty()
2925                 return m_data.m_value.object->empty();
2926             }
2927 
2928             case value_t::string:
2929             case value_t::boolean:
2930             case value_t::number_integer:
2931             case value_t::number_unsigned:
2932             case value_t::number_float:
2933             case value_t::binary:
2934             case value_t::discarded:
2935             default:
2936             {
2937                 // all other types are nonempty
2938                 return false;
2939             }
2940         }
2941     }
2942 
2943     /// @brief returns the number of elements
2944     /// @sa https://json.nlohmann.me/api/basic_json/size/
size() const2945     size_type size() const noexcept
2946     {
2947         switch (m_data.m_type)
2948         {
2949             case value_t::null:
2950             {
2951                 // null values are empty
2952                 return 0;
2953             }
2954 
2955             case value_t::array:
2956             {
2957                 // delegate call to array_t::size()
2958                 return m_data.m_value.array->size();
2959             }
2960 
2961             case value_t::object:
2962             {
2963                 // delegate call to object_t::size()
2964                 return m_data.m_value.object->size();
2965             }
2966 
2967             case value_t::string:
2968             case value_t::boolean:
2969             case value_t::number_integer:
2970             case value_t::number_unsigned:
2971             case value_t::number_float:
2972             case value_t::binary:
2973             case value_t::discarded:
2974             default:
2975             {
2976                 // all other types have size 1
2977                 return 1;
2978             }
2979         }
2980     }
2981 
2982     /// @brief returns the maximum possible number of elements
2983     /// @sa https://json.nlohmann.me/api/basic_json/max_size/
max_size() const2984     size_type max_size() const noexcept
2985     {
2986         switch (m_data.m_type)
2987         {
2988             case value_t::array:
2989             {
2990                 // delegate call to array_t::max_size()
2991                 return m_data.m_value.array->max_size();
2992             }
2993 
2994             case value_t::object:
2995             {
2996                 // delegate call to object_t::max_size()
2997                 return m_data.m_value.object->max_size();
2998             }
2999 
3000             case value_t::null:
3001             case value_t::string:
3002             case value_t::boolean:
3003             case value_t::number_integer:
3004             case value_t::number_unsigned:
3005             case value_t::number_float:
3006             case value_t::binary:
3007             case value_t::discarded:
3008             default:
3009             {
3010                 // all other types have max_size() == size()
3011                 return size();
3012             }
3013         }
3014     }
3015 
3016     /// @}
3017 
3018     ///////////////
3019     // modifiers //
3020     ///////////////
3021 
3022     /// @name modifiers
3023     /// @{
3024 
3025     /// @brief clears the contents
3026     /// @sa https://json.nlohmann.me/api/basic_json/clear/
clear()3027     void clear() noexcept
3028     {
3029         switch (m_data.m_type)
3030         {
3031             case value_t::number_integer:
3032             {
3033                 m_data.m_value.number_integer = 0;
3034                 break;
3035             }
3036 
3037             case value_t::number_unsigned:
3038             {
3039                 m_data.m_value.number_unsigned = 0;
3040                 break;
3041             }
3042 
3043             case value_t::number_float:
3044             {
3045                 m_data.m_value.number_float = 0.0;
3046                 break;
3047             }
3048 
3049             case value_t::boolean:
3050             {
3051                 m_data.m_value.boolean = false;
3052                 break;
3053             }
3054 
3055             case value_t::string:
3056             {
3057                 m_data.m_value.string->clear();
3058                 break;
3059             }
3060 
3061             case value_t::binary:
3062             {
3063                 m_data.m_value.binary->clear();
3064                 break;
3065             }
3066 
3067             case value_t::array:
3068             {
3069                 m_data.m_value.array->clear();
3070                 break;
3071             }
3072 
3073             case value_t::object:
3074             {
3075                 m_data.m_value.object->clear();
3076                 break;
3077             }
3078 
3079             case value_t::null:
3080             case value_t::discarded:
3081             default:
3082                 break;
3083         }
3084     }
3085 
3086     /// @brief add an object to an array
3087     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
push_back(basic_json && val)3088     void push_back(basic_json&& val)
3089     {
3090         // push_back only works for null objects or arrays
3091         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
3092         {
3093             JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
3094         }
3095 
3096         // transform null object into an array
3097         if (is_null())
3098         {
3099             m_data.m_type = value_t::array;
3100             m_data.m_value = value_t::array;
3101             assert_invariant();
3102         }
3103 
3104         // add element to array (move semantics)
3105         const auto old_capacity = m_data.m_value.array->capacity();
3106         m_data.m_value.array->push_back(std::move(val));
3107         set_parent(m_data.m_value.array->back(), old_capacity);
3108         // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
3109     }
3110 
3111     /// @brief add an object to an array
3112     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
operator +=(basic_json && val)3113     reference operator+=(basic_json&& val)
3114     {
3115         push_back(std::move(val));
3116         return *this;
3117     }
3118 
3119     /// @brief add an object to an array
3120     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
push_back(const basic_json & val)3121     void push_back(const basic_json& val)
3122     {
3123         // push_back only works for null objects or arrays
3124         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
3125         {
3126             JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
3127         }
3128 
3129         // transform null object into an array
3130         if (is_null())
3131         {
3132             m_data.m_type = value_t::array;
3133             m_data.m_value = value_t::array;
3134             assert_invariant();
3135         }
3136 
3137         // add element to array
3138         const auto old_capacity = m_data.m_value.array->capacity();
3139         m_data.m_value.array->push_back(val);
3140         set_parent(m_data.m_value.array->back(), old_capacity);
3141     }
3142 
3143     /// @brief add an object to an array
3144     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
operator +=(const basic_json & val)3145     reference operator+=(const basic_json& val)
3146     {
3147         push_back(val);
3148         return *this;
3149     }
3150 
3151     /// @brief add an object to an object
3152     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
push_back(const typename object_t::value_type & val)3153     void push_back(const typename object_t::value_type& val)
3154     {
3155         // push_back only works for null objects or objects
3156         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
3157         {
3158             JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
3159         }
3160 
3161         // transform null object into an object
3162         if (is_null())
3163         {
3164             m_data.m_type = value_t::object;
3165             m_data.m_value = value_t::object;
3166             assert_invariant();
3167         }
3168 
3169         // add element to object
3170         auto res = m_data.m_value.object->insert(val);
3171         set_parent(res.first->second);
3172     }
3173 
3174     /// @brief add an object to an object
3175     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
operator +=(const typename object_t::value_type & val)3176     reference operator+=(const typename object_t::value_type& val)
3177     {
3178         push_back(val);
3179         return *this;
3180     }
3181 
3182     /// @brief add an object to an object
3183     /// @sa https://json.nlohmann.me/api/basic_json/push_back/
push_back(initializer_list_t init)3184     void push_back(initializer_list_t init)
3185     {
3186         if (is_object() && init.size() == 2 && (*init.begin())->is_string())
3187         {
3188             basic_json&& key = init.begin()->moved_or_copied();
3189             push_back(typename object_t::value_type(
3190                           std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
3191         }
3192         else
3193         {
3194             push_back(basic_json(init));
3195         }
3196     }
3197 
3198     /// @brief add an object to an object
3199     /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
operator +=(initializer_list_t init)3200     reference operator+=(initializer_list_t init)
3201     {
3202         push_back(init);
3203         return *this;
3204     }
3205 
3206     /// @brief add an object to an array
3207     /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/
3208     template<class... Args>
emplace_back(Args &&...args)3209     reference emplace_back(Args&& ... args)
3210     {
3211         // emplace_back only works for null objects or arrays
3212         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
3213         {
3214             JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
3215         }
3216 
3217         // transform null object into an array
3218         if (is_null())
3219         {
3220             m_data.m_type = value_t::array;
3221             m_data.m_value = value_t::array;
3222             assert_invariant();
3223         }
3224 
3225         // add element to array (perfect forwarding)
3226         const auto old_capacity = m_data.m_value.array->capacity();
3227         m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
3228         return set_parent(m_data.m_value.array->back(), old_capacity);
3229     }
3230 
3231     /// @brief add an object to an object if key does not exist
3232     /// @sa https://json.nlohmann.me/api/basic_json/emplace/
3233     template<class... Args>
emplace(Args &&...args)3234     std::pair<iterator, bool> emplace(Args&& ... args)
3235     {
3236         // emplace only works for null objects or arrays
3237         if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
3238         {
3239             JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
3240         }
3241 
3242         // transform null object into an object
3243         if (is_null())
3244         {
3245             m_data.m_type = value_t::object;
3246             m_data.m_value = value_t::object;
3247             assert_invariant();
3248         }
3249 
3250         // add element to array (perfect forwarding)
3251         auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);
3252         set_parent(res.first->second);
3253 
3254         // create result iterator and set iterator to the result of emplace
3255         auto it = begin();
3256         it.m_it.object_iterator = res.first;
3257 
3258         // return pair of iterator and boolean
3259         return {it, res.second};
3260     }
3261 
3262     /// Helper for insertion of an iterator
3263     /// @note: This uses std::distance to support GCC 4.8,
3264     ///        see https://github.com/nlohmann/json/pull/1257
3265     template<typename... Args>
insert_iterator(const_iterator pos,Args &&...args)3266     iterator insert_iterator(const_iterator pos, Args&& ... args)
3267     {
3268         iterator result(this);
3269         JSON_ASSERT(m_data.m_value.array != nullptr);
3270 
3271         auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator);
3272         m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
3273         result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos;
3274 
3275         // This could have been written as:
3276         // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val);
3277         // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
3278 
3279         set_parents();
3280         return result;
3281     }
3282 
3283     /// @brief inserts element into array
3284     /// @sa https://json.nlohmann.me/api/basic_json/insert/
insert(const_iterator pos,const basic_json & val)3285     iterator insert(const_iterator pos, const basic_json& val)
3286     {
3287         // insert only works for arrays
3288         if (JSON_HEDLEY_LIKELY(is_array()))
3289         {
3290             // check if iterator pos fits to this JSON value
3291             if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
3292             {
3293                 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
3294             }
3295 
3296             // insert to array and return iterator
3297             return insert_iterator(pos, val);
3298         }
3299 
3300         JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
3301     }
3302 
3303     /// @brief inserts element into array
3304     /// @sa https://json.nlohmann.me/api/basic_json/insert/
insert(const_iterator pos,basic_json && val)3305     iterator insert(const_iterator pos, basic_json&& val)
3306     {
3307         return insert(pos, val);
3308     }
3309 
3310     /// @brief inserts copies of element into array
3311     /// @sa https://json.nlohmann.me/api/basic_json/insert/
insert(const_iterator pos,size_type cnt,const basic_json & val)3312     iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
3313     {
3314         // insert only works for arrays
3315         if (JSON_HEDLEY_LIKELY(is_array()))
3316         {
3317             // check if iterator pos fits to this JSON value
3318             if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
3319             {
3320                 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
3321             }
3322 
3323             // insert to array and return iterator
3324             return insert_iterator(pos, cnt, val);
3325         }
3326 
3327         JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
3328     }
3329 
3330     /// @brief inserts range of elements into array
3331     /// @sa https://json.nlohmann.me/api/basic_json/insert/
insert(const_iterator pos,const_iterator first,const_iterator last)3332     iterator insert(const_iterator pos, const_iterator first, const_iterator last)
3333     {
3334         // insert only works for arrays
3335         if (JSON_HEDLEY_UNLIKELY(!is_array()))
3336         {
3337             JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
3338         }
3339 
3340         // check if iterator pos fits to this JSON value
3341         if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
3342         {
3343             JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
3344         }
3345 
3346         // check if range iterators belong to the same JSON object
3347         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
3348         {
3349             JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
3350         }
3351 
3352         if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
3353         {
3354             JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
3355         }
3356 
3357         // insert to array and return iterator
3358         return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
3359     }
3360 
3361     /// @brief inserts elements from initializer list into array
3362     /// @sa https://json.nlohmann.me/api/basic_json/insert/
insert(const_iterator pos,initializer_list_t ilist)3363     iterator insert(const_iterator pos, initializer_list_t ilist)
3364     {
3365         // insert only works for arrays
3366         if (JSON_HEDLEY_UNLIKELY(!is_array()))
3367         {
3368             JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
3369         }
3370 
3371         // check if iterator pos fits to this JSON value
3372         if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
3373         {
3374             JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
3375         }
3376 
3377         // insert to array and return iterator
3378         return insert_iterator(pos, ilist.begin(), ilist.end());
3379     }
3380 
3381     /// @brief inserts range of elements into object
3382     /// @sa https://json.nlohmann.me/api/basic_json/insert/
insert(const_iterator first,const_iterator last)3383     void insert(const_iterator first, const_iterator last)
3384     {
3385         // insert only works for objects
3386         if (JSON_HEDLEY_UNLIKELY(!is_object()))
3387         {
3388             JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
3389         }
3390 
3391         // check if range iterators belong to the same JSON object
3392         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
3393         {
3394             JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
3395         }
3396 
3397         // passed iterators must belong to objects
3398         if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
3399         {
3400             JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
3401         }
3402 
3403         m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
3404     }
3405 
3406     /// @brief updates a JSON object from another object, overwriting existing keys
3407     /// @sa https://json.nlohmann.me/api/basic_json/update/
update(const_reference j,bool merge_objects=false)3408     void update(const_reference j, bool merge_objects = false)
3409     {
3410         update(j.begin(), j.end(), merge_objects);
3411     }
3412 
3413     /// @brief updates a JSON object from another object, overwriting existing keys
3414     /// @sa https://json.nlohmann.me/api/basic_json/update/
update(const_iterator first,const_iterator last,bool merge_objects=false)3415     void update(const_iterator first, const_iterator last, bool merge_objects = false)
3416     {
3417         // implicitly convert null value to an empty object
3418         if (is_null())
3419         {
3420             m_data.m_type = value_t::object;
3421             m_data.m_value.object = create<object_t>();
3422             assert_invariant();
3423         }
3424 
3425         if (JSON_HEDLEY_UNLIKELY(!is_object()))
3426         {
3427             JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
3428         }
3429 
3430         // check if range iterators belong to the same JSON object
3431         if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
3432         {
3433             JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
3434         }
3435 
3436         // passed iterators must belong to objects
3437         if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
3438         {
3439             JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
3440         }
3441 
3442         for (auto it = first; it != last; ++it)
3443         {
3444             if (merge_objects && it.value().is_object())
3445             {
3446                 auto it2 = m_data.m_value.object->find(it.key());
3447                 if (it2 != m_data.m_value.object->end())
3448                 {
3449                     it2->second.update(it.value(), true);
3450                     continue;
3451                 }
3452             }
3453             m_data.m_value.object->operator[](it.key()) = it.value();
3454 #if JSON_DIAGNOSTICS
3455             m_data.m_value.object->operator[](it.key()).m_parent = this;
3456 #endif
3457         }
3458     }
3459 
3460     /// @brief exchanges the values
3461     /// @sa https://json.nlohmann.me/api/basic_json/swap/
swap(reference other)3462     void swap(reference other) noexcept (
3463         std::is_nothrow_move_constructible<value_t>::value&&
3464         std::is_nothrow_move_assignable<value_t>::value&&
3465         std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3466         std::is_nothrow_move_assignable<json_value>::value
3467     )
3468     {
3469         std::swap(m_data.m_type, other.m_data.m_type);
3470         std::swap(m_data.m_value, other.m_data.m_value);
3471 
3472         set_parents();
3473         other.set_parents();
3474         assert_invariant();
3475     }
3476 
3477     /// @brief exchanges the values
3478     /// @sa https://json.nlohmann.me/api/basic_json/swap/
swap(reference left,reference right)3479     friend void swap(reference left, reference right) noexcept (
3480         std::is_nothrow_move_constructible<value_t>::value&&
3481         std::is_nothrow_move_assignable<value_t>::value&&
3482         std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3483         std::is_nothrow_move_assignable<json_value>::value
3484     )
3485     {
3486         left.swap(right);
3487     }
3488 
3489     /// @brief exchanges the values
3490     /// @sa https://json.nlohmann.me/api/basic_json/swap/
swap(array_t & other)3491     void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3492     {
3493         // swap only works for arrays
3494         if (JSON_HEDLEY_LIKELY(is_array()))
3495         {
3496             using std::swap;
3497             swap(*(m_data.m_value.array), other);
3498         }
3499         else
3500         {
3501             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
3502         }
3503     }
3504 
3505     /// @brief exchanges the values
3506     /// @sa https://json.nlohmann.me/api/basic_json/swap/
swap(object_t & other)3507     void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3508     {
3509         // swap only works for objects
3510         if (JSON_HEDLEY_LIKELY(is_object()))
3511         {
3512             using std::swap;
3513             swap(*(m_data.m_value.object), other);
3514         }
3515         else
3516         {
3517             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
3518         }
3519     }
3520 
3521     /// @brief exchanges the values
3522     /// @sa https://json.nlohmann.me/api/basic_json/swap/
swap(string_t & other)3523     void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3524     {
3525         // swap only works for strings
3526         if (JSON_HEDLEY_LIKELY(is_string()))
3527         {
3528             using std::swap;
3529             swap(*(m_data.m_value.string), other);
3530         }
3531         else
3532         {
3533             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
3534         }
3535     }
3536 
3537     /// @brief exchanges the values
3538     /// @sa https://json.nlohmann.me/api/basic_json/swap/
swap(binary_t & other)3539     void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3540     {
3541         // swap only works for strings
3542         if (JSON_HEDLEY_LIKELY(is_binary()))
3543         {
3544             using std::swap;
3545             swap(*(m_data.m_value.binary), other);
3546         }
3547         else
3548         {
3549             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
3550         }
3551     }
3552 
3553     /// @brief exchanges the values
3554     /// @sa https://json.nlohmann.me/api/basic_json/swap/
swap(typename binary_t::container_type & other)3555     void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)
3556     {
3557         // swap only works for strings
3558         if (JSON_HEDLEY_LIKELY(is_binary()))
3559         {
3560             using std::swap;
3561             swap(*(m_data.m_value.binary), other);
3562         }
3563         else
3564         {
3565             JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
3566         }
3567     }
3568 
3569     /// @}
3570 
3571     //////////////////////////////////////////
3572     // lexicographical comparison operators //
3573     //////////////////////////////////////////
3574 
3575     /// @name lexicographical comparison operators
3576     /// @{
3577 
3578     // note parentheses around operands are necessary; see
3579     // https://github.com/nlohmann/json/issues/1530
3580 #define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result)                       \
3581     const auto lhs_type = lhs.type();                                                                    \
3582     const auto rhs_type = rhs.type();                                                                    \
3583     \
3584     if (lhs_type == rhs_type) /* NOLINT(readability/braces) */                                           \
3585     {                                                                                                    \
3586         switch (lhs_type)                                                                                \
3587         {                                                                                                \
3588             case value_t::array:                                                                         \
3589                 return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array);                                     \
3590                 \
3591             case value_t::object:                                                                        \
3592                 return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object);                                   \
3593                 \
3594             case value_t::null:                                                                          \
3595                 return (null_result);                                                                    \
3596                 \
3597             case value_t::string:                                                                        \
3598                 return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string);                                   \
3599                 \
3600             case value_t::boolean:                                                                       \
3601                 return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean);                                   \
3602                 \
3603             case value_t::number_integer:                                                                \
3604                 return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer);                     \
3605                 \
3606             case value_t::number_unsigned:                                                               \
3607                 return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned);                   \
3608                 \
3609             case value_t::number_float:                                                                  \
3610                 return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float);                         \
3611                 \
3612             case value_t::binary:                                                                        \
3613                 return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary);                                   \
3614                 \
3615             case value_t::discarded:                                                                     \
3616             default:                                                                                     \
3617                 return (unordered_result);                                                               \
3618         }                                                                                                \
3619     }                                                                                                    \
3620     else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)                   \
3621     {                                                                                                    \
3622         return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float;      \
3623     }                                                                                                    \
3624     else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)                   \
3625     {                                                                                                    \
3626         return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer);      \
3627     }                                                                                                    \
3628     else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)                  \
3629     {                                                                                                    \
3630         return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float;     \
3631     }                                                                                                    \
3632     else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)                  \
3633     {                                                                                                    \
3634         return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned);     \
3635     }                                                                                                    \
3636     else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)                \
3637     {                                                                                                    \
3638         return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
3639     }                                                                                                    \
3640     else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)                \
3641     {                                                                                                    \
3642         return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
3643     }                                                                                                    \
3644     else if(compares_unordered(lhs, rhs))\
3645     {\
3646         return (unordered_result);\
3647     }\
3648     \
3649     return (default_result);
3650 
3651   JSON_PRIVATE_UNLESS_TESTED:
3652     // returns true if:
3653     // - any operand is NaN and the other operand is of number type
3654     // - any operand is discarded
3655     // in legacy mode, discarded values are considered ordered if
3656     // an operation is computed as an odd number of inverses of others
3657     static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
3658     {
3659         if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number())
3660                 || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number()))
3661         {
3662             return true;
3663         }
3664 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
3665         return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
3666 #else
3667         static_cast<void>(inverse);
3668         return lhs.is_discarded() || rhs.is_discarded();
3669 #endif
3670     }
3671 
3672   private:
compares_unordered(const_reference rhs,bool inverse=false) const3673     bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
3674     {
3675         return compares_unordered(*this, rhs, inverse);
3676     }
3677 
3678   public:
3679 #if JSON_HAS_THREE_WAY_COMPARISON
3680     /// @brief comparison: equal
3681     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
operator ==(const_reference rhs) const3682     bool operator==(const_reference rhs) const noexcept
3683     {
3684 #ifdef __GNUC__
3685 #pragma GCC diagnostic push
3686 #pragma GCC diagnostic ignored "-Wfloat-equal"
3687 #endif
3688         const_reference lhs = *this;
3689         JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
3690 #ifdef __GNUC__
3691 #pragma GCC diagnostic pop
3692 #endif
3693     }
3694 
3695     /// @brief comparison: equal
3696     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3697     template<typename ScalarType>
3698     requires std::is_scalar_v<ScalarType>
operator ==(ScalarType rhs) const3699     bool operator==(ScalarType rhs) const noexcept
3700     {
3701         return *this == basic_json(rhs);
3702     }
3703 
3704     /// @brief comparison: not equal
3705     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
operator !=(const_reference rhs) const3706     bool operator!=(const_reference rhs) const noexcept
3707     {
3708         if (compares_unordered(rhs, true))
3709         {
3710             return false;
3711         }
3712         return !operator==(rhs);
3713     }
3714 
3715     /// @brief comparison: 3-way
3716     /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
operator <=>(const_reference rhs) const3717     std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
3718     {
3719         const_reference lhs = *this;
3720         // default_result is used if we cannot compare values. In that case,
3721         // we compare types.
3722         JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
3723                                 std::partial_ordering::equivalent,
3724                                 std::partial_ordering::unordered,
3725                                 lhs_type <=> rhs_type) // *NOPAD*
3726     }
3727 
3728     /// @brief comparison: 3-way
3729     /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
3730     template<typename ScalarType>
3731     requires std::is_scalar_v<ScalarType>
operator <=>(ScalarType rhs) const3732     std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
3733     {
3734         return *this <=> basic_json(rhs); // *NOPAD*
3735     }
3736 
3737 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
3738     // all operators that are computed as an odd number of inverses of others
3739     // need to be overloaded to emulate the legacy comparison behavior
3740 
3741     /// @brief comparison: less than or equal
3742     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3743     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
operator <=(const_reference rhs) const3744     bool operator<=(const_reference rhs) const noexcept
3745     {
3746         if (compares_unordered(rhs, true))
3747         {
3748             return false;
3749         }
3750         return !(rhs < *this);
3751     }
3752 
3753     /// @brief comparison: less than or equal
3754     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3755     template<typename ScalarType>
3756     requires std::is_scalar_v<ScalarType>
operator <=(ScalarType rhs) const3757     bool operator<=(ScalarType rhs) const noexcept
3758     {
3759         return *this <= basic_json(rhs);
3760     }
3761 
3762     /// @brief comparison: greater than or equal
3763     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3764     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
operator >=(const_reference rhs) const3765     bool operator>=(const_reference rhs) const noexcept
3766     {
3767         if (compares_unordered(rhs, true))
3768         {
3769             return false;
3770         }
3771         return !(*this < rhs);
3772     }
3773 
3774     /// @brief comparison: greater than or equal
3775     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3776     template<typename ScalarType>
3777     requires std::is_scalar_v<ScalarType>
operator >=(ScalarType rhs) const3778     bool operator>=(ScalarType rhs) const noexcept
3779     {
3780         return *this >= basic_json(rhs);
3781     }
3782 #endif
3783 #else
3784     /// @brief comparison: equal
3785     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3786     friend bool operator==(const_reference lhs, const_reference rhs) noexcept
3787     {
3788 #ifdef __GNUC__
3789 #pragma GCC diagnostic push
3790 #pragma GCC diagnostic ignored "-Wfloat-equal"
3791 #endif
3792         JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
3793 #ifdef __GNUC__
3794 #pragma GCC diagnostic pop
3795 #endif
3796     }
3797 
3798     /// @brief comparison: equal
3799     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3800     template<typename ScalarType, typename std::enable_if<
3801                  std::is_scalar<ScalarType>::value, int>::type = 0>
3802     friend bool operator==(const_reference lhs, ScalarType rhs) noexcept
3803     {
3804         return lhs == basic_json(rhs);
3805     }
3806 
3807     /// @brief comparison: equal
3808     /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3809     template<typename ScalarType, typename std::enable_if<
3810                  std::is_scalar<ScalarType>::value, int>::type = 0>
3811     friend bool operator==(ScalarType lhs, const_reference rhs) noexcept
3812     {
3813         return basic_json(lhs) == rhs;
3814     }
3815 
3816     /// @brief comparison: not equal
3817     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
3818     friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
3819     {
3820         if (compares_unordered(lhs, rhs, true))
3821         {
3822             return false;
3823         }
3824         return !(lhs == rhs);
3825     }
3826 
3827     /// @brief comparison: not equal
3828     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
3829     template<typename ScalarType, typename std::enable_if<
3830                  std::is_scalar<ScalarType>::value, int>::type = 0>
3831     friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept
3832     {
3833         return lhs != basic_json(rhs);
3834     }
3835 
3836     /// @brief comparison: not equal
3837     /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
3838     template<typename ScalarType, typename std::enable_if<
3839                  std::is_scalar<ScalarType>::value, int>::type = 0>
3840     friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept
3841     {
3842         return basic_json(lhs) != rhs;
3843     }
3844 
3845     /// @brief comparison: less than
3846     /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
3847     friend bool operator<(const_reference lhs, const_reference rhs) noexcept
3848     {
3849         // default_result is used if we cannot compare values. In that case,
3850         // we compare types. Note we have to call the operator explicitly,
3851         // because MSVC has problems otherwise.
3852         JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
3853     }
3854 
3855     /// @brief comparison: less than
3856     /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
3857     template<typename ScalarType, typename std::enable_if<
3858                  std::is_scalar<ScalarType>::value, int>::type = 0>
3859     friend bool operator<(const_reference lhs, ScalarType rhs) noexcept
3860     {
3861         return lhs < basic_json(rhs);
3862     }
3863 
3864     /// @brief comparison: less than
3865     /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
3866     template<typename ScalarType, typename std::enable_if<
3867                  std::is_scalar<ScalarType>::value, int>::type = 0>
3868     friend bool operator<(ScalarType lhs, const_reference rhs) noexcept
3869     {
3870         return basic_json(lhs) < rhs;
3871     }
3872 
3873     /// @brief comparison: less than or equal
3874     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3875     friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
3876     {
3877         if (compares_unordered(lhs, rhs, true))
3878         {
3879             return false;
3880         }
3881         return !(rhs < lhs);
3882     }
3883 
3884     /// @brief comparison: less than or equal
3885     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3886     template<typename ScalarType, typename std::enable_if<
3887                  std::is_scalar<ScalarType>::value, int>::type = 0>
3888     friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept
3889     {
3890         return lhs <= basic_json(rhs);
3891     }
3892 
3893     /// @brief comparison: less than or equal
3894     /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3895     template<typename ScalarType, typename std::enable_if<
3896                  std::is_scalar<ScalarType>::value, int>::type = 0>
3897     friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
3898     {
3899         return basic_json(lhs) <= rhs;
3900     }
3901 
3902     /// @brief comparison: greater than
3903     /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
3904     friend bool operator>(const_reference lhs, const_reference rhs) noexcept
3905     {
3906         // double inverse
3907         if (compares_unordered(lhs, rhs))
3908         {
3909             return false;
3910         }
3911         return !(lhs <= rhs);
3912     }
3913 
3914     /// @brief comparison: greater than
3915     /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
3916     template<typename ScalarType, typename std::enable_if<
3917                  std::is_scalar<ScalarType>::value, int>::type = 0>
3918     friend bool operator>(const_reference lhs, ScalarType rhs) noexcept
3919     {
3920         return lhs > basic_json(rhs);
3921     }
3922 
3923     /// @brief comparison: greater than
3924     /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
3925     template<typename ScalarType, typename std::enable_if<
3926                  std::is_scalar<ScalarType>::value, int>::type = 0>
3927     friend bool operator>(ScalarType lhs, const_reference rhs) noexcept
3928     {
3929         return basic_json(lhs) > rhs;
3930     }
3931 
3932     /// @brief comparison: greater than or equal
3933     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3934     friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
3935     {
3936         if (compares_unordered(lhs, rhs, true))
3937         {
3938             return false;
3939         }
3940         return !(lhs < rhs);
3941     }
3942 
3943     /// @brief comparison: greater than or equal
3944     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3945     template<typename ScalarType, typename std::enable_if<
3946                  std::is_scalar<ScalarType>::value, int>::type = 0>
3947     friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept
3948     {
3949         return lhs >= basic_json(rhs);
3950     }
3951 
3952     /// @brief comparison: greater than or equal
3953     /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3954     template<typename ScalarType, typename std::enable_if<
3955                  std::is_scalar<ScalarType>::value, int>::type = 0>
3956     friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
3957     {
3958         return basic_json(lhs) >= rhs;
3959     }
3960 #endif
3961 
3962 #undef JSON_IMPLEMENT_OPERATOR
3963 
3964     /// @}
3965 
3966     ///////////////////
3967     // serialization //
3968     ///////////////////
3969 
3970     /// @name serialization
3971     /// @{
3972 #ifndef JSON_NO_IO
3973     /// @brief serialize to stream
3974     /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
operator <<(std::ostream & o,const basic_json & j)3975     friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
3976     {
3977         // read width member and use it as indentation parameter if nonzero
3978         const bool pretty_print = o.width() > 0;
3979         const auto indentation = pretty_print ? o.width() : 0;
3980 
3981         // reset width to 0 for subsequent calls to this stream
3982         o.width(0);
3983 
3984         // do the actual serialization
3985         serializer s(detail::output_adapter<char>(o), o.fill());
3986         s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
3987         return o;
3988     }
3989 
3990     /// @brief serialize to stream
3991     /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
3992     /// @deprecated This function is deprecated since 3.0.0 and will be removed in
3993     ///             version 4.0.0 of the library. Please use
3994     ///             operator<<(std::ostream&, const basic_json&) instead; that is,
3995     ///             replace calls like `j >> o;` with `o << j;`.
3996     JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
operator >>(const basic_json & j,std::ostream & o)3997     friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
3998     {
3999         return o << j;
4000     }
4001 #endif  // JSON_NO_IO
4002     /// @}
4003 
4004     /////////////////////
4005     // deserialization //
4006     /////////////////////
4007 
4008     /// @name deserialization
4009     /// @{
4010 
4011     /// @brief deserialize from a compatible input
4012     /// @sa https://json.nlohmann.me/api/basic_json/parse/
4013     template<typename InputType>
4014     JSON_HEDLEY_WARN_UNUSED_RESULT
parse(InputType && i,const parser_callback_t cb=nullptr,const bool allow_exceptions=true,const bool ignore_comments=false)4015     static basic_json parse(InputType&& i,
4016                             const parser_callback_t cb = nullptr,
4017                             const bool allow_exceptions = true,
4018                             const bool ignore_comments = false)
4019     {
4020         basic_json result;
4021         parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
4022         return result;
4023     }
4024 
4025     /// @brief deserialize from a pair of character iterators
4026     /// @sa https://json.nlohmann.me/api/basic_json/parse/
4027     template<typename IteratorType>
4028     JSON_HEDLEY_WARN_UNUSED_RESULT
parse(IteratorType first,IteratorType last,const parser_callback_t cb=nullptr,const bool allow_exceptions=true,const bool ignore_comments=false)4029     static basic_json parse(IteratorType first,
4030                             IteratorType last,
4031                             const parser_callback_t cb = nullptr,
4032                             const bool allow_exceptions = true,
4033                             const bool ignore_comments = false)
4034     {
4035         basic_json result;
4036         parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
4037         return result;
4038     }
4039 
4040     JSON_HEDLEY_WARN_UNUSED_RESULT
4041     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
parse(detail::span_input_adapter && i,const parser_callback_t cb=nullptr,const bool allow_exceptions=true,const bool ignore_comments=false)4042     static basic_json parse(detail::span_input_adapter&& i,
4043                             const parser_callback_t cb = nullptr,
4044                             const bool allow_exceptions = true,
4045                             const bool ignore_comments = false)
4046     {
4047         basic_json result;
4048         parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
4049         return result;
4050     }
4051 
4052     /// @brief check if the input is valid JSON
4053     /// @sa https://json.nlohmann.me/api/basic_json/accept/
4054     template<typename InputType>
accept(InputType && i,const bool ignore_comments=false)4055     static bool accept(InputType&& i,
4056                        const bool ignore_comments = false)
4057     {
4058         return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
4059     }
4060 
4061     /// @brief check if the input is valid JSON
4062     /// @sa https://json.nlohmann.me/api/basic_json/accept/
4063     template<typename IteratorType>
accept(IteratorType first,IteratorType last,const bool ignore_comments=false)4064     static bool accept(IteratorType first, IteratorType last,
4065                        const bool ignore_comments = false)
4066     {
4067         return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
4068     }
4069 
4070     JSON_HEDLEY_WARN_UNUSED_RESULT
4071     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
accept(detail::span_input_adapter && i,const bool ignore_comments=false)4072     static bool accept(detail::span_input_adapter&& i,
4073                        const bool ignore_comments = false)
4074     {
4075         return parser(i.get(), nullptr, false, ignore_comments).accept(true);
4076     }
4077 
4078     /// @brief generate SAX events
4079     /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
4080     template <typename InputType, typename SAX>
4081     JSON_HEDLEY_NON_NULL(2)
sax_parse(InputType && i,SAX * sax,input_format_t format=input_format_t::json,const bool strict=true,const bool ignore_comments=false)4082     static bool sax_parse(InputType&& i, SAX* sax,
4083                           input_format_t format = input_format_t::json,
4084                           const bool strict = true,
4085                           const bool ignore_comments = false)
4086     {
4087         auto ia = detail::input_adapter(std::forward<InputType>(i));
4088         return format == input_format_t::json
4089                ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
4090                : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
4091     }
4092 
4093     /// @brief generate SAX events
4094     /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
4095     template<class IteratorType, class SAX>
4096     JSON_HEDLEY_NON_NULL(3)
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)4097     static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
4098                           input_format_t format = input_format_t::json,
4099                           const bool strict = true,
4100                           const bool ignore_comments = false)
4101     {
4102         auto ia = detail::input_adapter(std::move(first), std::move(last));
4103         return format == input_format_t::json
4104                ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
4105                : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
4106     }
4107 
4108     /// @brief generate SAX events
4109     /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
4110     /// @deprecated This function is deprecated since 3.8.0 and will be removed in
4111     ///             version 4.0.0 of the library. Please use
4112     ///             sax_parse(ptr, ptr + len) instead.
4113     template <typename SAX>
4114     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
4115     JSON_HEDLEY_NON_NULL(2)
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)4116     static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
4117                           input_format_t format = input_format_t::json,
4118                           const bool strict = true,
4119                           const bool ignore_comments = false)
4120     {
4121         auto ia = i.get();
4122         return format == input_format_t::json
4123                // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4124                ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
4125                // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4126                : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
4127     }
4128 #ifndef JSON_NO_IO
4129     /// @brief deserialize from stream
4130     /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
4131     /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
4132     ///             version 4.0.0 of the library. Please use
4133     ///             operator>>(std::istream&, basic_json&) instead; that is,
4134     ///             replace calls like `j << i;` with `i >> j;`.
4135     JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
operator <<(basic_json & j,std::istream & i)4136     friend std::istream& operator<<(basic_json& j, std::istream& i)
4137     {
4138         return operator>>(i, j);
4139     }
4140 
4141     /// @brief deserialize from stream
4142     /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
operator >>(std::istream & i,basic_json & j)4143     friend std::istream& operator>>(std::istream& i, basic_json& j)
4144     {
4145         parser(detail::input_adapter(i)).parse(false, j);
4146         return i;
4147     }
4148 #endif  // JSON_NO_IO
4149     /// @}
4150 
4151     ///////////////////////////
4152     // convenience functions //
4153     ///////////////////////////
4154 
4155     /// @brief return the type as string
4156     /// @sa https://json.nlohmann.me/api/basic_json/type_name/
4157     JSON_HEDLEY_RETURNS_NON_NULL
type_name() const4158     const char* type_name() const noexcept
4159     {
4160         switch (m_data.m_type)
4161         {
4162             case value_t::null:
4163                 return "null";
4164             case value_t::object:
4165                 return "object";
4166             case value_t::array:
4167                 return "array";
4168             case value_t::string:
4169                 return "string";
4170             case value_t::boolean:
4171                 return "boolean";
4172             case value_t::binary:
4173                 return "binary";
4174             case value_t::discarded:
4175                 return "discarded";
4176             case value_t::number_integer:
4177             case value_t::number_unsigned:
4178             case value_t::number_float:
4179             default:
4180                 return "number";
4181         }
4182     }
4183 
4184   JSON_PRIVATE_UNLESS_TESTED:
4185     //////////////////////
4186     // member variables //
4187     //////////////////////
4188 
4189     struct data
4190     {
4191         /// the type of the current element
4192         value_t m_type = value_t::null;
4193 
4194         /// the value of the current element
4195         json_value m_value = {};
4196 
databasic_json::data4197         data(const value_t v)
4198             : m_type(v), m_value(v)
4199         {
4200         }
4201 
databasic_json::data4202         data(size_type cnt, const basic_json& val)
4203             : m_type(value_t::array)
4204         {
4205             m_value.array = create<array_t>(cnt, val);
4206         }
4207 
4208         data() noexcept = default;
4209         data(data&&) noexcept = default;
4210         data(const data&) noexcept = delete;
4211         data& operator=(data&&) noexcept = delete;
4212         data& operator=(const data&) noexcept = delete;
4213 
~databasic_json::data4214         ~data() noexcept
4215         {
4216             m_value.destroy(m_type);
4217         }
4218     };
4219 
4220     data m_data = {};
4221 
4222 #if JSON_DIAGNOSTICS
4223     /// a pointer to a parent value (for debugging purposes)
4224     basic_json* m_parent = nullptr;
4225 #endif
4226 
4227     //////////////////////////////////////////
4228     // binary serialization/deserialization //
4229     //////////////////////////////////////////
4230 
4231     /// @name binary serialization/deserialization support
4232     /// @{
4233 
4234   public:
4235     /// @brief create a CBOR serialization of a given JSON value
4236     /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
to_cbor(const basic_json & j)4237     static std::vector<std::uint8_t> to_cbor(const basic_json& j)
4238     {
4239         std::vector<std::uint8_t> result;
4240         to_cbor(j, result);
4241         return result;
4242     }
4243 
4244     /// @brief create a CBOR serialization of a given JSON value
4245     /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
to_cbor(const basic_json & j,detail::output_adapter<std::uint8_t> o)4246     static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)
4247     {
4248         binary_writer<std::uint8_t>(o).write_cbor(j);
4249     }
4250 
4251     /// @brief create a CBOR serialization of a given JSON value
4252     /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
to_cbor(const basic_json & j,detail::output_adapter<char> o)4253     static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
4254     {
4255         binary_writer<char>(o).write_cbor(j);
4256     }
4257 
4258     /// @brief create a MessagePack serialization of a given JSON value
4259     /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
to_msgpack(const basic_json & j)4260     static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
4261     {
4262         std::vector<std::uint8_t> result;
4263         to_msgpack(j, result);
4264         return result;
4265     }
4266 
4267     /// @brief create a MessagePack serialization of a given JSON value
4268     /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
to_msgpack(const basic_json & j,detail::output_adapter<std::uint8_t> o)4269     static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)
4270     {
4271         binary_writer<std::uint8_t>(o).write_msgpack(j);
4272     }
4273 
4274     /// @brief create a MessagePack serialization of a given JSON value
4275     /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
to_msgpack(const basic_json & j,detail::output_adapter<char> o)4276     static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
4277     {
4278         binary_writer<char>(o).write_msgpack(j);
4279     }
4280 
4281     /// @brief create a UBJSON serialization of a given JSON value
4282     /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
to_ubjson(const basic_json & j,const bool use_size=false,const bool use_type=false)4283     static std::vector<std::uint8_t> to_ubjson(const basic_json& j,
4284             const bool use_size = false,
4285             const bool use_type = false)
4286     {
4287         std::vector<std::uint8_t> result;
4288         to_ubjson(j, result, use_size, use_type);
4289         return result;
4290     }
4291 
4292     /// @brief create a UBJSON serialization of a given JSON value
4293     /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
to_ubjson(const basic_json & j,detail::output_adapter<std::uint8_t> o,const bool use_size=false,const bool use_type=false)4294     static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,
4295                           const bool use_size = false, const bool use_type = false)
4296     {
4297         binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);
4298     }
4299 
4300     /// @brief create a UBJSON serialization of a given JSON value
4301     /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
to_ubjson(const basic_json & j,detail::output_adapter<char> o,const bool use_size=false,const bool use_type=false)4302     static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
4303                           const bool use_size = false, const bool use_type = false)
4304     {
4305         binary_writer<char>(o).write_ubjson(j, use_size, use_type);
4306     }
4307 
4308     /// @brief create a BJData serialization of a given JSON value
4309     /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
to_bjdata(const basic_json & j,const bool use_size=false,const bool use_type=false)4310     static std::vector<std::uint8_t> to_bjdata(const basic_json& j,
4311             const bool use_size = false,
4312             const bool use_type = false)
4313     {
4314         std::vector<std::uint8_t> result;
4315         to_bjdata(j, result, use_size, use_type);
4316         return result;
4317     }
4318 
4319     /// @brief create a BJData serialization of a given JSON value
4320     /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
to_bjdata(const basic_json & j,detail::output_adapter<std::uint8_t> o,const bool use_size=false,const bool use_type=false)4321     static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o,
4322                           const bool use_size = false, const bool use_type = false)
4323     {
4324         binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true);
4325     }
4326 
4327     /// @brief create a BJData serialization of a given JSON value
4328     /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
to_bjdata(const basic_json & j,detail::output_adapter<char> o,const bool use_size=false,const bool use_type=false)4329     static void to_bjdata(const basic_json& j, detail::output_adapter<char> o,
4330                           const bool use_size = false, const bool use_type = false)
4331     {
4332         binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true);
4333     }
4334 
4335     /// @brief create a BSON serialization of a given JSON value
4336     /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
to_bson(const basic_json & j)4337     static std::vector<std::uint8_t> to_bson(const basic_json& j)
4338     {
4339         std::vector<std::uint8_t> result;
4340         to_bson(j, result);
4341         return result;
4342     }
4343 
4344     /// @brief create a BSON serialization of a given JSON value
4345     /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
to_bson(const basic_json & j,detail::output_adapter<std::uint8_t> o)4346     static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)
4347     {
4348         binary_writer<std::uint8_t>(o).write_bson(j);
4349     }
4350 
4351     /// @brief create a BSON serialization of a given JSON value
4352     /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
to_bson(const basic_json & j,detail::output_adapter<char> o)4353     static void to_bson(const basic_json& j, detail::output_adapter<char> o)
4354     {
4355         binary_writer<char>(o).write_bson(j);
4356     }
4357 
4358     /// @brief create a JSON value from an input in CBOR format
4359     /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
4360     template<typename InputType>
4361     JSON_HEDLEY_WARN_UNUSED_RESULT
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)4362     static basic_json from_cbor(InputType&& i,
4363                                 const bool strict = true,
4364                                 const bool allow_exceptions = true,
4365                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4366     {
4367         basic_json result;
4368         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4369         auto ia = detail::input_adapter(std::forward<InputType>(i));
4370         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
4371         return res ? result : basic_json(value_t::discarded);
4372     }
4373 
4374     /// @brief create a JSON value from an input in CBOR format
4375     /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
4376     template<typename IteratorType>
4377     JSON_HEDLEY_WARN_UNUSED_RESULT
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)4378     static basic_json from_cbor(IteratorType first, IteratorType last,
4379                                 const bool strict = true,
4380                                 const bool allow_exceptions = true,
4381                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4382     {
4383         basic_json result;
4384         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4385         auto ia = detail::input_adapter(std::move(first), std::move(last));
4386         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
4387         return res ? result : basic_json(value_t::discarded);
4388     }
4389 
4390     template<typename T>
4391     JSON_HEDLEY_WARN_UNUSED_RESULT
4392     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
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)4393     static basic_json from_cbor(const T* ptr, std::size_t len,
4394                                 const bool strict = true,
4395                                 const bool allow_exceptions = true,
4396                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4397     {
4398         return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
4399     }
4400 
4401     JSON_HEDLEY_WARN_UNUSED_RESULT
4402     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
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)4403     static basic_json from_cbor(detail::span_input_adapter&& i,
4404                                 const bool strict = true,
4405                                 const bool allow_exceptions = true,
4406                                 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4407     {
4408         basic_json result;
4409         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4410         auto ia = i.get();
4411         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4412         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
4413         return res ? result : basic_json(value_t::discarded);
4414     }
4415 
4416     /// @brief create a JSON value from an input in MessagePack format
4417     /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
4418     template<typename InputType>
4419     JSON_HEDLEY_WARN_UNUSED_RESULT
from_msgpack(InputType && i,const bool strict=true,const bool allow_exceptions=true)4420     static basic_json from_msgpack(InputType&& i,
4421                                    const bool strict = true,
4422                                    const bool allow_exceptions = true)
4423     {
4424         basic_json result;
4425         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4426         auto ia = detail::input_adapter(std::forward<InputType>(i));
4427         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
4428         return res ? result : basic_json(value_t::discarded);
4429     }
4430 
4431     /// @brief create a JSON value from an input in MessagePack format
4432     /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
4433     template<typename IteratorType>
4434     JSON_HEDLEY_WARN_UNUSED_RESULT
from_msgpack(IteratorType first,IteratorType last,const bool strict=true,const bool allow_exceptions=true)4435     static basic_json from_msgpack(IteratorType first, IteratorType last,
4436                                    const bool strict = true,
4437                                    const bool allow_exceptions = true)
4438     {
4439         basic_json result;
4440         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4441         auto ia = detail::input_adapter(std::move(first), std::move(last));
4442         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
4443         return res ? result : basic_json(value_t::discarded);
4444     }
4445 
4446     template<typename T>
4447     JSON_HEDLEY_WARN_UNUSED_RESULT
4448     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
from_msgpack(const T * ptr,std::size_t len,const bool strict=true,const bool allow_exceptions=true)4449     static basic_json from_msgpack(const T* ptr, std::size_t len,
4450                                    const bool strict = true,
4451                                    const bool allow_exceptions = true)
4452     {
4453         return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
4454     }
4455 
4456     JSON_HEDLEY_WARN_UNUSED_RESULT
4457     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
from_msgpack(detail::span_input_adapter && i,const bool strict=true,const bool allow_exceptions=true)4458     static basic_json from_msgpack(detail::span_input_adapter&& i,
4459                                    const bool strict = true,
4460                                    const bool allow_exceptions = true)
4461     {
4462         basic_json result;
4463         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4464         auto ia = i.get();
4465         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4466         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
4467         return res ? result : basic_json(value_t::discarded);
4468     }
4469 
4470     /// @brief create a JSON value from an input in UBJSON format
4471     /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
4472     template<typename InputType>
4473     JSON_HEDLEY_WARN_UNUSED_RESULT
from_ubjson(InputType && i,const bool strict=true,const bool allow_exceptions=true)4474     static basic_json from_ubjson(InputType&& i,
4475                                   const bool strict = true,
4476                                   const bool allow_exceptions = true)
4477     {
4478         basic_json result;
4479         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4480         auto ia = detail::input_adapter(std::forward<InputType>(i));
4481         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
4482         return res ? result : basic_json(value_t::discarded);
4483     }
4484 
4485     /// @brief create a JSON value from an input in UBJSON format
4486     /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
4487     template<typename IteratorType>
4488     JSON_HEDLEY_WARN_UNUSED_RESULT
from_ubjson(IteratorType first,IteratorType last,const bool strict=true,const bool allow_exceptions=true)4489     static basic_json from_ubjson(IteratorType first, IteratorType last,
4490                                   const bool strict = true,
4491                                   const bool allow_exceptions = true)
4492     {
4493         basic_json result;
4494         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4495         auto ia = detail::input_adapter(std::move(first), std::move(last));
4496         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
4497         return res ? result : basic_json(value_t::discarded);
4498     }
4499 
4500     template<typename T>
4501     JSON_HEDLEY_WARN_UNUSED_RESULT
4502     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
from_ubjson(const T * ptr,std::size_t len,const bool strict=true,const bool allow_exceptions=true)4503     static basic_json from_ubjson(const T* ptr, std::size_t len,
4504                                   const bool strict = true,
4505                                   const bool allow_exceptions = true)
4506     {
4507         return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
4508     }
4509 
4510     JSON_HEDLEY_WARN_UNUSED_RESULT
4511     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
from_ubjson(detail::span_input_adapter && i,const bool strict=true,const bool allow_exceptions=true)4512     static basic_json from_ubjson(detail::span_input_adapter&& i,
4513                                   const bool strict = true,
4514                                   const bool allow_exceptions = true)
4515     {
4516         basic_json result;
4517         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4518         auto ia = i.get();
4519         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4520         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
4521         return res ? result : basic_json(value_t::discarded);
4522     }
4523 
4524     /// @brief create a JSON value from an input in BJData format
4525     /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
4526     template<typename InputType>
4527     JSON_HEDLEY_WARN_UNUSED_RESULT
from_bjdata(InputType && i,const bool strict=true,const bool allow_exceptions=true)4528     static basic_json from_bjdata(InputType&& i,
4529                                   const bool strict = true,
4530                                   const bool allow_exceptions = true)
4531     {
4532         basic_json result;
4533         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4534         auto ia = detail::input_adapter(std::forward<InputType>(i));
4535         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
4536         return res ? result : basic_json(value_t::discarded);
4537     }
4538 
4539     /// @brief create a JSON value from an input in BJData format
4540     /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
4541     template<typename IteratorType>
4542     JSON_HEDLEY_WARN_UNUSED_RESULT
from_bjdata(IteratorType first,IteratorType last,const bool strict=true,const bool allow_exceptions=true)4543     static basic_json from_bjdata(IteratorType first, IteratorType last,
4544                                   const bool strict = true,
4545                                   const bool allow_exceptions = true)
4546     {
4547         basic_json result;
4548         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4549         auto ia = detail::input_adapter(std::move(first), std::move(last));
4550         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
4551         return res ? result : basic_json(value_t::discarded);
4552     }
4553 
4554     /// @brief create a JSON value from an input in BSON format
4555     /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
4556     template<typename InputType>
4557     JSON_HEDLEY_WARN_UNUSED_RESULT
from_bson(InputType && i,const bool strict=true,const bool allow_exceptions=true)4558     static basic_json from_bson(InputType&& i,
4559                                 const bool strict = true,
4560                                 const bool allow_exceptions = true)
4561     {
4562         basic_json result;
4563         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4564         auto ia = detail::input_adapter(std::forward<InputType>(i));
4565         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
4566         return res ? result : basic_json(value_t::discarded);
4567     }
4568 
4569     /// @brief create a JSON value from an input in BSON format
4570     /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
4571     template<typename IteratorType>
4572     JSON_HEDLEY_WARN_UNUSED_RESULT
from_bson(IteratorType first,IteratorType last,const bool strict=true,const bool allow_exceptions=true)4573     static basic_json from_bson(IteratorType first, IteratorType last,
4574                                 const bool strict = true,
4575                                 const bool allow_exceptions = true)
4576     {
4577         basic_json result;
4578         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4579         auto ia = detail::input_adapter(std::move(first), std::move(last));
4580         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
4581         return res ? result : basic_json(value_t::discarded);
4582     }
4583 
4584     template<typename T>
4585     JSON_HEDLEY_WARN_UNUSED_RESULT
4586     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
from_bson(const T * ptr,std::size_t len,const bool strict=true,const bool allow_exceptions=true)4587     static basic_json from_bson(const T* ptr, std::size_t len,
4588                                 const bool strict = true,
4589                                 const bool allow_exceptions = true)
4590     {
4591         return from_bson(ptr, ptr + len, strict, allow_exceptions);
4592     }
4593 
4594     JSON_HEDLEY_WARN_UNUSED_RESULT
4595     JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
from_bson(detail::span_input_adapter && i,const bool strict=true,const bool allow_exceptions=true)4596     static basic_json from_bson(detail::span_input_adapter&& i,
4597                                 const bool strict = true,
4598                                 const bool allow_exceptions = true)
4599     {
4600         basic_json result;
4601         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
4602         auto ia = i.get();
4603         // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4604         const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
4605         return res ? result : basic_json(value_t::discarded);
4606     }
4607     /// @}
4608 
4609     //////////////////////////
4610     // JSON Pointer support //
4611     //////////////////////////
4612 
4613     /// @name JSON Pointer functions
4614     /// @{
4615 
4616     /// @brief access specified element via JSON Pointer
4617     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
operator [](const json_pointer & ptr)4618     reference operator[](const json_pointer& ptr)
4619     {
4620         return ptr.get_unchecked(this);
4621     }
4622 
4623     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4624     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
operator [](const::nlohmann::json_pointer<BasicJsonType> & ptr)4625     reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
4626     {
4627         return ptr.get_unchecked(this);
4628     }
4629 
4630     /// @brief access specified element via JSON Pointer
4631     /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
operator [](const json_pointer & ptr) const4632     const_reference operator[](const json_pointer& ptr) const
4633     {
4634         return ptr.get_unchecked(this);
4635     }
4636 
4637     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4638     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
operator [](const::nlohmann::json_pointer<BasicJsonType> & ptr) const4639     const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
4640     {
4641         return ptr.get_unchecked(this);
4642     }
4643 
4644     /// @brief access specified element via JSON Pointer
4645     /// @sa https://json.nlohmann.me/api/basic_json/at/
at(const json_pointer & ptr)4646     reference at(const json_pointer& ptr)
4647     {
4648         return ptr.get_checked(this);
4649     }
4650 
4651     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4652     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
at(const::nlohmann::json_pointer<BasicJsonType> & ptr)4653     reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
4654     {
4655         return ptr.get_checked(this);
4656     }
4657 
4658     /// @brief access specified element via JSON Pointer
4659     /// @sa https://json.nlohmann.me/api/basic_json/at/
at(const json_pointer & ptr) const4660     const_reference at(const json_pointer& ptr) const
4661     {
4662         return ptr.get_checked(this);
4663     }
4664 
4665     template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4666     JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
at(const::nlohmann::json_pointer<BasicJsonType> & ptr) const4667     const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
4668     {
4669         return ptr.get_checked(this);
4670     }
4671 
4672     /// @brief return flattened JSON value
4673     /// @sa https://json.nlohmann.me/api/basic_json/flatten/
flatten() const4674     basic_json flatten() const
4675     {
4676         basic_json result(value_t::object);
4677         json_pointer::flatten("", *this, result);
4678         return result;
4679     }
4680 
4681     /// @brief unflatten a previously flattened JSON value
4682     /// @sa https://json.nlohmann.me/api/basic_json/unflatten/
unflatten() const4683     basic_json unflatten() const
4684     {
4685         return json_pointer::unflatten(*this);
4686     }
4687 
4688     /// @}
4689 
4690     //////////////////////////
4691     // JSON Patch functions //
4692     //////////////////////////
4693 
4694     /// @name JSON Patch functions
4695     /// @{
4696 
4697     /// @brief applies a JSON patch in-place without copying the object
4698     /// @sa https://json.nlohmann.me/api/basic_json/patch/
patch_inplace(const basic_json & json_patch)4699     void patch_inplace(const basic_json& json_patch)
4700     {
4701         basic_json& result = *this;
4702         // the valid JSON Patch operations
4703         enum class patch_operations {add, remove, replace, move, copy, test, invalid};
4704 
4705         const auto get_op = [](const std::string & op)
4706         {
4707             if (op == "add")
4708             {
4709                 return patch_operations::add;
4710             }
4711             if (op == "remove")
4712             {
4713                 return patch_operations::remove;
4714             }
4715             if (op == "replace")
4716             {
4717                 return patch_operations::replace;
4718             }
4719             if (op == "move")
4720             {
4721                 return patch_operations::move;
4722             }
4723             if (op == "copy")
4724             {
4725                 return patch_operations::copy;
4726             }
4727             if (op == "test")
4728             {
4729                 return patch_operations::test;
4730             }
4731 
4732             return patch_operations::invalid;
4733         };
4734 
4735         // wrapper for "add" operation; add value at ptr
4736         const auto operation_add = [&result](json_pointer & ptr, basic_json val)
4737         {
4738             // adding to the root of the target document means replacing it
4739             if (ptr.empty())
4740             {
4741                 result = val;
4742                 return;
4743             }
4744 
4745             // make sure the top element of the pointer exists
4746             json_pointer const top_pointer = ptr.top();
4747             if (top_pointer != ptr)
4748             {
4749                 result.at(top_pointer);
4750             }
4751 
4752             // get reference to parent of JSON pointer ptr
4753             const auto last_path = ptr.back();
4754             ptr.pop_back();
4755             // parent must exist when performing patch add per RFC6902 specs
4756             basic_json& parent = result.at(ptr);
4757 
4758             switch (parent.m_data.m_type)
4759             {
4760                 case value_t::null:
4761                 case value_t::object:
4762                 {
4763                     // use operator[] to add value
4764                     parent[last_path] = val;
4765                     break;
4766                 }
4767 
4768                 case value_t::array:
4769                 {
4770                     if (last_path == "-")
4771                     {
4772                         // special case: append to back
4773                         parent.push_back(val);
4774                     }
4775                     else
4776                     {
4777                         const auto idx = json_pointer::template array_index<basic_json_t>(last_path);
4778                         if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
4779                         {
4780                             // avoid undefined behavior
4781                             JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
4782                         }
4783 
4784                         // default case: insert add offset
4785                         parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
4786                     }
4787                     break;
4788                 }
4789 
4790                 // if there exists a parent it cannot be primitive
4791                 case value_t::string: // LCOV_EXCL_LINE
4792                 case value_t::boolean: // LCOV_EXCL_LINE
4793                 case value_t::number_integer: // LCOV_EXCL_LINE
4794                 case value_t::number_unsigned: // LCOV_EXCL_LINE
4795                 case value_t::number_float: // LCOV_EXCL_LINE
4796                 case value_t::binary: // LCOV_EXCL_LINE
4797                 case value_t::discarded: // LCOV_EXCL_LINE
4798                 default:            // LCOV_EXCL_LINE
4799                     JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
4800             }
4801         };
4802 
4803         // wrapper for "remove" operation; remove value at ptr
4804         const auto operation_remove = [this, & result](json_pointer & ptr)
4805         {
4806             // get reference to parent of JSON pointer ptr
4807             const auto last_path = ptr.back();
4808             ptr.pop_back();
4809             basic_json& parent = result.at(ptr);
4810 
4811             // remove child
4812             if (parent.is_object())
4813             {
4814                 // perform range check
4815                 auto it = parent.find(last_path);
4816                 if (JSON_HEDLEY_LIKELY(it != parent.end()))
4817                 {
4818                     parent.erase(it);
4819                 }
4820                 else
4821                 {
4822                     JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
4823                 }
4824             }
4825             else if (parent.is_array())
4826             {
4827                 // note erase performs range check
4828                 parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
4829             }
4830         };
4831 
4832         // type check: top level value must be an array
4833         if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
4834         {
4835             JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
4836         }
4837 
4838         // iterate and apply the operations
4839         for (const auto& val : json_patch)
4840         {
4841             // wrapper to get a value for an operation
4842             const auto get_value = [&val](const std::string & op,
4843                                           const std::string & member,
4844                                           bool string_type) -> basic_json &
4845             {
4846                 // find value
4847                 auto it = val.m_data.m_value.object->find(member);
4848 
4849                 // context-sensitive error message
4850                 const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\'');
4851 
4852                 // check if desired value is present
4853                 if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
4854                 {
4855                     // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
4856                     JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
4857                 }
4858 
4859                 // check if result is of type string
4860                 if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
4861                 {
4862                     // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
4863                     JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
4864                 }
4865 
4866                 // no error: return value
4867                 return it->second;
4868             };
4869 
4870             // type check: every element of the array must be an object
4871             if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
4872             {
4873                 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
4874             }
4875 
4876             // collect mandatory members
4877             const auto op = get_value("op", "op", true).template get<std::string>();
4878             const auto path = get_value(op, "path", true).template get<std::string>();
4879             json_pointer ptr(path);
4880 
4881             switch (get_op(op))
4882             {
4883                 case patch_operations::add:
4884                 {
4885                     operation_add(ptr, get_value("add", "value", false));
4886                     break;
4887                 }
4888 
4889                 case patch_operations::remove:
4890                 {
4891                     operation_remove(ptr);
4892                     break;
4893                 }
4894 
4895                 case patch_operations::replace:
4896                 {
4897                     // the "path" location must exist - use at()
4898                     result.at(ptr) = get_value("replace", "value", false);
4899                     break;
4900                 }
4901 
4902                 case patch_operations::move:
4903                 {
4904                     const auto from_path = get_value("move", "from", true).template get<std::string>();
4905                     json_pointer from_ptr(from_path);
4906 
4907                     // the "from" location must exist - use at()
4908                     basic_json const v = result.at(from_ptr);
4909 
4910                     // The move operation is functionally identical to a
4911                     // "remove" operation on the "from" location, followed
4912                     // immediately by an "add" operation at the target
4913                     // location with the value that was just removed.
4914                     operation_remove(from_ptr);
4915                     operation_add(ptr, v);
4916                     break;
4917                 }
4918 
4919                 case patch_operations::copy:
4920                 {
4921                     const auto from_path = get_value("copy", "from", true).template get<std::string>();
4922                     const json_pointer from_ptr(from_path);
4923 
4924                     // the "from" location must exist - use at()
4925                     basic_json const v = result.at(from_ptr);
4926 
4927                     // The copy is functionally identical to an "add"
4928                     // operation at the target location using the value
4929                     // specified in the "from" member.
4930                     operation_add(ptr, v);
4931                     break;
4932                 }
4933 
4934                 case patch_operations::test:
4935                 {
4936                     bool success = false;
4937                     JSON_TRY
4938                     {
4939                         // check if "value" matches the one at "path"
4940                         // the "path" location must exist - use at()
4941                         success = (result.at(ptr) == get_value("test", "value", false));
4942                     }
4943                     JSON_INTERNAL_CATCH (out_of_range&)
4944                     {
4945                         // ignore out of range errors: success remains false
4946                     }
4947 
4948                     // throw an exception if test fails
4949                     if (JSON_HEDLEY_UNLIKELY(!success))
4950                     {
4951                         JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
4952                     }
4953 
4954                     break;
4955                 }
4956 
4957                 case patch_operations::invalid:
4958                 default:
4959                 {
4960                     // op must be "add", "remove", "replace", "move", "copy", or
4961                     // "test"
4962                     JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
4963                 }
4964             }
4965         }
4966     }
4967 
4968     /// @brief applies a JSON patch to a copy of the current object
4969     /// @sa https://json.nlohmann.me/api/basic_json/patch/
patch(const basic_json & json_patch) const4970     basic_json patch(const basic_json& json_patch) const
4971     {
4972         basic_json result = *this;
4973         result.patch_inplace(json_patch);
4974         return result;
4975     }
4976 
4977     /// @brief creates a diff as a JSON patch
4978     /// @sa https://json.nlohmann.me/api/basic_json/diff/
4979     JSON_HEDLEY_WARN_UNUSED_RESULT
diff(const basic_json & source,const basic_json & target,const std::string & path="")4980     static basic_json diff(const basic_json& source, const basic_json& target,
4981                            const std::string& path = "")
4982     {
4983         // the patch
4984         basic_json result(value_t::array);
4985 
4986         // if the values are the same, return empty patch
4987         if (source == target)
4988         {
4989             return result;
4990         }
4991 
4992         if (source.type() != target.type())
4993         {
4994             // different types: replace value
4995             result.push_back(
4996             {
4997                 {"op", "replace"}, {"path", path}, {"value", target}
4998             });
4999             return result;
5000         }
5001 
5002         switch (source.type())
5003         {
5004             case value_t::array:
5005             {
5006                 // first pass: traverse common elements
5007                 std::size_t i = 0;
5008                 while (i < source.size() && i < target.size())
5009                 {
5010                     // recursive call to compare array values at index i
5011                     auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i)));
5012                     result.insert(result.end(), temp_diff.begin(), temp_diff.end());
5013                     ++i;
5014                 }
5015 
5016                 // We now reached the end of at least one array
5017                 // in a second pass, traverse the remaining elements
5018 
5019                 // remove my remaining elements
5020                 const auto end_index = static_cast<difference_type>(result.size());
5021                 while (i < source.size())
5022                 {
5023                     // add operations in reverse order to avoid invalid
5024                     // indices
5025                     result.insert(result.begin() + end_index, object(
5026                     {
5027                         {"op", "remove"},
5028                         {"path", detail::concat(path, '/', std::to_string(i))}
5029                     }));
5030                     ++i;
5031                 }
5032 
5033                 // add other remaining elements
5034                 while (i < target.size())
5035                 {
5036                     result.push_back(
5037                     {
5038                         {"op", "add"},
5039                         {"path", detail::concat(path, "/-")},
5040                         {"value", target[i]}
5041                     });
5042                     ++i;
5043                 }
5044 
5045                 break;
5046             }
5047 
5048             case value_t::object:
5049             {
5050                 // first pass: traverse this object's elements
5051                 for (auto it = source.cbegin(); it != source.cend(); ++it)
5052                 {
5053                     // escape the key name to be used in a JSON patch
5054                     const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
5055 
5056                     if (target.find(it.key()) != target.end())
5057                     {
5058                         // recursive call to compare object values at key it
5059                         auto temp_diff = diff(it.value(), target[it.key()], path_key);
5060                         result.insert(result.end(), temp_diff.begin(), temp_diff.end());
5061                     }
5062                     else
5063                     {
5064                         // found a key that is not in o -> remove it
5065                         result.push_back(object(
5066                         {
5067                             {"op", "remove"}, {"path", path_key}
5068                         }));
5069                     }
5070                 }
5071 
5072                 // second pass: traverse other object's elements
5073                 for (auto it = target.cbegin(); it != target.cend(); ++it)
5074                 {
5075                     if (source.find(it.key()) == source.end())
5076                     {
5077                         // found a key that is not in this -> add it
5078                         const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
5079                         result.push_back(
5080                         {
5081                             {"op", "add"}, {"path", path_key},
5082                             {"value", it.value()}
5083                         });
5084                     }
5085                 }
5086 
5087                 break;
5088             }
5089 
5090             case value_t::null:
5091             case value_t::string:
5092             case value_t::boolean:
5093             case value_t::number_integer:
5094             case value_t::number_unsigned:
5095             case value_t::number_float:
5096             case value_t::binary:
5097             case value_t::discarded:
5098             default:
5099             {
5100                 // both primitive type: replace value
5101                 result.push_back(
5102                 {
5103                     {"op", "replace"}, {"path", path}, {"value", target}
5104                 });
5105                 break;
5106             }
5107         }
5108 
5109         return result;
5110     }
5111     /// @}
5112 
5113     ////////////////////////////////
5114     // JSON Merge Patch functions //
5115     ////////////////////////////////
5116 
5117     /// @name JSON Merge Patch functions
5118     /// @{
5119 
5120     /// @brief applies a JSON Merge Patch
5121     /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/
merge_patch(const basic_json & apply_patch)5122     void merge_patch(const basic_json& apply_patch)
5123     {
5124         if (apply_patch.is_object())
5125         {
5126             if (!is_object())
5127             {
5128                 *this = object();
5129             }
5130             for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
5131             {
5132                 if (it.value().is_null())
5133                 {
5134                     erase(it.key());
5135                 }
5136                 else
5137                 {
5138                     operator[](it.key()).merge_patch(it.value());
5139                 }
5140             }
5141         }
5142         else
5143         {
5144             *this = apply_patch;
5145         }
5146     }
5147 
5148     /// @}
5149 };
5150 
5151 /// @brief user-defined to_string function for JSON values
5152 /// @sa https://json.nlohmann.me/api/basic_json/to_string/
5153 NLOHMANN_BASIC_JSON_TPL_DECLARATION
to_string(const NLOHMANN_BASIC_JSON_TPL & j)5154 std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
5155 {
5156     return j.dump();
5157 }
5158 
5159 inline namespace literals
5160 {
5161 inline namespace json_literals
5162 {
5163 
5164 /// @brief user-defined string literal for JSON values
5165 /// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/
5166 JSON_HEDLEY_NON_NULL(1)
5167 #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
operator ""_json(const char * s,std::size_t n)5168     inline nlohmann::json operator ""_json(const char* s, std::size_t n)
5169 #else
5170     inline nlohmann::json operator "" _json(const char* s, std::size_t n)
5171 #endif
5172 {
5173     return nlohmann::json::parse(s, s + n);
5174 }
5175 
5176 /// @brief user-defined string literal for JSON pointer
5177 /// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/
5178 JSON_HEDLEY_NON_NULL(1)
5179 #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
operator ""_json_pointer(const char * s,std::size_t n)5180     inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n)
5181 #else
5182     inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
5183 #endif
5184 {
5185     return nlohmann::json::json_pointer(std::string(s, n));
5186 }
5187 
5188 }  // namespace json_literals
5189 }  // namespace literals
5190 NLOHMANN_JSON_NAMESPACE_END
5191 
5192 ///////////////////////
5193 // nonmember support //
5194 ///////////////////////
5195 
5196 namespace std // NOLINT(cert-dcl58-cpp)
5197 {
5198 
5199 /// @brief hash value for JSON objects
5200 /// @sa https://json.nlohmann.me/api/basic_json/std_hash/
5201 NLOHMANN_BASIC_JSON_TPL_DECLARATION
5202 struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)
5203 {
operator ()std::hash5204     std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
5205     {
5206         return nlohmann::detail::hash(j);
5207     }
5208 };
5209 
5210 // specialization for std::less<value_t>
5211 template<>
5212 struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679
5213 {
5214     /*!
5215     @brief compare two value_t enum values
5216     @since version 3.0.0
5217     */
operator ()std::less5218     bool operator()(::nlohmann::detail::value_t lhs,
5219                     ::nlohmann::detail::value_t rhs) const noexcept
5220     {
5221 #if JSON_HAS_THREE_WAY_COMPARISON
5222         return std::is_lt(lhs <=> rhs); // *NOPAD*
5223 #else
5224         return ::nlohmann::detail::operator<(lhs, rhs);
5225 #endif
5226     }
5227 };
5228 
5229 // C++20 prohibit function specialization in the std namespace.
5230 #ifndef JSON_HAS_CPP_20
5231 
5232 /// @brief exchanges the values of two JSON objects
5233 /// @sa https://json.nlohmann.me/api/basic_json/std_swap/
5234 NLOHMANN_BASIC_JSON_TPL_DECLARATION
swap(nlohmann::NLOHMANN_BASIC_JSON_TPL & j1,nlohmann::NLOHMANN_BASIC_JSON_TPL & j2)5235 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)
5236     is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&&                          // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
5237     is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
5238 {
5239     j1.swap(j2);
5240 }
5241 
5242 #endif
5243 
5244 }  // namespace std
5245 
5246 #if JSON_USE_GLOBAL_UDLS
5247     #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
5248         using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5249         using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5250     #else
5251         using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5252         using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5253     #endif
5254 #endif
5255 
5256 #include <nlohmann/detail/macro_unscope.hpp>
5257 
5258 #endif  // INCLUDE_NLOHMANN_JSON_HPP_
5259