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