• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nlohmann / json / 14819724811

04 May 2025 09:12AM UTC coverage: 99.189%. Remained the same
14819724811

Pull #4771

github

web-flow
Merge 368abbf1d into 697c7e557
Pull Request #4771: Update to Doctest 2.4.12

1994 of 2129 branches covered (93.66%)

6358 of 6410 relevant lines covered (99.19%)

16529095.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.93
/include/nlohmann/json.hpp
1
//     __ _____ _____ _____
2
//  __|  |   __|     |   | |  JSON for Modern C++
3
// |  |  |__   |  |  | | | |  version 3.12.0
4
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5
//
6
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
7
// SPDX-License-Identifier: MIT
8

9
/****************************************************************************\
10
 * Note on documentation: The source files contain links to the online      *
11
 * documentation of the public API at https://json.nlohmann.me. This URL    *
12
 * contains the most recent documentation and should also be applicable to  *
13
 * previous versions; documentation for deprecated functions is not         *
14
 * removed, but marked deprecated. See "Generate documentation" section in  *
15
 * file docs/README.md.                                                     *
16
\****************************************************************************/
17

18
#ifndef INCLUDE_NLOHMANN_JSON_HPP_
19
#define INCLUDE_NLOHMANN_JSON_HPP_
20

21
#include <algorithm> // all_of, find, for_each
22
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
23
#include <functional> // hash, less
24
#include <initializer_list> // initializer_list
25
#ifndef JSON_NO_IO
26
    #include <iosfwd> // istream, ostream
27
#endif  // JSON_NO_IO
28
#include <iterator> // random_access_iterator_tag
29
#include <memory> // unique_ptr
30
#include <string> // string, stoi, to_string
31
#include <utility> // declval, forward, move, pair, swap
32
#include <vector> // vector
33

34
#include <nlohmann/adl_serializer.hpp>
35
#include <nlohmann/byte_container_with_subtype.hpp>
36
#include <nlohmann/detail/conversions/from_json.hpp>
37
#include <nlohmann/detail/conversions/to_json.hpp>
38
#include <nlohmann/detail/exceptions.hpp>
39
#include <nlohmann/detail/hash.hpp>
40
#include <nlohmann/detail/input/binary_reader.hpp>
41
#include <nlohmann/detail/input/input_adapters.hpp>
42
#include <nlohmann/detail/input/lexer.hpp>
43
#include <nlohmann/detail/input/parser.hpp>
44
#include <nlohmann/detail/iterators/internal_iterator.hpp>
45
#include <nlohmann/detail/iterators/iter_impl.hpp>
46
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
47
#include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
48
#include <nlohmann/detail/iterators/primitive_iterator.hpp>
49
#include <nlohmann/detail/json_custom_base_class.hpp>
50
#include <nlohmann/detail/json_pointer.hpp>
51
#include <nlohmann/detail/json_ref.hpp>
52
#include <nlohmann/detail/macro_scope.hpp>
53
#include <nlohmann/detail/string_concat.hpp>
54
#include <nlohmann/detail/string_escape.hpp>
55
#include <nlohmann/detail/string_utils.hpp>
56
#include <nlohmann/detail/meta/cpp_future.hpp>
57
#include <nlohmann/detail/meta/type_traits.hpp>
58
#include <nlohmann/detail/output/binary_writer.hpp>
59
#include <nlohmann/detail/output/output_adapters.hpp>
60
#include <nlohmann/detail/output/serializer.hpp>
61
#include <nlohmann/detail/value_t.hpp>
62
#include <nlohmann/json_fwd.hpp>
63
#include <nlohmann/ordered_map.hpp>
64

65
#if defined(JSON_HAS_CPP_17)
66
    #if JSON_HAS_STATIC_RTTI
67
        #include <any>
68
    #endif
69
    #include <string_view>
70
#endif
71

72
/*!
73
@brief namespace for Niels Lohmann
74
@see https://github.com/nlohmann
75
@since version 1.0.0
76
*/
77
NLOHMANN_JSON_NAMESPACE_BEGIN
78

79
/*!
80
@brief a class to store JSON values
81

82
@internal
83
@invariant The member variables @a m_value and @a m_type have the following
84
relationship:
85
- If `m_type == value_t::object`, then `m_value.object != nullptr`.
86
- If `m_type == value_t::array`, then `m_value.array != nullptr`.
87
- If `m_type == value_t::string`, then `m_value.string != nullptr`.
88
The invariants are checked by member function assert_invariant().
89

90
@note ObjectType trick from https://stackoverflow.com/a/9860911
91
@endinternal
92

93
@since version 1.0.0
94

95
@nosubgrouping
96
*/
97
NLOHMANN_BASIC_JSON_TPL_DECLARATION
98
class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
99
    : public ::nlohmann::detail::json_base_class<CustomBaseClass>
100
{
101
  private:
102
    template<detail::value_t> friend struct detail::external_constructor;
103

104
    template<typename>
105
    friend class ::nlohmann::json_pointer;
106
    // can be restored when json_pointer backwards compatibility is removed
107
    // friend ::nlohmann::json_pointer<StringType>;
108

109
    template<typename BasicJsonType, typename InputType>
110
    friend class ::nlohmann::detail::parser;
111
    friend ::nlohmann::detail::serializer<basic_json>;
112
    template<typename BasicJsonType>
113
    friend class ::nlohmann::detail::iter_impl;
114
    template<typename BasicJsonType, typename CharType>
115
    friend class ::nlohmann::detail::binary_writer;
116
    template<typename BasicJsonType, typename InputType, typename SAX>
117
    friend class ::nlohmann::detail::binary_reader;
118
    template<typename BasicJsonType, typename InputAdapterType>
119
    friend class ::nlohmann::detail::json_sax_dom_parser;
120
    template<typename BasicJsonType, typename InputAdapterType>
121
    friend class ::nlohmann::detail::json_sax_dom_callback_parser;
122
    friend class ::nlohmann::detail::exception;
123

124
    /// workaround type for MSVC
125
    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
126
    using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;
127

128
  JSON_PRIVATE_UNLESS_TESTED:
129
    // convenience aliases for types residing in namespace detail;
130
    using lexer = ::nlohmann::detail::lexer_base<basic_json>;
131

132
    template<typename InputAdapterType>
133
    static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
9,994,865✔
134
        InputAdapterType adapter,
135
        detail::parser_callback_t<basic_json>cb = nullptr,
136
        const bool allow_exceptions = true,
137
        const bool ignore_comments = false
138
    )
139
    {
140
        return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
9,994,865✔
141
               std::move(cb), allow_exceptions, ignore_comments);
19,989,730✔
142
    }
143

144
  private:
145
    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
146
    template<typename BasicJsonType>
147
    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
148
    template<typename BasicJsonType>
149
    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
150
    template<typename Iterator>
151
    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
152
    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
153

154
    template<typename CharType>
155
    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
156

157
    template<typename InputType>
158
    using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;
159
    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
160

161
  JSON_PRIVATE_UNLESS_TESTED:
162
    using serializer = ::nlohmann::detail::serializer<basic_json>;
163

164
  public:
165
    using value_t = detail::value_t;
166
    /// JSON Pointer, see @ref nlohmann::json_pointer
167
    using json_pointer = ::nlohmann::json_pointer<StringType>;
168
    template<typename T, typename SFINAE>
169
    using json_serializer = JSONSerializer<T, SFINAE>;
170
    /// how to treat decoding errors
171
    using error_handler_t = detail::error_handler_t;
172
    /// how to treat CBOR tags
173
    using cbor_tag_handler_t = detail::cbor_tag_handler_t;
174
    /// how to encode BJData
175
    using bjdata_version_t = detail::bjdata_version_t;
176
    /// helper type for initializer lists of basic_json values
177
    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
178

179
    using input_format_t = detail::input_format_t;
180
    /// SAX interface type, see @ref nlohmann::json_sax
181
    using json_sax_t = json_sax<basic_json>;
182

183
    ////////////////
184
    // exceptions //
185
    ////////////////
186

187
    /// @name exceptions
188
    /// Classes to implement user-defined exceptions.
189
    /// @{
190

191
    using exception = detail::exception;
192
    using parse_error = detail::parse_error;
193
    using invalid_iterator = detail::invalid_iterator;
194
    using type_error = detail::type_error;
195
    using out_of_range = detail::out_of_range;
196
    using other_error = detail::other_error;
197

198
    /// @}
199

200
    /////////////////////
201
    // container types //
202
    /////////////////////
203

204
    /// @name container types
205
    /// The canonic container types to use @ref basic_json like any other STL
206
    /// container.
207
    /// @{
208

209
    /// the type of elements in a basic_json container
210
    using value_type = basic_json;
211

212
    /// the type of an element reference
213
    using reference = value_type&;
214
    /// the type of an element const reference
215
    using const_reference = const value_type&;
216

217
    /// a type to represent differences between iterators
218
    using difference_type = std::ptrdiff_t;
219
    /// a type to represent container sizes
220
    using size_type = std::size_t;
221

222
    /// the allocator type
223
    using allocator_type = AllocatorType<basic_json>;
224

225
    /// the type of an element pointer
226
    using pointer = typename std::allocator_traits<allocator_type>::pointer;
227
    /// the type of an element const pointer
228
    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
229

230
    /// an iterator for a basic_json container
231
    using iterator = iter_impl<basic_json>;
232
    /// a const iterator for a basic_json container
233
    using const_iterator = iter_impl<const basic_json>;
234
    /// a reverse iterator for a basic_json container
235
    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
236
    /// a const reverse iterator for a basic_json container
237
    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
238

239
    /// @}
240

241
    /// @brief returns the allocator associated with the container
242
    /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/
243
    static allocator_type get_allocator()
244
    {
245
        return allocator_type();
246
    }
247

248
    /// @brief returns version information on the library
249
    /// @sa https://json.nlohmann.me/api/basic_json/meta/
250
    JSON_HEDLEY_WARN_UNUSED_RESULT
251
    static basic_json meta()
1✔
252
    {
253
        basic_json result;
1✔
254

255
        result["copyright"] = "(C) 2013-2025 Niels Lohmann";
1✔
256
        result["name"] = "JSON for Modern C++";
1✔
257
        result["url"] = "https://github.com/nlohmann/json";
1✔
258
        result["version"]["string"] =
2✔
259
            detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.',
2✔
260
                           std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.',
2✔
261
                           std::to_string(NLOHMANN_JSON_VERSION_PATCH));
262
        result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
1✔
263
        result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
1✔
264
        result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
1✔
265

266
#ifdef _WIN32
267
        result["platform"] = "win32";
268
#elif defined __linux__
269
        result["platform"] = "linux";
1✔
270
#elif defined __APPLE__
271
        result["platform"] = "apple";
272
#elif defined __unix__
273
        result["platform"] = "unix";
274
#else
275
        result["platform"] = "unknown";
276
#endif
277

278
#if defined(__ICC) || defined(__INTEL_COMPILER)
279
        result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
280
#elif defined(__clang__)
281
        result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
282
#elif defined(__GNUC__) || defined(__GNUG__)
283
        result["compiler"] = {{"family", "gcc"}, {"version", detail::concat(
7✔
284
                    std::to_string(__GNUC__), '.',
×
285
                    std::to_string(__GNUC_MINOR__), '.',
×
286
                    std::to_string(__GNUC_PATCHLEVEL__))
287
            }
288
        };
289
#elif defined(__HP_cc) || defined(__HP_aCC)
290
        result["compiler"] = "hp"
291
#elif defined(__IBMCPP__)
292
        result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
293
#elif defined(_MSC_VER)
294
        result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
295
#elif defined(__PGI)
296
        result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
297
#elif defined(__SUNPRO_CC)
298
        result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
299
#else
300
        result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
301
#endif
302

303
#if defined(_MSVC_LANG)
304
        result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
305
#elif defined(__cplusplus)
306
        result["compiler"]["c++"] = std::to_string(__cplusplus);
1✔
307
#else
308
        result["compiler"]["c++"] = "unknown";
309
#endif
310
        return result;
1✔
311
    }
6✔
312

313
    ///////////////////////////
314
    // JSON value data types //
315
    ///////////////////////////
316

317
    /// @name JSON value data types
318
    /// The data types to store a JSON value. These types are derived from
319
    /// the template arguments passed to class @ref basic_json.
320
    /// @{
321

322
    /// @brief default object key comparator type
323
    /// The actual object key comparator type (@ref object_comparator_t) may be
324
    /// different.
325
    /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
326
#if defined(JSON_HAS_CPP_14)
327
    // use of transparent comparator avoids unnecessary repeated construction of temporaries
328
    // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
329
    using default_object_comparator_t = std::less<>;
330
#else
331
    using default_object_comparator_t = std::less<StringType>;
332
#endif
333

334
    /// @brief a type for an object
335
    /// @sa https://json.nlohmann.me/api/basic_json/object_t/
336
    using object_t = ObjectType<StringType,
337
          basic_json,
338
          default_object_comparator_t,
339
          AllocatorType<std::pair<const StringType,
340
          basic_json>>>;
341

342
    /// @brief a type for an array
343
    /// @sa https://json.nlohmann.me/api/basic_json/array_t/
344
    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
345

346
    /// @brief a type for a string
347
    /// @sa https://json.nlohmann.me/api/basic_json/string_t/
348
    using string_t = StringType;
349

350
    /// @brief a type for a boolean
351
    /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/
352
    using boolean_t = BooleanType;
353

354
    /// @brief a type for a number (integer)
355
    /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/
356
    using number_integer_t = NumberIntegerType;
357

358
    /// @brief a type for a number (unsigned)
359
    /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/
360
    using number_unsigned_t = NumberUnsignedType;
361

362
    /// @brief a type for a number (floating-point)
363
    /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/
364
    using number_float_t = NumberFloatType;
365

366
    /// @brief a type for a packed binary type
367
    /// @sa https://json.nlohmann.me/api/basic_json/binary_t/
368
    using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
369

370
    /// @brief object key comparator type
371
    /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
372
    using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
373

374
    /// @}
375

376
  private:
377

378
    /// helper for exception-safe object creation
379
    template<typename T, typename... Args>
380
    JSON_HEDLEY_RETURNS_NON_NULL
381
    static T* create(Args&& ... args)
93,179,078✔
382
    {
383
        AllocatorType<T> alloc;
25✔
384
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
385

386
        auto deleter = [&](T * obj)
93,179,096✔
387
        {
388
            AllocatorTraits::deallocate(alloc, obj, 1);
×
389
        };
390
        std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);
93,179,078✔
391
        AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);
93,179,078✔
392
        JSON_ASSERT(obj != nullptr);
93,179,069✔
393
        return obj.release();
186,358,138✔
394
    }
93,179,085✔
395

396
    ////////////////////////
397
    // JSON value storage //
398
    ////////////////////////
399

400
  JSON_PRIVATE_UNLESS_TESTED:
401
    /*!
402
    @brief a JSON value
403

404
    The actual storage for a JSON value of the @ref basic_json class. This
405
    union combines the different storage types for the JSON value types
406
    defined in @ref value_t.
407

408
    JSON type | value_t type    | used type
409
    --------- | --------------- | ------------------------
410
    object    | object          | pointer to @ref object_t
411
    array     | array           | pointer to @ref array_t
412
    string    | string          | pointer to @ref string_t
413
    boolean   | boolean         | @ref boolean_t
414
    number    | number_integer  | @ref number_integer_t
415
    number    | number_unsigned | @ref number_unsigned_t
416
    number    | number_float    | @ref number_float_t
417
    binary    | binary          | pointer to @ref binary_t
418
    null      | null            | *no value is stored*
419

420
    @note Variable-length types (objects, arrays, and strings) are stored as
421
    pointers. The size of the union should not exceed 64 bits if the default
422
    value types are used.
423

424
    @since version 1.0.0
425
    */
426
    union json_value
427
    {
428
        /// object (stored with pointer to save storage)
429
        object_t* object;
430
        /// array (stored with pointer to save storage)
431
        array_t* array;
432
        /// string (stored with pointer to save storage)
433
        string_t* string;
434
        /// binary (stored with pointer to save storage)
435
        binary_t* binary;
436
        /// boolean
437
        boolean_t boolean;
438
        /// number (integer)
439
        number_integer_t number_integer;
440
        /// number (unsigned integer)
441
        number_unsigned_t number_unsigned;
442
        /// number (floating-point)
443
        number_float_t number_float;
444

445
        /// default constructor (for null values)
446
        json_value() = default;
447
        /// constructor for booleans
448
        json_value(boolean_t v) noexcept : boolean(v) {}
43,712✔
449
        /// constructor for numbers (integer)
450
        json_value(number_integer_t v) noexcept : number_integer(v) {}
18,893,806✔
451
        /// constructor for numbers (unsigned)
452
        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
64,144,129✔
453
        /// constructor for numbers (floating-point)
454
        json_value(number_float_t v) noexcept : number_float(v) {}
32,155,766✔
455
        /// constructor for empty values of a given type
456
        json_value(value_t t)
30,675,673✔
457
        {
458
            switch (t)
30,675,673✔
459
            {
460
                case value_t::object:
261,932✔
461
                {
462
                    object = create<object_t>();
261,931✔
463
                    break;
261,930✔
464
                }
465

466
                case value_t::array:
5,105,055✔
467
                {
468
                    array = create<array_t>();
5,105,055✔
469
                    break;
5,105,054✔
470
                }
471

472
                case value_t::string:
112✔
473
                {
474
                    string = create<string_t>("");
112✔
475
                    break;
111✔
476
                }
477

478
                case value_t::binary:
7✔
479
                {
480
                    binary = create<binary_t>();
7✔
481
                    break;
7✔
482
                }
483

484
                case value_t::boolean:
104✔
485
                {
486
                    boolean = static_cast<boolean_t>(false);
104✔
487
                    break;
104✔
488
                }
489

490
                case value_t::number_integer:
99✔
491
                {
492
                    number_integer = static_cast<number_integer_t>(0);
99✔
493
                    break;
99✔
494
                }
495

496
                case value_t::number_unsigned:
91✔
497
                {
498
                    number_unsigned = static_cast<number_unsigned_t>(0);
91✔
499
                    break;
91✔
500
                }
501

502
                case value_t::number_float:
101✔
503
                {
504
                    number_float = static_cast<number_float_t>(0.0);
101✔
505
                    break;
101✔
506
                }
507

508
                case value_t::null:
25,306,941✔
509
                {
510
                    object = nullptr;  // silence warning, see #821
25,306,941✔
511
                    break;
25,306,941✔
512
                }
513

514
                case value_t::discarded:
1,231✔
515
                default:
516
                {
517
                    object = nullptr;  // silence warning, see #821
1,231✔
518
                    if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
1,231!
519
                    {
520
                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE
521
                    }
522
                    break;
1,231✔
523
                }
524
            }
525
        }
30,675,669✔
526

527
        /// constructor for strings
528
        json_value(const string_t& value) : string(create<string_t>(value)) {}
78,668,731✔
529

530
        /// constructor for rvalue strings
531
        json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
8,860,616✔
532

533
        /// constructor for objects
534
        json_value(const object_t& value) : object(create<object_t>(value)) {}
234,285✔
535

536
        /// constructor for rvalue objects
537
        json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
8✔
538

539
        /// constructor for arrays
540
        json_value(const array_t& value) : array(create<array_t>(value)) {}
20,291✔
541

542
        /// constructor for rvalue arrays
543
        json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
12✔
544

545
        /// constructor for binary arrays
546
        json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
2,134✔
547

548
        /// constructor for rvalue binary arrays
549
        json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
98✔
550

551
        /// constructor for binary arrays (internal type)
552
        json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
3,242✔
553

554
        /// constructor for rvalue binary arrays (internal type)
555
        json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
3,277✔
556

557
        void destroy(value_t t)
921,334,754✔
558
        {
559
            if (
921,334,754✔
560
                (t == value_t::object && object == nullptr) ||
921,334,754✔
561
                (t == value_t::array && array == nullptr) ||
921,334,753✔
562
                (t == value_t::string && string == nullptr) ||
921,334,752✔
563
                (t == value_t::binary && binary == nullptr)
8,754!
564
            )
565
            {
566
                //not initialized (e.g., due to exception in the ctor)
567
                return;
8✔
568
            }
569
            if (t == value_t::array || t == value_t::object)
921,334,746✔
570
            {
571
                // flatten the current json_value to a heap-allocated stack
572
                std::vector<basic_json> stack;
5,631,617✔
573

574
                // move the top-level items to stack
575
                if (t == value_t::array)
5,631,617✔
576
                {
577
                    stack.reserve(array->size());
5,134,666✔
578
                    std::move(array->begin(), array->end(), std::back_inserter(stack));
5,134,666✔
579
                }
580
                else
581
                {
582
                    stack.reserve(object->size());
496,951✔
583
                    for (auto&& it : *object)
1,497,630✔
584
                    {
585
                        stack.push_back(std::move(it.second));
1,000,679✔
586
                    }
587
                }
588

589
                while (!stack.empty())
376,432,561✔
590
                {
591
                    // move the last item to a local variable to be processed
592
                    basic_json current_item(std::move(stack.back()));
185,400,472✔
593
                    stack.pop_back();
185,400,472✔
594

595
                    // if current_item is array/object, move
596
                    // its children to the stack to be processed later
597
                    if (current_item.is_array())
185,400,472✔
598
                    {
599
                        std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
5,118,009✔
600

601
                        current_item.m_data.m_value.array->clear();
5,118,009✔
602
                    }
603
                    else if (current_item.is_object())
180,282,463✔
604
                    {
605
                        for (auto&& it : *current_item.m_data.m_value.object)
3,703,019✔
606
                        {
607
                            stack.push_back(std::move(it.second));
3,211,556✔
608
                        }
609

610
                        current_item.m_data.m_value.object->clear();
491,463✔
611
                    }
612

613
                    // it's now safe that current_item gets destructed
614
                    // since it doesn't have any children
615
                }
616
            }
5,631,617✔
617

618
            switch (t)
921,334,746✔
619
            {
620
                case value_t::object:
496,951✔
621
                {
622
                    AllocatorType<object_t> alloc;
2✔
623
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
496,951✔
624
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
496,951✔
625
                    break;
496,951✔
626
                }
2✔
627

628
                case value_t::array:
5,134,666✔
629
                {
630
                    AllocatorType<array_t> alloc;
2✔
631
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
5,134,666✔
632
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
5,134,666✔
633
                    break;
5,134,666✔
634
                }
2✔
635

636
                case value_t::string:
87,538,686✔
637
                {
638
                    AllocatorType<string_t> alloc;
8✔
639
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
87,538,686✔
640
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
87,538,686✔
641
                    break;
87,538,686✔
642
                }
8✔
643

644
                case value_t::binary:
8,754✔
645
                {
646
                    AllocatorType<binary_t> alloc;
×
647
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
8,754✔
648
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
8,754✔
649
                    break;
8,754✔
650
                }
×
651

652
                case value_t::null:
828,155,689✔
653
                case value_t::boolean:
654
                case value_t::number_integer:
655
                case value_t::number_unsigned:
656
                case value_t::number_float:
657
                case value_t::discarded:
658
                default:
659
                {
660
                    break;
828,155,689✔
661
                }
662
            }
663
        }
664
    };
665

666
  private:
667
    /*!
668
    @brief checks the class invariants
669

670
    This function asserts the class invariants. It needs to be called at the
671
    end of every constructor to make sure that created objects respect the
672
    invariant. Furthermore, it has to be called each time the type of a JSON
673
    value is changed, because the invariant expresses a relationship between
674
    @a m_type and @a m_value.
675

676
    Furthermore, the parent relation is checked for arrays and objects: If
677
    @a check_parents true and the value is an array or object, then the
678
    container's elements must have the current value as parent.
679

680
    @param[in] check_parents  whether the parent relation should be checked.
681
               The value is true by default and should only be set to false
682
               during destruction of objects when the invariant does not
683
               need to hold.
684
    */
685
    void assert_invariant(bool check_parents = true) const noexcept
2,147,483,647✔
686
    {
687
        JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr);
2,147,483,647✔
688
        JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr);
2,147,483,647✔
689
        JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr);
2,147,483,647✔
690
        JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr);
2,147,483,647✔
691

692
#if JSON_DIAGNOSTICS
693
        JSON_TRY
694
        {
695
            // cppcheck-suppress assertWithSideEffect
696
            JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
2,012!
697
            {
698
                return j.m_parent == this;
699
            }));
700
        }
701
        JSON_CATCH(...) {} // LCOV_EXCL_LINE
702
#endif
703
        static_cast<void>(check_parents);
704
    }
2,147,483,647✔
705

706
    void set_parents()
772,117,395✔
707
    {
708
#if JSON_DIAGNOSTICS
709
        switch (m_data.m_type)
552✔
710
        {
711
            case value_t::array:
76✔
712
            {
713
                for (auto& element : *m_data.m_value.array)
268✔
714
                {
715
                    element.m_parent = this;
192✔
716
                }
717
                break;
76✔
718
            }
719

720
            case value_t::object:
230✔
721
            {
722
                for (auto& element : *m_data.m_value.object)
269✔
723
                {
724
                    element.second.m_parent = this;
39✔
725
                }
726
                break;
230✔
727
            }
728

729
            case value_t::null:
246✔
730
            case value_t::string:
731
            case value_t::boolean:
732
            case value_t::number_integer:
733
            case value_t::number_unsigned:
734
            case value_t::number_float:
735
            case value_t::binary:
736
            case value_t::discarded:
737
            default:
738
                break;
246✔
739
        }
740
#endif
741
    }
772,117,395✔
742

743
    iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)
4✔
744
    {
745
#if JSON_DIAGNOSTICS
746
        for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)
8✔
747
        {
748
            (it + i)->m_parent = this;
4✔
749
        }
750
#else
751
        static_cast<void>(count_set_parents);
752
#endif
753
        return it;
4✔
754
    }
755

756
    reference set_parent(reference j, std::size_t old_capacity = detail::unknown_size())
199,786✔
757
    {
758
#if JSON_DIAGNOSTICS
759
        if (old_capacity != detail::unknown_size())
57✔
760
        {
761
            // see https://github.com/nlohmann/json/issues/2838
762
            JSON_ASSERT(type() == value_t::array);
13✔
763
            if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
13✔
764
            {
765
                // capacity has changed: update all parents
766
                set_parents();
10✔
767
                return j;
10✔
768
            }
769
        }
770

771
        // ordered_json uses a vector internally, so pointers could have
772
        // been invalidated; see https://github.com/nlohmann/json/issues/2962
773
#ifdef JSON_HEDLEY_MSVC_VERSION
774
#pragma warning(push )
775
#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
776
#endif
777
        if (detail::is_ordered_map<object_t>::value)
778
        {
779
            set_parents();
3✔
780
            return j;
3✔
781
        }
782
#ifdef JSON_HEDLEY_MSVC_VERSION
783
#pragma warning( pop )
784
#endif
785

786
        j.m_parent = this;
44✔
787
#else
788
        static_cast<void>(j);
789
        static_cast<void>(old_capacity);
790
#endif
791
        return j;
199,773✔
792
    }
793

794
  public:
795
    //////////////////////////
796
    // JSON parser callback //
797
    //////////////////////////
798

799
    /// @brief parser event types
800
    /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/
801
    using parse_event_t = detail::parse_event_t;
802

803
    /// @brief per-element parser callback type
804
    /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/
805
    using parser_callback_t = detail::parser_callback_t<basic_json>;
806

807
    //////////////////
808
    // constructors //
809
    //////////////////
810

811
    /// @name constructors and destructors
812
    /// Constructors of class @ref basic_json, copy/move constructor, copy
813
    /// assignment, static functions creating objects, and the destructor.
814
    /// @{
815

816
    /// @brief create an empty value with a given type
817
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
818
    basic_json(const value_t v)
30,673,175✔
819
        : m_data(v)
30,673,175✔
820
    {
821
        assert_invariant();
30,673,174✔
822
    }
30,673,174✔
823

824
    /// @brief create a null object
825
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
826
    basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)
25,306,805✔
827
        : basic_json(value_t::null)
25,306,805✔
828
    {
829
        assert_invariant();
25,306,805✔
830
    }
25,306,805✔
831

832
    /// @brief create a JSON value from compatible types
833
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
834
    template < typename CompatibleType,
835
               typename U = detail::uncvref_t<CompatibleType>,
836
               detail::enable_if_t <
837
                   !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
838
    basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
149,623,124✔
839
                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
840
                                           std::forward<CompatibleType>(val))))
841
    {
149,623,124✔
842
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
149,623,124✔
843
        set_parents();
149,623,117✔
844
        assert_invariant();
149,623,117✔
845
    }
149,623,121✔
846

847
    /// @brief create a JSON value from an existing one
848
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
849
    template < typename BasicJsonType,
850
               detail::enable_if_t <
851
                   detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
852
    basic_json(const BasicJsonType& val)
255✔
853
#if JSON_DIAGNOSTIC_POSITIONS
854
        : start_position(val.start_pos()),
855
          end_position(val.end_pos())
856
#endif
857
    {
255✔
858
        using other_boolean_t = typename BasicJsonType::boolean_t;
859
        using other_number_float_t = typename BasicJsonType::number_float_t;
860
        using other_number_integer_t = typename BasicJsonType::number_integer_t;
861
        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
862
        using other_string_t = typename BasicJsonType::string_t;
863
        using other_object_t = typename BasicJsonType::object_t;
864
        using other_array_t = typename BasicJsonType::array_t;
865
        using other_binary_t = typename BasicJsonType::binary_t;
866

867
        switch (val.type())
255✔
868
        {
869
            case value_t::boolean:
1✔
870
                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
1✔
871
                break;
1✔
872
            case value_t::number_float:
1✔
873
                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
1✔
874
                break;
1✔
875
            case value_t::number_integer:
119✔
876
                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
119✔
877
                break;
119✔
878
            case value_t::number_unsigned:
7✔
879
                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
7✔
880
                break;
7✔
881
            case value_t::string:
3✔
882
                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
3✔
883
                break;
3✔
884
            case value_t::object:
114✔
885
                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
114✔
886
                break;
114✔
887
            case value_t::array:
3✔
888
                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
3✔
889
                break;
3✔
890
            case value_t::binary:
1✔
891
                JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
1✔
892
                break;
1✔
893
            case value_t::null:
5✔
894
                *this = nullptr;
5✔
895
                break;
5✔
896
            case value_t::discarded:
1✔
897
                m_data.m_type = value_t::discarded;
1✔
898
                break;
1✔
899
            default:            // LCOV_EXCL_LINE
900
                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
901
        }
902
        JSON_ASSERT(m_data.m_type == val.type());
255✔
903

904
        set_parents();
255✔
905
        assert_invariant();
255✔
906
    }
255✔
907

908
    /// @brief create a container (array or object) from an initializer list
909
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
910
    basic_json(initializer_list_t init,
11,023✔
911
               bool type_deduction = true,
912
               value_t manual_type = value_t::array)
913
    {
11,023✔
914
        // check if each element is an array with two elements whose first
915
        // element is a string
916
        bool is_an_object = std::all_of(init.begin(), init.end(),
11,023✔
917
                                        [](const detail::json_ref<basic_json>& element_ref)
15,055✔
918
        {
919
            // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int;
920
            // (many string types can be constructed from 0 via its null-pointer guise, so we get a
921
            // broken call to op[key_type], the wrong semantics, and a 4804 warning on Windows)
922
            return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string();
15,055✔
923
        });
924

925
        // adjust type if type deduction is not wanted
926
        if (!type_deduction)
11,023✔
927
        {
928
            // if an array is wanted, do not create an object though possible
929
            if (manual_type == value_t::array)
862✔
930
            {
931
                is_an_object = false;
67✔
932
            }
933

934
            // if an object is wanted but impossible, throw an exception
935
            if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
862✔
936
            {
937
                JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
3✔
938
            }
939
        }
940

941
        if (is_an_object)
11,022✔
942
        {
943
            // the initializer list is a list of pairs -> create an object
944
            m_data.m_type = value_t::object;
2,448✔
945
            m_data.m_value = value_t::object;
2,448✔
946

947
            for (auto& element_ref : init)
8,972✔
948
            {
949
                auto element = element_ref.moved_or_copied();
6,524✔
950
                m_data.m_value.object->emplace(
6,524✔
951
                    std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)),
6,524✔
952
                    std::move((*element.m_data.m_value.array)[1]));
6,524✔
953
            }
954
        }
955
        else
956
        {
957
            // the initializer list describes an array -> create an array
958
            m_data.m_type = value_t::array;
8,574✔
959
            m_data.m_value.array = create<array_t>(init.begin(), init.end());
8,574✔
960
        }
961

962
        set_parents();
11,022✔
963
        assert_invariant();
11,022✔
964
    }
11,023✔
965

966
    /// @brief explicitly create a binary array (without subtype)
967
    /// @sa https://json.nlohmann.me/api/basic_json/binary/
968
    JSON_HEDLEY_WARN_UNUSED_RESULT
969
    static basic_json binary(const typename binary_t::container_type& init)
2,134✔
970
    {
971
        auto res = basic_json();
2,134✔
972
        res.m_data.m_type = value_t::binary;
2,134✔
973
        res.m_data.m_value = init;
2,134✔
974
        return res;
2,134✔
975
    }
×
976

977
    /// @brief explicitly create a binary array (with subtype)
978
    /// @sa https://json.nlohmann.me/api/basic_json/binary/
979
    JSON_HEDLEY_WARN_UNUSED_RESULT
980
    static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
2✔
981
    {
982
        auto res = basic_json();
2✔
983
        res.m_data.m_type = value_t::binary;
2✔
984
        res.m_data.m_value = binary_t(init, subtype);
2✔
985
        return res;
2✔
986
    }
×
987

988
    /// @brief explicitly create a binary array
989
    /// @sa https://json.nlohmann.me/api/basic_json/binary/
990
    JSON_HEDLEY_WARN_UNUSED_RESULT
991
    static basic_json binary(typename binary_t::container_type&& init)
98✔
992
    {
993
        auto res = basic_json();
98✔
994
        res.m_data.m_type = value_t::binary;
98✔
995
        res.m_data.m_value = std::move(init);
98✔
996
        return res;
98✔
997
    }
×
998

999
    /// @brief explicitly create a binary array (with subtype)
1000
    /// @sa https://json.nlohmann.me/api/basic_json/binary/
1001
    JSON_HEDLEY_WARN_UNUSED_RESULT
1002
    static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
27✔
1003
    {
1004
        auto res = basic_json();
27✔
1005
        res.m_data.m_type = value_t::binary;
27✔
1006
        res.m_data.m_value = binary_t(std::move(init), subtype);
27✔
1007
        return res;
27✔
1008
    }
×
1009

1010
    /// @brief explicitly create an array from an initializer list
1011
    /// @sa https://json.nlohmann.me/api/basic_json/array/
1012
    JSON_HEDLEY_WARN_UNUSED_RESULT
1013
    static basic_json array(initializer_list_t init = {})
67✔
1014
    {
1015
        return basic_json(init, false, value_t::array);
67✔
1016
    }
1017

1018
    /// @brief explicitly create an object from an initializer list
1019
    /// @sa https://json.nlohmann.me/api/basic_json/object/
1020
    JSON_HEDLEY_WARN_UNUSED_RESULT
1021
    static basic_json object(initializer_list_t init = {})
795✔
1022
    {
1023
        return basic_json(init, false, value_t::object);
795✔
1024
    }
1025

1026
    /// @brief construct an array with count copies of given value
1027
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
1028
    basic_json(size_type cnt, const basic_json& val):
23✔
1029
        m_data{cnt, val}
23✔
1030
    {
1031
        set_parents();
23✔
1032
        assert_invariant();
23✔
1033
    }
23✔
1034

1035
    /// @brief construct a JSON container given an iterator range
1036
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
1037
    template < class InputIT, typename std::enable_if <
1038
                   std::is_same<InputIT, typename basic_json_t::iterator>::value ||
1039
                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
1040
    basic_json(InputIT first, InputIT last) // NOLINT(performance-unnecessary-value-param)
54✔
1041
    {
54✔
1042
        JSON_ASSERT(first.m_object != nullptr);
54✔
1043
        JSON_ASSERT(last.m_object != nullptr);
54✔
1044

1045
        // make sure the iterator fits the current value
1046
        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
54✔
1047
        {
1048
            JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
27✔
1049
        }
1050

1051
        // copy type from the first iterator
1052
        m_data.m_type = first.m_object->m_data.m_type;
45✔
1053

1054
        // check if the iterator range is complete for primitive values
1055
        switch (m_data.m_type)
45✔
1056
        {
1057
            case value_t::boolean:
30✔
1058
            case value_t::number_float:
1059
            case value_t::number_integer:
1060
            case value_t::number_unsigned:
1061
            case value_t::string:
1062
            {
1063
                if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
30✔
1064
                                         || !last.m_it.primitive_iterator.is_end()))
1065
                {
1066
                    JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
60✔
1067
                }
1068
                break;
10✔
1069
            }
1070

1071
            case value_t::null:
15✔
1072
            case value_t::object:
1073
            case value_t::array:
1074
            case value_t::binary:
1075
            case value_t::discarded:
1076
            default:
1077
                break;
15✔
1078
        }
1079

1080
        switch (m_data.m_type)
25✔
1081
        {
1082
            case value_t::number_integer:
2✔
1083
            {
1084
                m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer;
2✔
1085
                break;
2✔
1086
            }
1087

1088
            case value_t::number_unsigned:
2✔
1089
            {
1090
                m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned;
2✔
1091
                break;
2✔
1092
            }
1093

1094
            case value_t::number_float:
2✔
1095
            {
1096
                m_data.m_value.number_float = first.m_object->m_data.m_value.number_float;
2✔
1097
                break;
2✔
1098
            }
1099

1100
            case value_t::boolean:
2✔
1101
            {
1102
                m_data.m_value.boolean = first.m_object->m_data.m_value.boolean;
2✔
1103
                break;
2✔
1104
            }
1105

1106
            case value_t::string:
2✔
1107
            {
1108
                m_data.m_value = *first.m_object->m_data.m_value.string;
2✔
1109
                break;
2✔
1110
            }
1111

1112
            case value_t::object:
5✔
1113
            {
1114
                m_data.m_value.object = create<object_t>(first.m_it.object_iterator,
10✔
1115
                                        last.m_it.object_iterator);
5✔
1116
                break;
5✔
1117
            }
1118

1119
            case value_t::array:
6✔
1120
            {
1121
                m_data.m_value.array = create<array_t>(first.m_it.array_iterator,
12✔
1122
                                                       last.m_it.array_iterator);
6✔
1123
                break;
6✔
1124
            }
1125

1126
            case value_t::binary:
2✔
1127
            {
1128
                m_data.m_value = *first.m_object->m_data.m_value.binary;
2✔
1129
                break;
2✔
1130
            }
1131

1132
            case value_t::null:
2✔
1133
            case value_t::discarded:
1134
            default:
1135
                JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
2✔
1136
        }
1137

1138
        set_parents();
23✔
1139
        assert_invariant();
23✔
1140
    }
53✔
1141

1142
    ///////////////////////////////////////
1143
    // other constructors and destructor //
1144
    ///////////////////////////////////////
1145

1146
    template<typename JsonRef,
1147
             detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
1148
                                 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
1149
    basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
20,429✔
1150

1151
    /// @brief copy constructor
1152
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
1153
    basic_json(const basic_json& other)
55,607,826✔
1154
        : json_base_class_t(other)
55,607,593✔
1155
#if JSON_DIAGNOSTIC_POSITIONS
1156
        , start_position(other.start_position)
233✔
1157
        , end_position(other.end_position)
233✔
1158
#endif
1159
    {
1160
        m_data.m_type = other.m_data.m_type;
55,607,826✔
1161
        // check of passed value is valid
1162
        other.assert_invariant();
55,607,826✔
1163

1164
        switch (m_data.m_type)
55,607,826✔
1165
        {
1166
            case value_t::object:
234,215✔
1167
            {
1168
                m_data.m_value = *other.m_data.m_value.object;
234,215✔
1169
                break;
234,215✔
1170
            }
1171

1172
            case value_t::array:
20,189✔
1173
            {
1174
                m_data.m_value = *other.m_data.m_value.array;
20,189✔
1175
                break;
20,189✔
1176
            }
1177

1178
            case value_t::string:
19,328,578✔
1179
            {
1180
                m_data.m_value = *other.m_data.m_value.string;
19,328,578✔
1181
                break;
19,328,578✔
1182
            }
1183

1184
            case value_t::boolean:
14,471✔
1185
            {
1186
                m_data.m_value = other.m_data.m_value.boolean;
14,471✔
1187
                break;
14,471✔
1188
            }
1189

1190
            case value_t::number_integer:
5,198,637✔
1191
            {
1192
                m_data.m_value = other.m_data.m_value.number_integer;
5,198,637✔
1193
                break;
5,198,637✔
1194
            }
1195

1196
            case value_t::number_unsigned:
19,600,807✔
1197
            {
1198
                m_data.m_value = other.m_data.m_value.number_unsigned;
19,600,807✔
1199
                break;
19,600,807✔
1200
            }
1201

1202
            case value_t::number_float:
9,015,031✔
1203
            {
1204
                m_data.m_value = other.m_data.m_value.number_float;
9,015,031✔
1205
                break;
9,015,031✔
1206
            }
1207

1208
            case value_t::binary:
3,240✔
1209
            {
1210
                m_data.m_value = *other.m_data.m_value.binary;
3,240✔
1211
                break;
3,240✔
1212
            }
1213

1214
            case value_t::null:
2,192,658✔
1215
            case value_t::discarded:
1216
            default:
1217
                break;
2,192,658✔
1218
        }
1219

1220
        set_parents();
55,607,826✔
1221
        assert_invariant();
55,607,826✔
1222
    }
55,607,826✔
1223

1224
    /// @brief move constructor
1225
    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
1226
    basic_json(basic_json&& other) noexcept
535,796,496✔
1227
        : json_base_class_t(std::forward<json_base_class_t>(other)),
535,796,473✔
1228
          m_data(std::move(other.m_data)) // cppcheck-suppress[accessForwarded] TODO check
535,796,496✔
1229
#if JSON_DIAGNOSTIC_POSITIONS
1230
        , start_position(other.start_position) // cppcheck-suppress[accessForwarded] TODO check
2,416✔
1231
        , end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check
2,416✔
1232
#endif
1233
    {
1234
        // check that the passed value is valid
1235
        other.assert_invariant(false); // cppcheck-suppress[accessForwarded]
535,796,496✔
1236

1237
        // invalidate payload
1238
        other.m_data.m_type = value_t::null;
535,796,496✔
1239
        other.m_data.m_value = {};
535,796,496✔
1240

1241
#if JSON_DIAGNOSTIC_POSITIONS
1242
        other.start_position = std::string::npos;
2,416✔
1243
        other.end_position = std::string::npos;
2,416✔
1244
#endif
1245

1246
        set_parents();
535,796,496✔
1247
        assert_invariant();
535,796,496✔
1248
    }
535,796,496✔
1249

1250
    /// @brief copy assignment
1251
    /// @sa https://json.nlohmann.me/api/basic_json/operator=/
1252
    basic_json& operator=(basic_json other) noexcept (
25,714,186✔
1253
        std::is_nothrow_move_constructible<value_t>::value&&
1254
        std::is_nothrow_move_assignable<value_t>::value&&
1255
        std::is_nothrow_move_constructible<json_value>::value&&
1256
        std::is_nothrow_move_assignable<json_value>::value&&
1257
        std::is_nothrow_move_assignable<json_base_class_t>::value
1258
    )
1259
    {
1260
        // check that the passed value is valid
1261
        other.assert_invariant();
25,714,186✔
1262

1263
        using std::swap;
1264
        swap(m_data.m_type, other.m_data.m_type);
25,714,186✔
1265
        swap(m_data.m_value, other.m_data.m_value);
25,714,186✔
1266

1267
#if JSON_DIAGNOSTIC_POSITIONS
1268
        swap(start_position, other.start_position);
5,258✔
1269
        swap(end_position, other.end_position);
5,258✔
1270
#endif
1271

1272
        json_base_class_t::operator=(std::move(other));
25,714,186✔
1273

1274
        set_parents();
25,714,186✔
1275
        assert_invariant();
25,714,186✔
1276
        return *this;
25,714,186✔
1277
    }
1278

1279
    /// @brief destructor
1280
    /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/
1281
    ~basic_json() noexcept
771,711,936✔
1282
    {
1283
        assert_invariant(false);
771,711,936✔
1284
    }
771,711,936✔
1285

1286
    /// @}
1287

1288
  public:
1289
    ///////////////////////
1290
    // object inspection //
1291
    ///////////////////////
1292

1293
    /// @name object inspection
1294
    /// Functions to inspect the type of a JSON value.
1295
    /// @{
1296

1297
    /// @brief serialization
1298
    /// @sa https://json.nlohmann.me/api/basic_json/dump/
1299
    string_t dump(const int indent = -1,
79,746,297✔
1300
                  const char indent_char = ' ',
1301
                  const bool ensure_ascii = false,
1302
                  const error_handler_t error_handler = error_handler_t::strict) const
1303
    {
1304
        string_t result;
79,746,297✔
1305
        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
79,746,297✔
1306

1307
        if (indent >= 0)
79,746,297✔
1308
        {
1309
            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
28✔
1310
        }
1311
        else
1312
        {
1313
            s.dump(*this, false, ensure_ascii, 0);
79,746,269✔
1314
        }
1315

1316
        return result;
143,995,362✔
1317
    }
87,494,913✔
1318

1319
    /// @brief return the type of the JSON value (explicit)
1320
    /// @sa https://json.nlohmann.me/api/basic_json/type/
1321
    constexpr value_t type() const noexcept
152,233,493✔
1322
    {
1323
        return m_data.m_type;
152,233,493✔
1324
    }
1325

1326
    /// @brief return whether type is primitive
1327
    /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
1328
    constexpr bool is_primitive() const noexcept
187✔
1329
    {
1330
        return is_null() || is_string() || is_boolean() || is_number() || is_binary();
187✔
1331
    }
1332

1333
    /// @brief return whether type is structured
1334
    /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
1335
    constexpr bool is_structured() const noexcept
910✔
1336
    {
1337
        return is_array() || is_object();
910✔
1338
    }
1339

1340
    /// @brief return whether value is null
1341
    /// @sa https://json.nlohmann.me/api/basic_json/is_null/
1342
    constexpr bool is_null() const noexcept
462,784✔
1343
    {
1344
        return m_data.m_type == value_t::null;
462,784✔
1345
    }
1346

1347
    /// @brief return whether value is a boolean
1348
    /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
1349
    constexpr bool is_boolean() const noexcept
554✔
1350
    {
1351
        return m_data.m_type == value_t::boolean;
554✔
1352
    }
1353

1354
    /// @brief return whether value is a number
1355
    /// @sa https://json.nlohmann.me/api/basic_json/is_number/
1356
    constexpr bool is_number() const noexcept
6,037✔
1357
    {
1358
        return is_number_integer() || is_number_float();
6,037✔
1359
    }
1360

1361
    /// @brief return whether value is an integer number
1362
    /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
1363
    constexpr bool is_number_integer() const noexcept
497,922✔
1364
    {
1365
        return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
497,922✔
1366
    }
1367

1368
    /// @brief return whether value is an unsigned integer number
1369
    /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
1370
    constexpr bool is_number_unsigned() const noexcept
262,582✔
1371
    {
1372
        return m_data.m_type == value_t::number_unsigned;
262,582✔
1373
    }
1374

1375
    /// @brief return whether value is a floating-point number
1376
    /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
1377
    constexpr bool is_number_float() const noexcept
82,318✔
1378
    {
1379
        return m_data.m_type == value_t::number_float;
82,318✔
1380
    }
1381

1382
    /// @brief return whether value is an object
1383
    /// @sa https://json.nlohmann.me/api/basic_json/is_object/
1384
    constexpr bool is_object() const noexcept
186,876,544✔
1385
    {
1386
        return m_data.m_type == value_t::object;
186,876,544✔
1387
    }
1388

1389
    /// @brief return whether value is an array
1390
    /// @sa https://json.nlohmann.me/api/basic_json/is_array/
1391
    constexpr bool is_array() const noexcept
447,406,951✔
1392
    {
1393
        return m_data.m_type == value_t::array;
447,406,951✔
1394
    }
1395

1396
    /// @brief return whether value is a string
1397
    /// @sa https://json.nlohmann.me/api/basic_json/is_string/
1398
    constexpr bool is_string() const noexcept
3,346,172✔
1399
    {
1400
        return m_data.m_type == value_t::string;
3,346,172✔
1401
    }
1402

1403
    /// @brief return whether value is a binary array
1404
    /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
1405
    constexpr bool is_binary() const noexcept
1,355✔
1406
    {
1407
        return m_data.m_type == value_t::binary;
1,355✔
1408
    }
1409

1410
    /// @brief return whether value is discarded
1411
    /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
1412
    constexpr bool is_discarded() const noexcept
73,608✔
1413
    {
1414
        return m_data.m_type == value_t::discarded;
73,608✔
1415
    }
1416

1417
    /// @brief return the type of the JSON value (implicit)
1418
    /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/
1419
    constexpr operator value_t() const noexcept
2,127✔
1420
    {
1421
        return m_data.m_type;
2,127✔
1422
    }
1423

1424
    /// @}
1425

1426
  private:
1427
    //////////////////
1428
    // value access //
1429
    //////////////////
1430

1431
    /// get a boolean (explicit)
1432
    boolean_t get_impl(boolean_t* /*unused*/) const
1433
    {
1434
        if (JSON_HEDLEY_LIKELY(is_boolean()))
1435
        {
1436
            return m_data.m_value.boolean;
1437
        }
1438

1439
        JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
1440
    }
1441

1442
    /// get a pointer to the value (object)
1443
    object_t* get_impl_ptr(object_t* /*unused*/) noexcept
19✔
1444
    {
1445
        return is_object() ? m_data.m_value.object : nullptr;
19✔
1446
    }
1447

1448
    /// get a pointer to the value (object)
1449
    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
269✔
1450
    {
1451
        return is_object() ? m_data.m_value.object : nullptr;
269✔
1452
    }
1453

1454
    /// get a pointer to the value (array)
1455
    array_t* get_impl_ptr(array_t* /*unused*/) noexcept
18✔
1456
    {
1457
        return is_array() ? m_data.m_value.array : nullptr;
18✔
1458
    }
1459

1460
    /// get a pointer to the value (array)
1461
    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
54✔
1462
    {
1463
        return is_array() ? m_data.m_value.array : nullptr;
54✔
1464
    }
1465

1466
    /// get a pointer to the value (string)
1467
    string_t* get_impl_ptr(string_t* /*unused*/) noexcept
24✔
1468
    {
1469
        return is_string() ? m_data.m_value.string : nullptr;
24✔
1470
    }
1471

1472
    /// get a pointer to the value (string)
1473
    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
1,113,409✔
1474
    {
1475
        return is_string() ? m_data.m_value.string : nullptr;
1,113,409✔
1476
    }
1477

1478
    /// get a pointer to the value (boolean)
1479
    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
18✔
1480
    {
1481
        return is_boolean() ? &m_data.m_value.boolean : nullptr;
18✔
1482
    }
1483

1484
    /// get a pointer to the value (boolean)
1485
    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
204✔
1486
    {
1487
        return is_boolean() ? &m_data.m_value.boolean : nullptr;
204✔
1488
    }
1489

1490
    /// get a pointer to the value (integer number)
1491
    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
262,451✔
1492
    {
1493
        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;
262,451✔
1494
    }
1495

1496
    /// get a pointer to the value (integer number)
1497
    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
1,328✔
1498
    {
1499
        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;
1,328✔
1500
    }
1501

1502
    /// get a pointer to the value (unsigned number)
1503
    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
18✔
1504
    {
1505
        return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
18✔
1506
    }
1507

1508
    /// get a pointer to the value (unsigned number)
1509
    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
339✔
1510
    {
1511
        return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
339✔
1512
    }
1513

1514
    /// get a pointer to the value (floating-point number)
1515
    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
18✔
1516
    {
1517
        return is_number_float() ? &m_data.m_value.number_float : nullptr;
18✔
1518
    }
1519

1520
    /// get a pointer to the value (floating-point number)
1521
    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
472✔
1522
    {
1523
        return is_number_float() ? &m_data.m_value.number_float : nullptr;
472✔
1524
    }
1525

1526
    /// get a pointer to the value (binary)
1527
    binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
552✔
1528
    {
1529
        return is_binary() ? m_data.m_value.binary : nullptr;
552✔
1530
    }
1531

1532
    /// get a pointer to the value (binary)
1533
    constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
85✔
1534
    {
1535
        return is_binary() ? m_data.m_value.binary : nullptr;
85✔
1536
    }
1537

1538
    /*!
1539
    @brief helper function to implement get_ref()
1540

1541
    This function helps to implement get_ref() without code duplication for
1542
    const and non-const overloads
1543

1544
    @tparam ThisType will be deduced as `basic_json` or `const basic_json`
1545

1546
    @throw type_error.303 if ReferenceType does not match underlying value
1547
    type of the current JSON
1548
    */
1549
    template<typename ReferenceType, typename ThisType>
1550
    static ReferenceType get_ref_impl(ThisType& obj)
262,642✔
1551
    {
1552
        // delegate the call to get_ptr<>()
1553
        auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
262,642✔
1554

1555
        if (JSON_HEDLEY_LIKELY(ptr != nullptr))
262,642✔
1556
        {
1557
            return *ptr;
262,600✔
1558
        }
1559

1560
        JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
42✔
1561
    }
1562

1563
  public:
1564
    /// @name value access
1565
    /// Direct access to the stored value of a JSON value.
1566
    /// @{
1567

1568
    /// @brief get a pointer value (implicit)
1569
    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
1570
    template<typename PointerType, typename std::enable_if<
1571
                 std::is_pointer<PointerType>::value, int>::type = 0>
1572
    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
263,169✔
1573
    {
1574
        // delegate the call to get_impl_ptr<>()
1575
        return get_impl_ptr(static_cast<PointerType>(nullptr));
263,169✔
1576
    }
1577

1578
    /// @brief get a pointer value (implicit)
1579
    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
1580
    template < typename PointerType, typename std::enable_if <
1581
                   std::is_pointer<PointerType>::value&&
1582
                   std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
1583
    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
1,116,109✔
1584
    {
1585
        // delegate the call to get_impl_ptr<>() const
1586
        return get_impl_ptr(static_cast<PointerType>(nullptr));
1,116,109✔
1587
    }
1588

1589
  private:
1590
    /*!
1591
    @brief get a value (explicit)
1592

1593
    Explicit type conversion between the JSON value and a compatible value
1594
    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
1595
    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
1596
    The value is converted by calling the @ref json_serializer<ValueType>
1597
    `from_json()` method.
1598

1599
    The function is equivalent to executing
1600
    @code {.cpp}
1601
    ValueType ret;
1602
    JSONSerializer<ValueType>::from_json(*this, ret);
1603
    return ret;
1604
    @endcode
1605

1606
    This overloads is chosen if:
1607
    - @a ValueType is not @ref basic_json,
1608
    - @ref json_serializer<ValueType> has a `from_json()` method of the form
1609
      `void from_json(const basic_json&, ValueType&)`, and
1610
    - @ref json_serializer<ValueType> does not have a `from_json()` method of
1611
      the form `ValueType from_json(const basic_json&)`
1612

1613
    @tparam ValueType the returned value type
1614

1615
    @return copy of the JSON value, converted to @a ValueType
1616

1617
    @throw what @ref json_serializer<ValueType> `from_json()` method throws
1618

1619
    @liveexample{The example below shows several conversions from JSON values
1620
    to other types. There a few things to note: (1) Floating-point numbers can
1621
    be converted to integers\, (2) A JSON array can be converted to a standard
1622
    `std::vector<short>`\, (3) A JSON object can be converted to C++
1623
    associative containers such as `std::unordered_map<std::string\,
1624
    json>`.,get__ValueType_const}
1625

1626
    @since version 2.1.0
1627
    */
1628
    template < typename ValueType,
1629
               detail::enable_if_t <
1630
                   detail::is_default_constructible<ValueType>::value&&
1631
                   detail::has_from_json<basic_json_t, ValueType>::value,
1632
                   int > = 0 >
1633
    ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
1,116,192✔
1634
                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
1635
    {
1636
        auto ret = ValueType();
1,116,192✔
1637
        JSONSerializer<ValueType>::from_json(*this, ret);
1,116,192✔
1638
        return ret;
1,115,936✔
1639
    }
168✔
1640

1641
    /*!
1642
    @brief get a value (explicit); special case
1643

1644
    Explicit type conversion between the JSON value and a compatible value
1645
    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
1646
    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
1647
    The value is converted by calling the @ref json_serializer<ValueType>
1648
    `from_json()` method.
1649

1650
    The function is equivalent to executing
1651
    @code {.cpp}
1652
    return JSONSerializer<ValueType>::from_json(*this);
1653
    @endcode
1654

1655
    This overloads is chosen if:
1656
    - @a ValueType is not @ref basic_json and
1657
    - @ref json_serializer<ValueType> has a `from_json()` method of the form
1658
      `ValueType from_json(const basic_json&)`
1659

1660
    @note If @ref json_serializer<ValueType> has both overloads of
1661
    `from_json()`, this one is chosen.
1662

1663
    @tparam ValueType the returned value type
1664

1665
    @return copy of the JSON value, converted to @a ValueType
1666

1667
    @throw what @ref json_serializer<ValueType> `from_json()` method throws
1668

1669
    @since version 2.1.0
1670
    */
1671
    template < typename ValueType,
1672
               detail::enable_if_t <
1673
                   detail::has_non_default_from_json<basic_json_t, ValueType>::value,
1674
                   int > = 0 >
1675
    ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
103✔
1676
                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
1677
    {
1678
        return JSONSerializer<ValueType>::from_json(*this);
97✔
1679
    }
1680

1681
    /*!
1682
    @brief get special-case overload
1683

1684
    This overloads converts the current @ref basic_json in a different
1685
    @ref basic_json type
1686

1687
    @tparam BasicJsonType == @ref basic_json
1688

1689
    @return a copy of *this, converted into @a BasicJsonType
1690

1691
    @complexity Depending on the implementation of the called `from_json()`
1692
                method.
1693

1694
    @since version 3.2.0
1695
    */
1696
    template < typename BasicJsonType,
1697
               detail::enable_if_t <
1698
                   detail::is_basic_json<BasicJsonType>::value,
1699
                   int > = 0 >
1700
    BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
13✔
1701
    {
1702
        return *this;
13✔
1703
    }
1704

1705
    /*!
1706
    @brief get special-case overload
1707

1708
    This overloads avoids a lot of template boilerplate, it can be seen as the
1709
    identity method
1710

1711
    @tparam BasicJsonType == @ref basic_json
1712

1713
    @return a copy of *this
1714

1715
    @complexity Constant.
1716

1717
    @since version 2.1.0
1718
    */
1719
    template<typename BasicJsonType,
1720
             detail::enable_if_t<
1721
                 std::is_same<BasicJsonType, basic_json_t>::value,
1722
                 int> = 0>
1723
    basic_json get_impl(detail::priority_tag<3> /*unused*/) const
622✔
1724
    {
1725
        return *this;
622✔
1726
    }
1727

1728
    /*!
1729
    @brief get a pointer value (explicit)
1730
    @copydoc get()
1731
    */
1732
    template<typename PointerType,
1733
             detail::enable_if_t<
1734
                 std::is_pointer<PointerType>::value,
1735
                 int> = 0>
1736
    constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
1737
    -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
1738
    {
1739
        // delegate the call to get_ptr
1740
        return get_ptr<PointerType>();
1741
    }
1742

1743
  public:
1744
    /*!
1745
    @brief get a (pointer) value (explicit)
1746

1747
    Performs explicit type conversion between the JSON value and a compatible value if required.
1748

1749
    - If the requested type is a pointer to the internally stored JSON value that pointer is returned.
1750
    No copies are made.
1751

1752
    - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible
1753
    from the current @ref basic_json.
1754

1755
    - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()`
1756
    method.
1757

1758
    @tparam ValueTypeCV the provided value type
1759
    @tparam ValueType the returned value type
1760

1761
    @return copy of the JSON value, converted to @tparam ValueType if necessary
1762

1763
    @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
1764

1765
    @since version 2.1.0
1766
    */
1767
    template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
1768
#if defined(JSON_HAS_CPP_14)
1769
    constexpr
1770
#endif
1771
    auto get() const noexcept(
1,116,930✔
1772
    noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))
1773
    -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
1774
    {
1775
        // we cannot static_assert on ValueTypeCV being non-const, because
1776
        // there is support for get<const basic_json_t>(), which is why we
1777
        // still need the uncvref
1778
        static_assert(!std::is_reference<ValueTypeCV>::value,
1779
                      "get() cannot be used with reference types, you might want to use get_ref()");
1780
        return get_impl<ValueType>(detail::priority_tag<4> {});
2,230,850✔
1781
    }
1782

1783
    /*!
1784
    @brief get a pointer value (explicit)
1785

1786
    Explicit pointer access to the internally stored JSON value. No copies are
1787
    made.
1788

1789
    @warning The pointer becomes invalid if the underlying JSON object
1790
    changes.
1791

1792
    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
1793
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
1794
    @ref number_unsigned_t, or @ref number_float_t.
1795

1796
    @return pointer to the internally stored JSON value if the requested
1797
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
1798

1799
    @complexity Constant.
1800

1801
    @liveexample{The example below shows how pointers to internal values of a
1802
    JSON value can be requested. Note that no type conversions are made and a
1803
    `nullptr` is returned if the value and the requested pointer type does not
1804
    match.,get__PointerType}
1805

1806
    @sa see @ref get_ptr() for explicit pointer-member access
1807

1808
    @since version 1.0.0
1809
    */
1810
    template<typename PointerType, typename std::enable_if<
1811
                 std::is_pointer<PointerType>::value, int>::type = 0>
1812
    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
1813
    {
1814
        // delegate the call to get_ptr
1815
        return get_ptr<PointerType>();
1816
    }
1817

1818
    /// @brief get a value (explicit)
1819
    /// @sa https://json.nlohmann.me/api/basic_json/get_to/
1820
    template < typename ValueType,
1821
               detail::enable_if_t <
1822
                   !detail::is_basic_json<ValueType>::value&&
1823
                   detail::has_from_json<basic_json_t, ValueType>::value,
1824
                   int > = 0 >
1825
    ValueType & get_to(ValueType& v) const noexcept(noexcept(
275✔
1826
                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
1827
    {
1828
        JSONSerializer<ValueType>::from_json(*this, v);
275✔
1829
        return v;
272✔
1830
    }
1831

1832
    // specialization to allow calling get_to with a basic_json value
1833
    // see https://github.com/nlohmann/json/issues/2175
1834
    template<typename ValueType,
1835
             detail::enable_if_t <
1836
                 detail::is_basic_json<ValueType>::value,
1837
                 int> = 0>
1838
    ValueType & get_to(ValueType& v) const
36✔
1839
    {
1840
        v = *this;
36✔
1841
        return v;
36✔
1842
    }
1843

1844
    template <
1845
        typename T, std::size_t N,
1846
        typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
1847
        detail::enable_if_t <
1848
            detail::has_from_json<basic_json_t, Array>::value, int > = 0 >
1849
    Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
12✔
1850
    noexcept(noexcept(JSONSerializer<Array>::from_json(
1851
                          std::declval<const basic_json_t&>(), v)))
1852
    {
1853
        JSONSerializer<Array>::from_json(*this, v);
12✔
1854
        return v;
12✔
1855
    }
1856

1857
    /// @brief get a reference value (implicit)
1858
    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
1859
    template<typename ReferenceType, typename std::enable_if<
1860
                 std::is_reference<ReferenceType>::value, int>::type = 0>
1861
    ReferenceType get_ref()
262,512✔
1862
    {
1863
        // delegate call to get_ref_impl
1864
        return get_ref_impl<ReferenceType>(*this);
262,512✔
1865
    }
1866

1867
    /// @brief get a reference value (implicit)
1868
    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
1869
    template < typename ReferenceType, typename std::enable_if <
1870
                   std::is_reference<ReferenceType>::value&&
1871
                   std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
1872
    ReferenceType get_ref() const
130✔
1873
    {
1874
        // delegate call to get_ref_impl
1875
        return get_ref_impl<ReferenceType>(*this);
130✔
1876
    }
1877

1878
    /*!
1879
    @brief get a value (implicit)
1880

1881
    Implicit type conversion between the JSON value and a compatible value.
1882
    The call is realized by calling @ref get() const.
1883

1884
    @tparam ValueType non-pointer type compatible to the JSON value, for
1885
    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
1886
    `std::vector` types for JSON arrays. The character type of @ref string_t
1887
    as well as an initializer list of this type is excluded to avoid
1888
    ambiguities as these types implicitly convert to `std::string`.
1889

1890
    @return copy of the JSON value, converted to type @a ValueType
1891

1892
    @throw type_error.302 in case passed type @a ValueType is incompatible
1893
    to the JSON value type (e.g., the JSON value is of type boolean, but a
1894
    string is requested); see example below
1895

1896
    @complexity Linear in the size of the JSON value.
1897

1898
    @liveexample{The example below shows several conversions from JSON values
1899
    to other types. There a few things to note: (1) Floating-point numbers can
1900
    be converted to integers\, (2) A JSON array can be converted to a standard
1901
    `std::vector<short>`\, (3) A JSON object can be converted to C++
1902
    associative containers such as `std::unordered_map<std::string\,
1903
    json>`.,operator__ValueType}
1904

1905
    @since version 1.0.0
1906
    */
1907
    template < typename ValueType, typename std::enable_if <
1908
                   detail::conjunction <
1909
                       detail::negation<std::is_pointer<ValueType>>,
1910
                       detail::negation<std::is_same<ValueType, std::nullptr_t>>,
1911
                       detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
1912
                                        detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
1913
                                        detail::negation<detail::is_basic_json<ValueType>>,
1914
                                        detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,
1915
#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
1916
                                                detail::negation<std::is_same<ValueType, std::string_view>>,
1917
#endif
1918
#if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI
1919
                                                detail::negation<std::is_same<ValueType, std::any>>,
1920
#endif
1921
                                                detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
1922
                                                >::value, int >::type = 0 >
1923
                                        JSON_EXPLICIT operator ValueType() const
305✔
1924
    {
1925
        // delegate the call to get<>() const
1926
        return get<ValueType>();
303✔
1927
    }
1928

1929
    /// @brief get a binary value
1930
    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
1931
    binary_t& get_binary()
560✔
1932
    {
1933
        if (!is_binary())
560✔
1934
        {
1935
            JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
15✔
1936
        }
1937

1938
        return *get_ptr<binary_t*>();
545✔
1939
    }
1940

1941
    /// @brief get a binary value
1942
    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
1943
    const binary_t& get_binary() const
66✔
1944
    {
1945
        if (!is_binary())
66✔
1946
        {
1947
            JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
15✔
1948
        }
1949

1950
        return *get_ptr<const binary_t*>();
51✔
1951
    }
1952

1953
    /// @}
1954

1955
    ////////////////////
1956
    // element access //
1957
    ////////////////////
1958

1959
    /// @name element access
1960
    /// Access to the JSON value.
1961
    /// @{
1962

1963
    /// @brief access specified array element with bounds checking
1964
    /// @sa https://json.nlohmann.me/api/basic_json/at/
1965
    reference at(size_type idx)
98✔
1966
    {
1967
        // at only works for arrays
1968
        if (JSON_HEDLEY_LIKELY(is_array()))
98✔
1969
        {
1970
            JSON_TRY
1971
            {
1972
                return set_parent(m_data.m_value.array->at(idx));
91✔
1973
            }
1974
            JSON_CATCH (std::out_of_range&)
10✔
1975
            {
1976
                // create a better exception explanation
1977
                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
5✔
1978
            } // cppcheck-suppress[missingReturn]
1979
        }
1980
        else
1981
        {
1982
            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
7✔
1983
        }
1984
    }
1985

1986
    /// @brief access specified array element with bounds checking
1987
    /// @sa https://json.nlohmann.me/api/basic_json/at/
1988
    const_reference at(size_type idx) const
743✔
1989
    {
1990
        // at only works for arrays
1991
        if (JSON_HEDLEY_LIKELY(is_array()))
743✔
1992
        {
1993
            JSON_TRY
1994
            {
1995
                return m_data.m_value.array->at(idx);
734✔
1996
            }
1997
            JSON_CATCH (std::out_of_range&)
22✔
1998
            {
1999
                // create a better exception explanation
2000
                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
11✔
2001
            } // cppcheck-suppress[missingReturn]
2002
        }
2003
        else
2004
        {
2005
            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
9✔
2006
        }
2007
    }
2008

2009
    /// @brief access specified object element with bounds checking
2010
    /// @sa https://json.nlohmann.me/api/basic_json/at/
2011
    reference at(const typename object_t::key_type& key)
376✔
2012
    {
2013
        // at only works for objects
2014
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
376✔
2015
        {
2016
            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
14✔
2017
        }
2018

2019
        auto it = m_data.m_value.object->find(key);
362✔
2020
        if (it == m_data.m_value.object->end())
362✔
2021
        {
2022
            JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
20✔
2023
        }
2024
        return set_parent(it->second);
684✔
2025
    }
2026

2027
    /// @brief access specified object element with bounds checking
2028
    /// @sa https://json.nlohmann.me/api/basic_json/at/
2029
    template<class KeyType, detail::enable_if_t<
2030
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
2031
    reference at(KeyType && key)
144✔
2032
    {
2033
        // at only works for objects
2034
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
144✔
2035
        {
2036
            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
42✔
2037
        }
2038

2039
        auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
102✔
2040
        if (it == m_data.m_value.object->end())
102✔
2041
        {
2042
            JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
18✔
2043
        }
2044
        return set_parent(it->second);
192✔
2045
    }
2046

2047
    /// @brief access specified object element with bounds checking
2048
    /// @sa https://json.nlohmann.me/api/basic_json/at/
2049
    const_reference at(const typename object_t::key_type& key) const
620✔
2050
    {
2051
        // at only works for objects
2052
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
620✔
2053
        {
2054
            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
14✔
2055
        }
2056

2057
        auto it = m_data.m_value.object->find(key);
606✔
2058
        if (it == m_data.m_value.object->end())
606✔
2059
        {
2060
            JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
100✔
2061
        }
2062
        return it->second;
1,012✔
2063
    }
2064

2065
    /// @brief access specified object element with bounds checking
2066
    /// @sa https://json.nlohmann.me/api/basic_json/at/
2067
    template<class KeyType, detail::enable_if_t<
2068
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
2069
    const_reference at(KeyType && key) const
150✔
2070
    {
2071
        // at only works for objects
2072
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
150✔
2073
        {
2074
            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
42✔
2075
        }
2076

2077
        auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
108✔
2078
        if (it == m_data.m_value.object->end())
108✔
2079
        {
2080
            JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
18✔
2081
        }
2082
        return it->second;
204✔
2083
    }
2084

2085
    /// @brief access specified array element
2086
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2087
    reference operator[](size_type idx)
65,588✔
2088
    {
2089
        // implicitly convert a null value to an empty array
2090
        if (is_null())
65,588✔
2091
        {
2092
            m_data.m_type = value_t::array;
14✔
2093
            m_data.m_value.array = create<array_t>();
14✔
2094
            assert_invariant();
14✔
2095
        }
2096

2097
        // operator[] only works for arrays
2098
        if (JSON_HEDLEY_LIKELY(is_array()))
65,588✔
2099
        {
2100
            // fill up the array with null values if given idx is outside the range
2101
            if (idx >= m_data.m_value.array->size())
65,581✔
2102
            {
2103
#if JSON_DIAGNOSTICS
2104
                // remember array size & capacity before resizing
2105
                const auto old_size = m_data.m_value.array->size();
10✔
2106
                const auto old_capacity = m_data.m_value.array->capacity();
10✔
2107
#endif
2108
                m_data.m_value.array->resize(idx + 1);
46✔
2109

2110
#if JSON_DIAGNOSTICS
2111
                if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
10✔
2112
                {
2113
                    // capacity has changed: update all parents
2114
                    set_parents();
6✔
2115
                }
2116
                else
2117
                {
2118
                    // set parent for values added above
2119
                    set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));
4✔
2120
                }
2121
#endif
2122
                assert_invariant();
46✔
2123
            }
2124

2125
            return m_data.m_value.array->operator[](idx);
65,581✔
2126
        }
2127

2128
        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
7✔
2129
    }
2130

2131
    /// @brief access specified array element
2132
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2133
    const_reference operator[](size_type idx) const
6,680✔
2134
    {
2135
        // const operator[] only works for arrays
2136
        if (JSON_HEDLEY_LIKELY(is_array()))
6,680✔
2137
        {
2138
            return m_data.m_value.array->operator[](idx);
6,673✔
2139
        }
2140

2141
        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
7✔
2142
    }
2143

2144
    /// @brief access specified object element
2145
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2146
    reference operator[](typename object_t::key_type key) // NOLINT(performance-unnecessary-value-param)
2,016✔
2147
    {
2148
        // implicitly convert a null value to an empty object
2149
        if (is_null())
2,016✔
2150
        {
2151
            m_data.m_type = value_t::object;
558✔
2152
            m_data.m_value.object = create<object_t>();
558✔
2153
            assert_invariant();
558✔
2154
        }
2155

2156
        // operator[] only works for objects
2157
        if (JSON_HEDLEY_LIKELY(is_object()))
2,016✔
2158
        {
2159
            auto result = m_data.m_value.object->emplace(std::move(key), nullptr);
1,944✔
2160
            return set_parent(result.first->second);
3,888✔
2161
        }
2162

2163
        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
72✔
2164
    }
2165

2166
    /// @brief access specified object element
2167
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2168
    const_reference operator[](const typename object_t::key_type& key) const
765✔
2169
    {
2170
        // const operator[] only works for objects
2171
        if (JSON_HEDLEY_LIKELY(is_object()))
765✔
2172
        {
2173
            auto it = m_data.m_value.object->find(key);
681✔
2174
            JSON_ASSERT(it != m_data.m_value.object->end());
681✔
2175
            return it->second;
1,362✔
2176
        }
2177

2178
        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
84✔
2179
    }
2180

2181
    // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
2182
    // (they seemingly cannot be constrained to resolve the ambiguity)
2183
    template<typename T>
2184
    reference operator[](T* key)
1,616✔
2185
    {
2186
        return operator[](typename object_t::key_type(key));
3,213✔
2187
    }
2188

2189
    template<typename T>
2190
    const_reference operator[](T* key) const
516✔
2191
    {
2192
        return operator[](typename object_t::key_type(key));
1,024✔
2193
    }
2194

2195
    /// @brief access specified object element
2196
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2197
    template<class KeyType, detail::enable_if_t<
2198
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
2199
    reference operator[](KeyType && key)
34✔
2200
    {
2201
        // implicitly convert a null value to an empty object
2202
        if (is_null())
34✔
2203
        {
2204
            m_data.m_type = value_t::object;
2✔
2205
            m_data.m_value.object = create<object_t>();
2✔
2206
            assert_invariant();
2✔
2207
        }
2208

2209
        // operator[] only works for objects
2210
        if (JSON_HEDLEY_LIKELY(is_object()))
34✔
2211
        {
2212
            auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
22✔
2213
            return set_parent(result.first->second);
44✔
2214
        }
2215

2216
        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
12✔
2217
    }
2218

2219
    /// @brief access specified object element
2220
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
2221
    template<class KeyType, detail::enable_if_t<
2222
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
2223
    const_reference operator[](KeyType && key) const
28✔
2224
    {
2225
        // const operator[] only works for objects
2226
        if (JSON_HEDLEY_LIKELY(is_object()))
28✔
2227
        {
2228
            auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
14✔
2229
            JSON_ASSERT(it != m_data.m_value.object->end());
14✔
2230
            return it->second;
28✔
2231
        }
2232

2233
        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
14✔
2234
    }
2235

2236
  private:
2237
    template<typename KeyType>
2238
    using is_comparable_with_object_key = detail::is_comparable <
2239
        object_comparator_t, const typename object_t::key_type&, KeyType >;
2240

2241
    template<typename ValueType>
2242
    using value_return_type = std::conditional <
2243
        detail::is_c_string_uncvref<ValueType>::value,
2244
        string_t, typename std::decay<ValueType>::type >;
2245

2246
  public:
2247
    /// @brief access specified object element with default value
2248
    /// @sa https://json.nlohmann.me/api/basic_json/value/
2249
    template < class ValueType, detail::enable_if_t <
2250
                   !detail::is_transparent<object_comparator_t>::value
2251
                   && detail::is_getable<basic_json_t, ValueType>::value
2252
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2253
    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
242✔
2254
    {
2255
        // value only works for objects
2256
        if (JSON_HEDLEY_LIKELY(is_object()))
242✔
2257
        {
2258
            // If 'key' is found, return its value. Otherwise, return `default_value'.
2259
            const auto it = find(key);
226✔
2260
            if (it != end())
226✔
2261
            {
2262
                return it->template get<ValueType>();
179✔
2263
            }
2264

2265
            return default_value;
47✔
2266
        }
2267

2268
        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
16✔
2269
    }
2270

2271
    /// @brief access specified object element with default value
2272
    /// @sa https://json.nlohmann.me/api/basic_json/value/
2273
    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
2274
               detail::enable_if_t <
2275
                   !detail::is_transparent<object_comparator_t>::value
2276
                   && detail::is_getable<basic_json_t, ReturnType>::value
2277
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2278
    ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
520✔
2279
    {
2280
        // value only works for objects
2281
        if (JSON_HEDLEY_LIKELY(is_object()))
520✔
2282
        {
2283
            // If 'key' is found, return its value. Otherwise, return `default_value'.
2284
            const auto it = find(key);
476✔
2285
            if (it != end())
476✔
2286
            {
2287
                return it->template get<ReturnType>();
245✔
2288
            }
2289

2290
            return std::forward<ValueType>(default_value);
266✔
2291
        }
2292

2293
        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
44✔
2294
    }
2295

2296
    /// @brief access specified object element with default value
2297
    /// @sa https://json.nlohmann.me/api/basic_json/value/
2298
    template < class ValueType, class KeyType, detail::enable_if_t <
2299
                   detail::is_transparent<object_comparator_t>::value
2300
                   && !detail::is_json_pointer<KeyType>::value
2301
                   && is_comparable_with_object_key<KeyType>::value
2302
                   && detail::is_getable<basic_json_t, ValueType>::value
2303
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2304
    ValueType value(KeyType && key, const ValueType& default_value) const
140✔
2305
    {
2306
        // value only works for objects
2307
        if (JSON_HEDLEY_LIKELY(is_object()))
140✔
2308
        {
2309
            // If 'key' is found, return its value. Otherwise, return `default_value'.
2310
            const auto it = find(std::forward<KeyType>(key));
104✔
2311
            if (it != end())
104✔
2312
            {
2313
                return it->template get<ValueType>();
74✔
2314
            }
2315

2316
            return default_value;
30✔
2317
        }
2318

2319
        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
36✔
2320
    }
2321

2322
    /// @brief access specified object element via JSON Pointer with default value
2323
    /// @sa https://json.nlohmann.me/api/basic_json/value/
2324
    template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
2325
               detail::enable_if_t <
2326
                   detail::is_transparent<object_comparator_t>::value
2327
                   && !detail::is_json_pointer<KeyType>::value
2328
                   && is_comparable_with_object_key<KeyType>::value
2329
                   && detail::is_getable<basic_json_t, ReturnType>::value
2330
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2331
    ReturnType value(KeyType && key, ValueType && default_value) const
788✔
2332
    {
2333
        // value only works for objects
2334
        if (JSON_HEDLEY_LIKELY(is_object()))
788✔
2335
        {
2336
            // If 'key' is found, return its value. Otherwise, return `default_value'.
2337
            const auto it = find(std::forward<KeyType>(key));
668✔
2338
            if (it != end())
668✔
2339
            {
2340
                return it->template get<ReturnType>();
402✔
2341
            }
2342

2343
            return std::forward<ValueType>(default_value);
296✔
2344
        }
2345

2346
        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
120✔
2347
    }
2348

2349
    /// @brief access specified object element via JSON Pointer with default value
2350
    /// @sa https://json.nlohmann.me/api/basic_json/value/
2351
    template < class ValueType, detail::enable_if_t <
2352
                   detail::is_getable<basic_json_t, ValueType>::value
2353
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2354
    ValueType value(const json_pointer& ptr, const ValueType& default_value) const
2355
    {
2356
        // value only works for objects
2357
        if (JSON_HEDLEY_LIKELY(is_object()))
2358
        {
2359
            // If the pointer resolves to a value, return it. Otherwise, return
2360
            // 'default_value'.
2361
            JSON_TRY
2362
            {
2363
                return ptr.get_checked(this).template get<ValueType>();
2364
            }
2365
            JSON_INTERNAL_CATCH (out_of_range&)
2366
            {
2367
                return default_value;
2368
            }
2369
        }
2370

2371
        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
2372
    }
2373

2374
    /// @brief access specified object element via JSON Pointer with default value
2375
    /// @sa https://json.nlohmann.me/api/basic_json/value/
2376
    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
2377
               detail::enable_if_t <
2378
                   detail::is_getable<basic_json_t, ReturnType>::value
2379
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2380
    ReturnType value(const json_pointer& ptr, ValueType && default_value) const
316✔
2381
    {
2382
        // value only works for objects
2383
        if (JSON_HEDLEY_LIKELY(is_object()))
316✔
2384
        {
2385
            // If the pointer resolves to a value, return it. Otherwise, return
2386
            // 'default_value'.
2387
            JSON_TRY
2388
            {
2389
                return ptr.get_checked(this).template get<ReturnType>();
232✔
2390
            }
2391
            JSON_INTERNAL_CATCH (out_of_range&)
156✔
2392
            {
2393
                return std::forward<ValueType>(default_value);
96✔
2394
            }
2395
        }
2396

2397
        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
84✔
2398
    }
2399

2400
    template < class ValueType, class BasicJsonType, detail::enable_if_t <
2401
                   detail::is_basic_json<BasicJsonType>::value
2402
                   && detail::is_getable<basic_json_t, ValueType>::value
2403
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2404
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
2405
    ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
2406
    {
2407
        return value(ptr.convert(), default_value);
2408
    }
2409

2410
    template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
2411
               detail::enable_if_t <
2412
                   detail::is_basic_json<BasicJsonType>::value
2413
                   && detail::is_getable<basic_json_t, ReturnType>::value
2414
                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
2415
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
2416
    ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
4✔
2417
    {
2418
        return value(ptr.convert(), std::forward<ValueType>(default_value));
4✔
2419
    }
2420

2421
    /// @brief access the first element
2422
    /// @sa https://json.nlohmann.me/api/basic_json/front/
2423
    reference front()
13✔
2424
    {
2425
        return *begin();
13✔
2426
    }
2427

2428
    /// @brief access the first element
2429
    /// @sa https://json.nlohmann.me/api/basic_json/front/
2430
    const_reference front() const
576,458✔
2431
    {
2432
        return *cbegin();
576,458✔
2433
    }
2434

2435
    /// @brief access the last element
2436
    /// @sa https://json.nlohmann.me/api/basic_json/back/
2437
    reference back()
13✔
2438
    {
2439
        auto tmp = end();
13✔
2440
        --tmp;
13✔
2441
        return *tmp;
25✔
2442
    }
2443

2444
    /// @brief access the last element
2445
    /// @sa https://json.nlohmann.me/api/basic_json/back/
2446
    const_reference back() const
13✔
2447
    {
2448
        auto tmp = cend();
13✔
2449
        --tmp;
13✔
2450
        return *tmp;
25✔
2451
    }
2452

2453
    /// @brief remove element given an iterator
2454
    /// @sa https://json.nlohmann.me/api/basic_json/erase/
2455
    template < class IteratorType, detail::enable_if_t <
2456
                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
2457
                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
2458
    IteratorType erase(IteratorType pos) // NOLINT(performance-unnecessary-value-param)
134✔
2459
    {
2460
        // make sure the iterator fits the current value
2461
        if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
134✔
2462
        {
2463
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
45✔
2464
        }
2465

2466
        IteratorType result = end();
119✔
2467

2468
        switch (m_data.m_type)
119✔
2469
        {
2470
            case value_t::boolean:
22✔
2471
            case value_t::number_float:
2472
            case value_t::number_integer:
2473
            case value_t::number_unsigned:
2474
            case value_t::string:
2475
            case value_t::binary:
2476
            {
2477
                if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
22✔
2478
                {
2479
                    JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
30✔
2480
                }
2481

2482
                if (is_string())
12✔
2483
                {
2484
                    AllocatorType<string_t> alloc;
2485
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
2✔
2486
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
2✔
2487
                    m_data.m_value.string = nullptr;
2✔
2488
                }
2489
                else if (is_binary())
10✔
2490
                {
2491
                    AllocatorType<binary_t> alloc;
2492
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
2✔
2493
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
2✔
2494
                    m_data.m_value.binary = nullptr;
2✔
2495
                }
2496

2497
                m_data.m_type = value_t::null;
12✔
2498
                assert_invariant();
12✔
2499
                break;
12✔
2500
            }
2501

2502
            case value_t::object:
76✔
2503
            {
2504
                result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);
76✔
2505
                break;
76✔
2506
            }
2507

2508
            case value_t::array:
19✔
2509
            {
2510
                result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator);
19✔
2511
                break;
19✔
2512
            }
2513

2514
            case value_t::null:
2✔
2515
            case value_t::discarded:
2516
            default:
2517
                JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
2✔
2518
        }
2519

2520
        return result;
107✔
2521
    }
2522

2523
    /// @brief remove elements given an iterator range
2524
    /// @sa https://json.nlohmann.me/api/basic_json/erase/
2525
    template < class IteratorType, detail::enable_if_t <
2526
                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
2527
                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
2528
    IteratorType erase(IteratorType first, IteratorType last) // NOLINT(performance-unnecessary-value-param)
124✔
2529
    {
2530
        // make sure the iterator fits the current value
2531
        if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
124✔
2532
        {
2533
            JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
126✔
2534
        }
2535

2536
        IteratorType result = end();
82✔
2537

2538
        switch (m_data.m_type)
82✔
2539
        {
2540
            case value_t::boolean:
32✔
2541
            case value_t::number_float:
2542
            case value_t::number_integer:
2543
            case value_t::number_unsigned:
2544
            case value_t::string:
2545
            case value_t::binary:
2546
            {
2547
                if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
32✔
2548
                                       || !last.m_it.primitive_iterator.is_end()))
2549
                {
2550
                    JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
60✔
2551
                }
2552

2553
                if (is_string())
12✔
2554
                {
2555
                    AllocatorType<string_t> alloc;
2556
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
2✔
2557
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
2✔
2558
                    m_data.m_value.string = nullptr;
2✔
2559
                }
2560
                else if (is_binary())
10✔
2561
                {
2562
                    AllocatorType<binary_t> alloc;
2563
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
2✔
2564
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
2✔
2565
                    m_data.m_value.binary = nullptr;
2✔
2566
                }
2567

2568
                m_data.m_type = value_t::null;
12✔
2569
                assert_invariant();
12✔
2570
                break;
12✔
2571
            }
2572

2573
            case value_t::object:
36✔
2574
            {
2575
                result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator,
36✔
2576
                                              last.m_it.object_iterator);
18✔
2577
                break;
36✔
2578
            }
2579

2580
            case value_t::array:
12✔
2581
            {
2582
                result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator,
12✔
2583
                                             last.m_it.array_iterator);
12✔
2584
                break;
12✔
2585
            }
2586

2587
            case value_t::null:
2✔
2588
            case value_t::discarded:
2589
            default:
2590
                JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
2✔
2591
        }
2592

2593
        return result;
60✔
2594
    }
2595

2596
  private:
2597
    template < typename KeyType, detail::enable_if_t <
2598
                   detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
2599
    size_type erase_internal(KeyType && key)
227✔
2600
    {
2601
        // this erase only works for objects
2602
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
227✔
2603
        {
2604
            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
42✔
2605
        }
2606

2607
        return m_data.m_value.object->erase(std::forward<KeyType>(key));
249✔
2608
    }
2609

2610
    template < typename KeyType, detail::enable_if_t <
2611
                   !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
2612
    size_type erase_internal(KeyType && key)
22✔
2613
    {
2614
        // this erase only works for objects
2615
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
22✔
2616
        {
2617
            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
6✔
2618
        }
2619

2620
        const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
16✔
2621
        if (it != m_data.m_value.object->end())
16✔
2622
        {
2623
            m_data.m_value.object->erase(it);
8✔
2624
            return 1;
8✔
2625
        }
2626
        return 0;
8✔
2627
    }
2628

2629
  public:
2630

2631
    /// @brief remove element from a JSON object given a key
2632
    /// @sa https://json.nlohmann.me/api/basic_json/erase/
2633
    size_type erase(const typename object_t::key_type& key)
117✔
2634
    {
2635
        // the indirection via erase_internal() is added to avoid making this
2636
        // function a template and thus de-rank it during overload resolution
2637
        return erase_internal(key);
117✔
2638
    }
2639

2640
    /// @brief remove element from a JSON object given a key
2641
    /// @sa https://json.nlohmann.me/api/basic_json/erase/
2642
    template<class KeyType, detail::enable_if_t<
2643
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
2644
    size_type erase(KeyType && key)
132✔
2645
    {
2646
        return erase_internal(std::forward<KeyType>(key));
108✔
2647
    }
2648

2649
    /// @brief remove element from a JSON array given an index
2650
    /// @sa https://json.nlohmann.me/api/basic_json/erase/
2651
    void erase(const size_type idx)
32✔
2652
    {
2653
        // this erase only works for arrays
2654
        if (JSON_HEDLEY_LIKELY(is_array()))
32✔
2655
        {
2656
            if (JSON_HEDLEY_UNLIKELY(idx >= size()))
25✔
2657
            {
2658
                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
3✔
2659
            }
2660

2661
            m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
22✔
2662
        }
2663
        else
2664
        {
2665
            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
7✔
2666
        }
2667
    }
22✔
2668

2669
    /// @}
2670

2671
    ////////////
2672
    // lookup //
2673
    ////////////
2674

2675
    /// @name lookup
2676
    /// @{
2677

2678
    /// @brief find an element in a JSON object
2679
    /// @sa https://json.nlohmann.me/api/basic_json/find/
2680
    iterator find(const typename object_t::key_type& key)
127✔
2681
    {
2682
        auto result = end();
127✔
2683

2684
        if (is_object())
127✔
2685
        {
2686
            result.m_it.object_iterator = m_data.m_value.object->find(key);
113✔
2687
        }
2688

2689
        return result;
127✔
2690
    }
2691

2692
    /// @brief find an element in a JSON object
2693
    /// @sa https://json.nlohmann.me/api/basic_json/find/
2694
    const_iterator find(const typename object_t::key_type& key) const
936✔
2695
    {
2696
        auto result = cend();
936✔
2697

2698
        if (is_object())
936✔
2699
        {
2700
            result.m_it.object_iterator = m_data.m_value.object->find(key);
922✔
2701
        }
2702

2703
        return result;
936✔
2704
    }
2705

2706
    /// @brief find an element in a JSON object
2707
    /// @sa https://json.nlohmann.me/api/basic_json/find/
2708
    template<class KeyType, detail::enable_if_t<
2709
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
2710
    iterator find(KeyType && key)
270✔
2711
    {
2712
        auto result = end();
270✔
2713

2714
        if (is_object())
270✔
2715
        {
2716
            result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
228✔
2717
        }
2718

2719
        return result;
270✔
2720
    }
2721

2722
    /// @brief find an element in a JSON object
2723
    /// @sa https://json.nlohmann.me/api/basic_json/find/
2724
    template<class KeyType, detail::enable_if_t<
2725
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
2726
    const_iterator find(KeyType && key) const
818✔
2727
    {
2728
        auto result = cend();
818✔
2729

2730
        if (is_object())
818✔
2731
        {
2732
            result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
776✔
2733
        }
2734

2735
        return result;
818✔
2736
    }
2737

2738
    /// @brief returns the number of occurrences of a key in a JSON object
2739
    /// @sa https://json.nlohmann.me/api/basic_json/count/
2740
    size_type count(const typename object_t::key_type& key) const
168✔
2741
    {
2742
        // return 0 for all nonobject types
2743
        return is_object() ? m_data.m_value.object->count(key) : 0;
168✔
2744
    }
2745

2746
    /// @brief returns the number of occurrences of a key in a JSON object
2747
    /// @sa https://json.nlohmann.me/api/basic_json/count/
2748
    template<class KeyType, detail::enable_if_t<
2749
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
2750
    size_type count(KeyType && key) const
204✔
2751
    {
2752
        // return 0 for all nonobject types
2753
        return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
204✔
2754
    }
2755

2756
    /// @brief check the existence of an element in a JSON object
2757
    /// @sa https://json.nlohmann.me/api/basic_json/contains/
2758
    bool contains(const typename object_t::key_type& key) const
158✔
2759
    {
2760
        return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
158✔
2761
    }
2762

2763
    /// @brief check the existence of an element in a JSON object
2764
    /// @sa https://json.nlohmann.me/api/basic_json/contains/
2765
    template<class KeyType, detail::enable_if_t<
2766
                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
2767
    bool contains(KeyType && key) const
204✔
2768
    {
2769
        return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
204✔
2770
    }
2771

2772
    /// @brief check the existence of an element in a JSON object given a JSON pointer
2773
    /// @sa https://json.nlohmann.me/api/basic_json/contains/
2774
    bool contains(const json_pointer& ptr) const
96✔
2775
    {
2776
        return ptr.contains(this);
96✔
2777
    }
2778

2779
    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
2780
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
2781
    bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
4✔
2782
    {
2783
        return ptr.contains(this);
4✔
2784
    }
2785

2786
    /// @}
2787

2788
    ///////////////
2789
    // iterators //
2790
    ///////////////
2791

2792
    /// @name iterators
2793
    /// @{
2794

2795
    /// @brief returns an iterator to the first element
2796
    /// @sa https://json.nlohmann.me/api/basic_json/begin/
2797
    iterator begin() noexcept
198,351✔
2798
    {
2799
        iterator result(this);
198,351✔
2800
        result.set_begin();
198,351✔
2801
        return result;
198,351✔
2802
    }
2803

2804
    /// @brief returns an iterator to the first element
2805
    /// @sa https://json.nlohmann.me/api/basic_json/begin/
2806
    const_iterator begin() const noexcept
577,319✔
2807
    {
2808
        return cbegin();
577,319✔
2809
    }
2810

2811
    /// @brief returns a const iterator to the first element
2812
    /// @sa https://json.nlohmann.me/api/basic_json/cbegin/
2813
    const_iterator cbegin() const noexcept
1,154,683✔
2814
    {
2815
        const_iterator result(this);
1,154,683✔
2816
        result.set_begin();
1,154,683✔
2817
        return result;
1,154,683✔
2818
    }
2819

2820
    /// @brief returns an iterator to one past the last element
2821
    /// @sa https://json.nlohmann.me/api/basic_json/end/
2822
    iterator end() noexcept
2,148✔
2823
    {
2824
        iterator result(this);
2,148✔
2825
        result.set_end();
2,148✔
2826
        return result;
2,148✔
2827
    }
2828

2829
    /// @brief returns an iterator to one past the last element
2830
    /// @sa https://json.nlohmann.me/api/basic_json/end/
2831
    const_iterator end() const noexcept
579,029✔
2832
    {
2833
        return cend();
579,029✔
2834
    }
2835

2836
    /// @brief returns an iterator to one past the last element
2837
    /// @sa https://json.nlohmann.me/api/basic_json/cend/
2838
    const_iterator cend() const noexcept
581,713✔
2839
    {
2840
        const_iterator result(this);
581,713✔
2841
        result.set_end();
581,713✔
2842
        return result;
581,713✔
2843
    }
2844

2845
    /// @brief returns an iterator to the reverse-beginning
2846
    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
2847
    reverse_iterator rbegin() noexcept
582✔
2848
    {
2849
        return reverse_iterator(end());
582✔
2850
    }
2851

2852
    /// @brief returns an iterator to the reverse-beginning
2853
    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
2854
    const_reverse_iterator rbegin() const noexcept
26✔
2855
    {
2856
        return crbegin();
26✔
2857
    }
2858

2859
    /// @brief returns an iterator to the reverse-end
2860
    /// @sa https://json.nlohmann.me/api/basic_json/rend/
2861
    reverse_iterator rend() noexcept
62✔
2862
    {
2863
        return reverse_iterator(begin());
62✔
2864
    }
2865

2866
    /// @brief returns an iterator to the reverse-end
2867
    /// @sa https://json.nlohmann.me/api/basic_json/rend/
2868
    const_reverse_iterator rend() const noexcept
26✔
2869
    {
2870
        return crend();
26✔
2871
    }
2872

2873
    /// @brief returns a const reverse iterator to the last element
2874
    /// @sa https://json.nlohmann.me/api/basic_json/crbegin/
2875
    const_reverse_iterator crbegin() const noexcept
622✔
2876
    {
2877
        return const_reverse_iterator(cend());
622✔
2878
    }
2879

2880
    /// @brief returns a const reverse iterator to one before the first
2881
    /// @sa https://json.nlohmann.me/api/basic_json/crend/
2882
    const_reverse_iterator crend() const noexcept
104✔
2883
    {
2884
        return const_reverse_iterator(cbegin());
104✔
2885
    }
2886

2887
  public:
2888
    /// @brief wrapper to access iterator member functions in range-based for
2889
    /// @sa https://json.nlohmann.me/api/basic_json/items/
2890
    /// @deprecated This function is deprecated since 3.1.0 and will be removed in
2891
    ///             version 4.0.0 of the library. Please use @ref items() instead;
2892
    ///             that is, replace `json::iterator_wrapper(j)` with `j.items()`.
2893
    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
2894
    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
24✔
2895
    {
2896
        return ref.items();
24✔
2897
    }
2898

2899
    /// @brief wrapper to access iterator member functions in range-based for
2900
    /// @sa https://json.nlohmann.me/api/basic_json/items/
2901
    /// @deprecated This function is deprecated since 3.1.0 and will be removed in
2902
    ///         version 4.0.0 of the library. Please use @ref items() instead;
2903
    ///         that is, replace `json::iterator_wrapper(j)` with `j.items()`.
2904
    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
2905
    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
24✔
2906
    {
2907
        return ref.items();
24✔
2908
    }
2909

2910
    /// @brief helper to access iterator member functions in range-based for
2911
    /// @sa https://json.nlohmann.me/api/basic_json/items/
2912
    iteration_proxy<iterator> items() noexcept
58✔
2913
    {
2914
        return iteration_proxy<iterator>(*this);
58✔
2915
    }
2916

2917
    /// @brief helper to access iterator member functions in range-based for
2918
    /// @sa https://json.nlohmann.me/api/basic_json/items/
2919
    iteration_proxy<const_iterator> items() const noexcept
54✔
2920
    {
2921
        return iteration_proxy<const_iterator>(*this);
54✔
2922
    }
2923

2924
    /// @}
2925

2926
    //////////////
2927
    // capacity //
2928
    //////////////
2929

2930
    /// @name capacity
2931
    /// @{
2932

2933
    /// @brief checks whether the container is empty.
2934
    /// @sa https://json.nlohmann.me/api/basic_json/empty/
2935
    bool empty() const noexcept
81✔
2936
    {
2937
        switch (m_data.m_type)
81✔
2938
        {
2939
            case value_t::null:
6✔
2940
            {
2941
                // null values are empty
2942
                return true;
6✔
2943
            }
2944

2945
            case value_t::array:
27✔
2946
            {
2947
                // delegate call to array_t::empty()
2948
                return m_data.m_value.array->empty();
27✔
2949
            }
2950

2951
            case value_t::object:
12✔
2952
            {
2953
                // delegate call to object_t::empty()
2954
                return m_data.m_value.object->empty();
12✔
2955
            }
2956

2957
            case value_t::string:
36✔
2958
            case value_t::boolean:
2959
            case value_t::number_integer:
2960
            case value_t::number_unsigned:
2961
            case value_t::number_float:
2962
            case value_t::binary:
2963
            case value_t::discarded:
2964
            default:
2965
            {
2966
                // all other types are nonempty
2967
                return false;
36✔
2968
            }
2969
        }
2970
    }
2971

2972
    /// @brief returns the number of elements
2973
    /// @sa https://json.nlohmann.me/api/basic_json/size/
2974
    size_type size() const noexcept
24,320✔
2975
    {
2976
        switch (m_data.m_type)
24,320✔
2977
        {
2978
            case value_t::null:
9✔
2979
            {
2980
                // null values are empty
2981
                return 0;
9✔
2982
            }
2983

2984
            case value_t::array:
24,199✔
2985
            {
2986
                // delegate call to array_t::size()
2987
                return m_data.m_value.array->size();
24,199✔
2988
            }
2989

2990
            case value_t::object:
54✔
2991
            {
2992
                // delegate call to object_t::size()
2993
                return m_data.m_value.object->size();
54✔
2994
            }
2995

2996
            case value_t::string:
58✔
2997
            case value_t::boolean:
2998
            case value_t::number_integer:
2999
            case value_t::number_unsigned:
3000
            case value_t::number_float:
3001
            case value_t::binary:
3002
            case value_t::discarded:
3003
            default:
3004
            {
3005
                // all other types have size 1
3006
                return 1;
58✔
3007
            }
3008
        }
3009
    }
3010

3011
    /// @brief returns the maximum possible number of elements
3012
    /// @sa https://json.nlohmann.me/api/basic_json/max_size/
3013
    size_type max_size() const noexcept
29,123✔
3014
    {
3015
        switch (m_data.m_type)
29,123✔
3016
        {
3017
            case value_t::array:
16,384✔
3018
            {
3019
                // delegate call to array_t::max_size()
3020
                return m_data.m_value.array->max_size();
16,384✔
3021
            }
3022

3023
            case value_t::object:
12,727✔
3024
            {
3025
                // delegate call to object_t::max_size()
3026
                return m_data.m_value.object->max_size();
12,727✔
3027
            }
3028

3029
            case value_t::null:
12✔
3030
            case value_t::string:
3031
            case value_t::boolean:
3032
            case value_t::number_integer:
3033
            case value_t::number_unsigned:
3034
            case value_t::number_float:
3035
            case value_t::binary:
3036
            case value_t::discarded:
3037
            default:
3038
            {
3039
                // all other types have max_size() == size()
3040
                return size();
12✔
3041
            }
3042
        }
3043
    }
3044

3045
    /// @}
3046

3047
    ///////////////
3048
    // modifiers //
3049
    ///////////////
3050

3051
    /// @name modifiers
3052
    /// @{
3053

3054
    /// @brief clears the contents
3055
    /// @sa https://json.nlohmann.me/api/basic_json/clear/
3056
    void clear() noexcept
13✔
3057
    {
3058
        switch (m_data.m_type)
13✔
3059
        {
3060
            case value_t::number_integer:
1✔
3061
            {
3062
                m_data.m_value.number_integer = 0;
1✔
3063
                break;
1✔
3064
            }
3065

3066
            case value_t::number_unsigned:
1✔
3067
            {
3068
                m_data.m_value.number_unsigned = 0;
1✔
3069
                break;
1✔
3070
            }
3071

3072
            case value_t::number_float:
1✔
3073
            {
3074
                m_data.m_value.number_float = 0.0;
1✔
3075
                break;
1✔
3076
            }
3077

3078
            case value_t::boolean:
1✔
3079
            {
3080
                m_data.m_value.boolean = false;
1✔
3081
                break;
1✔
3082
            }
3083

3084
            case value_t::string:
1✔
3085
            {
3086
                m_data.m_value.string->clear();
1✔
3087
                break;
1✔
3088
            }
3089

3090
            case value_t::binary:
2✔
3091
            {
3092
                m_data.m_value.binary->clear();
2✔
3093
                break;
2✔
3094
            }
3095

3096
            case value_t::array:
3✔
3097
            {
3098
                m_data.m_value.array->clear();
3✔
3099
                break;
3✔
3100
            }
3101

3102
            case value_t::object:
2✔
3103
            {
3104
                m_data.m_value.object->clear();
2✔
3105
                break;
2✔
3106
            }
3107

3108
            case value_t::null:
1✔
3109
            case value_t::discarded:
3110
            default:
3111
                break;
1✔
3112
        }
3113
    }
13✔
3114

3115
    /// @brief add an object to an array
3116
    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
3117
    void push_back(basic_json&& val)
77✔
3118
    {
3119
        // push_back only works for null objects or arrays
3120
        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
77✔
3121
        {
3122
            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
6✔
3123
        }
3124

3125
        // transform a null object into an array
3126
        if (is_null())
71✔
3127
        {
3128
            m_data.m_type = value_t::array;
10✔
3129
            m_data.m_value = value_t::array;
10✔
3130
            assert_invariant();
10✔
3131
        }
3132

3133
        // add the element to the array (move semantics)
3134
        const auto old_capacity = m_data.m_value.array->capacity();
71✔
3135
        m_data.m_value.array->push_back(std::move(val));
71✔
3136
        set_parent(m_data.m_value.array->back(), old_capacity);
71✔
3137
        // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
3138
    }
71✔
3139

3140
    /// @brief add an object to an array
3141
    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
3142
    reference operator+=(basic_json&& val)
4✔
3143
    {
3144
        push_back(std::move(val));
4✔
3145
        return *this;
3✔
3146
    }
3147

3148
    /// @brief add an object to an array
3149
    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
3150
    void push_back(const basic_json& val)
73✔
3151
    {
3152
        // push_back only works for null objects or arrays
3153
        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
73✔
3154
        {
3155
            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
2✔
3156
        }
3157

3158
        // transform a null object into an array
3159
        if (is_null())
71✔
3160
        {
3161
            m_data.m_type = value_t::array;
11✔
3162
            m_data.m_value = value_t::array;
11✔
3163
            assert_invariant();
11✔
3164
        }
3165

3166
        // add the element to the array
3167
        const auto old_capacity = m_data.m_value.array->capacity();
71✔
3168
        m_data.m_value.array->push_back(val);
71✔
3169
        set_parent(m_data.m_value.array->back(), old_capacity);
71✔
3170
    }
71✔
3171

3172
    /// @brief add an object to an array
3173
    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
3174
    reference operator+=(const basic_json& val)
4✔
3175
    {
3176
        push_back(val);
4✔
3177
        return *this;
3✔
3178
    }
3179

3180
    /// @brief add an object to an object
3181
    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
3182
    void push_back(const typename object_t::value_type& val)
16✔
3183
    {
3184
        // push_back only works for null objects or objects
3185
        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
16✔
3186
        {
3187
            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
2✔
3188
        }
3189

3190
        // transform a null object into an object
3191
        if (is_null())
14✔
3192
        {
3193
            m_data.m_type = value_t::object;
2✔
3194
            m_data.m_value = value_t::object;
2✔
3195
            assert_invariant();
2✔
3196
        }
3197

3198
        // add the element to the object
3199
        auto res = m_data.m_value.object->insert(val);
14✔
3200
        set_parent(res.first->second);
14✔
3201
    }
14✔
3202

3203
    /// @brief add an object to an object
3204
    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
3205
    reference operator+=(const typename object_t::value_type& val)
5✔
3206
    {
3207
        push_back(val);
5✔
3208
        return *this;
4✔
3209
    }
3210

3211
    /// @brief add an object to an object
3212
    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
3213
    void push_back(initializer_list_t init)
46✔
3214
    {
3215
        if (is_object() && init.size() == 2 && (*init.begin())->is_string())
46✔
3216
        {
3217
            basic_json&& key = init.begin()->moved_or_copied();
6✔
3218
            push_back(typename object_t::value_type(
12✔
3219
                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
12✔
3220
        }
6✔
3221
        else
3222
        {
3223
            push_back(basic_json(init));
40✔
3224
        }
3225
    }
42✔
3226

3227
    /// @brief add an object to an object
3228
    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
3229
    reference operator+=(initializer_list_t init)
8✔
3230
    {
3231
        push_back(init);
8✔
3232
        return *this;
7✔
3233
    }
3234

3235
    /// @brief add an object to an array
3236
    /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/
3237
    template<class... Args>
3238
    reference emplace_back(Args&& ... args)
9✔
3239
    {
3240
        // emplace_back only works for null objects or arrays
3241
        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
9✔
3242
        {
3243
            JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
1✔
3244
        }
3245

3246
        // transform a null object into an array
3247
        if (is_null())
8✔
3248
        {
3249
            m_data.m_type = value_t::array;
2✔
3250
            m_data.m_value = value_t::array;
2✔
3251
            assert_invariant();
2✔
3252
        }
3253

3254
        // add the element to the array (perfect forwarding)
3255
        const auto old_capacity = m_data.m_value.array->capacity();
8✔
3256
        m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
8✔
3257
        return set_parent(m_data.m_value.array->back(), old_capacity);
8✔
3258
    }
3259

3260
    /// @brief add an object to an object if key does not exist
3261
    /// @sa https://json.nlohmann.me/api/basic_json/emplace/
3262
    template<class... Args>
3263
    std::pair<iterator, bool> emplace(Args&& ... args)
197,125✔
3264
    {
3265
        // emplace only works for null objects or arrays
3266
        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
197,125✔
3267
        {
3268
            JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
1✔
3269
        }
3270

3271
        // transform a null object into an object
3272
        if (is_null())
197,124✔
3273
        {
3274
            m_data.m_type = value_t::object;
6✔
3275
            m_data.m_value = value_t::object;
6✔
3276
            assert_invariant();
6✔
3277
        }
3278

3279
        // add the element to the array (perfect forwarding)
3280
        auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);
197,124✔
3281
        set_parent(res.first->second);
197,124✔
3282

3283
        // create a result iterator and set iterator to the result of emplace
3284
        auto it = begin();
197,124✔
3285
        it.m_it.object_iterator = res.first;
197,124✔
3286

3287
        // return pair of iterator and boolean
3288
        return {it, res.second};
394,248✔
3289
    }
3290

3291
    /// Helper for insertion of an iterator
3292
    /// @note: This uses std::distance to support GCC 4.8,
3293
    ///        see https://github.com/nlohmann/json/pull/1257
3294
    template<typename... Args>
3295
    iterator insert_iterator(const_iterator pos, Args&& ... args) // NOLINT(performance-unnecessary-value-param)
102✔
3296
    {
3297
        iterator result(this);
102✔
3298
        JSON_ASSERT(m_data.m_value.array != nullptr);
102✔
3299

3300
        auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator);
102✔
3301
        m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
102✔
3302
        result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos;
102✔
3303

3304
        // This could have been written as:
3305
        // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val);
3306
        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
3307

3308
        set_parents();
102✔
3309
        return result;
102✔
3310
    }
3311

3312
    /// @brief inserts element into array
3313
    /// @sa https://json.nlohmann.me/api/basic_json/insert/
3314
    iterator insert(const_iterator pos, const basic_json& val) // NOLINT(performance-unnecessary-value-param)
36✔
3315
    {
3316
        // insert only works for arrays
3317
        if (JSON_HEDLEY_LIKELY(is_array()))
36✔
3318
        {
3319
            // check if iterator pos fits to this JSON value
3320
            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
34✔
3321
            {
3322
                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
6✔
3323
            }
3324

3325
            // insert to array and return iterator
3326
            return insert_iterator(pos, val);
32✔
3327
        }
3328

3329
        JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
2✔
3330
    }
3331

3332
    /// @brief inserts element into array
3333
    /// @sa https://json.nlohmann.me/api/basic_json/insert/
3334
    iterator insert(const_iterator pos, basic_json&& val) // NOLINT(performance-unnecessary-value-param)
18✔
3335
    {
3336
        return insert(pos, val);
18✔
3337
    }
3338

3339
    /// @brief inserts copies of element into array
3340
    /// @sa https://json.nlohmann.me/api/basic_json/insert/
3341
    iterator insert(const_iterator pos, size_type cnt, const basic_json& val) // NOLINT(performance-unnecessary-value-param)
7✔
3342
    {
3343
        // insert only works for arrays
3344
        if (JSON_HEDLEY_LIKELY(is_array()))
7✔
3345
        {
3346
            // check if iterator pos fits to this JSON value
3347
            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
6✔
3348
            {
3349
                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
3✔
3350
            }
3351

3352
            // insert to array and return iterator
3353
            return insert_iterator(pos, cnt, val);
5✔
3354
        }
3355

3356
        JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
1✔
3357
    }
3358

3359
    /// @brief inserts range of elements into array
3360
    /// @sa https://json.nlohmann.me/api/basic_json/insert/
3361
    iterator insert(const_iterator pos, const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param)
66✔
3362
    {
3363
        // insert only works for arrays
3364
        if (JSON_HEDLEY_UNLIKELY(!is_array()))
66✔
3365
        {
3366
            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
1✔
3367
        }
3368

3369
        // check if iterator pos fits to this JSON value
3370
        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
65✔
3371
        {
3372
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
3✔
3373
        }
3374

3375
        // check if range iterators belong to the same JSON object
3376
        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
64✔
3377
        {
3378
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
3✔
3379
        }
3380

3381
        if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
63✔
3382
        {
3383
            JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
3✔
3384
        }
3385

3386
        // insert to array and return iterator
3387
        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
62✔
3388
    }
3389

3390
    /// @brief inserts elements from initializer list into array
3391
    /// @sa https://json.nlohmann.me/api/basic_json/insert/
3392
    iterator insert(const_iterator pos, initializer_list_t ilist) // NOLINT(performance-unnecessary-value-param)
5✔
3393
    {
3394
        // insert only works for arrays
3395
        if (JSON_HEDLEY_UNLIKELY(!is_array()))
5✔
3396
        {
3397
            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
1✔
3398
        }
3399

3400
        // check if iterator pos fits to this JSON value
3401
        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
4✔
3402
        {
3403
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
3✔
3404
        }
3405

3406
        // insert to array and return iterator
3407
        return insert_iterator(pos, ilist.begin(), ilist.end());
3✔
3408
    }
3409

3410
    /// @brief inserts range of elements into object
3411
    /// @sa https://json.nlohmann.me/api/basic_json/insert/
3412
    void insert(const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param)
8✔
3413
    {
3414
        // insert only works for objects
3415
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
8✔
3416
        {
3417
            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
1✔
3418
        }
3419

3420
        // check if range iterators belong to the same JSON object
3421
        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
7✔
3422
        {
3423
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
3✔
3424
        }
3425

3426
        // passed iterators must belong to objects
3427
        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
6✔
3428
        {
3429
            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
3✔
3430
        }
3431

3432
        m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
5✔
3433
        set_parents();
5✔
3434
    }
5✔
3435

3436
    /// @brief updates a JSON object from another object, overwriting existing keys
3437
    /// @sa https://json.nlohmann.me/api/basic_json/update/
3438
    void update(const_reference j, bool merge_objects = false)
13✔
3439
    {
3440
        update(j.begin(), j.end(), merge_objects);
13✔
3441
    }
10✔
3442

3443
    /// @brief updates a JSON object from another object, overwriting existing keys
3444
    /// @sa https://json.nlohmann.me/api/basic_json/update/
3445
    void update(const_iterator first, const_iterator last, bool merge_objects = false) // NOLINT(performance-unnecessary-value-param)
21✔
3446
    {
3447
        // implicitly convert a null value to an empty object
3448
        if (is_null())
21✔
3449
        {
3450
            m_data.m_type = value_t::object;
2✔
3451
            m_data.m_value.object = create<object_t>();
2✔
3452
            assert_invariant();
2✔
3453
        }
3454

3455
        if (JSON_HEDLEY_UNLIKELY(!is_object()))
21✔
3456
        {
3457
            JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
2✔
3458
        }
3459

3460
        // check if range iterators belong to the same JSON object
3461
        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
19✔
3462
        {
3463
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
3✔
3464
        }
3465

3466
        // passed iterators must belong to objects
3467
        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
18✔
3468
        {
3469
            JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
4✔
3470
        }
3471

3472
        for (auto it = first; it != last; ++it)
33✔
3473
        {
3474
            if (merge_objects && it.value().is_object())
19✔
3475
            {
3476
                auto it2 = m_data.m_value.object->find(it.key());
1✔
3477
                if (it2 != m_data.m_value.object->end())
1!
3478
                {
3479
                    it2->second.update(it.value(), true);
1✔
3480
                    continue;
1✔
3481
                }
3482
            }
3483
            m_data.m_value.object->operator[](it.key()) = it.value();
18✔
3484
#if JSON_DIAGNOSTICS
3485
            m_data.m_value.object->operator[](it.key()).m_parent = this;
3✔
3486
#endif
3487
        }
3488
    }
14✔
3489

3490
    /// @brief exchanges the values
3491
    /// @sa https://json.nlohmann.me/api/basic_json/swap/
3492
    void swap(reference other) noexcept (
16✔
3493
        std::is_nothrow_move_constructible<value_t>::value&&
3494
        std::is_nothrow_move_assignable<value_t>::value&&
3495
        std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3496
        std::is_nothrow_move_assignable<json_value>::value
3497
    )
3498
    {
3499
        std::swap(m_data.m_type, other.m_data.m_type);
16✔
3500
        std::swap(m_data.m_value, other.m_data.m_value);
16✔
3501

3502
        set_parents();
16✔
3503
        other.set_parents();
16✔
3504
        assert_invariant();
16✔
3505
    }
16✔
3506

3507
    /// @brief exchanges the values
3508
    /// @sa https://json.nlohmann.me/api/basic_json/swap/
3509
    friend void swap(reference left, reference right) noexcept (
15✔
3510
        std::is_nothrow_move_constructible<value_t>::value&&
3511
        std::is_nothrow_move_assignable<value_t>::value&&
3512
        std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3513
        std::is_nothrow_move_assignable<json_value>::value
3514
    )
3515
    {
3516
        left.swap(right);
15✔
3517
    }
15✔
3518

3519
    /// @brief exchanges the values
3520
    /// @sa https://json.nlohmann.me/api/basic_json/swap/
3521
    void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3✔
3522
    {
3523
        // swap only works for arrays
3524
        if (JSON_HEDLEY_LIKELY(is_array()))
3✔
3525
        {
3526
            using std::swap;
3527
            swap(*(m_data.m_value.array), other);
2✔
3528
        }
3529
        else
3530
        {
3531
            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
1✔
3532
        }
3533
    }
2✔
3534

3535
    /// @brief exchanges the values
3536
    /// @sa https://json.nlohmann.me/api/basic_json/swap/
3537
    void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3✔
3538
    {
3539
        // swap only works for objects
3540
        if (JSON_HEDLEY_LIKELY(is_object()))
3✔
3541
        {
3542
            using std::swap;
3543
            swap(*(m_data.m_value.object), other);
2✔
3544
        }
3545
        else
3546
        {
3547
            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
1✔
3548
        }
3549
    }
2✔
3550

3551
    /// @brief exchanges the values
3552
    /// @sa https://json.nlohmann.me/api/basic_json/swap/
3553
    void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3✔
3554
    {
3555
        // swap only works for strings
3556
        if (JSON_HEDLEY_LIKELY(is_string()))
3✔
3557
        {
3558
            using std::swap;
3559
            swap(*(m_data.m_value.string), other);
2✔
3560
        }
3561
        else
3562
        {
3563
            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
1✔
3564
        }
3565
    }
2✔
3566

3567
    /// @brief exchanges the values
3568
    /// @sa https://json.nlohmann.me/api/basic_json/swap/
3569
    void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
3✔
3570
    {
3571
        // swap only works for strings
3572
        if (JSON_HEDLEY_LIKELY(is_binary()))
3✔
3573
        {
3574
            using std::swap;
3575
            swap(*(m_data.m_value.binary), other);
2✔
3576
        }
3577
        else
3578
        {
3579
            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
1✔
3580
        }
3581
    }
2✔
3582

3583
    /// @brief exchanges the values
3584
    /// @sa https://json.nlohmann.me/api/basic_json/swap/
3585
    void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)
3✔
3586
    {
3587
        // swap only works for strings
3588
        if (JSON_HEDLEY_LIKELY(is_binary()))
3✔
3589
        {
3590
            using std::swap;
3591
            swap(*(m_data.m_value.binary), other);
2✔
3592
        }
3593
        else
3594
        {
3595
            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
1✔
3596
        }
3597
    }
2✔
3598

3599
    /// @}
3600

3601
    //////////////////////////////////////////
3602
    // lexicographical comparison operators //
3603
    //////////////////////////////////////////
3604

3605
    /// @name lexicographical comparison operators
3606
    /// @{
3607

3608
    // note parentheses around operands are necessary; see
3609
    // https://github.com/nlohmann/json/issues/1530
3610
#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result)                       \
3611
    const auto lhs_type = lhs.type();                                                                    \
3612
    const auto rhs_type = rhs.type();                                                                    \
3613
    \
3614
    if (lhs_type == rhs_type) /* NOLINT(readability/braces) */                                           \
3615
    {                                                                                                    \
3616
        switch (lhs_type)                                                                                \
3617
        {                                                                                                \
3618
            case value_t::array:                                                                         \
3619
                return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array);                                     \
3620
                \
3621
            case value_t::object:                                                                        \
3622
                return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object);                                   \
3623
                \
3624
            case value_t::null:                                                                          \
3625
                return (null_result);                                                                    \
3626
                \
3627
            case value_t::string:                                                                        \
3628
                return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string);                                   \
3629
                \
3630
            case value_t::boolean:                                                                       \
3631
                return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean);                                   \
3632
                \
3633
            case value_t::number_integer:                                                                \
3634
                return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer);                     \
3635
                \
3636
            case value_t::number_unsigned:                                                               \
3637
                return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned);                   \
3638
                \
3639
            case value_t::number_float:                                                                  \
3640
                return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float);                         \
3641
                \
3642
            case value_t::binary:                                                                        \
3643
                return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary);                                   \
3644
                \
3645
            case value_t::discarded:                                                                     \
3646
            default:                                                                                     \
3647
                return (unordered_result);                                                               \
3648
        }                                                                                                \
3649
    }                                                                                                    \
3650
    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)                   \
3651
    {                                                                                                    \
3652
        return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float;      \
3653
    }                                                                                                    \
3654
    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)                   \
3655
    {                                                                                                    \
3656
        return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer);      \
3657
    }                                                                                                    \
3658
    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)                  \
3659
    {                                                                                                    \
3660
        return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float;     \
3661
    }                                                                                                    \
3662
    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)                  \
3663
    {                                                                                                    \
3664
        return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned);     \
3665
    }                                                                                                    \
3666
    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)                \
3667
    {                                                                                                    \
3668
        return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
3669
    }                                                                                                    \
3670
    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)                \
3671
    {                                                                                                    \
3672
        return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
3673
    }                                                                                                    \
3674
    else if(compares_unordered(lhs, rhs))\
3675
    {\
3676
        return (unordered_result);\
3677
    }\
3678
    \
3679
    return (default_result);
3680

3681
  JSON_PRIVATE_UNLESS_TESTED:
3682
    // returns true if:
3683
    // - any operand is NaN and the other operand is of number type
3684
    // - any operand is discarded
3685
    // in legacy mode, discarded values are considered ordered if
3686
    // an operation is computed as an odd number of inverses of others
3687
    static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
38,372✔
3688
    {
3689
        if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number())
44,570✔
3690
                || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number()))
44,570✔
3691
        {
3692
            return true;
952✔
3693
        }
3694
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
3695
        return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
19,889✔
3696
#else
3697
        static_cast<void>(inverse);
3698
        return lhs.is_discarded() || rhs.is_discarded();
17,531✔
3699
#endif
3700
    }
3701

3702
  private:
3703
    bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
2,456✔
3704
    {
3705
        return compares_unordered(*this, rhs, inverse);
2,456✔
3706
    }
3707

3708
  public:
3709
#if JSON_HAS_THREE_WAY_COMPARISON
3710
    /// @brief comparison: equal
3711
    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3712
    bool operator==(const_reference rhs) const noexcept
3,348✔
3713
    {
3714
#ifdef __GNUC__
3715
#pragma GCC diagnostic push
3716
#pragma GCC diagnostic ignored "-Wfloat-equal"
3717
#endif
3718
        const_reference lhs = *this;
3,348✔
3719
        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
3,348✔
3720
#ifdef __GNUC__
3721
#pragma GCC diagnostic pop
3722
#endif
3723
    }
3724

3725
    /// @brief comparison: equal
3726
    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3727
    template<typename ScalarType>
3728
    requires std::is_scalar_v<ScalarType>
3729
    bool operator==(ScalarType rhs) const noexcept
23✔
3730
    {
3731
        return *this == basic_json(rhs);
23✔
3732
    }
3733

3734
    /// @brief comparison: not equal
3735
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
3736
    bool operator!=(const_reference rhs) const noexcept
1,116✔
3737
    {
3738
        if (compares_unordered(rhs, true))
1,116✔
3739
        {
3740
            return false;
140✔
3741
        }
3742
        return !operator==(rhs);
976✔
3743
    }
3744

3745
    /// @brief comparison: 3-way
3746
    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
3747
    std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
8,932✔
3748
    {
3749
        const_reference lhs = *this;
8,932✔
3750
        // default_result is used if we cannot compare values. In that case,
3751
        // we compare types.
3752
        JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
8,932✔
3753
                                std::partial_ordering::equivalent,
3754
                                std::partial_ordering::unordered,
3755
                                lhs_type <=> rhs_type) // *NOPAD*
3756
    }
3757

3758
    /// @brief comparison: 3-way
3759
    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
3760
    template<typename ScalarType>
3761
    requires std::is_scalar_v<ScalarType>
3762
    std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
3763
    {
3764
        return *this <=> basic_json(rhs); // *NOPAD*
3765
    }
3766

3767
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
3768
    // all operators that are computed as an odd number of inverses of others
3769
    // need to be overloaded to emulate the legacy comparison behavior
3770

3771
    /// @brief comparison: less than or equal
3772
    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3773
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
3774
    bool operator<=(const_reference rhs) const noexcept
856✔
3775
    {
3776
        if (compares_unordered(rhs, true))
856✔
3777
        {
3778
            return false;
28✔
3779
        }
3780
        return !(rhs < *this);
828✔
3781
    }
3782

3783
    /// @brief comparison: less than or equal
3784
    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3785
    template<typename ScalarType>
3786
    requires std::is_scalar_v<ScalarType>
3787
    bool operator<=(ScalarType rhs) const noexcept
3788
    {
3789
        return *this <= basic_json(rhs);
3790
    }
3791

3792
    /// @brief comparison: greater than or equal
3793
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3794
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
3795
    bool operator>=(const_reference rhs) const noexcept
484✔
3796
    {
3797
        if (compares_unordered(rhs, true))
484✔
3798
        {
3799
            return false;
28✔
3800
        }
3801
        return !(*this < rhs);
456✔
3802
    }
3803

3804
    /// @brief comparison: greater than or equal
3805
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3806
    template<typename ScalarType>
3807
    requires std::is_scalar_v<ScalarType>
3808
    bool operator>=(ScalarType rhs) const noexcept
3809
    {
3810
        return *this >= basic_json(rhs);
3811
    }
3812
#endif
3813
#else
3814
    /// @brief comparison: equal
3815
    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3816
    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
52,160,762✔
3817
    {
3818
#ifdef __GNUC__
3819
#pragma GCC diagnostic push
3820
#pragma GCC diagnostic ignored "-Wfloat-equal"
3821
#endif
3822
        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
52,160,762✔
3823
#ifdef __GNUC__
3824
#pragma GCC diagnostic pop
3825
#endif
3826
    }
3827

3828
    /// @brief comparison: equal
3829
    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3830
    template<typename ScalarType, typename std::enable_if<
3831
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3832
    friend bool operator==(const_reference lhs, ScalarType rhs) noexcept
262✔
3833
    {
3834
        return lhs == basic_json(rhs);
262✔
3835
    }
3836

3837
    /// @brief comparison: equal
3838
    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
3839
    template<typename ScalarType, typename std::enable_if<
3840
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3841
    friend bool operator==(ScalarType lhs, const_reference rhs) noexcept
58✔
3842
    {
3843
        return basic_json(lhs) == rhs;
58✔
3844
    }
3845

3846
    /// @brief comparison: not equal
3847
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
3848
    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
1,234✔
3849
    {
3850
        if (compares_unordered(lhs, rhs, true))
1,234✔
3851
        {
3852
            return false;
140✔
3853
        }
3854
        return !(lhs == rhs);
1,094✔
3855
    }
3856

3857
    /// @brief comparison: not equal
3858
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
3859
    template<typename ScalarType, typename std::enable_if<
3860
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3861
    friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept
22✔
3862
    {
3863
        return lhs != basic_json(rhs);
22✔
3864
    }
3865

3866
    /// @brief comparison: not equal
3867
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
3868
    template<typename ScalarType, typename std::enable_if<
3869
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3870
    friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept
22✔
3871
    {
3872
        return basic_json(lhs) != rhs;
22✔
3873
    }
3874

3875
    /// @brief comparison: less than
3876
    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
3877
    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
7,916✔
3878
    {
3879
        // default_result is used if we cannot compare values. In that case,
3880
        // we compare types. Note we have to call the operator explicitly,
3881
        // because MSVC has problems otherwise.
3882
        JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
7,916✔
3883
    }
3884

3885
    /// @brief comparison: less than
3886
    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
3887
    template<typename ScalarType, typename std::enable_if<
3888
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3889
    friend bool operator<(const_reference lhs, ScalarType rhs) noexcept
4✔
3890
    {
3891
        return lhs < basic_json(rhs);
4✔
3892
    }
3893

3894
    /// @brief comparison: less than
3895
    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
3896
    template<typename ScalarType, typename std::enable_if<
3897
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3898
    friend bool operator<(ScalarType lhs, const_reference rhs) noexcept
4✔
3899
    {
3900
        return basic_json(lhs) < rhs;
4✔
3901
    }
3902

3903
    /// @brief comparison: less than or equal
3904
    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3905
    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
3,217✔
3906
    {
3907
        if (compares_unordered(lhs, rhs, true))
3,217✔
3908
        {
3909
            return false;
140✔
3910
        }
3911
        return !(rhs < lhs);
3,077✔
3912
    }
3913

3914
    /// @brief comparison: less than or equal
3915
    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3916
    template<typename ScalarType, typename std::enable_if<
3917
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3918
    friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept
4✔
3919
    {
3920
        return lhs <= basic_json(rhs);
4✔
3921
    }
3922

3923
    /// @brief comparison: less than or equal
3924
    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
3925
    template<typename ScalarType, typename std::enable_if<
3926
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3927
    friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
4✔
3928
    {
3929
        return basic_json(lhs) <= rhs;
4✔
3930
    }
3931

3932
    /// @brief comparison: greater than
3933
    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
3934
    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
1,721✔
3935
    {
3936
        // double inverse
3937
        if (compares_unordered(lhs, rhs))
1,721✔
3938
        {
3939
            return false;
224✔
3940
        }
3941
        return !(lhs <= rhs);
1,497✔
3942
    }
3943

3944
    /// @brief comparison: greater than
3945
    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
3946
    template<typename ScalarType, typename std::enable_if<
3947
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3948
    friend bool operator>(const_reference lhs, ScalarType rhs) noexcept
5✔
3949
    {
3950
        return lhs > basic_json(rhs);
5✔
3951
    }
3952

3953
    /// @brief comparison: greater than
3954
    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
3955
    template<typename ScalarType, typename std::enable_if<
3956
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3957
    friend bool operator>(ScalarType lhs, const_reference rhs) noexcept
4✔
3958
    {
3959
        return basic_json(lhs) > rhs;
4✔
3960
    }
3961

3962
    /// @brief comparison: greater than or equal
3963
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3964
    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
976✔
3965
    {
3966
        if (compares_unordered(lhs, rhs, true))
976✔
3967
        {
3968
            return false;
140✔
3969
        }
3970
        return !(lhs < rhs);
836✔
3971
    }
3972

3973
    /// @brief comparison: greater than or equal
3974
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3975
    template<typename ScalarType, typename std::enable_if<
3976
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3977
    friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept
4✔
3978
    {
3979
        return lhs >= basic_json(rhs);
4✔
3980
    }
3981

3982
    /// @brief comparison: greater than or equal
3983
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
3984
    template<typename ScalarType, typename std::enable_if<
3985
                 std::is_scalar<ScalarType>::value, int>::type = 0>
3986
    friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
4✔
3987
    {
3988
        return basic_json(lhs) >= rhs;
4✔
3989
    }
3990
#endif
3991

3992
#undef JSON_IMPLEMENT_OPERATOR
3993

3994
    /// @}
3995

3996
    ///////////////////
3997
    // serialization //
3998
    ///////////////////
3999

4000
    /// @name serialization
4001
    /// @{
4002
#ifndef JSON_NO_IO
4003
    /// @brief serialize to stream
4004
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
4005
    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
102✔
4006
    {
4007
        // read width member and use it as the indentation parameter if nonzero
4008
        const bool pretty_print = o.width() > 0;
102✔
4009
        const auto indentation = pretty_print ? o.width() : 0;
102✔
4010

4011
        // reset width to 0 for subsequent calls to this stream
4012
        o.width(0);
102✔
4013

4014
        // do the actual serialization
4015
        serializer s(detail::output_adapter<char>(o), o.fill());
102✔
4016
        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
102✔
4017
        return o;
102✔
4018
    }
102✔
4019

4020
    /// @brief serialize to stream
4021
    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
4022
    /// @deprecated This function is deprecated since 3.0.0 and will be removed in
4023
    ///             version 4.0.0 of the library. Please use
4024
    ///             operator<<(std::ostream&, const basic_json&) instead; that is,
4025
    ///             replace calls like `j >> o;` with `o << j;`.
4026
    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
4027
    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
3✔
4028
    {
4029
        return o << j;
3✔
4030
    }
4031
#endif  // JSON_NO_IO
4032
    /// @}
4033

4034
    /////////////////////
4035
    // deserialization //
4036
    /////////////////////
4037

4038
    /// @name deserialization
4039
    /// @{
4040

4041
    /// @brief deserialize from a compatible input
4042
    /// @sa https://json.nlohmann.me/api/basic_json/parse/
4043
    template<typename InputType>
4044
    JSON_HEDLEY_WARN_UNUSED_RESULT
4045
    static basic_json parse(InputType&& i,
9,982,315✔
4046
                            parser_callback_t cb = nullptr,
4047
                            const bool allow_exceptions = true,
4048
                            const bool ignore_comments = false)
4049
    {
4050
        basic_json result;
9,982,315✔
4051
        parser(detail::input_adapter(std::forward<InputType>(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded]
25,485,537✔
4052
        return result;
2,230,937✔
4053
    }
7,751,378✔
4054

4055
    /// @brief deserialize from a pair of character iterators
4056
    /// @sa https://json.nlohmann.me/api/basic_json/parse/
4057
    template<typename IteratorType>
4058
    JSON_HEDLEY_WARN_UNUSED_RESULT
4059
    static basic_json parse(IteratorType first,
276✔
4060
                            IteratorType last,
4061
                            parser_callback_t cb = nullptr,
4062
                            const bool allow_exceptions = true,
4063
                            const bool ignore_comments = false)
4064
    {
4065
        basic_json result;
276✔
4066
        parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]
316✔
4067
        return result;
256✔
4068
    }
20✔
4069

4070
    JSON_HEDLEY_WARN_UNUSED_RESULT
4071
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
4072
    static basic_json parse(detail::span_input_adapter&& i,
4073
                            parser_callback_t cb = nullptr,
4074
                            const bool allow_exceptions = true,
4075
                            const bool ignore_comments = false)
4076
    {
4077
        basic_json result;
4078
        parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]
4079
        return result;
4080
    }
4081

4082
    /// @brief check if the input is valid JSON
4083
    /// @sa https://json.nlohmann.me/api/basic_json/accept/
4084
    template<typename InputType>
4085
    static bool accept(InputType&& i,
5,846✔
4086
                       const bool ignore_comments = false)
4087
    {
4088
        return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
5,846✔
4089
    }
4090

4091
    /// @brief check if the input is valid JSON
4092
    /// @sa https://json.nlohmann.me/api/basic_json/accept/
4093
    template<typename IteratorType>
4094
    static bool accept(IteratorType first, IteratorType last,
23✔
4095
                       const bool ignore_comments = false)
4096
    {
4097
        return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
23✔
4098
    }
4099

4100
    JSON_HEDLEY_WARN_UNUSED_RESULT
4101
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
4102
    static bool accept(detail::span_input_adapter&& i,
4103
                       const bool ignore_comments = false)
4104
    {
4105
        return parser(i.get(), nullptr, false, ignore_comments).accept(true);
4106
    }
4107

4108
    /// @brief generate SAX events
4109
    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
4110
    template <typename InputType, typename SAX>
4111
    JSON_HEDLEY_NON_NULL(2)
4112
    static bool sax_parse(InputType&& i, SAX* sax,
892✔
4113
                          input_format_t format = input_format_t::json,
4114
                          const bool strict = true,
4115
                          const bool ignore_comments = false)
4116
    {
4117
        auto ia = detail::input_adapter(std::forward<InputType>(i));
892✔
4118
        return format == input_format_t::json
4119
               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
1,788✔
4120
               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
1,783✔
4121
    }
5✔
4122

4123
    /// @brief generate SAX events
4124
    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
4125
    template<class IteratorType, class SAX>
4126
    JSON_HEDLEY_NON_NULL(3)
4127
    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
24✔
4128
                          input_format_t format = input_format_t::json,
4129
                          const bool strict = true,
4130
                          const bool ignore_comments = false)
4131
    {
4132
        auto ia = detail::input_adapter(std::move(first), std::move(last));
24✔
4133
        return format == input_format_t::json
4134
               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
48✔
4135
               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
48✔
4136
    }
4137

4138
    /// @brief generate SAX events
4139
    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
4140
    /// @deprecated This function is deprecated since 3.8.0 and will be removed in
4141
    ///             version 4.0.0 of the library. Please use
4142
    ///             sax_parse(ptr, ptr + len) instead.
4143
    template <typename SAX>
4144
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
4145
    JSON_HEDLEY_NON_NULL(2)
4146
    static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
4147
                          input_format_t format = input_format_t::json,
4148
                          const bool strict = true,
4149
                          const bool ignore_comments = false)
4150
    {
4151
        auto ia = i.get();
4152
        return format == input_format_t::json
4153
               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4154
               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
4155
               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4156
               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
4157
    }
4158
#ifndef JSON_NO_IO
4159
    /// @brief deserialize from stream
4160
    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
4161
    /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
4162
    ///             version 4.0.0 of the library. Please use
4163
    ///             operator>>(std::istream&, basic_json&) instead; that is,
4164
    ///             replace calls like `j << i;` with `i >> j;`.
4165
    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
4166
    friend std::istream& operator<<(basic_json& j, std::istream& i)
4✔
4167
    {
4168
        return operator>>(i, j);
4✔
4169
    }
4170

4171
    /// @brief deserialize from stream
4172
    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
4173
    friend std::istream& operator>>(std::istream& i, basic_json& j)
304✔
4174
    {
4175
        parser(detail::input_adapter(i)).parse(false, j);
424✔
4176
        return i;
264✔
4177
    }
4178
#endif  // JSON_NO_IO
4179
    /// @}
4180

4181
    ///////////////////////////
4182
    // convenience functions //
4183
    ///////////////////////////
4184

4185
    /// @brief return the type as string
4186
    /// @sa https://json.nlohmann.me/api/basic_json/type_name/
4187
    JSON_HEDLEY_RETURNS_NON_NULL
4188
    const char* type_name() const noexcept
1,062✔
4189
    {
4190
        switch (m_data.m_type)
1,062✔
4191
        {
4192
            case value_t::null:
248✔
4193
                return "null";
248✔
4194
            case value_t::object:
50✔
4195
                return "object";
50✔
4196
            case value_t::array:
124✔
4197
                return "array";
124✔
4198
            case value_t::string:
134✔
4199
                return "string";
134✔
4200
            case value_t::boolean:
126✔
4201
                return "boolean";
126✔
4202
            case value_t::binary:
1✔
4203
                return "binary";
1✔
4204
            case value_t::discarded:
1✔
4205
                return "discarded";
1✔
4206
            case value_t::number_integer:
378✔
4207
            case value_t::number_unsigned:
4208
            case value_t::number_float:
4209
            default:
4210
                return "number";
378✔
4211
        }
4212
    }
4213

4214
  JSON_PRIVATE_UNLESS_TESTED:
4215
    //////////////////////
4216
    // member variables //
4217
    //////////////////////
4218

4219
    struct data
4220
    {
4221
        /// the type of the current element
4222
        value_t m_type = value_t::null;
4223

4224
        /// the value of the current element
4225
        json_value m_value = {};
4226

4227
        data(const value_t v)
30,673,175✔
4228
            : m_type(v), m_value(v)
30,673,175✔
4229
        {
4230
        }
30,673,174✔
4231

4232
        data(size_type cnt, const basic_json& val)
23✔
4233
            : m_type(value_t::array)
23✔
4234
        {
4235
            m_value.array = create<array_t>(cnt, val);
23✔
4236
        }
23✔
4237

4238
        data() noexcept = default;
205,242,282✔
4239
        data(data&&) noexcept = default;
4240
        data(const data&) noexcept = delete;
4241
        data& operator=(data&&) noexcept = delete;
4242
        data& operator=(const data&) noexcept = delete;
4243

4244
        ~data() noexcept
771,711,975✔
4245
        {
4246
            m_value.destroy(m_type);
771,711,975✔
4247
        }
771,711,975✔
4248
    };
4249

4250
    data m_data = {};
4251

4252
#if JSON_DIAGNOSTICS
4253
    /// a pointer to a parent value (for debugging purposes)
4254
    basic_json* m_parent = nullptr;
4255
#endif
4256

4257
#if JSON_DIAGNOSTIC_POSITIONS
4258
    /// the start position of the value
4259
    std::size_t start_position = std::string::npos;
4260
    /// the end position of the value
4261
    std::size_t end_position = std::string::npos;
4262
  public:
4263
    constexpr std::size_t start_pos() const noexcept
107✔
4264
    {
4265
        return start_position;
107✔
4266
    }
4267

4268
    constexpr std::size_t end_pos() const noexcept
73✔
4269
    {
4270
        return end_position;
73✔
4271
    }
4272
#endif
4273

4274
    //////////////////////////////////////////
4275
    // binary serialization/deserialization //
4276
    //////////////////////////////////////////
4277

4278
    /// @name binary serialization/deserialization support
4279
    /// @{
4280

4281
  public:
4282
    /// @brief create a CBOR serialization of a given JSON value
4283
    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
4284
    static std::vector<std::uint8_t> to_cbor(const basic_json& j)
197,265✔
4285
    {
4286
        std::vector<std::uint8_t> result;
197,265✔
4287
        to_cbor(j, result);
197,265✔
4288
        return result;
197,265✔
4289
    }
×
4290

4291
    /// @brief create a CBOR serialization of a given JSON value
4292
    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
4293
    static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)
197,395✔
4294
    {
4295
        binary_writer<std::uint8_t>(o).write_cbor(j);
197,395✔
4296
    }
197,395✔
4297

4298
    /// @brief create a CBOR serialization of a given JSON value
4299
    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
4300
    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
2✔
4301
    {
4302
        binary_writer<char>(o).write_cbor(j);
2✔
4303
    }
2✔
4304

4305
    /// @brief create a MessagePack serialization of a given JSON value
4306
    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
4307
    static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
361,996✔
4308
    {
4309
        std::vector<std::uint8_t> result;
361,996✔
4310
        to_msgpack(j, result);
361,996✔
4311
        return result;
361,996✔
4312
    }
×
4313

4314
    /// @brief create a MessagePack serialization of a given JSON value
4315
    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
4316
    static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)
362,244✔
4317
    {
4318
        binary_writer<std::uint8_t>(o).write_msgpack(j);
362,244✔
4319
    }
362,244✔
4320

4321
    /// @brief create a MessagePack serialization of a given JSON value
4322
    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
4323
    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
4✔
4324
    {
4325
        binary_writer<char>(o).write_msgpack(j);
4✔
4326
    }
4✔
4327

4328
    /// @brief create a UBJSON serialization of a given JSON value
4329
    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
4330
    static std::vector<std::uint8_t> to_ubjson(const basic_json& j,
98,984✔
4331
            const bool use_size = false,
4332
            const bool use_type = false)
4333
    {
4334
        std::vector<std::uint8_t> result;
98,984✔
4335
        to_ubjson(j, result, use_size, use_type);
98,984✔
4336
        return result;
98,984✔
4337
    }
×
4338

4339
    /// @brief create a UBJSON serialization of a given JSON value
4340
    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
4341
    static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,
99,026✔
4342
                          const bool use_size = false, const bool use_type = false)
4343
    {
4344
        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);
99,026✔
4345
    }
99,026✔
4346

4347
    /// @brief create a UBJSON serialization of a given JSON value
4348
    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
4349
    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
4350
                          const bool use_size = false, const bool use_type = false)
4351
    {
4352
        binary_writer<char>(o).write_ubjson(j, use_size, use_type);
4353
    }
4354

4355
    /// @brief create a BJData serialization of a given JSON value
4356
    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
4357
    static std::vector<std::uint8_t> to_bjdata(const basic_json& j,
99,298✔
4358
            const bool use_size = false,
4359
            const bool use_type = false,
4360
            const bjdata_version_t version = bjdata_version_t::draft2)
4361
    {
4362
        std::vector<std::uint8_t> result;
99,298✔
4363
        to_bjdata(j, result, use_size, use_type, version);
99,298✔
4364
        return result;
99,298✔
4365
    }
×
4366

4367
    /// @brief create a BJData serialization of a given JSON value
4368
    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
4369
    static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o,
99,340✔
4370
                          const bool use_size = false, const bool use_type = false,
4371
                          const bjdata_version_t version = bjdata_version_t::draft2)
4372
    {
4373
        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true, version);
99,340✔
4374
    }
99,340✔
4375

4376
    /// @brief create a BJData serialization of a given JSON value
4377
    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
4378
    static void to_bjdata(const basic_json& j, detail::output_adapter<char> o,
4379
                          const bool use_size = false, const bool use_type = false,
4380
                          const bjdata_version_t version = bjdata_version_t::draft2)
4381
    {
4382
        binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true, version);
4383
    }
4384

4385
    /// @brief create a BSON serialization of a given JSON value
4386
    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
4387
    static std::vector<std::uint8_t> to_bson(const basic_json& j)
109✔
4388
    {
4389
        std::vector<std::uint8_t> result;
109✔
4390
        to_bson(j, result);
117✔
4391
        return result;
101✔
4392
    }
8✔
4393

4394
    /// @brief create a BSON serialization of a given JSON value
4395
    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
4396
    static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)
115✔
4397
    {
4398
        binary_writer<std::uint8_t>(o).write_bson(j);
131✔
4399
    }
107✔
4400

4401
    /// @brief create a BSON serialization of a given JSON value
4402
    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
4403
    static void to_bson(const basic_json& j, detail::output_adapter<char> o)
2✔
4404
    {
4405
        binary_writer<char>(o).write_bson(j);
2✔
4406
    }
2✔
4407

4408
    /// @brief create a JSON value from an input in CBOR format
4409
    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
4410
    template<typename InputType>
4411
    JSON_HEDLEY_WARN_UNUSED_RESULT
4412
    static basic_json from_cbor(InputType&& i,
395,519✔
4413
                                const bool strict = true,
4414
                                const bool allow_exceptions = true,
4415
                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4416
    {
4417
        basic_json result;
395,519✔
4418
        auto ia = detail::input_adapter(std::forward<InputType>(i));
395,519✔
4419
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
395,519✔
4420
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
396,066✔
4421
        return res ? result : basic_json(value_t::discarded);
789,944✔
4422
    }
396,066✔
4423

4424
    /// @brief create a JSON value from an input in CBOR format
4425
    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
4426
    template<typename IteratorType>
4427
    JSON_HEDLEY_WARN_UNUSED_RESULT
4428
    static basic_json from_cbor(IteratorType first, IteratorType last,
2✔
4429
                                const bool strict = true,
4430
                                const bool allow_exceptions = true,
4431
                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4432
    {
4433
        basic_json result;
2✔
4434
        auto ia = detail::input_adapter(std::move(first), std::move(last));
2✔
4435
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
2✔
4436
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
2✔
4437
        return res ? result : basic_json(value_t::discarded);
4✔
4438
    }
2✔
4439

4440
    template<typename T>
4441
    JSON_HEDLEY_WARN_UNUSED_RESULT
4442
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
4443
    static basic_json from_cbor(const T* ptr, std::size_t len,
4444
                                const bool strict = true,
4445
                                const bool allow_exceptions = true,
4446
                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4447
    {
4448
        return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
4449
    }
4450

4451
    JSON_HEDLEY_WARN_UNUSED_RESULT
4452
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
4453
    static basic_json from_cbor(detail::span_input_adapter&& i,
138✔
4454
                                const bool strict = true,
4455
                                const bool allow_exceptions = true,
4456
                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4457
    {
4458
        basic_json result;
138✔
4459
        auto ia = i.get();
138✔
4460
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
138✔
4461
        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4462
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
138✔
4463
        return res ? result : basic_json(value_t::discarded);
276✔
4464
    }
138✔
4465

4466
    /// @brief create a JSON value from an input in MessagePack format
4467
    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
4468
    template<typename InputType>
4469
    JSON_HEDLEY_WARN_UNUSED_RESULT
4470
    static basic_json from_msgpack(InputType&& i,
692,138✔
4471
                                   const bool strict = true,
4472
                                   const bool allow_exceptions = true)
4473
    {
4474
        basic_json result;
692,138✔
4475
        auto ia = detail::input_adapter(std::forward<InputType>(i));
692,138✔
4476
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
692,138✔
4477
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
692,323✔
4478
        return res ? result : basic_json(value_t::discarded);
1,383,906✔
4479
    }
692,053✔
4480

4481
    /// @brief create a JSON value from an input in MessagePack format
4482
    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
4483
    template<typename IteratorType>
4484
    JSON_HEDLEY_WARN_UNUSED_RESULT
4485
    static basic_json from_msgpack(IteratorType first, IteratorType last,
8✔
4486
                                   const bool strict = true,
4487
                                   const bool allow_exceptions = true)
4488
    {
4489
        basic_json result;
8✔
4490
        auto ia = detail::input_adapter(std::move(first), std::move(last));
8✔
4491
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
8✔
4492
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
8✔
4493
        return res ? result : basic_json(value_t::discarded);
16✔
4494
    }
8✔
4495

4496
    template<typename T>
4497
    JSON_HEDLEY_WARN_UNUSED_RESULT
4498
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
4499
    static basic_json from_msgpack(const T* ptr, std::size_t len,
3✔
4500
                                   const bool strict = true,
4501
                                   const bool allow_exceptions = true)
4502
    {
4503
        return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
3✔
4504
    }
4505

4506
    JSON_HEDLEY_WARN_UNUSED_RESULT
4507
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
4508
    static basic_json from_msgpack(detail::span_input_adapter&& i,
276✔
4509
                                   const bool strict = true,
4510
                                   const bool allow_exceptions = true)
4511
    {
4512
        basic_json result;
276✔
4513
        auto ia = i.get();
276✔
4514
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
276✔
4515
        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4516
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
276✔
4517
        return res ? result : basic_json(value_t::discarded);
552✔
4518
    }
276✔
4519

4520
    /// @brief create a JSON value from an input in UBJSON format
4521
    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
4522
    template<typename InputType>
4523
    JSON_HEDLEY_WARN_UNUSED_RESULT
4524
    static basic_json from_ubjson(InputType&& i,
198,303✔
4525
                                  const bool strict = true,
4526
                                  const bool allow_exceptions = true)
4527
    {
4528
        basic_json result;
198,303✔
4529
        auto ia = detail::input_adapter(std::forward<InputType>(i));
198,303✔
4530
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
198,303✔
4531
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
198,603✔
4532
        return res ? result : basic_json(value_t::discarded);
396,006✔
4533
    }
198,595✔
4534

4535
    /// @brief create a JSON value from an input in UBJSON format
4536
    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
4537
    template<typename IteratorType>
4538
    JSON_HEDLEY_WARN_UNUSED_RESULT
4539
    static basic_json from_ubjson(IteratorType first, IteratorType last,
4540
                                  const bool strict = true,
4541
                                  const bool allow_exceptions = true)
4542
    {
4543
        basic_json result;
4544
        auto ia = detail::input_adapter(std::move(first), std::move(last));
4545
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
4546
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
4547
        return res ? result : basic_json(value_t::discarded);
4548
    }
4549

4550
    template<typename T>
4551
    JSON_HEDLEY_WARN_UNUSED_RESULT
4552
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
4553
    static basic_json from_ubjson(const T* ptr, std::size_t len,
4554
                                  const bool strict = true,
4555
                                  const bool allow_exceptions = true)
4556
    {
4557
        return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
4558
    }
4559

4560
    JSON_HEDLEY_WARN_UNUSED_RESULT
4561
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
4562
    static basic_json from_ubjson(detail::span_input_adapter&& i,
42✔
4563
                                  const bool strict = true,
4564
                                  const bool allow_exceptions = true)
4565
    {
4566
        basic_json result;
42✔
4567
        auto ia = i.get();
42✔
4568
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
42✔
4569
        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4570
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
42✔
4571
        return res ? result : basic_json(value_t::discarded);
84✔
4572
    }
42✔
4573

4574
    /// @brief create a JSON value from an input in BJData format
4575
    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
4576
    template<typename InputType>
4577
    JSON_HEDLEY_WARN_UNUSED_RESULT
4578
    static basic_json from_bjdata(InputType&& i,
199,326✔
4579
                                  const bool strict = true,
4580
                                  const bool allow_exceptions = true)
4581
    {
4582
        basic_json result;
199,326✔
4583
        auto ia = detail::input_adapter(std::forward<InputType>(i));
199,326✔
4584
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
199,326✔
4585
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]
199,667✔
4586
        return res ? result : basic_json(value_t::discarded);
397,970✔
4587
    }
199,667✔
4588

4589
    /// @brief create a JSON value from an input in BJData format
4590
    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
4591
    template<typename IteratorType>
4592
    JSON_HEDLEY_WARN_UNUSED_RESULT
4593
    static basic_json from_bjdata(IteratorType first, IteratorType last,
4594
                                  const bool strict = true,
4595
                                  const bool allow_exceptions = true)
4596
    {
4597
        basic_json result;
4598
        auto ia = detail::input_adapter(std::move(first), std::move(last));
4599
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
4600
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]
4601
        return res ? result : basic_json(value_t::discarded);
4602
    }
4603

4604
    /// @brief create a JSON value from an input in BSON format
4605
    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
4606
    template<typename InputType>
4607
    JSON_HEDLEY_WARN_UNUSED_RESULT
4608
    static basic_json from_bson(InputType&& i,
226✔
4609
                                const bool strict = true,
4610
                                const bool allow_exceptions = true)
4611
    {
4612
        basic_json result;
226✔
4613
        auto ia = detail::input_adapter(std::forward<InputType>(i));
226✔
4614
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
226✔
4615
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
233✔
4616
        return res ? result : basic_json(value_t::discarded);
438✔
4617
    }
233✔
4618

4619
    /// @brief create a JSON value from an input in BSON format
4620
    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
4621
    template<typename IteratorType>
4622
    JSON_HEDLEY_WARN_UNUSED_RESULT
4623
    static basic_json from_bson(IteratorType first, IteratorType last,
4624
                                const bool strict = true,
4625
                                const bool allow_exceptions = true)
4626
    {
4627
        basic_json result;
4628
        auto ia = detail::input_adapter(std::move(first), std::move(last));
4629
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
4630
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
4631
        return res ? result : basic_json(value_t::discarded);
4632
    }
4633

4634
    template<typename T>
4635
    JSON_HEDLEY_WARN_UNUSED_RESULT
4636
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
4637
    static basic_json from_bson(const T* ptr, std::size_t len,
4638
                                const bool strict = true,
4639
                                const bool allow_exceptions = true)
4640
    {
4641
        return from_bson(ptr, ptr + len, strict, allow_exceptions);
4642
    }
4643

4644
    JSON_HEDLEY_WARN_UNUSED_RESULT
4645
    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
4646
    static basic_json from_bson(detail::span_input_adapter&& i,
5✔
4647
                                const bool strict = true,
4648
                                const bool allow_exceptions = true)
4649
    {
4650
        basic_json result;
5✔
4651
        auto ia = i.get();
5✔
4652
        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
5✔
4653
        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
4654
        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
5✔
4655
        return res ? result : basic_json(value_t::discarded);
10✔
4656
    }
5✔
4657
    /// @}
4658

4659
    //////////////////////////
4660
    // JSON Pointer support //
4661
    //////////////////////////
4662

4663
    /// @name JSON Pointer functions
4664
    /// @{
4665

4666
    /// @brief access specified element via JSON Pointer
4667
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
4668
    reference operator[](const json_pointer& ptr)
98✔
4669
    {
4670
        return ptr.get_unchecked(this);
98✔
4671
    }
4672

4673
    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4674
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
4675
    reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
4✔
4676
    {
4677
        return ptr.get_unchecked(this);
4✔
4678
    }
4679

4680
    /// @brief access specified element via JSON Pointer
4681
    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
4682
    const_reference operator[](const json_pointer& ptr) const
86✔
4683
    {
4684
        return ptr.get_unchecked(this);
86✔
4685
    }
4686

4687
    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4688
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
4689
    const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
4690
    {
4691
        return ptr.get_unchecked(this);
4692
    }
4693

4694
    /// @brief access specified element via JSON Pointer
4695
    /// @sa https://json.nlohmann.me/api/basic_json/at/
4696
    reference at(const json_pointer& ptr)
307✔
4697
    {
4698
        return ptr.get_checked(this);
305✔
4699
    }
4700

4701
    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4702
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
4703
    reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
4✔
4704
    {
4705
        return ptr.get_checked(this);
4✔
4706
    }
4707

4708
    /// @brief access specified element via JSON Pointer
4709
    /// @sa https://json.nlohmann.me/api/basic_json/at/
4710
    const_reference at(const json_pointer& ptr) const
34✔
4711
    {
4712
        return ptr.get_checked(this);
34✔
4713
    }
4714

4715
    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
4716
    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
4717
    const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
4718
    {
4719
        return ptr.get_checked(this);
4720
    }
4721

4722
    /// @brief return flattened JSON value
4723
    /// @sa https://json.nlohmann.me/api/basic_json/flatten/
4724
    basic_json flatten() const
18✔
4725
    {
4726
        basic_json result(value_t::object);
18✔
4727
        json_pointer::flatten("", *this, result);
18✔
4728
        return result;
18✔
4729
    }
×
4730

4731
    /// @brief unflatten a previously flattened JSON value
4732
    /// @sa https://json.nlohmann.me/api/basic_json/unflatten/
4733
    basic_json unflatten() const
25✔
4734
    {
4735
        return json_pointer::unflatten(*this);
24✔
4736
    }
4737

4738
    /// @}
4739

4740
    //////////////////////////
4741
    // JSON Patch functions //
4742
    //////////////////////////
4743

4744
    /// @name JSON Patch functions
4745
    /// @{
4746

4747
    /// @brief applies a JSON patch in-place without copying the object
4748
    /// @sa https://json.nlohmann.me/api/basic_json/patch/
4749
    void patch_inplace(const basic_json& json_patch)
215✔
4750
    {
4751
        basic_json& result = *this;
215✔
4752
        // the valid JSON Patch operations
4753
        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
4754

4755
        const auto get_op = [](const string_t& op)
219✔
4756
        {
4757
            if (op == "add")
219✔
4758
            {
4759
                return patch_operations::add;
72✔
4760
            }
4761
            if (op == "remove")
147✔
4762
            {
4763
                return patch_operations::remove;
34✔
4764
            }
4765
            if (op == "replace")
113✔
4766
            {
4767
                return patch_operations::replace;
36✔
4768
            }
4769
            if (op == "move")
77✔
4770
            {
4771
                return patch_operations::move;
20✔
4772
            }
4773
            if (op == "copy")
57✔
4774
            {
4775
                return patch_operations::copy;
13✔
4776
            }
4777
            if (op == "test")
44✔
4778
            {
4779
                return patch_operations::test;
42✔
4780
            }
4781

4782
            return patch_operations::invalid;
2✔
4783
        };
4784

4785
        // wrapper for "add" operation; add value at ptr
4786
        const auto operation_add = [&result](json_pointer & ptr, const basic_json & val)
304✔
4787
        {
4788
            // adding to the root of the target document means replacing it
4789
            if (ptr.empty())
89✔
4790
            {
4791
                result = val;
4✔
4792
                return;
4✔
4793
            }
4794

4795
            // make sure the top element of the pointer exists
4796
            json_pointer const top_pointer = ptr.top();
85✔
4797
            if (top_pointer != ptr)
85✔
4798
            {
4799
                result.at(top_pointer);
35✔
4800
            }
4801

4802
            // get reference to the parent of the JSON pointer ptr
4803
            const auto last_path = ptr.back();
77✔
4804
            ptr.pop_back();
77✔
4805
            // parent must exist when performing patch add per RFC6902 specs
4806
            basic_json& parent = result.at(ptr);
77✔
4807

4808
            switch (parent.m_data.m_type)
76✔
4809
            {
4810
                case value_t::null:
48✔
4811
                case value_t::object:
4812
                {
4813
                    // use operator[] to add value
4814
                    parent[last_path] = val;
48✔
4815
                    break;
48✔
4816
                }
4817

4818
                case value_t::array:
28✔
4819
                {
4820
                    if (last_path == "-")
28!
4821
                    {
4822
                        // special case: append to back
4823
                        parent.push_back(val);
9✔
4824
                    }
4825
                    else
4826
                    {
4827
                        const auto idx = json_pointer::template array_index<basic_json_t>(last_path);
19✔
4828
                        if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
16✔
4829
                        {
4830
                            // avoid undefined behavior
4831
                            JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
3✔
4832
                        }
4833

4834
                        // default case: insert add offset
4835
                        parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
13✔
4836
                    }
4837
                    break;
22✔
4838
                }
4839

4840
                // if there exists a parent, it cannot be primitive
4841
                case value_t::string: // LCOV_EXCL_LINE
4842
                case value_t::boolean: // LCOV_EXCL_LINE
4843
                case value_t::number_integer: // LCOV_EXCL_LINE
4844
                case value_t::number_unsigned: // LCOV_EXCL_LINE
4845
                case value_t::number_float: // LCOV_EXCL_LINE
4846
                case value_t::binary: // LCOV_EXCL_LINE
4847
                case value_t::discarded: // LCOV_EXCL_LINE
4848
                default:            // LCOV_EXCL_LINE
4849
                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
4850
            }
4851
        };
88✔
4852

4853
        // wrapper for "remove" operation; remove value at ptr
4854
        const auto operation_remove = [this, & result](json_pointer & ptr)
39✔
4855
        {
4856
            // get reference to the parent of the JSON pointer ptr
4857
            const auto last_path = ptr.back();
46✔
4858
            ptr.pop_back();
45✔
4859
            basic_json& parent = result.at(ptr);
45✔
4860

4861
            // remove child
4862
            if (parent.is_object())
44✔
4863
            {
4864
                // perform range check
4865
                auto it = parent.find(last_path);
27✔
4866
                if (JSON_HEDLEY_LIKELY(it != parent.end()))
27✔
4867
                {
4868
                    parent.erase(it);
25✔
4869
                }
4870
                else
4871
                {
4872
                    JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
2✔
4873
                }
4874
            }
4875
            else if (parent.is_array())
17!
4876
            {
4877
                // note erase performs range check
4878
                parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
17✔
4879
            }
4880
        };
45✔
4881

4882
        // type check: top level value must be an array
4883
        if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
215✔
4884
        {
4885
            JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
3✔
4886
        }
4887

4888
        // iterate and apply the operations
4889
        for (const auto& val : json_patch)
567✔
4890
        {
4891
            // wrapper to get a value for an operation
4892
            const auto get_value = [&val](const string_t& op,
881✔
4893
                                          const string_t& member,
4894
                                          bool string_type) -> basic_json &
4895
            {
4896
                // find value
4897
                auto it = val.m_data.m_value.object->find(member);
647✔
4898

4899
                // context-sensitive error message
4900
                const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable)
880✔
4901

4902
                // check if the desired value is present
4903
                if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
647✔
4904
                {
4905
                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
4906
                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
19✔
4907
                }
4908

4909
                // check if the result is of type string
4910
                if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
628✔
4911
                {
4912
                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
4913
                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
10✔
4914
                }
4915

4916
                // no error: return value
4917
                return it->second;
1,236✔
4918
            };
647✔
4919

4920
            // type check: every element of the array must be an object
4921
            if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
234✔
4922
            {
4923
                JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
3✔
4924
            }
4925

4926
            // collect mandatory members
4927
            const auto op = get_value("op", "op", true).template get<string_t>();
926✔
4928
            const auto path = get_value(op, "path", true).template get<string_t>();
243✔
4929
            json_pointer ptr(path);
219✔
4930

4931
            switch (get_op(op))
219✔
4932
            {
4933
                case patch_operations::add:
72✔
4934
                {
4935
                    operation_add(ptr, get_value("add", "value", false));
225✔
4936
                    break;
59✔
4937
                }
4938

4939
                case patch_operations::remove:
34✔
4940
                {
4941
                    operation_remove(ptr);
34✔
4942
                    break;
27✔
4943
                }
4944

4945
                case patch_operations::replace:
36✔
4946
                {
4947
                    // the "path" location must exist - use at()
4948
                    result.at(ptr) = get_value("replace", "value", false);
118✔
4949
                    break;
30✔
4950
                }
4951

4952
                case patch_operations::move:
20✔
4953
                {
4954
                    const auto from_path = get_value("move", "from", true).template get<string_t>();
65✔
4955
                    json_pointer from_ptr(from_path);
15✔
4956

4957
                    // the "from" location must exist - use at()
4958
                    basic_json const v = result.at(from_ptr);
15✔
4959

4960
                    // The move operation is functionally identical to a
4961
                    // "remove" operation on the "from" location, followed
4962
                    // immediately by an "add" operation at the target
4963
                    // location with the value that was just removed.
4964
                    operation_remove(from_ptr);
12✔
4965
                    operation_add(ptr, v);
12✔
4966
                    break;
10✔
4967
                }
16✔
4968

4969
                case patch_operations::copy:
13✔
4970
                {
4971
                    const auto from_path = get_value("copy", "from", true).template get<string_t>();
42✔
4972
                    const json_pointer from_ptr(from_path);
10✔
4973

4974
                    // the "from" location must exist - use at()
4975
                    basic_json const v = result.at(from_ptr);
10✔
4976

4977
                    // The copy is functionally identical to an "add"
4978
                    // operation at the target location using the value
4979
                    // specified in the "from" member.
4980
                    operation_add(ptr, v);
7✔
4981
                    break;
5✔
4982
                }
11✔
4983

4984
                case patch_operations::test:
42✔
4985
                {
4986
                    bool success = false;
42✔
4987
                    JSON_TRY
4988
                    {
4989
                        // check if "value" matches the one at "path"
4990
                        // the "path" location must exist - use at()
4991
                        success = (result.at(ptr) == get_value("test", "value", false));
168✔
4992
                    }
4993
                    JSON_INTERNAL_CATCH (out_of_range&)
8✔
4994
                    {
4995
                        // ignore out of range errors: success remains false
4996
                    }
4997

4998
                    // throw an exception if the test fails
4999
                    if (JSON_HEDLEY_UNLIKELY(!success))
37✔
5000
                    {
5001
                        JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
10✔
5002
                    }
5003

5004
                    break;
27✔
5005
                }
5006

5007
                case patch_operations::invalid:
2✔
5008
                default:
5009
                {
5010
                    // op must be "add", "remove", "replace", "move", "copy", or
5011
                    // "test"
5012
                    JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
2✔
5013
                }
5014
            }
5015
        }
5016
    }
138✔
5017

5018
    /// @brief applies a JSON patch to a copy of the current object
5019
    /// @sa https://json.nlohmann.me/api/basic_json/patch/
5020
    basic_json patch(const basic_json& json_patch) const
215✔
5021
    {
5022
        basic_json result = *this;
215✔
5023
        result.patch_inplace(json_patch);
215✔
5024
        return result;
138✔
5025
    }
77✔
5026

5027
    /// @brief creates a diff as a JSON patch
5028
    /// @sa https://json.nlohmann.me/api/basic_json/diff/
5029
    JSON_HEDLEY_WARN_UNUSED_RESULT
5030
    static basic_json diff(const basic_json& source, const basic_json& target,
87✔
5031
                           const string_t& path = "")
5032
    {
5033
        // the patch
5034
        basic_json result(value_t::array);
87✔
5035

5036
        // if the values are the same, return an empty patch
5037
        if (source == target)
87✔
5038
        {
5039
            return result;
33✔
5040
        }
5041

5042
        if (source.type() != target.type())
54✔
5043
        {
5044
            // different types: replace value
5045
            result.push_back(
20✔
5046
            {
5047
                {"op", "replace"}, {"path", path}, {"value", target}
5048
            });
5049
            return result;
2✔
5050
        }
5051

5052
        switch (source.type())
52✔
5053
        {
5054
            case value_t::array:
13✔
5055
            {
5056
                // first pass: traverse common elements
5057
                std::size_t i = 0;
13✔
5058
                while (i < source.size() && i < target.size())
41✔
5059
                {
5060
                    // recursive call to compare array values at index i
5061
                    auto temp_diff = diff(source[i], target[i], detail::concat<string_t>(path, '/', detail::to_string<string_t>(i)));
28✔
5062
                    result.insert(result.end(), temp_diff.begin(), temp_diff.end());
28✔
5063
                    ++i;
28✔
5064
                }
5065

5066
                // We now reached the end of at least one array
5067
                // in a second pass, traverse the remaining elements
5068

5069
                // remove my remaining elements
5070
                const auto end_index = static_cast<difference_type>(result.size());
13✔
5071
                while (i < source.size())
19✔
5072
                {
5073
                    // add operations in reverse order to avoid invalid
5074
                    // indices
5075
                    result.insert(result.begin() + end_index, object(
42✔
5076
                    {
5077
                        {"op", "remove"},
5078
                        {"path", detail::concat<string_t>(path, '/', detail::to_string<string_t>(i))}
×
5079
                    }));
5080
                    ++i;
6✔
5081
                }
5082

5083
                // add other remaining elements
5084
                while (i < target.size())
20✔
5085
                {
5086
                    result.push_back(
70✔
5087
                    {
5088
                        {"op", "add"},
5089
                        {"path", detail::concat<string_t>(path, "/-")},
5090
                        {"value", target[i]}
14✔
5091
                    });
5092
                    ++i;
7✔
5093
                }
5094

5095
                break;
13✔
5096
            }
5097

5098
            case value_t::object:
29✔
5099
            {
5100
                // first pass: traverse this object's elements
5101
                for (auto it = source.cbegin(); it != source.cend(); ++it)
105✔
5102
                {
5103
                    // escape the key name to be used in a JSON patch
5104
                    const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
38✔
5105

5106
                    if (target.find(it.key()) != target.end())
38✔
5107
                    {
5108
                        // recursive call to compare object values at key it
5109
                        auto temp_diff = diff(it.value(), target[it.key()], path_key);
31✔
5110
                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
31✔
5111
                    }
31✔
5112
                    else
5113
                    {
5114
                        // found a key that is not in o -> remove it
5115
                        result.push_back(object(
49✔
5116
                        {
5117
                            {"op", "remove"}, {"path", path_key}
5118
                        }));
5119
                    }
5120
                }
5121

5122
                // second pass: traverse other object's elements
5123
                for (auto it = target.cbegin(); it != target.cend(); ++it)
109✔
5124
                {
5125
                    if (source.find(it.key()) == source.end())
40✔
5126
                    {
5127
                        // found a key that is not in this -> add it
5128
                        const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));
9✔
5129
                        result.push_back(
90✔
5130
                        {
5131
                            {"op", "add"}, {"path", path_key},
5132
                            {"value", it.value()}
18✔
5133
                        });
5134
                    }
×
5135
                }
5136

5137
                break;
29✔
5138
            }
5139

5140
            case value_t::null:
10✔
5141
            case value_t::string:
5142
            case value_t::boolean:
5143
            case value_t::number_integer:
5144
            case value_t::number_unsigned:
5145
            case value_t::number_float:
5146
            case value_t::binary:
5147
            case value_t::discarded:
5148
            default:
5149
            {
5150
                // both primitive types: replace value
5151
                result.push_back(
100✔
5152
                {
5153
                    {"op", "replace"}, {"path", path}, {"value", target}
5154
                });
5155
                break;
10✔
5156
            }
5157
        }
5158

5159
        return result;
52✔
5160
    }
302✔
5161
    /// @}
5162

5163
    ////////////////////////////////
5164
    // JSON Merge Patch functions //
5165
    ////////////////////////////////
5166

5167
    /// @name JSON Merge Patch functions
5168
    /// @{
5169

5170
    /// @brief applies a JSON Merge Patch
5171
    /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/
5172
    void merge_patch(const basic_json& apply_patch)
34✔
5173
    {
5174
        if (apply_patch.is_object())
34✔
5175
        {
5176
            if (!is_object())
18✔
5177
            {
5178
                *this = object();
3✔
5179
            }
5180
            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
66✔
5181
            {
5182
                if (it.value().is_null())
24✔
5183
                {
5184
                    erase(it.key());
7✔
5185
                }
5186
                else
5187
                {
5188
                    operator[](it.key()).merge_patch(it.value());
17✔
5189
                }
5190
            }
5191
        }
5192
        else
5193
        {
5194
            *this = apply_patch;
16✔
5195
        }
5196
    }
34✔
5197

5198
    /// @}
5199
};
5200

5201
/// @brief user-defined to_string function for JSON values
5202
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
5203
NLOHMANN_BASIC_JSON_TPL_DECLARATION
5204
std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
5✔
5205
{
5206
    return j.dump();
5✔
5207
}
5208

5209
inline namespace literals
5210
{
5211
inline namespace json_literals
5212
{
5213

5214
/// @brief user-defined string literal for JSON values
5215
/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/
5216
JSON_HEDLEY_NON_NULL(1)
5217
#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
5218
    inline nlohmann::json operator ""_json(const char* s, std::size_t n)
230✔
5219
#else
5220
    inline nlohmann::json operator "" _json(const char* s, std::size_t n)
5221
#endif
5222
{
5223
    return nlohmann::json::parse(s, s + n);
230✔
5224
}
5225

5226
/// @brief user-defined string literal for JSON pointer
5227
/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/
5228
JSON_HEDLEY_NON_NULL(1)
5229
#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
5230
    inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n)
456✔
5231
#else
5232
    inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
5233
#endif
5234
{
5235
    return nlohmann::json::json_pointer(std::string(s, n));
912✔
5236
}
5237

5238
}  // namespace json_literals
5239
}  // namespace literals
5240
NLOHMANN_JSON_NAMESPACE_END
5241

5242
///////////////////////
5243
// nonmember support //
5244
///////////////////////
5245

5246
namespace std // NOLINT(cert-dcl58-cpp)
5247
{
5248

5249
/// @brief hash value for JSON objects
5250
/// @sa https://json.nlohmann.me/api/basic_json/std_hash/
5251
NLOHMANN_BASIC_JSON_TPL_DECLARATION
5252
struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)
5253
{
5254
    std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
48✔
5255
    {
5256
        return nlohmann::detail::hash(j);
48✔
5257
    }
5258
};
5259

5260
// specialization for std::less<value_t>
5261
template<>
5262
struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679
5263
{
5264
    /*!
5265
    @brief compare two value_t enum values
5266
    @since version 3.0.0
5267
    */
5268
    bool operator()(::nlohmann::detail::value_t lhs,
400✔
5269
                    ::nlohmann::detail::value_t rhs) const noexcept
5270
    {
5271
#if JSON_HAS_THREE_WAY_COMPARISON
5272
        return std::is_lt(lhs <=> rhs); // *NOPAD*
200✔
5273
#else
5274
        return ::nlohmann::detail::operator<(lhs, rhs);
200✔
5275
#endif
5276
    }
5277
};
5278

5279
// C++20 prohibit function specialization in the std namespace.
5280
#ifndef JSON_HAS_CPP_20
5281

5282
/// @brief exchanges the values of two JSON objects
5283
/// @sa https://json.nlohmann.me/api/basic_json/std_swap/
5284
NLOHMANN_BASIC_JSON_TPL_DECLARATION
5285
inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept(  // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp)
5286
    is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&&                          // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
5287
    is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
5288
{
5289
    j1.swap(j2);
5290
}
5291

5292
#endif
5293

5294
}  // namespace std
5295

5296
#if JSON_USE_GLOBAL_UDLS
5297
    #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
5298
        using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5299
        using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5300
    #else
5301
        using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5302
        using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
5303
    #endif
5304
#endif
5305

5306
#include <nlohmann/detail/macro_unscope.hpp>
5307

5308
#endif  // INCLUDE_NLOHMANN_JSON_HPP_
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc