json.hpp.re2c 198.8 KB
Newer Older
N
Niels 已提交
1
/*!
N
Niels 已提交
2 3 4 5 6 7 8
@mainpage

These pages contain the API documentation of JSON for Modern C++, a C++11
header-only JSON class.

Class @ref nlohmann::basic_json is a good entry point for the documentation.

N
Niels 已提交
9 10 11 12
@copyright The code is licensed under the MIT License
           <http://opensource.org/licenses/MIT>,
           Copyright (c) 2013-2015 Niels Lohmann.
@author Niels Lohmann <http://nlohmann.me>
N
Niels 已提交
13
@see https://github.com/nlohmann/json to download the source code
N
Niels 已提交
14 15
*/

N
Niels 已提交
16 17
#ifndef NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_HPP
N
cleanup  
Niels 已提交
18 19

#include <algorithm>
20
#include <array>
N
Niels 已提交
21
#include <ciso646>
N
Niels 已提交
22
#include <cmath>
N
Niels 已提交
23
#include <cstdio>
N
cleanup  
Niels 已提交
24 25
#include <functional>
#include <initializer_list>
N
Niels 已提交
26
#include <iomanip>
N
cleanup  
Niels 已提交
27 28 29 30 31
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
N
Niels 已提交
32
#include <sstream>
N
cleanup  
Niels 已提交
33 34 35 36 37
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

N
Niels 已提交
38 39 40 41 42 43 44
// enable ssize_t on MinGW
#ifdef __GNUC__
    #ifdef __MINGW32__
        #include <sys/types.h>
    #endif
#endif

N
Niels 已提交
45 46
// enable ssize_t for MSVC
#ifdef _MSC_VER
N
Niels 已提交
47
    #include <basetsd.h>
N
Niels 已提交
48 49 50
    using ssize_t = SSIZE_T;
#endif

N
cleanup  
Niels 已提交
51
/*!
N
Niels 已提交
52
@brief namespace for Niels Lohmann
N
cleanup  
Niels 已提交
53 54 55 56 57
@see https://github.com/nlohmann
*/
namespace nlohmann
{

N
Niels 已提交
58

59 60 61 62
/*!
@brief unnamed namespace with internal helper functions
*/
namespace
N
Niels 已提交
63
{
64 65 66 67
/*!
@brief Helper to determine whether there's a key_type for T.
@sa http://stackoverflow.com/a/7728728/266378
*/
N
Niels 已提交
68
template<typename T>
N
Niels 已提交
69
struct has_mapped_type
N
Niels 已提交
70 71
{
  private:
N
Niels 已提交
72
    template<typename C> static char test(typename C::mapped_type*);
N
Niels 已提交
73 74 75 76
    template<typename C> static int  test(...);
  public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
77 78 79 80 81 82 83

/// "equality" comparison for floating point numbers
template<typename T>
static bool approx(const T a, const T b)
{
    return not (a > b or a < b);
}
N
Niels 已提交
84
}
N
Niels 已提交
85

N
cleanup  
Niels 已提交
86
/*!
N
Niels 已提交
87
@brief a class to store JSON values
N
cleanup  
Niels 已提交
88

N
Niels 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102
@tparam ObjectType type for JSON objects (@c std::map by default; will be used
in @ref object_t)
@tparam ArrayType type for JSON arrays (@c std::vector by default; will be used
in @ref array_t)
@tparam StringType type for JSON strings and object keys (@c std::string by
default; will be used in @ref string_t)
@tparam BooleanType type for JSON booleans (@c `bool` by default; will be used
in @ref boolean_t)
@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
default; will be used in @ref number_integer_t)
@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
default; will be used in @ref number_float_t)
@tparam AllocatorType type of the allocator to use (@c `std::allocator` by
default)
N
Niels 已提交
103

N
Niels 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
@requirement The class satisfies the following concept requirements:
- Basic
 - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible)
 - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible)
 - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible)
 - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable)
 - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable)
 - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible)
- Layout
 - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType)
- Library-wide
 - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable)
 - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable)
 - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable)
 - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer)
- Container
 - [Container](http://en.cppreference.com/w/cpp/concept/Container)
 - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
N
Niels 已提交
122

N
Niels 已提交
123 124
@note ObjectType trick from http://stackoverflow.com/a/9860911

N
Niels 已提交
125
@see RFC 7159 <http://rfc7159.net/rfc7159>
N
cleanup  
Niels 已提交
126 127 128 129 130 131 132
*/
template <
    template<typename U, typename V, typename... Args> class ObjectType = std::map,
    template<typename U, typename... Args> class ArrayType = std::vector,
    class StringType = std::string,
    class BooleanType = bool,
    class NumberIntegerType = int64_t,
N
Niels 已提交
133
    class NumberFloatType = double,
N
Niels 已提交
134
    template<typename U> class AllocatorType = std::allocator
N
cleanup  
Niels 已提交
135 136 137
    >
class basic_json
{
138 139 140 141 142 143 144
  private:
    /// workaround type for MSVC
    using __basic_json =
        basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType>;

  public:

N
cleanup  
Niels 已提交
145 146 147 148
    /////////////////////
    // container types //
    /////////////////////

N
Niels 已提交
149 150 151
    /// @name container types
    /// @{

N
Niels 已提交
152
    /// the type of elements in a basic_json container
N
cleanup  
Niels 已提交
153
    using value_type = basic_json;
N
Niels 已提交
154

N
Niels 已提交
155
    /// the type of an element reference
N
Niels 已提交
156
    using reference = value_type&;
N
Niels 已提交
157

N
Niels 已提交
158
    /// the type of an element const reference
N
Niels 已提交
159
    using const_reference = const value_type&;
N
Niels 已提交
160

N
Niels 已提交
161
    /// a type to represent differences between iterators
N
Niels 已提交
162 163
    using difference_type = std::ptrdiff_t;

N
Niels 已提交
164
    /// a type to represent container sizes
N
Niels 已提交
165 166 167
    using size_type = std::size_t;

    /// the allocator type
N
Niels 已提交
168
    using allocator_type = AllocatorType<basic_json>;
N
Niels 已提交
169

N
cleanup  
Niels 已提交
170
    /// the type of an element pointer
N
Niels 已提交
171
    using pointer = typename std::allocator_traits<allocator_type>::pointer;
N
cleanup  
Niels 已提交
172
    /// the type of an element const pointer
N
Niels 已提交
173
    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
N
Niels 已提交
174

N
Niels 已提交
175 176 177
    // forward declaration
    template<typename Base> class json_reverse_iterator;

N
Niels 已提交
178 179 180 181 182
    /// an iterator for a basic_json container
    class iterator;
    /// a const iterator for a basic_json container
    class const_iterator;
    /// a reverse iterator for a basic_json container
N
Niels 已提交
183
    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
N
Niels 已提交
184
    /// a const reverse iterator for a basic_json container
N
Niels 已提交
185
    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
N
Niels 已提交
186

N
Niels 已提交
187 188 189
    /// @}


N
Niels 已提交
190 191 192
    /*!
    @brief returns the allocator associated with the container
    */
193
    static allocator_type get_allocator()
N
Niels 已提交
194 195 196 197 198
    {
        return allocator_type();
    }


N
cleanup  
Niels 已提交
199 200 201 202
    ///////////////////////////
    // JSON value data types //
    ///////////////////////////

N
Niels 已提交
203 204 205
    /// @name JSON value data types
    /// @{

N
Niels 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    /*!
    @brief a type for an object

    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
    > An object is an unordered collection of zero or more name/value pairs,
    > where a name is a string and a value is a string, number, boolean, null,
    > object, or array.

    To store objects in C++, a type is defined by the template parameters @a
    ObjectType which chooses the container (e.g., `std::map` or
    `std::unordered_map`), @a StringType which chooses the type of the keys or
    names, and @a AllocatorType which chooses the allocator to use.

    #### Default type

    With the default values for @a ObjectType (`std::map`), @a StringType
    (`std::string`), and @a AllocatorType (`std::allocator`), the default value
    for @a object_t is:

    @code {.cpp}
    std::map<
      std::string, // key_type
      basic_json, // value_type
      std::less<std::string>, // key_compare
      std::allocator<std::pair<const std::string, basic_json>> // allocator_type
    >
    @endcode

    #### Behavior

    The choice of @a object_t influences the behavior of the JSON class. With
    the default type, objects have the following behavior:

    - When all names are unique, objects will be interoperable in the sense
      that all software implementations receiving that object will agree on the
      name-value mappings.
    - When the names within an object are not unique, later stored name/value
      pairs overwrite previously stored name/value pairs, leaving the used
      names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
      be treated as equal and both stored as `{"key": 1}`.
    - Internally, name/value pairs are stored in lexicographical order of the
      names. Objects will also be serialized (see @ref dump) in this order. For
      instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and
      serialized as `{"a": 2, "b": 1}`.
    - When comparing objects, the order of the name/value pairs is irrelevant.
      This makes objects interoperable in the sense that they will not be
      affected by these differences. For instance, `{"b": 1, "a": 2}` and
      `{"a": 2, "b": 1}` will be treated as equal.

    #### Limits

    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
    > An implementation may set limits on the maximum depth of nesting.

    In this class, the object's limit of nesting is not constraint explicitly.
    However, a maximum depth of nesting may be introduced by the compiler or
    runtime environment. A theoretical limit can be queried by calling the @ref
    max_size function of a JSON object.

    #### Storage

    Objects are stored as pointers in a `basic_json` type. That is, for any
    access to object values, a pointer of type `object_t*` must be dereferenced.

    @sa array_t
    */
N
Niels 已提交
272 273
    using object_t =
        ObjectType<StringType, basic_json, std::less<StringType>, AllocatorType<std::pair<const StringType, basic_json>>>;
N
Niels 已提交
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

    /*!
    @brief a type for an array

    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
    > An array is an ordered sequence of zero or more values.

    To store objects in C++, a type is defined by the template parameters @a
    ArrayType which chooses the container (e.g., `std::vector` or `std::list`)
    and @a AllocatorType which chooses the allocator to use.

    #### Default type

    With the default values for @a ArrayType (`std::vector`) and @a
    AllocatorType (`std::allocator`), the default value for @a array_t is:

    @code {.cpp}
    std::vector<
      basic_json, // value_type
      std::allocator<basic_json> // allocator_type
    >
    @endcode

    #### Limits

    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
    > An implementation may set limits on the maximum depth of nesting.

    In this class, the array's limit of nesting is not constraint explicitly.
    However, a maximum depth of nesting may be introduced by the compiler or
    runtime environment. A theoretical limit can be queried by calling the @ref
    max_size function of a JSON array.

    #### Storage

    Arrays are stored as pointers in a `basic_json` type. That is, for any
    access to array values, a pointer of type `array_t*` must be dereferenced.
    */
N
Niels 已提交
312
    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
N
Niels 已提交
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355

    /*!
    @brief a type for a string

    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
    > A string is a sequence of zero or more Unicode characters.

    To store objects in C++, a type is defined by the template parameters @a
    StringType which chooses the container (e.g., `std::string`) to use.

    Unicode values are split by the JSON class into byte-sized characters
    during deserialization.

    #### Default type

    With the default values for @a StringType (`std::string`), the default
    value for @a string_t is:

    @code {.cpp}
    std::string
    @endcode

    #### String comparison

    [RFC 7159](http://rfc7159.net/rfc7159) states:
    > Software implementations are typically required to test names of object
    > members for equality. Implementations that transform the textual
    > representation into sequences of Unicode code units and then perform the
    > comparison numerically, code unit by code unit, are interoperable in the
    > sense that implementations will agree in all cases on equality or
    > inequality of two strings. For example, implementations that compare
    > strings with escaped characters unconverted may incorrectly find that
    > `"a\\b"` and `"a\u005Cb"` are not equal.

    This implementation is interoperable as it does compare strings code unit
    by code unit.

    #### Storage

    String values are stored as pointers in a `basic_json` type. That is, for
    any access to string values, a pointer of type `string_t*` must be
    dereferenced.
    */
N
cleanup  
Niels 已提交
356
    using string_t = StringType;
N
Niels 已提交
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

    /*!
    @brief a type for a boolean

    [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
    type which differentiates the two literals `true` and `false`.

    To store objects in C++, a type is defined by the template parameter @a
    BooleanType which chooses the type to use.

    #### Default type

    With the default values for @a BooleanType (`bool`), the default value for
    @a boolean_t is:

    @code {.cpp}
    bool
    @endcode

    #### Storage

    Boolean values are stored directly inside a `basic_json` type.
    */
N
cleanup  
Niels 已提交
380
    using boolean_t = BooleanType;
N
Niels 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443

    /*!
    @brief a type for a number (integer)

    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
    > The representation of numbers is similar to that used in most programming
    > languages. A number is represented in base 10 using decimal digits. It
    > contains an integer component that may be prefixed with an optional minus
    > sign, which may be followed by a fraction part and/or an exponent part.
    > Leading zeros are not allowed. (...) Numeric values that cannot be
    > represented in the grammar below (such as Infinity and NaN) are not
    > permitted.

    This description includes both integer and floating-point numbers. However,
    C++ allows more precise storage if it is known whether the number is an
    integer or a floating-point number. Therefore, two different types, @ref
    number_integer_t and @ref number_float_t are used.

    To store integer numbers in C++, a type is defined by the template
    parameter @a NumberIntegerType which chooses the type to use.

    #### Default type

    With the default values for @a NumberIntegerType (`int64_t`), the default
    value for @a number_integer_t is:

    @code {.cpp}
    int64_t
    @endcode

    #### Default behavior

    - The restrictions about leading zeros is not enforced in C++. Instead,
      leading zeros in integer literals lead to an interpretation as octal
      number. Internally, the value will be stored as decimal number. For
      instance, the C++ integer literal `010` will be serialized to `8`. During
      deserialization, leading zeros yield an error.
    - Not-a-number (NaN) values will be serialized to `null`.

    #### Limits

    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
    > An implementation may set limits on the range and precision of numbers.

    When the default type is used, the maximal integer number that can be
    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
    that are out of range will yield over/underflow when used in a constructor.
    During deserialization, too large or small integer numbers will be
    automatically be stored as @ref number_float_t.

    [RFC 7159](http://rfc7159.net/rfc7159) further states:
    > Note that when such software is used, numbers that are integers and are
    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
    > that implementations will agree exactly on their numeric values.

    As this range is a subrange of the exactly supported range [INT64_MIN,
    INT64_MAX], this class's integer type is interoperable.

    #### Storage

    Integer number values are stored directly inside a `basic_json` type.
    */
N
cleanup  
Niels 已提交
444
    using number_integer_t = NumberIntegerType;
N
Niels 已提交
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503

    /*!
    @brief a type for a number (floating-point)

    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
    > The representation of numbers is similar to that used in most programming
    > languages. A number is represented in base 10 using decimal digits. It
    > contains an integer component that may be prefixed with an optional minus
    > sign, which may be followed by a fraction part and/or an exponent part.
    > Leading zeros are not allowed. (...) Numeric values that cannot be
    > represented in the grammar below (such as Infinity and NaN) are not
    > permitted.

    This description includes both integer and floating-point numbers. However,
    C++ allows more precise storage if it is known whether the number is an
    integer or a floating-point number. Therefore, two different types, @ref
    number_integer_t and @ref number_float_t are used.

    To store floating-point numbers in C++, a type is defined by the template
    parameter @a NumberFloatType which chooses the type to use.

    #### Default type

    With the default values for @a NumberFloatType (`double`), the default
    value for @a number_float_t is:

    @code {.cpp}
    double
    @endcode

    #### Default behavior

    - The restrictions about leading zeros is not enforced in C++. Instead,
      leading zeros in floating-point literals will be ignored. Internally, the
      value will be stored as decimal number. For instance, the C++
      floating-point literal `01.2` will be serialized to `1.2`. During
      deserialization, leading zeros yield an error.
    - Not-a-number (NaN) values will be serialized to `null`.

    #### Limits

    [RFC 7159](http://rfc7159.net/rfc7159) states:
    > This specification allows implementations to set limits on the range and
    > precision of numbers accepted. Since software that implements IEEE
    > 754-2008 binary64 (double precision) numbers is generally available and
    > widely used, good interoperability can be achieved by implementations that
    > expect no more precision or range than these provide, in the sense that
    > implementations will approximate JSON numbers within the expected
    > precision.

    This implementation does exactly follow this approach, as it uses double
    precision floating-point numbers. Note values smaller than
    `-1.79769313486232e+308` and values greather than `1.79769313486232e+308`
    will be stored as NaN internally and be serialized to `null`.

    #### Storage

    Floating-point number values are stored directly inside a `basic_json` type.
    */
N
cleanup  
Niels 已提交
504 505
    using number_float_t = NumberFloatType;

N
Niels 已提交
506 507
    /// @}

N
cleanup  
Niels 已提交
508

N
Niels 已提交
509 510 511
    ///////////////////////////
    // JSON type enumeration //
    ///////////////////////////
N
Niels 已提交
512

N
Niels 已提交
513
    /*!
N
Niels 已提交
514
    @brief the JSON type enumeration
N
Niels 已提交
515

N
Niels 已提交
516 517 518
    This enumeration collects the different JSON types. It is internally used
    to distinguish the stored values, and the functions is_null, is_object,
    is_array, is_string, is_boolean, is_number, and is_discarded rely on it.
N
Niels 已提交
519
    */
N
Niels 已提交
520 521 522 523 524 525 526 527 528 529 530 531
    enum class value_t : uint8_t
    {
        null,           ///< null value
        object,         ///< object (unordered set of name/value pairs)
        array,          ///< array (ordered collection of values)
        string,         ///< string value
        boolean,        ///< boolean value
        number_integer, ///< number value (integer)
        number_float,   ///< number value (floating-point)
        discarded       ///< (internal) indicates the parser callback chose not to keep the value
    };

N
Niels 已提交
532

N
Niels 已提交
533
  private:
N
cleanup  
Niels 已提交
534 535 536 537 538 539 540 541 542 543 544 545 546
    ////////////////////////
    // JSON value storage //
    ////////////////////////

    /// a JSON value
    union json_value
    {
        /// object (stored with pointer to save storage)
        object_t* object;
        /// array (stored with pointer to save storage)
        array_t* array;
        /// string (stored with pointer to save storage)
        string_t* string;
N
Niels 已提交
547
        /// boolean
N
cleanup  
Niels 已提交
548 549 550
        boolean_t boolean;
        /// number (integer)
        number_integer_t number_integer;
N
Niels 已提交
551
        /// number (floating-point)
N
cleanup  
Niels 已提交
552 553 554
        number_float_t number_float;

        /// default constructor (for null values)
555
        json_value() noexcept = default;
N
cleanup  
Niels 已提交
556
        /// constructor for booleans
557
        json_value(boolean_t v) noexcept : boolean(v) {}
N
cleanup  
Niels 已提交
558
        /// constructor for numbers (integer)
559
        json_value(number_integer_t v) noexcept : number_integer(v) {}
N
Niels 已提交
560
        /// constructor for numbers (floating-point)
561
        json_value(number_float_t v) noexcept : number_float(v) {}
N
Niels 已提交
562
        /// constructor for empty values of a given type
563
        json_value(value_t t)
N
Niels 已提交
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
        {
            switch (t)
            {
                case (value_t::null):
                case (value_t::discarded):
                {
                    break;
                }

                case (value_t::object):
                {
                    AllocatorType<object_t> alloc;
                    object = alloc.allocate(1);
                    alloc.construct(object);
                    break;
                }
N
cleanup  
Niels 已提交
580

N
Niels 已提交
581 582 583 584 585 586 587
                case (value_t::array):
                {
                    AllocatorType<array_t> alloc;
                    array = alloc.allocate(1);
                    alloc.construct(array);
                    break;
                }
N
cleanup  
Niels 已提交
588

N
Niels 已提交
589 590 591 592 593 594 595
                case (value_t::string):
                {
                    AllocatorType<string_t> alloc;
                    string = alloc.allocate(1);
                    alloc.construct(string, "");
                    break;
                }
N
cleanup  
Niels 已提交
596

N
Niels 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
                case (value_t::boolean):
                {
                    boolean = boolean_t(false);
                    break;
                }

                case (value_t::number_integer):
                {
                    number_integer = number_integer_t(0);
                    break;
                }

                case (value_t::number_float):
                {
                    number_float = number_float_t(0.0);
                    break;
                }
            }
        }
N
Niels 已提交
616 617

        /// constructor for strings
618
        json_value(const string_t& value)
N
Niels 已提交
619 620 621 622 623 624 625
        {
            AllocatorType<string_t> alloc;
            string = alloc.allocate(1);
            alloc.construct(string, value);
        }

        /// constructor for objects
626
        json_value(const object_t& value)
N
Niels 已提交
627 628 629 630 631 632 633
        {
            AllocatorType<object_t> alloc;
            object = alloc.allocate(1);
            alloc.construct(object, value);
        }

        /// constructor for arrays
634
        json_value(const array_t& value)
N
Niels 已提交
635 636 637 638 639
        {
            AllocatorType<array_t> alloc;
            array = alloc.allocate(1);
            alloc.construct(array, value);
        }
N
cleanup  
Niels 已提交
640 641
    };

N
Niels 已提交
642 643

  public:
N
Niels 已提交
644 645 646 647
    //////////////////////////
    // JSON parser callback //
    //////////////////////////

N
Niels 已提交
648 649 650 651 652 653
    /*!
    @brief JSON callback events

    This enumeration lists the parser events that can trigger calling a
    callback function of type @ref parser_callback_t during parsing.
    */
N
Niels 已提交
654 655
    enum class parse_event_t : uint8_t
    {
N
Niels 已提交
656 657 658 659 660 661 662 663 664 665 666 667
        /// the parser read `{` and started to process a JSON object
        object_start,
        /// the parser read `}` and finished processing a JSON object
        object_end,
        /// the parser read `[` and started to process a JSON array
        array_start,
        /// the parser read `]` and finished processing a JSON array
        array_end,
        /// the parser read a key of a value in an object
        key,
        /// the parser finished reading a JSON value
        value
N
Niels 已提交
668 669
    };

N
Niels 已提交
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
    /*!
    @brief per-element parser callback type

    With a parser callback function, the result of parsing a JSON text can be
    influenced. When passed to @ref parse(std::istream&, parser_callback_t) or
    @ref parse(const string_t&, parser_callback_t), it is called on certain
    events (passed as @ref parse_event_t via parameter @a event) with a set
    recursion depth @a depth and context JSON value @a parsed. The return value
    of the callback function is a boolean indicating whether the element that
    emitted the callback shall be kept or not.

    We distinguish six scenarios (determined by the event type) in which the
    callback function can be called. The following table describes the values
    of the parameters @a depth, @a event, and @a parsed.

    parameter @a event | description | parameter @a depth | parameter @a parsed
    ------------------ | ----------- | ------------------ | -------------------
    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value

    Discarding a value (i.e., returning `false`) has different effects depending on the
    context in which function was called:

    - Discarded values in structured types are skipped. That is, the parser
      will behave as if the discarded value was never read.
    - In case a value outside a structured type is skipped, it is replaced with
      `null`. This case happens if the top-level element is skipped.

    @param[in] depth   the depth of the recursion during parsing

    @param[in] event   an event of type parse_event_t indicating the context in
    the callback function has been called

    @param[in,out] parsed  the current intermediate parse result; note that
    writing to this value has no effect for parse_event_t::key events

    @return Whether the JSON value which called the function during parsing
    should be kept (`true`) or not (`false`). In the latter case, it is either
    skipped completely or replaced by an empty discarded object.

    @sa @ref parse(std::istream&, parser_callback_t) or
    @ref parse(const string_t&, parser_callback_t) for examples
    */
    using parser_callback_t = std::function<bool(
                                  int depth, parse_event_t event, basic_json& parsed)>;
N
Niels 已提交
719

N
cleanup  
Niels 已提交
720 721 722 723 724

    //////////////////
    // constructors //
    //////////////////

N
Niels 已提交
725 726 727
    /*!
    @brief create an empty value with a given type

N
Niels 已提交
728 729 730 731 732
    Create an empty JSON value with a given type. The value will be default
    initialized with an empty value which depends on the type:

    Value type  | initial value
    ----------- | -------------
N
Niels 已提交
733 734 735 736 737 738
    null        | `null`
    boolean     | `false`
    string      | `""`
    number      | `0`
    object      | `{}`
    array       | `[]`
N
Niels 已提交
739

N
Niels 已提交
740
    @param[in] value  the type of the value to create
N
Niels 已提交
741 742 743

    @complexity Constant.

N
Niels 已提交
744
    @throw std::bad_alloc if allocation for object, array, or string value
N
Niels 已提交
745
    fails
N
Niels 已提交
746 747 748

    @liveexample{The following code shows the constructor for different @ref
    value_t values,basic_json__value_t}
N
Niels 已提交
749
    */
750
    basic_json(const value_t value)
N
Niels 已提交
751 752
        : m_type(value), m_value(value)
    {}
N
cleanup  
Niels 已提交
753

N
Niels 已提交
754 755
    /*!
    @brief create a null object (implicitly)
N
Niels 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768 769

    Create a `null` JSON value. This is the implicit version of the `null`
    value constructor as it takes no parameters.

    @complexity Constant.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.
    - As postcondition, it holds: `basic_json().empty() == true`.

    @liveexample{The following code shows the constructor for a `null` JSON
    value.,basic_json}

    @sa basic_json(std::nullptr_t)
N
Niels 已提交
770 771
    @ingroup container
    */
772
    basic_json() noexcept = default;
N
cleanup  
Niels 已提交
773

N
Niels 已提交
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    /*!
    @brief create a null object (explicitly)

    Create a `null` JSON value. This is the explicitly version of the `null`
    value constructor as it takes a null pointer as parameter. It allows to
    create `null` values by explicitly assigning a @c nullptr to a JSON value.
    The passed null pointer itself is not read - it is only used to choose the
    right constructor.

    @complexity Constant.

    @liveexample{The following code shows the constructor with null pointer
    parameter.,basic_json__nullptr_t}

    @sa basic_json()
    */
790
    basic_json(std::nullptr_t) noexcept
N
Niels 已提交
791
        : basic_json(value_t::null)
N
cleanup  
Niels 已提交
792 793
    {}

N
Niels 已提交
794 795 796 797 798
    /*!
    @brief create an object (explicit)

    Create an object JSON value with a given content.

N
Niels 已提交
799
    @param[in] value  a value for the object
N
Niels 已提交
800 801 802

    @complexity Linear in the size of the passed @a value.

N
Niels 已提交
803
    @throw std::bad_alloc if allocation for object value fails
N
Niels 已提交
804 805 806 807 808 809

    @liveexample{The following code shows the constructor with an @ref object_t
    parameter.,basic_json__object_t}

    @sa basic_json(const CompatibleObjectType&)
    */
810
    basic_json(const object_t& value)
N
Niels 已提交
811 812
        : m_type(value_t::object), m_value(value)
    {}
N
cleanup  
Niels 已提交
813

N
Niels 已提交
814 815 816 817 818 819 820 821 822 823
    /*!
    @brief create an object (implicit)

    Create an object JSON value with a given content. This constructor allows
    any type that can be used to construct values of type @ref object_t.
    Examples include the types `std::map` and `std::unordered_map`.

    @tparam CompatibleObjectType an object type whose `key_type` and
    `value_type` is compatible to @ref object_t

N
Niels 已提交
824
    @param[in] value  a value for the object
N
Niels 已提交
825 826 827

    @complexity Linear in the size of the passed @a value.

N
Niels 已提交
828
    @throw std::bad_alloc if allocation for object value fails
N
Niels 已提交
829 830 831 832 833 834 835

    @liveexample{The following code shows the constructor with several
    compatible object type parameters.,basic_json__CompatibleObjectType}

    @sa basic_json(const object_t&)
    */
    template <class CompatibleObjectType, typename
N
cleanup  
Niels 已提交
836
              std::enable_if<
N
Niels 已提交
837 838
                  std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
                  std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
N
cleanup  
Niels 已提交
839
              = 0>
N
Niels 已提交
840
    basic_json(const CompatibleObjectType& value)
N
Niels 已提交
841 842
        : m_type(value_t::object)
    {
N
Niels 已提交
843
        AllocatorType<object_t> alloc;
N
Niels 已提交
844
        m_value.object = alloc.allocate(1);
845 846 847
        using std::begin;
        using std::end;
        alloc.construct(m_value.object, begin(value), end(value));
N
Niels 已提交
848
    }
N
cleanup  
Niels 已提交
849

N
Niels 已提交
850 851 852 853 854
    /*!
    @brief create an array (explicit)

    Create an array JSON value with a given content.

N
Niels 已提交
855
    @param[in] value  a value for the array
N
Niels 已提交
856 857 858

    @complexity Linear in the size of the passed @a value.

N
Niels 已提交
859
    @throw std::bad_alloc if allocation for array value fails
N
Niels 已提交
860 861 862 863 864 865

    @liveexample{The following code shows the constructor with an @ref array_t
    parameter.,basic_json__array_t}

    @sa basic_json(const CompatibleArrayType&)
    */
866
    basic_json(const array_t& value)
N
Niels 已提交
867 868
        : m_type(value_t::array), m_value(value)
    {}
N
cleanup  
Niels 已提交
869

N
Niels 已提交
870 871 872 873 874 875 876 877 878 879
    /*!
    @brief create an array (implicit)

    Create an array JSON value with a given content. This constructor allows
    any type that can be used to construct values of type @ref array_t.
    Examples include the types `std::vector`, `std::list`, and `std::set`.

    @tparam CompatibleArrayType an object type whose `value_type` is compatible
    to @ref array_t

N
Niels 已提交
880
    @param[in] value  a value for the array
N
Niels 已提交
881 882 883

    @complexity Linear in the size of the passed @a value.

N
Niels 已提交
884
    @throw std::bad_alloc if allocation for array value fails
N
Niels 已提交
885 886 887 888 889 890 891

    @liveexample{The following code shows the constructor with several
    compatible array type parameters.,basic_json__CompatibleArrayType}

    @sa basic_json(const array_t&)
    */
    template <class CompatibleArrayType, typename
N
cleanup  
Niels 已提交
892
              std::enable_if<
N
Niels 已提交
893 894 895 896
                  not std::is_same<CompatibleArrayType, typename __basic_json::iterator>::value and
                  not std::is_same<CompatibleArrayType, typename __basic_json::const_iterator>::value and
                  not std::is_same<CompatibleArrayType, typename __basic_json::reverse_iterator>::value and
                  not std::is_same<CompatibleArrayType, typename __basic_json::const_reverse_iterator>::value and
N
Niels 已提交
897 898 899
                  not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
                  not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
                  std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
N
cleanup  
Niels 已提交
900
              = 0>
N
Niels 已提交
901
    basic_json(const CompatibleArrayType& value)
N
Niels 已提交
902 903
        : m_type(value_t::array)
    {
N
Niels 已提交
904
        AllocatorType<array_t> alloc;
N
Niels 已提交
905
        m_value.array = alloc.allocate(1);
906 907 908
        using std::begin;
        using std::end;
        alloc.construct(m_value.array, begin(value), end(value));
N
Niels 已提交
909
    }
N
cleanup  
Niels 已提交
910

N
Niels 已提交
911 912 913 914 915 916 917 918 919
    /*!
    @brief create a string (explicit)

    Create an string JSON value with a given content.

    @param[in] value  a value for the string

    @complexity Linear in the size of the passed @a value.

N
Niels 已提交
920
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
921 922 923 924 925 926 927

    @liveexample{The following code shows the constructor with an @ref string_t
    parameter.,basic_json__string_t}

    @sa basic_json(const typename string_t::value_type*)
    @sa basic_json(const CompatibleStringType&)
    */
928
    basic_json(const string_t& value)
N
Niels 已提交
929 930
        : m_type(value_t::string), m_value(value)
    {}
N
cleanup  
Niels 已提交
931

N
Niels 已提交
932 933 934
    /*!
    @brief create a string (explicit)

N
Niels 已提交
935
    Create a string JSON value with a given content.
N
Niels 已提交
936 937 938 939 940

    @param[in] value  a literal value for the string

    @complexity Linear in the size of the passed @a value.

N
Niels 已提交
941
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
942 943 944 945 946 947 948

    @liveexample{The following code shows the constructor with string literal
    parameter.,basic_json__string_t_value_type}

    @sa basic_json(const string_t&)
    @sa basic_json(const CompatibleStringType&)
    */
949
    basic_json(const typename string_t::value_type* value)
N
Niels 已提交
950 951
        : basic_json(string_t(value))
    {}
N
cleanup  
Niels 已提交
952

N
Niels 已提交
953 954 955 956 957 958 959 960 961 962 963 964
    /*!
    @brief create a string (implicit)

    Create a string JSON value with a given content.

    @param[in] value  a value for the string

    @tparam CompatibleStringType an string type which is compatible to @ref
    string_t

    @complexity Linear in the size of the passed @a value.

N
Niels 已提交
965
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
966 967 968 969 970 971

    @liveexample{The following code shows the construction of a string value
    from a compatible type.,basic_json__CompatibleStringType}

    @sa basic_json(const string_t&)
    */
N
Niels 已提交
972
    template <class CompatibleStringType, typename
N
cleanup  
Niels 已提交
973
              std::enable_if<
N
Niels 已提交
974
                  std::is_constructible<string_t, CompatibleStringType>::value, int>::type
N
cleanup  
Niels 已提交
975
              = 0>
N
Niels 已提交
976
    basic_json(const CompatibleStringType& value)
N
cleanup  
Niels 已提交
977 978 979
        : basic_json(string_t(value))
    {}

N
Niels 已提交
980 981 982 983 984 985 986 987 988 989 990 991
    /*!
    @brief create a boolean (explicit)

    Creates a JSON boolean type from a given value.

    @param[in] value  a boolean value to store

    @complexity Constant.

    @liveexample{The example below demonstrates boolean
    values.,basic_json__boolean_t}
    */
992
    basic_json(boolean_t value)
N
cleanup  
Niels 已提交
993 994 995
        : m_type(value_t::boolean), m_value(value)
    {}

N
Niels 已提交
996 997 998
    /*!
    @brief create an integer number (explicit)

N
Niels 已提交
999 1000 1001 1002 1003
    Create an interger number JSON value with a given content.

    @tparam T  helper type to compare number_integer_t and int (not visible in)
    the interface.

N
Niels 已提交
1004
    @param[in] value  an integer to create a JSON number from
N
Niels 已提交
1005

N
Niels 已提交
1006 1007 1008 1009 1010 1011
    @note This constructor would have the same signature as @ref
    basic_json(const int value), so we need to switch this one off in case
    number_integer_t is the same as int. This is done via the helper type @a T.

    @complexity Constant.

N
Niels 已提交
1012 1013
    @liveexample{The example below shows the construction of a JSON integer
    number value.,basic_json__number_integer_t}
N
Niels 已提交
1014 1015

    @sa basic_json(const int)
N
Niels 已提交
1016 1017 1018 1019 1020 1021 1022
    */
    template<typename T,
             typename std::enable_if<
                 not (std::is_same<T, int>::value)
                 and std::is_same<T, number_integer_t>::value
                 , int>::type = 0>
    basic_json(const number_integer_t value)
N
cleanup  
Niels 已提交
1023 1024 1025
        : m_type(value_t::number_integer), m_value(value)
    {}

N
Niels 已提交
1026
    /*!
N
Niels 已提交
1027 1028
    @brief create an integer number from an enum type (explicit)

N
Niels 已提交
1029
    Create an integer number JSON value with a given content.
N
Niels 已提交
1030

N
Niels 已提交
1031
    @param[in] value  an integer to create a JSON number from
N
Niels 已提交
1032

N
Niels 已提交
1033 1034 1035 1036 1037 1038 1039 1040 1041
    @note This constructor allows to pass enums directly to a constructor. As
    C++ has no way of specifying the type of an anonymous enum explicitly, we
    can only rely on the fact that such values implicitly convert to int. As
    int may already be the same type of number_integer_t, we may need to switch
    off the constructor @ref basic_json(const number_integer_t).

    @complexity Constant.

    @liveexample{The example below shows the construction of a JSON integer
N
Niels 已提交
1042
    number value from an anonymous enum.,basic_json__const_int}
N
Niels 已提交
1043 1044

    @sa basic_json(const number_integer_t)
N
Niels 已提交
1045 1046 1047 1048
    */
    basic_json(const int value)
        : m_type(value_t::number_integer),
          m_value(static_cast<number_integer_t>(value))
N
Niels 已提交
1049 1050
    {}

N
Niels 已提交
1051 1052 1053
    /*!
    @brief create an integer number (implicit)

N
Niels 已提交
1054
    Create an integer number JSON value with a given content. This constructor
N
Niels 已提交
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
    allows any type that can be used to construct values of type @ref
    number_integer_t. Examples may include the types `int`, `int32_t`, or
    `short`.

    @tparam CompatibleNumberIntegerType an integer type which is compatible to
    @ref number_integer_t.

    @param[in] value  an integer to create a JSON number from

    @complexity Constant.

    @liveexample{The example below shows the construction of several JSON
    integer number values from compatible
    types.,basic_json__CompatibleIntegerNumberType}

    @sa basic_json(const number_integer_t)
    */
    template<typename CompatibleNumberIntegerType, typename
N
cleanup  
Niels 已提交
1073
             std::enable_if<
N
Niels 已提交
1074 1075
                 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
N
cleanup  
Niels 已提交
1076
             = 0>
N
Niels 已提交
1077
    basic_json(const CompatibleNumberIntegerType value) noexcept
N
Niels 已提交
1078 1079
        : m_type(value_t::number_integer),
          m_value(static_cast<number_integer_t>(value))
N
cleanup  
Niels 已提交
1080 1081
    {}

N
Niels 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
    /*!
    @brief create a floating-point number (explicit)

    Create a floating-point number JSON value with a given content.

    @param[in] value  a floating-point value to create a JSON number from

    @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
    disallows NaN values:
    > Numeric values that cannot be represented in the grammar below (such
    > as Infinity and NaN) are not permitted.
    In case the parameter @a value is not a number, a JSON null value is
    created instead.

N
Niels 已提交
1096
    @complexity Constant.
N
Niels 已提交
1097 1098 1099 1100

    @liveexample{The following example creates several floating-point
    values.,basic_json__number_float_t}
    */
N
Niels 已提交
1101
    basic_json(const number_float_t value)
N
cleanup  
Niels 已提交
1102
        : m_type(value_t::number_float), m_value(value)
N
Niels 已提交
1103 1104 1105 1106 1107 1108 1109 1110
    {
        // replace infinity and NAN by null
        if (not std::isfinite(value))
        {
            m_type = value_t::null;
            m_value = json_value();
        }
    }
N
cleanup  
Niels 已提交
1111

N
Niels 已提交
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
    /*!
    @brief create an floating-point number (implicit)

    Create an floating-point number JSON value with a given content. This
    constructor allows any type that can be used to construct values of type
    @ref number_float_t. Examples may include the types `float`.

    @tparam CompatibleNumberFloatType a floating-point type which is compatible
    to @ref number_float_t.

    @param[in] value  a floating-point to create a JSON number from

    @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
    disallows NaN values:
    > Numeric values that cannot be represented in the grammar below (such
    > as Infinity and NaN) are not permitted.
    In case the parameter @a value is not a number, a JSON null value is
    created instead.

    @complexity Constant.

    @liveexample{The example below shows the construction of several JSON
    floating-point number values from compatible
    types.,basic_json__CompatibleNumberFloatType}

    @sa basic_json(const number_float_t)
    */
N
Niels 已提交
1139
    template<typename CompatibleNumberFloatType, typename = typename
N
cleanup  
Niels 已提交
1140
             std::enable_if<
N
Niels 已提交
1141 1142
                 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
                 std::is_floating_point<CompatibleNumberFloatType>::value>::type
N
cleanup  
Niels 已提交
1143
             >
N
Niels 已提交
1144
    basic_json(const CompatibleNumberFloatType value) noexcept
N
Niels 已提交
1145 1146
        : basic_json(number_float_t(value))
    {}
N
cleanup  
Niels 已提交
1147

N
Niels 已提交
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
    /*!
    @brief create a container (array or object) from an initializer list

    Creates a JSON value of type array or object from the passed initializer
    list @a init. In case @a type_deduction is `true` (default), the type of
    the JSON value to be created is deducted from the initializer list @a init
    according to the following rules:

    1. If the list is empty, an empty JSON object value `{}` is created.
    2. If the list consists of pairs whose first element is a string, a JSON
    object value is created where the first elements of the pairs are treated
    as keys and the second elements are as values.
    3. In all other cases, an array is created.

    The rules aim to create the best fit between a C++ initializer list and
    JSON values. The ratioinale is as follows:

    1. The empty initializer list is written as `{}` which is exactly an empty
    JSON object.
    2. C++ has now way of describing mapped types other than to list a list of
    pairs. As JSON requires that keys must be of type string, rule 2 is the
    weakest constraint one can pose on initializer lists to interpret them as
    an object.
    3. In all other cases, the initializer list could not be interpreted as
    JSON object type, so interpreting it as JSON array type is safe.

N
Niels 已提交
1174 1175
    With the rules described above, the following JSON values cannot be
    expressed by an initializer list:
N
Niels 已提交
1176

N
Niels 已提交
1177 1178 1179 1180 1181
    - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>)
      with an empty initializer list in this case
    - arrays whose elements satisfy rule 2: use @ref
      array(std::initializer_list<basic_json>) with the same initializer list
      in this case
N
Niels 已提交
1182 1183 1184 1185 1186

    @note When used without parentheses around an empty initializer list, @ref
    basic_json() is called instead of this function, yielding the JSON null
    value.

N
Niels 已提交
1187
    @param[in] init  initializer list with JSON values
N
Niels 已提交
1188

N
Niels 已提交
1189 1190 1191
    @param[in] type_deduction internal parameter; when set to `true`, the type
    of the JSON value is deducted from the initializer list @a init; when set
    to `false`, the type provided via @a manual_type is forced. This mode is
N
Niels 已提交
1192 1193
    used by the functions @ref array(std::initializer_list<basic_json>) and
    @ref object(std::initializer_list<basic_json>).
N
Niels 已提交
1194

N
Niels 已提交
1195
    @param[in] manual_type internal parameter; when @a type_deduction is set to
N
Niels 已提交
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
    `false`, the created JSON value will use the provided type (only @ref
    value_t::array and @ref value_t::object are valid); when @a type_deduction
    is set to `true`, this parameter has no effect

    @throw std::domain_error if @a type_deduction is `false`, @a manual_type is
    `value_t::object`, but @a init contains an element which is not a pair
    whose first element is a string

    @complexity Linear in the size of the initializer list @a init.

    @liveexample{The example below shows how JSON values are created from
    initializer lists,basic_json__list_init_t}

N
Niels 已提交
1209 1210 1211 1212
    @sa basic_json array(std::initializer_list<basic_json>) - create a JSON
    array value from an initializer list
    @sa basic_json object(std::initializer_list<basic_json>) - create a JSON
    object value from an initializer list
N
Niels 已提交
1213
    */
N
Niels 已提交
1214 1215
    basic_json(std::initializer_list<basic_json> init,
               bool type_deduction = true,
N
Niels 已提交
1216
               value_t manual_type = value_t::array)
N
cleanup  
Niels 已提交
1217 1218 1219 1220
    {
        // the initializer list could describe an object
        bool is_object = true;

N
Niels 已提交
1221 1222
        // check if each element is an array with two elements whose first element
        // is a string
N
Niels 已提交
1223
        for (const auto& element : init)
N
cleanup  
Niels 已提交
1224
        {
N
Niels 已提交
1225 1226
            if (element.m_type != value_t::array or element.size() != 2
                    or element[0].m_type != value_t::string)
N
cleanup  
Niels 已提交
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
            {
                // we found an element that makes it impossible to use the
                // initializer list as object
                is_object = false;
                break;
            }
        }

        // adjust type if type deduction is not wanted
        if (not type_deduction)
        {
            // if array is wanted, do not create an object though possible
            if (manual_type == value_t::array)
            {
                is_object = false;
            }

            // if object is wanted but impossible, throw an exception
            if (manual_type == value_t::object and not is_object)
            {
N
Niels 已提交
1247
                throw std::domain_error("cannot create object from initializer list");
N
cleanup  
Niels 已提交
1248 1249 1250 1251 1252 1253 1254
            }
        }

        if (is_object)
        {
            // the initializer list is a list of pairs -> create object
            m_type = value_t::object;
N
Niels 已提交
1255
            m_value = value_t::object;
N
Niels 已提交
1256

N
Niels 已提交
1257
            for (auto& element : init)
N
cleanup  
Niels 已提交
1258 1259 1260 1261 1262 1263 1264 1265
            {
                m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1]));
            }
        }
        else
        {
            // the initializer list describes an array -> create array
            m_type = value_t::array;
N
Niels 已提交
1266
            AllocatorType<array_t> alloc;
N
Niels 已提交
1267
            m_value.array = alloc.allocate(1);
N
Niels 已提交
1268
            alloc.construct(m_value.array, std::move(init));
N
cleanup  
Niels 已提交
1269 1270 1271
        }
    }

N
Niels 已提交
1272 1273 1274 1275 1276 1277 1278 1279 1280
    /*!
    @brief explicitly create an array from an initializer list

    Creates a JSON array value from a given initializer list. That is, given a
    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
    initializer list is empty, the empty array `[]` is created.

    @note This function is only needed to express two edge cases that cannot be
    realized with the initializer list constructor (@ref
N
Niels 已提交
1281 1282
    basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
    are:
N
Niels 已提交
1283 1284 1285 1286 1287 1288
    1. creating an array whose elements are all pairs whose first element is a
    string - in this case, the initializer list constructor would create an
    object, taking the first elements as keys
    2. creating an empty array - passing the empty initializer list to the
    initializer list constructor yields an empty object

N
Niels 已提交
1289
    @param[in] init  initializer list with JSON values to create an array from
N
Niels 已提交
1290 1291 1292 1293 1294 1295 1296 1297 1298
    (optional)

    @return JSON array value

    @complexity Linear in the size of @a init.

    @liveexample{The following code shows an example for the @ref array
    function.,array}

N
Niels 已提交
1299 1300 1301 1302
    @sa basic_json(std::initializer_list<basic_json>, bool, value_t) - create a
    JSON value from an initializer list
    @sa basic_json object(std::initializer_list<basic_json>) - create a JSON
    object value from an initializer list
N
Niels 已提交
1303
    */
N
Niels 已提交
1304 1305
    static basic_json array(std::initializer_list<basic_json> init =
                                std::initializer_list<basic_json>())
N
cleanup  
Niels 已提交
1306
    {
N
Niels 已提交
1307
        return basic_json(init, false, value_t::array);
N
cleanup  
Niels 已提交
1308 1309
    }

N
Niels 已提交
1310 1311 1312 1313 1314 1315 1316 1317
    /*!
    @brief explicitly create an object from an initializer list

    Creates a JSON object value from a given initializer list. The initializer
    lists elements must be pairs, and their first elments must be strings. If
    the initializer list is empty, the empty object `{}` is created.

    @note This function is only added for symmetry reasons. In contrast to the
N
Niels 已提交
1318 1319 1320 1321 1322
    related function @ref basic_json array(std::initializer_list<basic_json>),
    there are no cases which can only be expressed by this function. That is,
    any initializer list @a init can also be passed to the initializer list
    constructor @ref basic_json(std::initializer_list<basic_json>, bool,
    value_t).
N
Niels 已提交
1323

N
Niels 已提交
1324
    @param[in] init  initializer list to create an object from (optional)
N
Niels 已提交
1325 1326 1327 1328

    @return JSON object value

    @throw std::domain_error if @a init is not a pair whose first elements are
N
Niels 已提交
1329 1330
    strings; thrown by @ref basic_json(std::initializer_list<basic_json>, bool,
    value_t)
N
Niels 已提交
1331 1332 1333 1334 1335 1336

    @complexity Linear in the size of @a init.

    @liveexample{The following code shows an example for the @ref object
    function.,object}

N
Niels 已提交
1337 1338 1339 1340
    @sa basic_json(std::initializer_list<basic_json>, bool, value_t) - create a
    JSON value from an initializer list
    @sa basic_json array(std::initializer_list<basic_json>) - create a JSON
    array value from an initializer list
N
Niels 已提交
1341
    */
N
Niels 已提交
1342 1343
    static basic_json object(std::initializer_list<basic_json> init =
                                 std::initializer_list<basic_json>())
N
cleanup  
Niels 已提交
1344
    {
N
Niels 已提交
1345
        return basic_json(init, false, value_t::object);
N
cleanup  
Niels 已提交
1346 1347
    }

N
Niels 已提交
1348 1349 1350 1351 1352 1353 1354
    /*!
    @brief construct an array with count copies of given value

    Constructs a JSON array value by creating @a count copies of a passed
    value. In case @a count is `0`, an empty array is created. As postcondition,
    `std::distance(begin(),end()) == count` holds.

N
Niels 已提交
1355 1356
    @param[in] count  the number of JSON copies of @a value to create
    @param[in] value  the JSON value to copy
N
Niels 已提交
1357 1358 1359 1360 1361 1362 1363 1364

    @complexity Linear in @a count.

    @liveexample{The following code shows examples for the @ref
    basic_json(size_type\, const basic_json&)
    constructor.,basic_json__size_type_basic_json}
    */
    basic_json(size_type count, const basic_json& value)
N
Niels 已提交
1365 1366 1367 1368
        : m_type(value_t::array)
    {
        AllocatorType<array_t> alloc;
        m_value.array = alloc.allocate(1);
N
Niels 已提交
1369
        alloc.construct(m_value.array, count, value);
N
Niels 已提交
1370
    }
N
Niels 已提交
1371

N
Niels 已提交
1372 1373 1374 1375 1376
    /*!
    @brief construct a JSON container given an iterator range

    Constructs the JSON value with the contents of the range `[first, last)`.
    The semantics depends on the different types a JSON value can have:
N
Niels 已提交
1377
    - In case of primitive types (number, boolean, or string), @a first must
N
Niels 已提交
1378 1379
      be `begin()` and @a last must be `end()`. In this case, the value is
      copied. Otherwise, std::out_of_range is thrown.
N
Niels 已提交
1380
    - In case of structured types (array, object), the constructor behaves
N
Niels 已提交
1381
      as similar versions for `std::vector`.
N
Niels 已提交
1382
    - In case of a null type, std::domain_error is thrown.
N
Niels 已提交
1383 1384 1385 1386 1387 1388 1389 1390 1391

    @tparam InputIT an input iterator type (@ref iterator or @ref
    const_iterator)

    @param[in] first begin of the range to copy from (included)
    @param[in] last end of the range to copy from (excluded)

    @throw std::domain_error if iterators are not compatible; that is, do not
    belong to the same JSON value
N
Niels 已提交
1392
    @throw std::out_of_range if iterators are for a primitive type (number,
N
Niels 已提交
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
    boolean, or string) where an out of range error can be detected easily
    @throw std::bad_alloc if allocation for object, array, or string fails
    @throw std::domain_error if called with a null value

    @complexity Linear in distance between @a first and @a last.

    @liveexample{The example below shows several ways to create JSON values by
    specifying a subrange with iterators.,basic_json__InputIt_InputIt}
    */
    template <class InputIT, typename
N
Niels 已提交
1403
              std::enable_if<
N
Niels 已提交
1404 1405
                  std::is_same<InputIT, typename __basic_json::iterator>::value or
                  std::is_same<InputIT, typename __basic_json::const_iterator>::value
N
Niels 已提交
1406 1407
                  , int>::type
              = 0>
N
Niels 已提交
1408
    basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
N
Niels 已提交
1409 1410
    {
        // make sure iterator fits the current value
N
Niels 已提交
1411
        if (first.m_object != last.m_object)
N
Niels 已提交
1412
        {
N
Niels 已提交
1413
            throw std::domain_error("iterators are not compatible");
N
Niels 已提交
1414 1415
        }

N
Niels 已提交
1416
        // check if iterator range is complete for primitive values
N
Niels 已提交
1417 1418 1419 1420 1421 1422 1423
        switch (m_type)
        {
            case value_t::number_integer:
            case value_t::number_float:
            case value_t::boolean:
            case value_t::string:
            {
1424
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
N
Niels 已提交
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
                {
                    throw std::out_of_range("iterators out of range");
                }
                break;
            }

            default:
            {
                break;
            }
        }

        switch (m_type)
        {
            case value_t::number_integer:
            {
                m_value.number_integer = first.m_object->m_value.number_integer;
                break;
            }

            case value_t::number_float:
            {
                m_value.number_float = first.m_object->m_value.number_float;
                break;
            }

            case value_t::boolean:
            {
                m_value.boolean = first.m_object->m_value.boolean;
                break;
            }

            case value_t::string:
            {
N
Niels 已提交
1459
                m_value = *first.m_object->m_value.string;
N
Niels 已提交
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
                break;
            }

            case value_t::object:
            {
                AllocatorType<object_t> alloc;
                m_value.object = alloc.allocate(1);
                alloc.construct(m_value.object, first.m_it.object_iterator, last.m_it.object_iterator);
                break;
            }

            case value_t::array:
            {
                AllocatorType<array_t> alloc;
                m_value.array = alloc.allocate(1);
                alloc.construct(m_value.array, first.m_it.array_iterator, last.m_it.array_iterator);
                break;
            }

            default:
            {
N
Niels 已提交
1481
                throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
N
Niels 已提交
1482 1483 1484 1485
            }
        }
    }

N
cleanup  
Niels 已提交
1486 1487 1488 1489
    ///////////////////////////////////////
    // other constructors and destructor //
    ///////////////////////////////////////

N
Niels 已提交
1490 1491
    /*!
    @brief copy constructor
N
Niels 已提交
1492

N
Niels 已提交
1493 1494
    Creates a copy of a given JSON value.

N
Niels 已提交
1495
    @param[in] other  the JSON value to copy
N
Niels 已提交
1496 1497 1498 1499 1500 1501 1502

    @complexity Linear in the size of @a other.

    @requirement This function satisfies the Container requirements:
    - The complexity is linear.
    - As postcondition, it holds: `other == basic_json(other)`.

N
Niels 已提交
1503
    @throw std::bad_alloc if allocation for object, array, or string fails.
N
Niels 已提交
1504 1505 1506

    @liveexample{The following code shows an example for the copy
    constructor.,basic_json__basic_json}
N
Niels 已提交
1507

N
Niels 已提交
1508 1509
    @ingroup container
    */
1510
    basic_json(const basic_json& other)
N
cleanup  
Niels 已提交
1511 1512 1513 1514 1515
        : m_type(other.m_type)
    {
        switch (m_type)
        {
            case (value_t::null):
N
Niels 已提交
1516
            case (value_t::discarded):
N
cleanup  
Niels 已提交
1517 1518 1519
            {
                break;
            }
N
Niels 已提交
1520

N
cleanup  
Niels 已提交
1521 1522
            case (value_t::object):
            {
N
Niels 已提交
1523
                m_value = *other.m_value.object;
N
cleanup  
Niels 已提交
1524 1525
                break;
            }
N
Niels 已提交
1526

N
cleanup  
Niels 已提交
1527 1528
            case (value_t::array):
            {
N
Niels 已提交
1529
                m_value = *other.m_value.array;
N
cleanup  
Niels 已提交
1530 1531
                break;
            }
N
Niels 已提交
1532

N
cleanup  
Niels 已提交
1533 1534
            case (value_t::string):
            {
N
Niels 已提交
1535
                m_value = *other.m_value.string;
N
cleanup  
Niels 已提交
1536 1537
                break;
            }
N
Niels 已提交
1538

N
cleanup  
Niels 已提交
1539 1540
            case (value_t::boolean):
            {
N
Niels 已提交
1541
                m_value = other.m_value.boolean;
N
cleanup  
Niels 已提交
1542 1543
                break;
            }
N
Niels 已提交
1544

N
cleanup  
Niels 已提交
1545 1546
            case (value_t::number_integer):
            {
N
Niels 已提交
1547
                m_value = other.m_value.number_integer;
N
cleanup  
Niels 已提交
1548 1549
                break;
            }
N
Niels 已提交
1550

N
cleanup  
Niels 已提交
1551 1552
            case (value_t::number_float):
            {
N
Niels 已提交
1553
                m_value = other.m_value.number_float;
N
cleanup  
Niels 已提交
1554 1555 1556 1557 1558
                break;
            }
        }
    }

N
Niels 已提交
1559 1560 1561 1562 1563 1564 1565
    /*!
    @brief move constructor

    Move constructor. Constructs a JSON value with the contents of the given
    value @a other using move semantics. It "steals" the resources from @a
    other and leaves it as JSON null value.

N
Niels 已提交
1566
    @param[in,out] other  value to move to this object
N
Niels 已提交
1567 1568 1569 1570 1571 1572 1573 1574

    @post @a other is a JSON null value

    @complexity Constant.

    @liveexample{The code below shows the move constructor explicitly called
    via std::move.,basic_json__moveconstructor}
    */
1575
    basic_json(basic_json&& other) noexcept
N
cleanup  
Niels 已提交
1576 1577 1578
        : m_type(std::move(other.m_type)),
          m_value(std::move(other.m_value))
    {
N
Niels 已提交
1579
        // invalidate payload
N
cleanup  
Niels 已提交
1580 1581 1582 1583
        other.m_type = value_t::null;
        other.m_value = {};
    }

N
Niels 已提交
1584 1585
    /*!
    @brief copy assignment
N
Niels 已提交
1586

N
Niels 已提交
1587 1588 1589 1590
    Copy assignment operator. Copies a JSON value via the "copy and swap"
    strategy: It is expressed in terms of the copy constructor, destructor, and
    the swap() member function.

N
Niels 已提交
1591
    @param[in] other  value to copy from
N
Niels 已提交
1592 1593 1594 1595 1596 1597

    @complexity Linear.

    @requirement This function satisfies the Container requirements:
    - The complexity is linear.

N
Niels 已提交
1598 1599 1600 1601 1602
    @liveexample{The code below shows and example for the copy assignment. It
    creates a copy of value `a` which is then swapped with `b`. Finally\, the
    copy of `a` (which is the null value after the swap) is
    destroyed.,basic_json__copyassignment}

N
Niels 已提交
1603 1604
    @ingroup container
    */
1605
    reference& operator=(basic_json other) noexcept (
N
Niels 已提交
1606 1607 1608 1609 1610
        std::is_nothrow_move_constructible<value_t>::value and
        std::is_nothrow_move_assignable<value_t>::value and
        std::is_nothrow_move_constructible<json_value>::value and
        std::is_nothrow_move_assignable<json_value>::value
    )
N
cleanup  
Niels 已提交
1611
    {
N
Niels 已提交
1612
        using std::swap;
N
cleanup  
Niels 已提交
1613 1614 1615 1616 1617
        std::swap(m_type, other.m_type);
        std::swap(m_value, other.m_value);
        return *this;
    }

N
Niels 已提交
1618 1619
    /*!
    @brief destructor
N
Niels 已提交
1620

N
Niels 已提交
1621
    Destroys the JSON value and frees all allocated memory.
N
Niels 已提交
1622 1623 1624 1625 1626 1627 1628

    @complexity Linear.

    @requirement This function satisfies the Container requirements:
    - The complexity is linear.
    - All stored elements are destroyed and all memory is freed.

N
Niels 已提交
1629 1630
    @ingroup container
    */
N
Niels 已提交
1631
    ~basic_json()
N
cleanup  
Niels 已提交
1632 1633 1634 1635 1636
    {
        switch (m_type)
        {
            case (value_t::object):
            {
N
Niels 已提交
1637
                AllocatorType<object_t> alloc;
N
Niels 已提交
1638 1639
                alloc.destroy(m_value.object);
                alloc.deallocate(m_value.object, 1);
N
cleanup  
Niels 已提交
1640 1641 1642
                m_value.object = nullptr;
                break;
            }
N
Niels 已提交
1643

N
cleanup  
Niels 已提交
1644 1645
            case (value_t::array):
            {
N
Niels 已提交
1646
                AllocatorType<array_t> alloc;
N
Niels 已提交
1647 1648
                alloc.destroy(m_value.array);
                alloc.deallocate(m_value.array, 1);
N
cleanup  
Niels 已提交
1649 1650 1651
                m_value.array = nullptr;
                break;
            }
N
Niels 已提交
1652

N
cleanup  
Niels 已提交
1653 1654
            case (value_t::string):
            {
N
Niels 已提交
1655
                AllocatorType<string_t> alloc;
N
Niels 已提交
1656
                alloc.destroy(m_value.string);
N
Niels 已提交
1657
                alloc.deallocate(m_value.string, 1);
N
cleanup  
Niels 已提交
1658 1659 1660
                m_value.string = nullptr;
                break;
            }
N
Niels 已提交
1661 1662

            default:
N
cleanup  
Niels 已提交
1663
            {
N
Niels 已提交
1664
                // all other types need no specific destructor
N
cleanup  
Niels 已提交
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
                break;
            }
        }
    }


  public:
    ///////////////////////
    // object inspection //
    ///////////////////////

N
Niels 已提交
1676 1677 1678
    /// @name object inspection
    /// @{

N
cleanup  
Niels 已提交
1679
    /*!
N
Niels 已提交
1680 1681
    @brief serialization

N
Niels 已提交
1682
    Serialization function for JSON values. The function tries to mimick
N
Niels 已提交
1683 1684
    Python's @p json.dumps() function, and currently supports its @p indent
    parameter.
N
cleanup  
Niels 已提交
1685

N
Niels 已提交
1686
    @param[in] indent if indent is nonnegative, then array elements and object
N
Niels 已提交
1687 1688 1689
    members will be pretty-printed with that indent level. An indent level of 0
    will only insert newlines. -1 (the default) selects the most compact
    representation
N
cleanup  
Niels 已提交
1690

N
Niels 已提交
1691 1692 1693 1694 1695 1696 1697
    @return string containing the serialization of the JSON value

    @complexity Linear.

    @liveexample{The following example shows the effect of different @a indent
    parameters to the result of the serializaion.,dump}

N
cleanup  
Niels 已提交
1698 1699
    @see https://docs.python.org/2/library/json.html#json.dump
    */
N
Niels 已提交
1700
    string_t dump(const int indent = -1) const
N
cleanup  
Niels 已提交
1701
    {
N
Niels 已提交
1702 1703
        std::stringstream ss;

N
cleanup  
Niels 已提交
1704 1705
        if (indent >= 0)
        {
N
Niels 已提交
1706
            dump(ss, true, static_cast<unsigned int>(indent));
N
cleanup  
Niels 已提交
1707 1708 1709
        }
        else
        {
N
Niels 已提交
1710
            dump(ss, false, 0);
N
cleanup  
Niels 已提交
1711
        }
N
Niels 已提交
1712 1713

        return ss.str();
N
cleanup  
Niels 已提交
1714 1715
    }

N
Niels 已提交
1716 1717 1718 1719 1720 1721 1722
    /*!
    @brief return the type of the JSON value (explicit)

    Return the type of the JSON value as a value from the @ref value_t
    enumeration.

    @return the type of the JSON value
N
Niels 已提交
1723 1724 1725 1726 1727

    @complexity Constant.

    @liveexample{The following code exemplifies @ref type() for all JSON
    types.,type}
N
Niels 已提交
1728
    */
1729
    value_t type() const noexcept
N
cleanup  
Niels 已提交
1730 1731 1732 1733
    {
        return m_type;
    }

N
Niels 已提交
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770
    /*!
    @brief return whether type is primitive

    This function returns true iff the JSON type is primitive (string, number,
    boolean, or null).

    @return `true` if type is primitive (string, number, boolean, or null),
    `false` otherwise.

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_primitive for all JSON
    types.,is_primitive}
    */
    bool is_primitive() const noexcept
    {
        return is_null() or is_string() or is_boolean() or is_number();
    }

    /*!
    @brief return whether type is structured

    This function returns true iff the JSON type is structured (array or
    object).

    @return `true` if type is structured (array or object), `false` otherwise.

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_structured for all JSON
    types.,is_structured}
    */
    bool is_structured() const noexcept
    {
        return is_array() or is_object();
    }

N
Niels 已提交
1771 1772 1773 1774 1775
    /*!
    @brief return whether value is null

    This function returns true iff the JSON value is null.

N
Niels 已提交
1776
    @return `true` if type is null, `false` otherwise.
N
Niels 已提交
1777 1778 1779 1780

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_null for all JSON
N
Niels 已提交
1781
    types.,is_null}
N
Niels 已提交
1782
    */
1783
    bool is_null() const noexcept
N
Niels 已提交
1784 1785 1786 1787
    {
        return m_type == value_t::null;
    }

N
Niels 已提交
1788 1789 1790 1791 1792
    /*!
    @brief return whether value is a boolean

    This function returns true iff the JSON value is a boolean.

N
Niels 已提交
1793
    @return `true` if type is boolean, `false` otherwise.
N
Niels 已提交
1794 1795 1796 1797

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_boolean for all JSON
N
Niels 已提交
1798
    types.,is_boolean}
N
Niels 已提交
1799
    */
1800
    bool is_boolean() const noexcept
N
Niels 已提交
1801 1802 1803 1804
    {
        return m_type == value_t::boolean;
    }

N
Niels 已提交
1805 1806 1807 1808 1809 1810
    /*!
    @brief return whether value is a number

    This function returns true iff the JSON value is a number. This includes
    both integer and floating-point values.

N
Niels 已提交
1811
    @return `true` if type is number, `false` otherwise.
N
Niels 已提交
1812 1813 1814 1815

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number for all JSON
N
Niels 已提交
1816
    types.,is_number}
N
Niels 已提交
1817
    */
1818
    bool is_number() const noexcept
N
Niels 已提交
1819
    {
N
Niels 已提交
1820
        return is_number_integer() or is_number_float();
N
Niels 已提交
1821 1822
    }

N
Niels 已提交
1823 1824 1825 1826 1827 1828
    /*!
    @brief return whether value is an integer number

    This function returns true iff the JSON value is an integer number. This
    excludes floating-point values.

N
Niels 已提交
1829
    @return `true` if type is an integer number, `false` otherwise.
N
Niels 已提交
1830 1831 1832 1833

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number_integer for all
N
Niels 已提交
1834
    JSON types.,is_number_integer}
N
Niels 已提交
1835
    */
N
Niels 已提交
1836 1837 1838 1839 1840
    bool is_number_integer() const noexcept
    {
        return m_type == value_t::number_integer;
    }

N
Niels 已提交
1841 1842 1843 1844 1845 1846
    /*!
    @brief return whether value is a floating-point number

    This function returns true iff the JSON value is a floating-point number.
    This excludes integer values.

N
Niels 已提交
1847
    @return `true` if type is a floating-point number, `false` otherwise.
N
Niels 已提交
1848 1849 1850 1851

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number_float for all
N
Niels 已提交
1852
    JSON types.,is_number_float}
N
Niels 已提交
1853
    */
N
Niels 已提交
1854 1855 1856 1857 1858
    bool is_number_float() const noexcept
    {
        return m_type == value_t::number_float;
    }

N
Niels 已提交
1859 1860 1861 1862 1863
    /*!
    @brief return whether value is an object

    This function returns true iff the JSON value is an object.

N
Niels 已提交
1864
    @return `true` if type is object, `false` otherwise.
N
Niels 已提交
1865 1866 1867 1868

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_object for all JSON
N
Niels 已提交
1869
    types.,is_object}
N
Niels 已提交
1870
    */
1871
    bool is_object() const noexcept
N
Niels 已提交
1872 1873 1874 1875
    {
        return m_type == value_t::object;
    }

N
Niels 已提交
1876 1877 1878 1879 1880
    /*!
    @brief return whether value is an array

    This function returns true iff the JSON value is an array.

N
Niels 已提交
1881
    @return `true` if type is array, `false` otherwise.
N
Niels 已提交
1882 1883 1884 1885

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_array for all JSON
N
Niels 已提交
1886
    types.,is_array}
N
Niels 已提交
1887
    */
1888
    bool is_array() const noexcept
N
Niels 已提交
1889 1890 1891 1892
    {
        return m_type == value_t::array;
    }

N
Niels 已提交
1893 1894 1895 1896 1897
    /*!
    @brief return whether value is a string

    This function returns true iff the JSON value is a string.

N
Niels 已提交
1898
    @return `true` if type is string, `false` otherwise.
N
Niels 已提交
1899 1900 1901 1902

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_string for all JSON
N
Niels 已提交
1903
    types.,is_string}
N
Niels 已提交
1904
    */
1905
    bool is_string() const noexcept
N
Niels 已提交
1906 1907 1908 1909
    {
        return m_type == value_t::string;
    }

N
Niels 已提交
1910 1911 1912 1913 1914 1915
    /*!
    @brief return whether value is discarded

    This function returns true iff the JSON value was discarded during parsing
    with a callback function (see @ref parser_callback_t).

N
Niels 已提交
1916 1917 1918 1919
    @note This function will always be `false` for JSON values after parsing.
    That is, discarded values can only occur during parsing, but will be
    removed when inside a structured value or replaced by null in other cases.

N
Niels 已提交
1920 1921 1922 1923
    @return `true` if type is discarded, `false` otherwise.

    @complexity Constant.

N
Niels 已提交
1924 1925
    @liveexample{The following code exemplifies @ref is_discarded for all JSON
    types.,is_discarded}
N
Niels 已提交
1926
    */
1927
    bool is_discarded() const noexcept
N
Niels 已提交
1928 1929 1930 1931
    {
        return m_type == value_t::discarded;
    }

N
Niels 已提交
1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
    /*!
    @brief return the type of the JSON value (implicit)

    Implicitly return the type of the JSON value as a value from the @ref
    value_t enumeration.

    @return the type of the JSON value

    @complexity Constant.

    @liveexample{The following code exemplifies the value_t operator for all
    JSON types.,operator__value_t}
    */
1945
    operator value_t() const noexcept
N
Niels 已提交
1946 1947 1948 1949
    {
        return m_type;
    }

N
Niels 已提交
1950 1951
    /// @}

N
Niels 已提交
1952
  private:
N
Niels 已提交
1953 1954 1955
    //////////////////
    // value access //
    //////////////////
N
cleanup  
Niels 已提交
1956

N
Niels 已提交
1957
    /// get an object (explicit)
N
cleanup  
Niels 已提交
1958 1959
    template <class T, typename
              std::enable_if<
N
Niels 已提交
1960
                  std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
N
Niels 已提交
1961
                  std::is_convertible<__basic_json, typename T::mapped_type>::value
N
Niels 已提交
1962
                  , int>::type = 0>
1963
    T get_impl(T*) const
N
cleanup  
Niels 已提交
1964 1965 1966 1967
    {
        switch (m_type)
        {
            case (value_t::object):
N
Niels 已提交
1968
            {
N
cleanup  
Niels 已提交
1969
                return T(m_value.object->begin(), m_value.object->end());
N
Niels 已提交
1970
            }
N
cleanup  
Niels 已提交
1971
            default:
N
Niels 已提交
1972
            {
N
Niels 已提交
1973
                throw std::domain_error("type must be object, but is " + type_name());
N
Niels 已提交
1974 1975 1976 1977 1978
            }
        }
    }

    /// get an object (explicit)
1979
    object_t get_impl(object_t*) const
N
Niels 已提交
1980 1981 1982 1983 1984 1985 1986 1987 1988
    {
        switch (m_type)
        {
            case (value_t::object):
            {
                return *(m_value.object);
            }
            default:
            {
N
Niels 已提交
1989
                throw std::domain_error("type must be object, but is " + type_name());
N
Niels 已提交
1990
            }
N
cleanup  
Niels 已提交
1991 1992 1993
        }
    }

N
Niels 已提交
1994
    /// get an array (explicit)
N
cleanup  
Niels 已提交
1995 1996
    template <class T, typename
              std::enable_if<
N
Niels 已提交
1997 1998
                  std::is_convertible<__basic_json, typename T::value_type>::value and
                  not std::is_same<__basic_json, typename T::value_type>::value and
N
Niels 已提交
1999 2000
                  not std::is_arithmetic<T>::value and
                  not std::is_convertible<std::string, T>::value and
2001
                  not has_mapped_type<T>::value
N
Niels 已提交
2002
                  , int>::type = 0>
2003
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2004 2005 2006 2007
    {
        switch (m_type)
        {
            case (value_t::array):
N
Niels 已提交
2008 2009 2010 2011 2012 2013 2014 2015 2016
            {
                T to_vector;
                std::transform(m_value.array->begin(), m_value.array->end(),
                               std::inserter(to_vector, to_vector.end()), [](basic_json i)
                {
                    return i.get<typename T::value_type>();
                });
                return to_vector;
            }
N
cleanup  
Niels 已提交
2017
            default:
N
Niels 已提交
2018
            {
N
Niels 已提交
2019
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2020
            }
N
cleanup  
Niels 已提交
2021 2022 2023
        }
    }

N
Niels 已提交
2024 2025
    /// get an array (explicit)
    template <class T, typename
N
cleanup  
Niels 已提交
2026
              std::enable_if<
N
Niels 已提交
2027 2028
                  std::is_convertible<__basic_json, T>::value and
                  not std::is_same<__basic_json, T>::value
N
Niels 已提交
2029
                  , int>::type = 0>
2030
    std::vector<T> get_impl(std::vector<T>*) const
N
cleanup  
Niels 已提交
2031 2032 2033
    {
        switch (m_type)
        {
N
Niels 已提交
2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
            case (value_t::array):
            {
                std::vector<T> to_vector;
                to_vector.reserve(m_value.array->size());
                std::transform(m_value.array->begin(), m_value.array->end(),
                               std::inserter(to_vector, to_vector.end()), [](basic_json i)
                {
                    return i.get<T>();
                });
                return to_vector;
            }
N
cleanup  
Niels 已提交
2045
            default:
N
Niels 已提交
2046
            {
N
Niels 已提交
2047
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2048
            }
N
cleanup  
Niels 已提交
2049 2050 2051
        }
    }

N
Niels 已提交
2052 2053 2054 2055
    /// get an array (explicit)
    template <class T, typename
              std::enable_if<
                  std::is_same<basic_json, typename T::value_type>::value and
2056
                  not has_mapped_type<T>::value
N
Niels 已提交
2057
                  , int>::type = 0>
2058
    T get_impl(T*) const
N
Niels 已提交
2059 2060 2061 2062 2063 2064 2065 2066 2067
    {
        switch (m_type)
        {
            case (value_t::array):
            {
                return T(m_value.array->begin(), m_value.array->end());
            }
            default:
            {
N
Niels 已提交
2068
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2069 2070 2071 2072
            }
        }
    }

N
Niels 已提交
2073
    /// get an array (explicit)
2074
    array_t get_impl(array_t*) const
N
Niels 已提交
2075 2076 2077 2078 2079 2080 2081 2082 2083
    {
        switch (m_type)
        {
            case (value_t::array):
            {
                return *(m_value.array);
            }
            default:
            {
N
Niels 已提交
2084
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2085 2086 2087 2088 2089
            }
        }
    }

    /// get a string (explicit)
N
cleanup  
Niels 已提交
2090 2091
    template <typename T, typename
              std::enable_if<
N
Niels 已提交
2092 2093
                  std::is_convertible<string_t, T>::value
                  , int>::type = 0>
2094
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2095 2096 2097
    {
        switch (m_type)
        {
N
Niels 已提交
2098 2099 2100 2101
            case (value_t::string):
            {
                return *m_value.string;
            }
N
cleanup  
Niels 已提交
2102
            default:
N
Niels 已提交
2103
            {
N
Niels 已提交
2104
                throw std::domain_error("type must be string, but is " + type_name());
N
Niels 已提交
2105
            }
N
cleanup  
Niels 已提交
2106 2107 2108
        }
    }

N
Niels 已提交
2109
    /// get a number (explicit)
N
cleanup  
Niels 已提交
2110 2111
    template<typename T, typename
             std::enable_if<
N
Niels 已提交
2112 2113
                 std::is_arithmetic<T>::value
                 , int>::type = 0>
2114
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2115 2116 2117 2118
    {
        switch (m_type)
        {
            case (value_t::number_integer):
N
Niels 已提交
2119
            {
N
cleanup  
Niels 已提交
2120
                return static_cast<T>(m_value.number_integer);
N
Niels 已提交
2121
            }
N
cleanup  
Niels 已提交
2122
            case (value_t::number_float):
N
Niels 已提交
2123
            {
N
cleanup  
Niels 已提交
2124
                return static_cast<T>(m_value.number_float);
N
Niels 已提交
2125
            }
N
cleanup  
Niels 已提交
2126
            default:
N
Niels 已提交
2127
            {
N
Niels 已提交
2128
                throw std::domain_error("type must be number, but is " + type_name());
N
Niels 已提交
2129 2130 2131 2132 2133
            }
        }
    }

    /// get a boolean (explicit)
2134
    boolean_t get_impl(boolean_t*) const
N
Niels 已提交
2135 2136 2137 2138 2139 2140 2141 2142 2143
    {
        switch (m_type)
        {
            case (value_t::boolean):
            {
                return m_value.boolean;
            }
            default:
            {
N
Niels 已提交
2144
                throw std::domain_error("type must be boolean, but is " + type_name());
N
Niels 已提交
2145
            }
N
cleanup  
Niels 已提交
2146 2147 2148
        }
    }

N
Niels 已提交
2149
    /// get a pointer to the value (object)
N
Niels 已提交
2150 2151 2152 2153 2154 2155 2156
    object_t* get_impl_ptr(object_t*) noexcept
    {
        return is_object() ? m_value.object : nullptr;
    }

    /// get a pointer to the value (object)
    const object_t* get_impl_ptr(const object_t*) const noexcept
N
Niels 已提交
2157 2158 2159 2160 2161
    {
        return is_object() ? m_value.object : nullptr;
    }

    /// get a pointer to the value (array)
N
Niels 已提交
2162
    array_t* get_impl_ptr(array_t*) noexcept
N
Niels 已提交
2163 2164 2165 2166
    {
        return is_array() ? m_value.array : nullptr;
    }

N
Niels 已提交
2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
    /// get a pointer to the value (array)
    const array_t* get_impl_ptr(const array_t*) const noexcept
    {
        return is_array() ? m_value.array : nullptr;
    }

    /// get a pointer to the value (string)
    string_t* get_impl_ptr(string_t*) noexcept
    {
        return is_string() ? m_value.string : nullptr;
    }

N
Niels 已提交
2179
    /// get a pointer to the value (string)
N
Niels 已提交
2180
    const string_t* get_impl_ptr(const string_t*) const noexcept
N
Niels 已提交
2181 2182 2183 2184 2185
    {
        return is_string() ? m_value.string : nullptr;
    }

    /// get a pointer to the value (boolean)
N
Niels 已提交
2186 2187 2188 2189 2190 2191 2192
    boolean_t* get_impl_ptr(boolean_t*) noexcept
    {
        return is_boolean() ? &m_value.boolean : nullptr;
    }

    /// get a pointer to the value (boolean)
    const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
N
Niels 已提交
2193 2194 2195 2196 2197
    {
        return is_boolean() ? &m_value.boolean : nullptr;
    }

    /// get a pointer to the value (integer number)
N
Niels 已提交
2198
    number_integer_t* get_impl_ptr(number_integer_t*) noexcept
N
Niels 已提交
2199 2200 2201 2202
    {
        return is_number_integer() ? &m_value.number_integer : nullptr;
    }

N
Niels 已提交
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214
    /// get a pointer to the value (integer number)
    const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
    {
        return is_number_integer() ? &m_value.number_integer : nullptr;
    }

    /// get a pointer to the value (floating-point number)
    number_float_t* get_impl_ptr(number_float_t*) noexcept
    {
        return is_number_float() ? &m_value.number_float : nullptr;
    }

N
Niels 已提交
2215
    /// get a pointer to the value (floating-point number)
N
Niels 已提交
2216
    const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
N
Niels 已提交
2217 2218 2219 2220
    {
        return is_number_float() ? &m_value.number_float : nullptr;
    }

N
Niels 已提交
2221
  public:
N
Niels 已提交
2222 2223 2224 2225

    /// @name value access
    /// @{

N
Niels 已提交
2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
    /*!
    @brief get a value (explicit)

    Explicit type conversion between the JSON value and a compatible value.

    @tparam ValueType non-pointer type compatible to the JSON value, for
    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
    `std::vector` types for JSON arrays

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

    @throw std::domain_error in case passed type @a ValueType is incompatible
    to JSON

    @complexity Linear in the size of the JSON value.

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

    @internal
    The idea of using a casted null pointer to choose the correct
    implementation is from <http://stackoverflow.com/a/8315197/266378>.
    @endinternal

    @sa @ref operator ValueType() const for implicit conversion
    @sa @ref get() for pointer-member access
    */
    template<typename ValueType, typename
             std::enable_if<
                 not std::is_pointer<ValueType>::value
                 , int>::type = 0>
    ValueType get() const
N
Niels 已提交
2262
    {
N
Niels 已提交
2263
        return get_impl(static_cast<ValueType*>(nullptr));
N
Niels 已提交
2264 2265
    }

N
Niels 已提交
2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294
    /*!
    @brief get a pointer value (explicit)

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

    @warning Writing data to the pointee of the result yields an undefined
    state.

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

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

    @complexity Constant.

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

    @sa @ref get_ptr() for explicit pointer-member access
    */
    template<typename PointerType, typename
             std::enable_if<
                 std::is_pointer<PointerType>::value
                 , int>::type = 0>
N
Niels 已提交
2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309
    PointerType get() noexcept
    {
        // delegate the call to get_ptr
        return get_ptr<PointerType>();
    }

    /*!
    @brief get a pointer value (explicit)
    @copydoc get()
    */
    template<typename PointerType, typename
             std::enable_if<
                 std::is_pointer<PointerType>::value
                 , int>::type = 0>
    const PointerType get() const noexcept
N
Niels 已提交
2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
    {
        // delegate the call to get_ptr
        return get_ptr<PointerType>();
    }

    /*!
    @brief get a pointer value (implicit)

    Implict pointer access to the internally stored JSON value. No copies are
    made.

    @warning Writing data to the pointee of the result yields an undefined
    state.

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

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

    @complexity Constant.

    @liveexample{The example below shows how pointers to internal values of a
    JSON value can be requested. Note that no type conversions are made and a
    `nullptr` is returned if the value and the requested pointer type does not
    match.,get_ptr}
    */
    template<typename PointerType, typename
             std::enable_if<
                 std::is_pointer<PointerType>::value
                 , int>::type = 0>
N
Niels 已提交
2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
    PointerType get_ptr() noexcept
    {
        // delegate the call to get_impl_ptr<>()
        return get_impl_ptr(static_cast<PointerType>(nullptr));
    }

    /*!
    @brief get a pointer value (implicit)
    @copydoc get_ptr()
    */
    template<typename PointerType, typename
             std::enable_if<
                 std::is_pointer<PointerType>::value
                 and std::is_const<PointerType>::value
                 , int>::type = 0>
    const PointerType get_ptr() const noexcept
N
Niels 已提交
2358
    {
N
Niels 已提交
2359 2360
        // delegate the call to get_impl_ptr<>() const
        return get_impl_ptr(static_cast<const PointerType>(nullptr));
N
Niels 已提交
2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391
    }

    /*!
    @brief get a value (implicit)

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

    @tparam ValueType non-pointer type compatible to the JSON value, for
    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
    `std::vector` types for JSON arrays

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

    @throw std::domain_error in case passed type @a ValueType is incompatible
    to JSON, thrown by @ref get() const

    @complexity Linear in the size of the JSON value.

    @liveexample{The example below shows serveral conversions from JSON values
    to other types. There a few things to note: (1) Floating-point numbers can
    be converted to integers\, (2) A JSON array can be converted to a standard
    `std::vector<short>`\, (3) A JSON object can be converted to C++
    assiciative containers such as `std::unordered_map<std::string\,
    json>`.,operator__ValueType}
    */
    template<typename ValueType, typename
             std::enable_if<
                 not std::is_pointer<ValueType>::value
                 , int>::type = 0>
    operator ValueType() const
N
cleanup  
Niels 已提交
2392
    {
N
Niels 已提交
2393 2394
        // delegate the call to get<>() const
        return get<ValueType>();
N
cleanup  
Niels 已提交
2395 2396
    }

N
Niels 已提交
2397 2398
    /// @}

N
cleanup  
Niels 已提交
2399 2400 2401 2402 2403

    ////////////////////
    // element access //
    ////////////////////

N
Niels 已提交
2404 2405 2406
    /// @name element access
    /// @{

N
Niels 已提交
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425
    /*!
    @brief access specified array element with bounds checking

    Returns a reference to the element at specified location @a idx, with
    bounds checking.

    @param[in] idx  index of the element to access

    @return reference to the element at index @a idx

    @throw std::domain_error if JSON is not an array
    @throw std::out_of_range if the index @a idx is out of range of the array;
    that is, `idx >= size()`

    @complexity Constant.

    @liveexample{The example below shows how array elements can be read and
    written using at.,at__size_type}
    */
2426
    reference at(size_type idx)
N
cleanup  
Niels 已提交
2427 2428 2429 2430
    {
        // at only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
2431
            throw std::domain_error("cannot use at() with " + type_name());
N
cleanup  
Niels 已提交
2432 2433
        }

2434
        return m_value.array->at(idx);
N
cleanup  
Niels 已提交
2435 2436
    }

N
Niels 已提交
2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455
    /*!
    @brief access specified array element with bounds checking

    Returns a const reference to the element at specified location @a idx, with
    bounds checking.

    @param[in] idx  index of the element to access

    @return const reference to the element at index @a idx

    @throw std::domain_error if JSON is not an array
    @throw std::out_of_range if the index @a idx is out of range of the array;
    that is, `idx >= size()`

    @complexity Constant.

    @liveexample{The example below shows how array elements can be read using
    at.,at__size_type_const}
    */
2456
    const_reference at(size_type idx) const
N
cleanup  
Niels 已提交
2457 2458 2459 2460
    {
        // at only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
2461
            throw std::domain_error("cannot use at() with " + type_name());
N
cleanup  
Niels 已提交
2462 2463
        }

2464 2465 2466
        return m_value.array->at(idx);
    }

N
Niels 已提交
2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485
    /*!
    @brief access specified object element with bounds checking

    Returns a reference to the element at with specified key @a key, with
    bounds checking.

    @param[in] key  key of the element to access

    @return reference to the element at key @a key

    @throw std::domain_error if JSON is not an object
    @throw std::out_of_range if the key @a key is is not stored in the object;
    that is, `find(key) == end()`

    @complexity Logarithmic in the size of the container.

    @liveexample{The example below shows how object elements can be read and
    written using at.,at__object_t_key_type}
    */
2486
    reference at(const typename object_t::key_type& key)
2487 2488 2489 2490
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2491
            throw std::domain_error("cannot use at() with " + type_name());
2492 2493 2494 2495 2496
        }

        return m_value.object->at(key);
    }

N
Niels 已提交
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515
    /*!
    @brief access specified object element with bounds checking

    Returns a const reference to the element at with specified key @a key, with
    bounds checking.

    @param[in] key  key of the element to access

    @return const reference to the element at key @a key

    @throw std::domain_error if JSON is not an object
    @throw std::out_of_range if the key @a key is is not stored in the object;
    that is, `find(key) == end()`

    @complexity Logarithmic in the size of the container.

    @liveexample{The example below shows how object elements can be read using
    at.,at__object_t_key_type_const}
    */
2516
    const_reference at(const typename object_t::key_type& key) const
2517 2518 2519 2520
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2521
            throw std::domain_error("cannot use at() with " + type_name());
2522 2523 2524
        }

        return m_value.object->at(key);
N
cleanup  
Niels 已提交
2525 2526
    }

N
Niels 已提交
2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
    /*!
    @brief access specified array element

    Returns a reference to the element at specified location @a idx.

    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
    then the array is silently filled up with `null` values to make `idx` a
    valid reference to the last stored element.

    @param[in] idx  index of the element to access

    @return reference to the element at index @a idx

    @throw std::domain_error if JSON is not an array or null

    @complexity Constant if @a idx is in the range of the array. Otherwise
    linear in `idx - size()`.

    @liveexample{The example below shows how array elements can be read and
    written using [] operator. Note the addition of `null`
    values.,operatorarray__size_type}
    */
2549
    reference operator[](size_type idx)
N
cleanup  
Niels 已提交
2550
    {
N
Niels 已提交
2551 2552 2553 2554
        // implicitly convert null to object
        if (m_type == value_t::null)
        {
            m_type = value_t::array;
N
Niels 已提交
2555
            AllocatorType<array_t> alloc;
N
Niels 已提交
2556 2557 2558 2559 2560
            m_value.array = alloc.allocate(1);
            alloc.construct(m_value.array);
        }

        // [] only works for arrays
N
cleanup  
Niels 已提交
2561 2562
        if (m_type != value_t::array)
        {
N
Niels 已提交
2563
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2564 2565
        }

2566
        for (size_t i = m_value.array->size(); i <= idx; ++i)
N
Niels 已提交
2567 2568 2569 2570
        {
            m_value.array->push_back(basic_json());
        }

2571
        return m_value.array->operator[](idx);
N
cleanup  
Niels 已提交
2572 2573
    }

N
Niels 已提交
2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589
    /*!
    @brief access specified array element

    Returns a const reference to the element at specified location @a idx.

    @param[in] idx  index of the element to access

    @return const reference to the element at index @a idx

    @throw std::domain_error if JSON is not an array

    @complexity Constant.

    @liveexample{The example below shows how array elements can be read using
    the [] operator.,operatorarray__size_type_const}
    */
2590
    const_reference operator[](size_type idx) const
N
cleanup  
Niels 已提交
2591 2592 2593 2594
    {
        // at only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
2595
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2596 2597
        }

2598
        return m_value.array->operator[](idx);
N
cleanup  
Niels 已提交
2599 2600
    }

N
Niels 已提交
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620
    /*!
    @brief access specified object element

    Returns a reference to the element at with specified key @a key.

    @note If @a key is not found in the object, then it is silently added to
    the object and filled with a `null` value to make `key` a valid reference.
    In case the value was `null` before, it is converted to an object.

    @param[in] key  key of the element to access

    @return reference to the element at key @a key

    @throw std::domain_error if JSON is not an object or null

    @complexity Logarithmic in the size of the container.

    @liveexample{The example below shows how object elements can be read and
    written using the [] operator.,operatorarray__key_type}
    */
2621
    reference operator[](const typename object_t::key_type& key)
N
cleanup  
Niels 已提交
2622
    {
N
Niels 已提交
2623 2624 2625 2626
        // implicitly convert null to object
        if (m_type == value_t::null)
        {
            m_type = value_t::object;
N
Niels 已提交
2627
            AllocatorType<object_t> alloc;
N
Niels 已提交
2628 2629 2630 2631
            m_value.object = alloc.allocate(1);
            alloc.construct(m_value.object);
        }

N
Niels 已提交
2632
        // [] only works for objects
N
cleanup  
Niels 已提交
2633 2634
        if (m_type != value_t::object)
        {
N
Niels 已提交
2635
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2636 2637 2638 2639 2640
        }

        return m_value.object->operator[](key);
    }

N
Niels 已提交
2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656
    /*!
    @brief access specified object element

    Returns a reference to the element at with specified key @a key.

    @param[in] key  key of the element to access

    @return reference to the element at key @a key

    @throw std::domain_error if JSON is not an object or null

    @complexity Logarithmic in the size of the container.

    @liveexample{The example below shows how object elements can be read using
    the [] operator.,operatorarray__key_type_const}
    */
2657
    const_reference operator[](const typename object_t::key_type& key) const
2658 2659 2660 2661
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2662
            throw std::domain_error("cannot use operator[] with " + type_name());
2663 2664 2665 2666 2667
        }

        return m_value.object->operator[](key);
    }

N
Niels 已提交
2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689
    /*!
    @brief access specified object element

    Returns a reference to the element at with specified key @a key.

    @note If @a key is not found in the object, then it is silently added to
    the object and filled with a `null` value to make `key` a valid reference.
    In case the value was `null` before, it is converted to an object.

    @note This function is required for compatibility reasons with Clang.

    @param[in] key  key of the element to access

    @return reference to the element at key @a key

    @throw std::domain_error if JSON is not an object or null

    @complexity Logarithmic in the size of the container.

    @liveexample{The example below shows how object elements can be read and
    written using the [] operator.,operatorarray__key_type}
    */
N
Niels 已提交
2690
    template<typename T, std::size_t n>
2691
    reference operator[](const T (&key)[n])
N
cleanup  
Niels 已提交
2692
    {
N
Niels 已提交
2693 2694 2695 2696
        // implicitly convert null to object
        if (m_type == value_t::null)
        {
            m_type = value_t::object;
N
Niels 已提交
2697
            m_value = value_t::object;
N
Niels 已提交
2698 2699
        }

N
cleanup  
Niels 已提交
2700 2701 2702
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2703
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2704 2705 2706 2707 2708
        }

        return m_value.object->operator[](key);
    }

N
Niels 已提交
2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
    /*!
    @brief access specified object element

    Returns a reference to the element at with specified key @a key.

    @note This function is required for compatibility reasons with Clang.

    @param[in] key  key of the element to access

    @return reference to the element at key @a key

    @throw std::domain_error if JSON is not an object or null

    @complexity Logarithmic in the size of the container.

    @liveexample{The example below shows how object elements can be read using
    the [] operator.,operatorarray__key_type_const}
    */
N
Niels 已提交
2727
    template<typename T, std::size_t n>
2728
    const_reference operator[](const T (&key)[n]) const
2729 2730 2731 2732
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2733
            throw std::domain_error("cannot use operator[] with " + type_name());
2734 2735 2736 2737 2738
        }

        return m_value.object->operator[](key);
    }

N
Niels 已提交
2739 2740 2741 2742 2743 2744
    /*!
    @brief access the first element

    Returns a reference to the first element in the container. For a JSON
    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.

N
Niels 已提交
2745
    @return In case of a structured type (array or object), a reference to the
N
Niels 已提交
2746 2747 2748 2749 2750 2751 2752
    first element is returned. In cast of number, string, or boolean values, a
    reference to the value is returned.

    @complexity Constant.

    @note Calling `front` on an empty container is undefined.

N
Niels 已提交
2753
    @throw std::out_of_range when called on null value
N
Niels 已提交
2754 2755 2756

    @liveexample{The following code shows an example for @ref front.,front}
    */
2757
    reference front()
N
Niels 已提交
2758 2759 2760 2761
    {
        return *begin();
    }

N
Niels 已提交
2762 2763 2764
    /*!
    @copydoc basic_json::front()
    */
2765
    const_reference front() const
N
Niels 已提交
2766 2767 2768 2769
    {
        return *cbegin();
    }

N
Niels 已提交
2770 2771 2772 2773 2774 2775 2776
    /*!
    @brief access the last element

    Returns a reference to the last element in the container. For a JSON
    container `c`, the expression `c.back()` is equivalent to `{ auto tmp =
    c.end(); --tmp; return *tmp; }`.

N
Niels 已提交
2777
    @return In case of a structured type (array or object), a reference to the
N
Niels 已提交
2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788
    last element is returned. In cast of number, string, or boolean values, a
    reference to the value is returned.

    @complexity Constant.

    @note Calling `back` on an empty container is undefined.

    @throw std::out_of_range when called on null value.

    @liveexample{The following code shows an example for @ref back.,back}
    */
2789
    reference back()
N
Niels 已提交
2790 2791 2792 2793 2794 2795
    {
        auto tmp = end();
        --tmp;
        return *tmp;
    }

N
Niels 已提交
2796 2797 2798
    /*!
    @copydoc basic_json::back()
    */
2799
    const_reference back() const
N
Niels 已提交
2800 2801 2802 2803 2804 2805
    {
        auto tmp = cend();
        --tmp;
        return *tmp;
    }

N
Niels 已提交
2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839
    /*!
    @brief remove element given an iterator

    Removes the element specified by iterator @a pos. Invalidates iterators and
    references at or after the point of the erase, including the end()
    iterator. The iterator @a pos must be valid and dereferenceable. Thus the
    end() iterator (which is valid, but is not dereferencable) cannot be used
    as a value for @a pos.

    If called on a primitive type other than null, the resulting JSON value
    will be `null`.

    @param[in] pos iterator to the element to remove
    @return Iterator following the last removed element. If the iterator @a pos
    refers to the last element, the end() iterator is returned.

    @tparam InteratorType an @ref iterator or @ref const_iterator

    @throw std::domain_error if called on a `null` value
    @throw std::domain_error if called on an iterator which does not belong to
    the current JSON value
    @throw std::out_of_range if called on a primitive type with invalid iterator
    (i.e., any iterator which is not end())

    @complexity The complexity depends on the type:
    - objects: amortized constant
    - arrays: linear in distance between pos and the end of the container
    - strings: linear in the length of the string
    - other types: constant

    @liveexample{The example shows the result of erase for different JSON
    types.,erase__IteratorType}
    */
    template <class InteratorType, typename
2840
              std::enable_if<
N
Niels 已提交
2841 2842
                  std::is_same<InteratorType, typename __basic_json::iterator>::value or
                  std::is_same<InteratorType, typename __basic_json::const_iterator>::value
2843 2844
                  , int>::type
              = 0>
N
Niels 已提交
2845
    InteratorType erase(InteratorType pos)
2846 2847
    {
        // make sure iterator fits the current value
N
Niels 已提交
2848
        if (this != pos.m_object)
2849
        {
N
Niels 已提交
2850
            throw std::domain_error("iterator does not fit current value");
2851 2852
        }

N
Niels 已提交
2853
        InteratorType result = end();
2854 2855 2856 2857 2858 2859 2860 2861

        switch (m_type)
        {
            case value_t::number_integer:
            case value_t::number_float:
            case value_t::boolean:
            case value_t::string:
            {
2862
                if (not pos.m_it.primitive_iterator.is_begin())
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890
                {
                    throw std::out_of_range("iterator out of range");
                }

                if (m_type == value_t::string)
                {
                    delete m_value.string;
                    m_value.string = nullptr;
                }

                m_type = value_t::null;
                break;
            }

            case value_t::object:
            {
                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
                break;
            }

            case value_t::array:
            {
                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
                break;
            }

            default:
            {
N
Niels 已提交
2891
                throw std::domain_error("cannot use erase() with " + type_name());
2892 2893 2894 2895 2896 2897
            }
        }

        return result;
    }

N
Niels 已提交
2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932
    /*!
    @brief remove elements given an iterator range

    Removes the element specified by the range `[first; last)`. Invalidates
    iterators and references at or after the point of the erase, including the
    end() iterator. The iterator @a first does not need to be dereferenceable
    if `first == last`: erasing an empty range is a no-op.

    If called on a primitive type other than null, the resulting JSON value
    will be `null`.

    @param[in] first iterator to the beginning of the range to remove
    @param[in] last iterator past the end of the range to remove
    @return Iterator following the last removed element. If the iterator @a
    second refers to the last element, the end() iterator is returned.

    @tparam InteratorType an @ref iterator or @ref const_iterator

    @throw std::domain_error if called on a `null` value
    @throw std::domain_error if called on iterators which does not belong to
    the current JSON value
    @throw std::out_of_range if called on a primitive type with invalid iterators
    (i.e., if `first != begin()` and `last != end()`)

    @complexity The complexity depends on the type:
    - objects: `log(size()) + std::distance(first, last)`
    - arrays: linear in the distance between @a first and @a last, plus linear
      in the distance between @a last and end of the container
    - strings: linear in the length of the string
    - other types: constant

    @liveexample{The example shows the result of erase for different JSON
    types.,erase__IteratorType_IteratorType}
    */
    template <class InteratorType, typename
2933
              std::enable_if<
N
Niels 已提交
2934 2935
                  std::is_same<InteratorType, typename basic_json::iterator>::value or
                  std::is_same<InteratorType, typename basic_json::const_iterator>::value
2936 2937
                  , int>::type
              = 0>
N
Niels 已提交
2938
    InteratorType erase(InteratorType first, InteratorType last)
2939 2940
    {
        // make sure iterator fits the current value
N
Niels 已提交
2941
        if (this != first.m_object or this != last.m_object)
2942
        {
N
Niels 已提交
2943
            throw std::domain_error("iterators do not fit current value");
2944 2945
        }

N
Niels 已提交
2946
        InteratorType result = end();
2947 2948 2949 2950 2951 2952 2953 2954

        switch (m_type)
        {
            case value_t::number_integer:
            case value_t::number_float:
            case value_t::boolean:
            case value_t::string:
            {
2955
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985
                {
                    throw std::out_of_range("iterators out of range");
                }

                if (m_type == value_t::string)
                {
                    delete m_value.string;
                    m_value.string = nullptr;
                }

                m_type = value_t::null;
                break;
            }

            case value_t::object:
            {
                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
                                              last.m_it.object_iterator);
                break;
            }

            case value_t::array:
            {
                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
                                             last.m_it.array_iterator);
                break;
            }

            default:
            {
N
Niels 已提交
2986
                throw std::domain_error("cannot use erase with " + type_name());
2987 2988 2989 2990 2991 2992
            }
        }

        return result;
    }

N
Niels 已提交
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009
    /*!
    @brief remove element from a JSON object given a key

    Removes elements from a JSON object with the key value @a key.

    @param[in] key value of the elements to remove

    @return Number of elements removed. If ObjectType is the default `std::map`
    type, the return value will always be `0` (@a key was not found) or `1` (@a
    key was found).

    @throw std::domain_error when called on a type other than JSON object

    @complexity `log(size()) + count(key)`

    @liveexample{The example shows the effect of erase.,erase__key_type}
    */
3010
    size_type erase(const typename object_t::key_type& key)
3011
    {
N
Niels 已提交
3012
        // this erase only works for objects
3013 3014
        if (m_type != value_t::object)
        {
N
Niels 已提交
3015
            throw std::domain_error("cannot use erase() with " + type_name());
3016 3017 3018 3019 3020
        }

        return m_value.object->erase(key);
    }

N
Niels 已提交
3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034
    /*!
    @brief remove element from a JSON array given an index

    Removes element from a JSON array at the index @a idx.

    @param[in] idx index of the element to remove

    @throw std::domain_error when called on a type other than JSON array
    @throw std::out_of_range when `idx >= size()`

    @complexity Linear in distance between @a idx and the end of the container.

    @liveexample{The example shows the effect of erase.,erase__size_type}
    */
3035
    void erase(const size_type idx)
N
Niels 已提交
3036 3037 3038 3039
    {
        // this erase only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
3040
            throw std::domain_error("cannot use erase() with " + type_name());
N
Niels 已提交
3041 3042
        }

N
Niels 已提交
3043
        if (idx >= size())
N
Niels 已提交
3044 3045 3046 3047
        {
            throw std::out_of_range("index out of range");
        }

N
Niels 已提交
3048
        m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
N
Niels 已提交
3049 3050
    }

N
Niels 已提交
3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065
    /*!
    @brief find an element in a JSON object

    Finds an element in a JSON object with key equivalent to @a key. If the
    element is not found or the JSON value is not an object, end() is returned.

    @param[in] key key value of the element to search for

    @return Iterator to an element with key equivalent to @a key. If no such
    element is found, past-the-end (see end()) iterator is returned.

    @complexity Logarithmic in the size of the JSON object.

    @liveexample{The example shows how find is used.,find__key_type}
    */
3066
    iterator find(typename object_t::key_type key)
N
Niels 已提交
3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077
    {
        auto result = end();

        if (m_type == value_t::object)
        {
            result.m_it.object_iterator = m_value.object->find(key);
        }

        return result;
    }

N
Niels 已提交
3078 3079 3080 3081
    /*!
    @brief find an element in a JSON object
    @copydoc find(typename object_t::key_type)
    */
3082
    const_iterator find(typename object_t::key_type key) const
N
Niels 已提交
3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093
    {
        auto result = cend();

        if (m_type == value_t::object)
        {
            result.m_it.object_iterator = m_value.object->find(key);
        }

        return result;
    }

N
Niels 已提交
3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109
    /*!
    @brief returns the number of occurrences of a key in a JSON object

    Returns the number of elements with key @a key. If ObjectType is the
    default `std::map` type, the return value will always be `0` (@a key was
    not found) or `1` (@a key was found).

    @param[in] key key value of the element to count

    @return Number of elements with key @a key. If the JSON value is not an
    object, the return value will be `0`.

    @complexity Logarithmic in the size of the JSON object.

    @liveexample{The example shows how count is used.,count}
    */
3110
    size_type count(typename object_t::key_type key) const
3111 3112 3113 3114 3115
    {
        // return 0 for all nonobject types
        return (m_type == value_t::object) ? m_value.object->count(key) : 0;
    }

N
Niels 已提交
3116 3117
    /// @}

N
Niels 已提交
3118

N
cleanup  
Niels 已提交
3119 3120 3121 3122
    ///////////////
    // iterators //
    ///////////////

N
Niels 已提交
3123 3124 3125
    /// @name iterators
    /// @{

N
Niels 已提交
3126 3127
    /*!
    @brief returns an iterator to the first element
N
Niels 已提交
3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141

    Returns an iterator to the first element.

    @image html range-begin-end.svg "Illustration from cppreference.com"

    @return iterator to the first element

    @complexity Constant.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.

    @liveexample{The following code shows an example for @ref begin.,begin}

N
Niels 已提交
3142 3143
    @ingroup container
    */
N
Niels 已提交
3144
    iterator begin()
N
cleanup  
Niels 已提交
3145 3146 3147 3148 3149 3150
    {
        iterator result(this);
        result.set_begin();
        return result;
    }

N
Niels 已提交
3151
    /*!
N
Niels 已提交
3152
    @copydoc basic_json::cbegin()
N
Niels 已提交
3153 3154
    @ingroup container
    */
N
Niels 已提交
3155
    const_iterator begin() const
N
cleanup  
Niels 已提交
3156
    {
N
Niels 已提交
3157
        return cbegin();
N
cleanup  
Niels 已提交
3158 3159
    }

N
Niels 已提交
3160 3161
    /*!
    @brief returns a const iterator to the first element
N
Niels 已提交
3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176

    Returns a const iterator to the first element.

    @image html range-begin-end.svg "Illustration from cppreference.com"

    @return const iterator to the first element

    @complexity Constant.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.
    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.

    @liveexample{The following code shows an example for @ref cbegin.,cbegin}

N
Niels 已提交
3177 3178
    @ingroup container
    */
N
Niels 已提交
3179
    const_iterator cbegin() const
N
cleanup  
Niels 已提交
3180 3181 3182 3183 3184 3185
    {
        const_iterator result(this);
        result.set_begin();
        return result;
    }

N
Niels 已提交
3186 3187
    /*!
    @brief returns an iterator to one past the last element
N
Niels 已提交
3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201

    Returns an iterator to one past the last element.

    @image html range-begin-end.svg "Illustration from cppreference.com"

    @return iterator one past the last element

    @complexity Constant.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.

    @liveexample{The following code shows an example for @ref end.,end}

N
Niels 已提交
3202 3203
    @ingroup container
    */
N
Niels 已提交
3204
    iterator end()
N
cleanup  
Niels 已提交
3205 3206 3207 3208 3209 3210
    {
        iterator result(this);
        result.set_end();
        return result;
    }

N
Niels 已提交
3211
    /*!
N
Niels 已提交
3212
    @copydoc basic_json::cend()
N
Niels 已提交
3213 3214
    @ingroup container
    */
N
Niels 已提交
3215
    const_iterator end() const
N
cleanup  
Niels 已提交
3216
    {
N
Niels 已提交
3217
        return cend();
N
cleanup  
Niels 已提交
3218 3219
    }

N
Niels 已提交
3220 3221
    /*!
    @brief returns a const iterator to one past the last element
N
Niels 已提交
3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236

    Returns a const iterator to one past the last element.

    @image html range-begin-end.svg "Illustration from cppreference.com"

    @return const iterator one past the last element

    @complexity Constant.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.
    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.

    @liveexample{The following code shows an example for @ref cend.,cend}

N
Niels 已提交
3237 3238
    @ingroup container
    */
N
Niels 已提交
3239
    const_iterator cend() const
N
cleanup  
Niels 已提交
3240 3241 3242 3243 3244 3245
    {
        const_iterator result(this);
        result.set_end();
        return result;
    }

N
Niels 已提交
3246
    /*!
N
Niels 已提交
3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260
    @brief returns an iterator to the reverse-beginning

    Returns an iterator to the reverse-beginning; that is, the last element.

    @image html range-rbegin-rend.svg "Illustration from cppreference.com"

    @complexity Constant.

    @requirement This function satisfies the ReversibleContainer requirements:
    - The complexity is constant.
    - Has the semantics of `reverse_iterator(end())`.

    @liveexample{The following code shows an example for @ref rbegin.,rbegin}

N
Niels 已提交
3261 3262
    @ingroup reversiblecontainer
    */
N
Niels 已提交
3263
    reverse_iterator rbegin()
N
Niels 已提交
3264 3265 3266 3267
    {
        return reverse_iterator(end());
    }

N
Niels 已提交
3268
    /*!
N
Niels 已提交
3269
    @copydoc basic_json::crbegin()
N
Niels 已提交
3270 3271
    @ingroup reversiblecontainer
    */
N
Niels 已提交
3272
    const_reverse_iterator rbegin() const
N
Niels 已提交
3273
    {
N
Niels 已提交
3274
        return crbegin();
N
Niels 已提交
3275 3276
    }

N
Niels 已提交
3277
    /*!
N
Niels 已提交
3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292
    @brief returns an iterator to the reverse-end

    Returns an iterator to the reverse-end; that is, one before the first
    element.

    @image html range-rbegin-rend.svg "Illustration from cppreference.com"

    @complexity Constant.

    @requirement This function satisfies the ReversibleContainer requirements:
    - The complexity is constant.
    - Has the semantics of `reverse_iterator(begin())`.

    @liveexample{The following code shows an example for @ref rend.,rend}

N
Niels 已提交
3293 3294
    @ingroup reversiblecontainer
    */
N
Niels 已提交
3295
    reverse_iterator rend()
N
Niels 已提交
3296 3297 3298 3299
    {
        return reverse_iterator(begin());
    }

N
Niels 已提交
3300
    /*!
N
Niels 已提交
3301
    @copydoc basic_json::crend()
N
Niels 已提交
3302 3303
    @ingroup reversiblecontainer
    */
N
Niels 已提交
3304
    const_reverse_iterator rend() const
N
Niels 已提交
3305
    {
N
Niels 已提交
3306
        return crend();
N
Niels 已提交
3307 3308
    }

N
Niels 已提交
3309
    /*!
N
Niels 已提交
3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324
    @brief returns a const reverse iterator to the last element

    Returns a const iterator to the reverse-beginning; that is, the last
    element.

    @image html range-rbegin-rend.svg "Illustration from cppreference.com"

    @complexity Constant.

    @requirement This function satisfies the ReversibleContainer requirements:
    - The complexity is constant.
    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.

    @liveexample{The following code shows an example for @ref crbegin.,crbegin}

N
Niels 已提交
3325 3326
    @ingroup reversiblecontainer
    */
N
Niels 已提交
3327
    const_reverse_iterator crbegin() const
N
Niels 已提交
3328 3329 3330 3331
    {
        return const_reverse_iterator(cend());
    }

N
Niels 已提交
3332
    /*!
N
Niels 已提交
3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347
    @brief returns a const reverse iterator to one before the first

    Returns a const reverse iterator to the reverse-end; that is, one before
    the first element.

    @image html range-rbegin-rend.svg "Illustration from cppreference.com"

    @complexity Constant.

    @requirement This function satisfies the ReversibleContainer requirements:
    - The complexity is constant.
    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.

    @liveexample{The following code shows an example for @ref crend.,crend}

N
Niels 已提交
3348 3349
    @ingroup reversiblecontainer
    */
N
Niels 已提交
3350
    const_reverse_iterator crend() const
N
Niels 已提交
3351 3352 3353 3354
    {
        return const_reverse_iterator(cbegin());
    }

N
Niels 已提交
3355 3356
    /// @}

N
cleanup  
Niels 已提交
3357 3358 3359 3360 3361

    //////////////
    // capacity //
    //////////////

N
Niels 已提交
3362 3363 3364
    /// @name capacity
    /// @{

N
Niels 已提交
3365 3366
    /*!
    @brief checks whether the container is empty
N
Niels 已提交
3367 3368 3369

    Checks if a JSON value has no elements.

N
Niels 已提交
3370
    @return The return value depends on the different types and is
N
Niels 已提交
3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
            defined as follows:
            Value type  | return value
            ----------- | -------------
            null        | @c true
            boolean     | @c false
            string      | @c false
            number      | @c false
            object      | result of function object_t::empty()
            array       | result of function array_t::empty()

    @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
                Container concept; that is, their empty() functions have
                constant complexity.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.
    - Has the semantics of `begin() == end()`.

    @liveexample{The following code uses @ref empty to check if a @ref json
    object contains any elements.,empty}

N
Niels 已提交
3392 3393
    @ingroup container
    */
3394
    bool empty() const noexcept
N
cleanup  
Niels 已提交
3395 3396 3397 3398 3399 3400 3401
    {
        switch (m_type)
        {
            case (value_t::null):
            {
                return true;
            }
N
Niels 已提交
3402

N
cleanup  
Niels 已提交
3403 3404 3405 3406
            case (value_t::array):
            {
                return m_value.array->empty();
            }
N
Niels 已提交
3407

N
cleanup  
Niels 已提交
3408 3409 3410 3411
            case (value_t::object):
            {
                return m_value.object->empty();
            }
N
Niels 已提交
3412

N
Niels 已提交
3413 3414 3415 3416 3417 3418
            default:
            {
                // all other types are nonempty
                return false;
            }
        }
N
cleanup  
Niels 已提交
3419 3420
    }

N
Niels 已提交
3421 3422
    /*!
    @brief returns the number of elements
N
Niels 已提交
3423 3424 3425

    Returns the number of elements in a JSON value.

N
Niels 已提交
3426
    @return The return value depends on the different types and is
N
Niels 已提交
3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447
            defined as follows:
            Value type  | return value
            ----------- | -------------
            null        | @c 0
            boolean     | @c 1
            string      | @c 1
            number      | @c 1
            object      | result of function object_t::size()
            array       | result of function array_t::size()

    @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
                Container concept; that is, their size() functions have
                constant complexity.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.
    - Has the semantics of `std::distance(begin(), end())`.

    @liveexample{The following code calls @ref size on the different value
    types.,size}

N
Niels 已提交
3448 3449
    @ingroup container
    */
3450
    size_type size() const noexcept
N
cleanup  
Niels 已提交
3451 3452 3453 3454 3455 3456 3457
    {
        switch (m_type)
        {
            case (value_t::null):
            {
                return 0;
            }
N
Niels 已提交
3458

N
cleanup  
Niels 已提交
3459 3460 3461 3462
            case (value_t::array):
            {
                return m_value.array->size();
            }
N
Niels 已提交
3463

N
cleanup  
Niels 已提交
3464 3465 3466 3467
            case (value_t::object):
            {
                return m_value.object->size();
            }
N
Niels 已提交
3468

N
Niels 已提交
3469 3470 3471 3472 3473 3474
            default:
            {
                // all other types have size 1
                return 1;
            }
        }
N
cleanup  
Niels 已提交
3475 3476
    }

N
Niels 已提交
3477 3478
    /*!
    @brief returns the maximum possible number of elements
N
Niels 已提交
3479 3480 3481 3482 3483

    Returns the maximum number of elements a JSON value is able to hold due to
    system or library implementation limitations, i.e. `std::distance(begin(),
    end())` for the JSON value.

N
Niels 已提交
3484
    @return The return value depends on the different types and is
N
Niels 已提交
3485 3486 3487
            defined as follows:
            Value type  | return value
            ----------- | -------------
3488 3489 3490 3491
            null        | @c 0 (same as size())
            boolean     | @c 1 (same as size())
            string      | @c 1 (same as size())
            number      | @c 1 (same as size())
N
Niels 已提交
3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506
            object      | result of function object_t::max_size()
            array       | result of function array_t::max_size()

    @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
                Container concept; that is, their max_size() functions have
                constant complexity.

    @requirement This function satisfies the Container requirements:
    - The complexity is constant.
    - Has the semantics of returning `b.size()` where `b` is the largest
      possible JSON value.

    @liveexample{The following code calls @ref max_size on the different value
    types. Note the output is implementation specific.,max_size}

N
Niels 已提交
3507 3508
    @ingroup container
    */
3509
    size_type max_size() const noexcept
N
cleanup  
Niels 已提交
3510 3511 3512 3513 3514 3515 3516
    {
        switch (m_type)
        {
            case (value_t::array):
            {
                return m_value.array->max_size();
            }
N
Niels 已提交
3517

N
cleanup  
Niels 已提交
3518 3519 3520 3521
            case (value_t::object):
            {
                return m_value.object->max_size();
            }
N
Niels 已提交
3522

N
Niels 已提交
3523 3524
            default:
            {
3525 3526
                // all other types have max_size() == size()
                return size();
N
Niels 已提交
3527 3528
            }
        }
N
cleanup  
Niels 已提交
3529 3530
    }

N
Niels 已提交
3531 3532
    /// @}

N
cleanup  
Niels 已提交
3533 3534 3535 3536 3537

    ///////////////
    // modifiers //
    ///////////////

N
Niels 已提交
3538 3539 3540
    /// @name modifiers
    /// @{

N
Niels 已提交
3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561
    /*!
    @brief clears the contents

    Clears the content of a JSON value and resets it to the default value as
    if @ref basic_json(value_t) would have been called:

    Value type  | initial value
    ----------- | -------------
    null        | `null`
    boolean     | `false`
    string      | `""`
    number      | `0`
    object      | `{}`
    array       | `[]`

    @note Floating-point numbers are set to `0.0` which will be serialized to
    `0`. The vale type remains @ref number_float_t.

    @complexity Linear in the size of the JSON value.

    @liveexample{The example below shows the effect of @ref clear to different
N
Niels 已提交
3562
    JSON types.,clear}
N
Niels 已提交
3563
    */
3564
    void clear() noexcept
N
cleanup  
Niels 已提交
3565 3566 3567 3568
    {
        switch (m_type)
        {
            case (value_t::null):
N
Niels 已提交
3569
            case (value_t::discarded):
N
cleanup  
Niels 已提交
3570 3571 3572
            {
                break;
            }
N
Niels 已提交
3573

N
cleanup  
Niels 已提交
3574 3575
            case (value_t::number_integer):
            {
N
Niels 已提交
3576
                m_value.number_integer = 0;
N
cleanup  
Niels 已提交
3577 3578
                break;
            }
N
Niels 已提交
3579

N
cleanup  
Niels 已提交
3580 3581
            case (value_t::number_float):
            {
N
Niels 已提交
3582
                m_value.number_float = 0.0;
N
cleanup  
Niels 已提交
3583 3584
                break;
            }
N
Niels 已提交
3585

N
cleanup  
Niels 已提交
3586 3587
            case (value_t::boolean):
            {
N
Niels 已提交
3588
                m_value.boolean = false;
N
cleanup  
Niels 已提交
3589 3590
                break;
            }
N
Niels 已提交
3591

N
cleanup  
Niels 已提交
3592 3593 3594 3595 3596
            case (value_t::string):
            {
                m_value.string->clear();
                break;
            }
N
Niels 已提交
3597

N
cleanup  
Niels 已提交
3598 3599 3600 3601 3602
            case (value_t::array):
            {
                m_value.array->clear();
                break;
            }
N
Niels 已提交
3603

N
cleanup  
Niels 已提交
3604 3605 3606 3607 3608 3609 3610 3611
            case (value_t::object):
            {
                m_value.object->clear();
                break;
            }
        }
    }

3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628
    /*!
    @brief add an object to an array

    Appends the given element @a value to the end of the JSON value. If the
    function is called on a JSON null value, an empty array is created before
    appending @a value.

    @param value the value to add to the JSON array

    @throw std::domain_error when called on a type other than JSON array or null

    @complexity Amortized constant.

    @liveexample{The example shows how `push_back` and `+=` can be used to add
    elements to a JSON array. Note how the `null` value was silently converted
    to a JSON array.,push_back}
    */
3629
    void push_back(basic_json&& value)
N
cleanup  
Niels 已提交
3630 3631 3632 3633
    {
        // push_back only works for null objects or arrays
        if (not(m_type == value_t::null or m_type == value_t::array))
        {
N
Niels 已提交
3634
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
3635 3636 3637 3638 3639 3640
        }

        // transform null object into an array
        if (m_type == value_t::null)
        {
            m_type = value_t::array;
N
Niels 已提交
3641
            m_value = value_t::array;
N
cleanup  
Niels 已提交
3642 3643 3644 3645 3646 3647 3648 3649
        }

        // add element to array (move semantics)
        m_value.array->push_back(std::move(value));
        // invalidate object
        value.m_type = value_t::null;
    }

3650 3651 3652 3653
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
3654
    reference operator+=(basic_json&& value)
N
Niels 已提交
3655 3656 3657 3658 3659
    {
        push_back(std::move(value));
        return *this;
    }

3660 3661 3662 3663
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
3664
    void push_back(const basic_json& value)
N
cleanup  
Niels 已提交
3665 3666 3667 3668
    {
        // push_back only works for null objects or arrays
        if (not(m_type == value_t::null or m_type == value_t::array))
        {
N
Niels 已提交
3669
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
3670 3671 3672 3673 3674 3675
        }

        // transform null object into an array
        if (m_type == value_t::null)
        {
            m_type = value_t::array;
N
Niels 已提交
3676
            m_value = value_t::array;
N
cleanup  
Niels 已提交
3677 3678 3679 3680 3681 3682
        }

        // add element to array
        m_value.array->push_back(value);
    }

3683 3684 3685 3686
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
3687
    reference operator+=(const basic_json& value)
N
cleanup  
Niels 已提交
3688 3689 3690 3691 3692
    {
        push_back(value);
        return *this;
    }

3693 3694 3695 3696 3697 3698 3699
    /*!
    @brief add an object to an object

    Inserts the given element @a value to the JSON object. If the function is
    called on a JSON null value, an empty object is created before inserting @a
    value.

N
Niels 已提交
3700
    @param[in] value the value to add to the JSON object
3701 3702 3703 3704 3705 3706 3707 3708 3709 3710

    @throw std::domain_error when called on a type other than JSON object or
    null

    @complexity Logarithmic in the size of the container, O(log(`size()`)).

    @liveexample{The example shows how `push_back` and `+=` can be used to add
    elements to a JSON object. Note how the `null` value was silently converted
    to a JSON object.,push_back__object_t__value}
    */
3711
    void push_back(const typename object_t::value_type& value)
N
cleanup  
Niels 已提交
3712 3713 3714 3715
    {
        // push_back only works for null objects or objects
        if (not(m_type == value_t::null or m_type == value_t::object))
        {
N
Niels 已提交
3716
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
3717 3718 3719 3720 3721 3722
        }

        // transform null object into an object
        if (m_type == value_t::null)
        {
            m_type = value_t::object;
N
Niels 已提交
3723
            m_value = value_t::object;
N
cleanup  
Niels 已提交
3724 3725 3726 3727 3728 3729
        }

        // add element to array
        m_value.object->insert(value);
    }

3730 3731 3732 3733
    /*!
    @brief add an object to an object
    @copydoc push_back(const typename object_t::value_type&)
    */
3734
    reference operator+=(const typename object_t::value_type& value)
N
cleanup  
Niels 已提交
3735 3736 3737 3738 3739
    {
        push_back(value);
        return operator[](value.first);
    }

N
Niels 已提交
3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881
    /*!
    @brief inserts element

    Inserts element @a value before iterator @a pos.

    @param[in] pos iterator before which the content will be inserted; may be
    the end() iterator
    @param[in] value element to insert
    @return iterator pointing to the inserted @a value.

    @throw std::domain_error if called on JSON values other than arrays
    @throw std::domain_error if @a pos is not an iterator of *this

    @complexity Constant plus linear in the distance between pos and end of the
    container.

    @liveexample{The example shows how insert is used.,insert}
    */
    iterator insert(const_iterator pos, const basic_json& value)
    {
        // insert only works for arrays
        if (m_type != value_t::array)
        {
            throw std::domain_error("cannot use insert() with " + type_name());
        }

        // check if iterator pos fits to this JSON value
        if (pos.m_object != this)
        {
            throw std::domain_error("iterator does not fit current value");
        }

        // insert to array and return iterator
        iterator result(this);
        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, value);
        return result;
    }

    /*!
    @brief inserts element
    @copydoc insert(const_iterator, const basic_json&)
    */
    iterator insert(const_iterator pos, basic_json&& value)
    {
        return insert(pos, value);
    }

    /*!
    @brief inserts elements

    Inserts @a count copies of @a value before iterator @a pos.

    @param[in] pos iterator before which the content will be inserted; may be
    the end() iterator
    @param[in] count number of copies of @a value to insert
    @param[in] value element to insert
    @return iterator pointing to the first element inserted, or @a pos if
    `count==0`

    @throw std::domain_error if called on JSON values other than arrays
    @throw std::domain_error if @a pos is not an iterator of *this

    @complexity Linear in @a count plus linear in the distance between @a pos
    and end of the container.

    @liveexample{The example shows how insert is used.,insert__count}
    */
    iterator insert(const_iterator pos, size_type count, const basic_json& value)
    {
        // insert only works for arrays
        if (m_type != value_t::array)
        {
            throw std::domain_error("cannot use insert() with " + type_name());
        }

        // check if iterator pos fits to this JSON value
        if (pos.m_object != this)
        {
            throw std::domain_error("iterator does not fit current value");
        }

        // insert to array and return iterator
        iterator result(this);
        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, count, value);
        return result;
    }

    /*!
    @brief inserts elements

    Inserts elements from range `[first, last)` before iterator @a pos.

    @param[in] pos iterator before which the content will be inserted; may be
    the end() iterator
    @param[in] first begin of the range of elements to insert
    @param[in] last end of the range of elements to insert

    @throw std::domain_error if called on JSON values other than arrays
    @throw std::domain_error if @a pos is not an iterator of *this
    @throw std::domain_error if @a first and @a last do not belong to the same
    JSON value
    @throw std::domain_error if @a first or @a last are iterators into
    container for which insert is called
    @return iterator pointing to the first element inserted, or @a pos if
    `first==last`

    @complexity Linear in `std::distance(first, last)` plus linear in the
    distance between @a pos and end of the container.

    @liveexample{The example shows how insert is used.,insert__range}
    */
    iterator insert(const_iterator pos, const_iterator first, const_iterator last)
    {
        // insert only works for arrays
        if (m_type != value_t::array)
        {
            throw std::domain_error("cannot use insert() with " + type_name());
        }

        // check if iterator pos fits to this JSON value
        if (pos.m_object != this)
        {
            throw std::domain_error("iterator does not fit current value");
        }

        if (first.m_object != last.m_object)
        {
            throw std::domain_error("iterators does not fit");
        }

        if (first.m_object == this or last.m_object == this)
        {
            throw std::domain_error("passed iterators may not belong to container");
        }

        // insert to array and return iterator
        iterator result(this);
        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator,
                                     first.m_it.array_iterator, last.m_it.array_iterator);
        return result;
    }

N
Niels 已提交
3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920
    /*!
    @brief inserts elements

    Inserts elements from initializer list @a ilist before iterator @a pos.

    @param[in] pos iterator before which the content will be inserted; may be
    the end() iterator
    @param[in] ilist initializer list to insert the values from

    @throw std::domain_error if called on JSON values other than arrays
    @throw std::domain_error if @a pos is not an iterator of *this
    @return iterator pointing to the first element inserted, or @a pos if
    `ilist` is empty

    @complexity Linear in `ilist.size()` plus linear in the distance between @a
    pos and end of the container.

    @liveexample{The example shows how insert is used.,insert__ilist}
    */
    iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
    {
        // insert only works for arrays
        if (m_type != value_t::array)
        {
            throw std::domain_error("cannot use insert() with " + type_name());
        }

        // check if iterator pos fits to this JSON value
        if (pos.m_object != this)
        {
            throw std::domain_error("iterator does not fit current value");
        }

        // insert to array and return iterator
        iterator result(this);
        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
        return result;
    }

N
Niels 已提交
3921 3922
    /*!
    @brief exchanges the values
N
Niels 已提交
3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935

    Exchanges the contents of the JSON value with those of @a other. Does not
    invoke any move, copy, or swap operations on individual elements. All
    iterators and references remain valid. The past-the-end iterator is
    invalidated.

    @param[in,out] other JSON value to exchange the contents with

    @complexity Constant.

    @liveexample{The example below shows how JSON arrays can be
    swapped.,swap__reference}

N
Niels 已提交
3936 3937
    @ingroup container
    */
3938
    void swap(reference other) noexcept (
N
Niels 已提交
3939 3940 3941 3942 3943
        std::is_nothrow_move_constructible<value_t>::value and
        std::is_nothrow_move_assignable<value_t>::value and
        std::is_nothrow_move_constructible<json_value>::value and
        std::is_nothrow_move_assignable<json_value>::value
    )
N
cleanup  
Niels 已提交
3944 3945 3946 3947 3948
    {
        std::swap(m_type, other.m_type);
        std::swap(m_value, other.m_value);
    }

N
Niels 已提交
3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967
    /*!
    @brief exchanges the values

    Exchanges the contents of a JSON array with those of @a other. Does not
    invoke any move, copy, or swap operations on individual elements. All
    iterators and references remain valid. The past-the-end iterator is
    invalidated.

    @param[in,out] other array to exchange the contents with

    @throw std::domain_error when JSON value is not an array

    @complexity Constant.

    @liveexample{The example below shows how JSON values can be
    swapped.,swap__array_t}

    @ingroup container
    */
3968
    void swap(array_t& other)
N
cleanup  
Niels 已提交
3969 3970 3971 3972
    {
        // swap only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
3973
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
3974 3975 3976 3977 3978 3979
        }

        // swap arrays
        std::swap(*(m_value.array), other);
    }

3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998
    /*!
    @brief exchanges the values

    Exchanges the contents of a JSON object with those of @a other. Does not
    invoke any move, copy, or swap operations on individual elements. All
    iterators and references remain valid. The past-the-end iterator is
    invalidated.

    @param[in,out] other object to exchange the contents with

    @throw std::domain_error when JSON value is not an object

    @complexity Constant.

    @liveexample{The example below shows how JSON values can be
    swapped.,swap__object_t}

    @ingroup container
    */
3999
    void swap(object_t& other)
N
cleanup  
Niels 已提交
4000 4001 4002 4003
    {
        // swap only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
4004
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
4005 4006
        }

4007
        // swap objects
N
cleanup  
Niels 已提交
4008 4009 4010
        std::swap(*(m_value.object), other);
    }

4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029
    /*!
    @brief exchanges the values

    Exchanges the contents of a JSON string with those of @a other. Does not
    invoke any move, copy, or swap operations on individual elements. All
    iterators and references remain valid. The past-the-end iterator is
    invalidated.

    @param[in,out] other string to exchange the contents with

    @throw std::domain_error when JSON value is not a string

    @complexity Constant.

    @liveexample{The example below shows how JSON values can be
    swapped.,swap__string_t}

    @ingroup container
    */
4030
    void swap(string_t& other)
N
cleanup  
Niels 已提交
4031 4032 4033 4034
    {
        // swap only works for strings
        if (m_type != value_t::string)
        {
N
Niels 已提交
4035
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
4036 4037
        }

4038
        // swap strings
N
cleanup  
Niels 已提交
4039 4040 4041
        std::swap(*(m_value.string), other);
    }

N
Niels 已提交
4042 4043
    /// @}

N
cleanup  
Niels 已提交
4044 4045 4046 4047 4048

    //////////////////////////////////////////
    // lexicographical comparison operators //
    //////////////////////////////////////////

N
Niels 已提交
4049 4050 4051
    /// @name lexicographical comparison operators
    /// @{

N
Niels 已提交
4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082
  private:
    /*!
    @brief comparison operator for JSON types

    Returns an ordering that is similar to Python:
    - order: null < boolean < number < object < array < string
    - furthermore, each type is not smaller than itself
    */
    friend bool operator<(const value_t lhs, const value_t rhs)
    {
        static constexpr std::array<uint8_t, 7> order = {{
                0, // null
                3, // object
                4, // array
                5, // string
                1, // boolean
                2, // integer
                2  // float
            }
        };

        // discarded values are not comparable
        if (lhs == value_t::discarded or rhs == value_t::discarded)
        {
            return false;
        }

        return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)];
    }

  public:
N
Niels 已提交
4083 4084
    /*!
    @brief comparison: equal
N
Niels 已提交
4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100

    Compares two JSON values for equality according to the following rules:
    - Two JSON values are equal if (1) they are from the same type and (2)
      their stored values are the same.
    - Integer and floating-point numbers are automatically converted before
      comparison. Floating-point numbers are compared indirectly: two
      floating-point numbers `f1` and `f2` are considered equal if neither
      `f1 > f2` nor `f2 > f1` holds.
    - Two JSON null values are equal.

    @param[in] lhs  first JSON value to consider
    @param[in] rhs  second JSON value to consider
    @return whether the values @a lhs and @a rhs are equal

    @complexity Linear.

4101 4102
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__equal}
N
Niels 已提交
4103

N
Niels 已提交
4104 4105
    @ingroup container
    */
N
Niels 已提交
4106
    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4107
    {
F
Florian Weber 已提交
4108 4109
        const auto lhs_type = lhs.type();
        const auto rhs_type = rhs.type();
N
Niels 已提交
4110

F
Florian Weber 已提交
4111
        if (lhs_type == rhs_type)
N
cleanup  
Niels 已提交
4112
        {
F
Florian Weber 已提交
4113
            switch (lhs_type)
N
cleanup  
Niels 已提交
4114
            {
F
Florian Weber 已提交
4115
                case (value_t::array):
N
cleanup  
Niels 已提交
4116
                    return *lhs.m_value.array == *rhs.m_value.array;
F
Florian Weber 已提交
4117
                case (value_t::object):
N
cleanup  
Niels 已提交
4118
                    return *lhs.m_value.object == *rhs.m_value.object;
F
Florian Weber 已提交
4119
                case (value_t::null):
N
cleanup  
Niels 已提交
4120
                    return true;
F
Florian Weber 已提交
4121
                case (value_t::string):
N
cleanup  
Niels 已提交
4122
                    return *lhs.m_value.string == *rhs.m_value.string;
F
Florian Weber 已提交
4123
                case (value_t::boolean):
N
cleanup  
Niels 已提交
4124
                    return lhs.m_value.boolean == rhs.m_value.boolean;
F
Florian Weber 已提交
4125
                case (value_t::number_integer):
N
cleanup  
Niels 已提交
4126
                    return lhs.m_value.number_integer == rhs.m_value.number_integer;
F
Florian Weber 已提交
4127
                case (value_t::number_float):
4128
                    return approx(lhs.m_value.number_float, rhs.m_value.number_float);
N
Niels 已提交
4129 4130
                case (value_t::discarded):
                    return false;
N
cleanup  
Niels 已提交
4131 4132
            }
        }
F
Florian Weber 已提交
4133 4134
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
        {
4135 4136
            return approx(static_cast<number_float_t>(lhs.m_value.number_integer),
                          rhs.m_value.number_float);
F
Florian Weber 已提交
4137 4138 4139 4140 4141 4142
        }
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
        {
            return approx(lhs.m_value.number_float,
                          static_cast<number_float_t>(rhs.m_value.number_integer));
        }
N
cleanup  
Niels 已提交
4143 4144 4145
        return false;
    }

N
Niels 已提交
4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175
    /*!
    @brief comparison: equal

    The functions compares the given JSON value against a null pointer. As the
    null pointer can be used to initialize a JSON value to null, a comparison
    of JSON value @a v with a null pointer should be equivalent to call
    `v.is_null()`.

    @param[in] v  JSON value to consider
    @return whether @a v is null

    @complexity Constant.

    @liveexample{The example compares several JSON types to the null pointer.
    ,operator__equal__nullptr_t}
    */
    friend bool operator==(const_reference v, std::nullptr_t) noexcept
    {
        return v.is_null();
    }

    /*!
    @brief comparison: equal
    @copydoc operator==(const_reference, std::nullptr_t)
    */
    friend bool operator==(std::nullptr_t, const_reference v) noexcept
    {
        return v.is_null();
    }

N
Niels 已提交
4176 4177
    /*!
    @brief comparison: not equal
N
Niels 已提交
4178 4179 4180 4181 4182 4183 4184 4185 4186

    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.

    @param[in] lhs  first JSON value to consider
    @param[in] rhs  second JSON value to consider
    @return whether the values @a lhs and @a rhs are not equal

    @complexity Linear.

4187 4188
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__notequal}
N
Niels 已提交
4189

N
Niels 已提交
4190 4191
    @ingroup container
    */
N
Niels 已提交
4192
    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4193 4194 4195 4196
    {
        return not (lhs == rhs);
    }

N
Niels 已提交
4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226
    /*!
    @brief comparison: not equal

    The functions compares the given JSON value against a null pointer. As the
    null pointer can be used to initialize a JSON value to null, a comparison
    of JSON value @a v with a null pointer should be equivalent to call
    `not v.is_null()`.

    @param[in] v  JSON value to consider
    @return whether @a v is not null

    @complexity Constant.

    @liveexample{The example compares several JSON types to the null pointer.
    ,operator__notequal__nullptr_t}
    */
    friend bool operator!=(const_reference v, std::nullptr_t) noexcept
    {
        return not v.is_null();
    }

    /*!
    @brief comparison: not equal
    @copydoc operator!=(const_reference, std::nullptr_t)
    */
    friend bool operator!=(std::nullptr_t, const_reference v) noexcept
    {
        return not v.is_null();
    }

N
Niels 已提交
4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245
    /*!
    @brief comparison: less than

    Compares whether one JSON value @a lhs is less than another JSON value @a
    rhs according to the following rules:
    - If @a lhs and @a rhs have the same type, the values are compared using
      the default `<` operator.
    - Integer and floating-point numbers are automatically converted before
      comparison
    - In case @a lhs and @a rhs have different types, the values are ignored
      and the order of the types is considered, see
      @ref operator<(const value_t, const value_t).

    @param[in] lhs  first JSON value to consider
    @param[in] rhs  second JSON value to consider
    @return whether @a lhs is less than @a rhs

    @complexity Linear.

4246 4247
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__less}
N
Niels 已提交
4248
    */
N
Niels 已提交
4249
    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4250
    {
F
Florian Weber 已提交
4251 4252
        const auto lhs_type = lhs.type();
        const auto rhs_type = rhs.type();
N
Niels 已提交
4253

F
Florian Weber 已提交
4254
        if (lhs_type == rhs_type)
N
cleanup  
Niels 已提交
4255
        {
F
Florian Weber 已提交
4256
            switch (lhs_type)
N
cleanup  
Niels 已提交
4257
            {
F
Florian Weber 已提交
4258
                case (value_t::array):
N
cleanup  
Niels 已提交
4259
                    return *lhs.m_value.array < *rhs.m_value.array;
F
Florian Weber 已提交
4260
                case (value_t::object):
N
cleanup  
Niels 已提交
4261
                    return *lhs.m_value.object < *rhs.m_value.object;
F
Florian Weber 已提交
4262
                case (value_t::null):
N
cleanup  
Niels 已提交
4263
                    return false;
F
Florian Weber 已提交
4264
                case (value_t::string):
N
cleanup  
Niels 已提交
4265
                    return *lhs.m_value.string < *rhs.m_value.string;
F
Florian Weber 已提交
4266
                case (value_t::boolean):
N
cleanup  
Niels 已提交
4267
                    return lhs.m_value.boolean < rhs.m_value.boolean;
F
Florian Weber 已提交
4268
                case (value_t::number_integer):
N
cleanup  
Niels 已提交
4269
                    return lhs.m_value.number_integer < rhs.m_value.number_integer;
F
Florian Weber 已提交
4270
                case (value_t::number_float):
N
cleanup  
Niels 已提交
4271
                    return lhs.m_value.number_float < rhs.m_value.number_float;
N
Niels 已提交
4272 4273
                case (value_t::discarded):
                    return false;
N
cleanup  
Niels 已提交
4274 4275
            }
        }
F
Florian Weber 已提交
4276 4277
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
        {
4278 4279
            return static_cast<number_float_t>(lhs.m_value.number_integer) <
                   rhs.m_value.number_float;
F
Florian Weber 已提交
4280 4281 4282 4283 4284 4285
        }
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
        {
            return lhs.m_value.number_float <
                   static_cast<number_float_t>(rhs.m_value.number_integer);
        }
N
cleanup  
Niels 已提交
4286

N
Niels 已提交
4287 4288
        // We only reach this line if we cannot compare values. In that case,
        // we compare types.
F
Florian Weber 已提交
4289
        return lhs_type < rhs_type;
N
cleanup  
Niels 已提交
4290 4291
    }

N
Niels 已提交
4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303
    /*!
    @brief comparison: less than or equal

    Compares whether one JSON value @a lhs is less than or equal to another
    JSON value by calculating `not (rhs < lhs)`.

    @param[in] lhs  first JSON value to consider
    @param[in] rhs  second JSON value to consider
    @return whether @a lhs is less than or equal to @a rhs

    @complexity Linear.

4304 4305
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__greater}
N
Niels 已提交
4306
    */
N
Niels 已提交
4307
    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4308 4309 4310 4311
    {
        return not (rhs < lhs);
    }

N
Niels 已提交
4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323
    /*!
    @brief comparison: greater than

    Compares whether one JSON value @a lhs is greater than another
    JSON value by calculating `not (lhs <= rhs)`.

    @param[in] lhs  first JSON value to consider
    @param[in] rhs  second JSON value to consider
    @return whether @a lhs is greater than to @a rhs

    @complexity Linear.

4324 4325
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__lessequal}
N
Niels 已提交
4326
    */
N
Niels 已提交
4327
    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4328 4329 4330 4331
    {
        return not (lhs <= rhs);
    }

N
Niels 已提交
4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343
    /*!
    @brief comparison: greater than or equal

    Compares whether one JSON value @a lhs is greater than or equal to another
    JSON value by calculating `not (lhs < rhs)`.

    @param[in] lhs  first JSON value to consider
    @param[in] rhs  second JSON value to consider
    @return whether @a lhs is greater than or equal to @a rhs

    @complexity Linear.

4344 4345
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__greaterequal}
N
Niels 已提交
4346
    */
N
Niels 已提交
4347
    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4348 4349 4350 4351
    {
        return not (lhs < rhs);
    }

N
Niels 已提交
4352 4353
    /// @}

N
cleanup  
Niels 已提交
4354 4355 4356 4357 4358

    ///////////////////
    // serialization //
    ///////////////////

N
Niels 已提交
4359 4360 4361
    /// @name serialization
    /// @{

N
Niels 已提交
4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378
    /*!
    @brief serialize to stream

    Serialize the given JSON value @a j to the output stream @a o. The JSON
    value will be serialized using the @ref dump member function. The
    indentation of the output can be controlled with the member variable
    `width` of the output stream @a o. For instance, using the manipulator
    `std::setw(4)` on @a o sets the indentation level to `4` and the
    serialization result is the same as calling `dump(4)`.

    @param[in,out] o  stream to serialize to
    @param[in] j  JSON value to serialize

    @return the stream @a o

    @complexity Linear.

N
Niels 已提交
4379 4380
    @liveexample{The example below shows the serialization with different
    parameters to `width` to adjust the indentation level.,operator_serialize}
N
Niels 已提交
4381
    */
N
cleanup  
Niels 已提交
4382 4383
    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
    {
N
Niels 已提交
4384
        // read width member and use it as indentation parameter if nonzero
N
Niels 已提交
4385 4386
        const bool pretty_print = (o.width() > 0);
        const auto indentation = (pretty_print ? o.width() : 0);
N
Niels 已提交
4387

N
Niels 已提交
4388 4389 4390 4391
        // reset width to 0 for subsequent calls to this stream
        o.width(0);

        // do the actual serialization
N
Niels 已提交
4392
        j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
N
cleanup  
Niels 已提交
4393 4394 4395
        return o;
    }

N
Niels 已提交
4396 4397 4398 4399
    /*!
    @brief serialize to stream
    @copydoc operator<<(std::ostream&, const basic_json&)
    */
N
cleanup  
Niels 已提交
4400 4401
    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
    {
A
Alexandre Hamez 已提交
4402
        return o << j;
N
cleanup  
Niels 已提交
4403 4404
    }

N
Niels 已提交
4405 4406
    /// @}

N
cleanup  
Niels 已提交
4407

N
Niels 已提交
4408 4409 4410 4411
    /////////////////////
    // deserialization //
    /////////////////////

N
Niels 已提交
4412 4413 4414
    /// @name deserialization
    /// @{

N
Niels 已提交
4415 4416 4417 4418
    /*!
    @brief deserialize from string

    @param[in] s  string to read a serialized JSON value from
N
Niels 已提交
4419 4420 4421
    @param[in] cb a parser callback function of type @ref parser_callback_t
    which is used to control the deserialization by filtering unwanted values
    (optional)
N
Niels 已提交
4422 4423 4424 4425 4426 4427 4428

    @return result of the deserialization

    @complexity Linear in the length of the input. The parser is a predictive
    LL(1) parser. The complexity can be higher if the parser callback function
    @a cb has a super-linear complexity.

N
Niels 已提交
4429 4430
    @liveexample{The example below demonstrates the parse function with and
    without callback function.,parse__string__parser_callback_t}
N
Niels 已提交
4431 4432 4433 4434

    @sa parse(std::istream&, parser_callback_t) for a version that reads from
    an input stream
    */
4435
    static basic_json parse(const string_t& s, parser_callback_t cb = nullptr)
N
Niels 已提交
4436
    {
N
Niels 已提交
4437
        return parser(s, cb).parse();
N
Niels 已提交
4438 4439
    }

N
Niels 已提交
4440 4441 4442 4443
    /*!
    @brief deserialize from stream

    @param[in,out] i  stream to read a serialized JSON value from
N
Niels 已提交
4444 4445 4446
    @param[in] cb a parser callback function of type @ref parser_callback_t
    which is used to control the deserialization by filtering unwanted values
    (optional)
N
Niels 已提交
4447 4448 4449 4450 4451 4452 4453

    @return result of the deserialization

    @complexity Linear in the length of the input. The parser is a predictive
    LL(1) parser. The complexity can be higher if the parser callback function
    @a cb has a super-linear complexity.

N
Niels 已提交
4454 4455
    @liveexample{The example below demonstrates the parse function with and
    without callback function.,parse__istream__parser_callback_t}
N
Niels 已提交
4456 4457 4458 4459

    @sa parse(const string_t&, parser_callback_t) for a version that reads
    from a string
    */
4460
    static basic_json parse(std::istream& i, parser_callback_t cb = nullptr)
A
Aaron Burghardt 已提交
4461
    {
N
Niels 已提交
4462
        return parser(i, cb).parse();
N
Niels 已提交
4463 4464
    }

N
Niels 已提交
4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484
    /*!
    @brief deserialize from stream

    Deserializes an input stream to a JSON value.

    @param[in,out] i  input stream to read a serialized JSON value from
    @param[in,out] j  JSON value to write the deserialized input to

    @throw std::invalid_argument in case of parse errors

    @complexity Linear in the length of the input. The parser is a predictive
    LL(1) parser.

    @liveexample{The example below shows how a JSON value is constructed by
    reading a serialization from a stream.,operator_deserialize}

    @sa parse(std::istream&, parser_callback_t) for a variant with a parser
    callback function to filter values while parsing
    */
    friend std::istream& operator<<(basic_json& j, std::istream& i)
N
Niels 已提交
4485 4486 4487 4488 4489
    {
        j = parser(i).parse();
        return i;
    }

N
Niels 已提交
4490 4491 4492 4493 4494
    /*!
    @brief deserialize from stream
    @copydoc operator<<(basic_json&, std::istream&)
    */
    friend std::istream& operator>>(std::istream& i, basic_json& j)
N
Niels 已提交
4495 4496 4497 4498 4499
    {
        j = parser(i).parse();
        return i;
    }

N
Niels 已提交
4500 4501
    /// @}

N
Niels 已提交
4502

N
cleanup  
Niels 已提交
4503 4504 4505 4506 4507 4508
  private:
    ///////////////////////////
    // convenience functions //
    ///////////////////////////

    /// return the type as string
N
Niels 已提交
4509
    string_t type_name() const
N
cleanup  
Niels 已提交
4510 4511 4512 4513 4514 4515 4516
    {
        switch (m_type)
        {
            case (value_t::null):
            {
                return "null";
            }
N
Niels 已提交
4517

N
cleanup  
Niels 已提交
4518 4519 4520 4521
            case (value_t::object):
            {
                return "object";
            }
N
Niels 已提交
4522

N
cleanup  
Niels 已提交
4523 4524 4525 4526
            case (value_t::array):
            {
                return "array";
            }
N
Niels 已提交
4527

N
cleanup  
Niels 已提交
4528 4529 4530 4531
            case (value_t::string):
            {
                return "string";
            }
N
Niels 已提交
4532

N
cleanup  
Niels 已提交
4533 4534 4535 4536
            case (value_t::boolean):
            {
                return "boolean";
            }
N
Niels 已提交
4537

N
Niels 已提交
4538 4539 4540 4541 4542
            case (value_t::discarded):
            {
                return "discarded";
            }

N
Niels 已提交
4543
            default:
N
cleanup  
Niels 已提交
4544 4545 4546 4547 4548 4549
            {
                return "number";
            }
        }
    }

N
Niels 已提交
4550
    /*!
N
Niels 已提交
4551
    @brief escape a string
N
Niels 已提交
4552

N
Niels 已提交
4553 4554 4555 4556 4557
    Escape a string by replacing certain special characters by a sequence of an
    escape character (backslash) and another character and other control
    characters by a sequence of "\u" followed by a four-digit hex
    representation.

N
Niels 已提交
4558 4559
    @param[out] o  the stream to write the escaped string to
    @param[in] s  the string to escape
N
Niels 已提交
4560
    */
N
Niels 已提交
4561
    static void escape_string(std::ostream& o, const string_t& s)
N
Niels 已提交
4562
    {
N
Niels 已提交
4563
        for (const auto c : s)
N
Niels 已提交
4564 4565 4566
        {
            switch (c)
            {
N
Niels 已提交
4567
                // quotation mark (0x22)
N
Niels 已提交
4568 4569
                case '"':
                {
N
Niels 已提交
4570
                    o << "\\\"";
N
Niels 已提交
4571 4572
                    break;
                }
N
Niels 已提交
4573

N
Niels 已提交
4574
                // reverse solidus (0x5c)
N
Niels 已提交
4575 4576
                case '\\':
                {
N
Niels 已提交
4577
                    o << "\\\\";
N
Niels 已提交
4578 4579
                    break;
                }
N
Niels 已提交
4580

N
Niels 已提交
4581
                // backspace (0x08)
N
Niels 已提交
4582 4583
                case '\b':
                {
N
Niels 已提交
4584
                    o << "\\b";
N
Niels 已提交
4585 4586
                    break;
                }
N
Niels 已提交
4587

N
Niels 已提交
4588
                // formfeed (0x0c)
N
Niels 已提交
4589 4590
                case '\f':
                {
N
Niels 已提交
4591
                    o << "\\f";
N
Niels 已提交
4592 4593
                    break;
                }
N
Niels 已提交
4594

N
Niels 已提交
4595
                // newline (0x0a)
N
Niels 已提交
4596 4597
                case '\n':
                {
N
Niels 已提交
4598
                    o << "\\n";
N
Niels 已提交
4599 4600
                    break;
                }
N
Niels 已提交
4601

N
Niels 已提交
4602
                // carriage return (0x0d)
N
Niels 已提交
4603 4604
                case '\r':
                {
N
Niels 已提交
4605
                    o << "\\r";
N
Niels 已提交
4606 4607
                    break;
                }
N
Niels 已提交
4608

N
Niels 已提交
4609
                // horizontal tab (0x09)
N
Niels 已提交
4610 4611
                case '\t':
                {
N
Niels 已提交
4612
                    o << "\\t";
N
Niels 已提交
4613 4614
                    break;
                }
N
Niels 已提交
4615

N
Niels 已提交
4616 4617
                default:
                {
4618
                    if (c >= 0x00 and c <= 0x1f)
N
Niels 已提交
4619 4620 4621
                    {
                        // control characters (everything between 0x00 and 0x1f)
                        // -> create four-digit hex representation
N
Niels 已提交
4622
                        o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << int(c) << std::dec;
N
Niels 已提交
4623 4624 4625 4626
                    }
                    else
                    {
                        // all other characters are added as-is
N
Niels 已提交
4627
                        o << c;
N
Niels 已提交
4628 4629
                    }
                    break;
N
Niels 已提交
4630 4631 4632 4633 4634
                }
            }
        }
    }

N
cleanup  
Niels 已提交
4635
    /*!
N
Niels 已提交
4636
    @brief internal implementation of the serialization function
N
Niels 已提交
4637

N
Niels 已提交
4638 4639 4640 4641
    This function is called by the public member function dump and organizes
    the serializaion internally. The indentation level is propagated as
    additional parameter. In case of arrays and objects, the function is called
    recursively. Note that
N
Niels 已提交
4642

N
Niels 已提交
4643
    - strings and object keys are escaped using escape_string()
N
Niels 已提交
4644
    - integer numbers are converted implictly via operator<<
N
Niels 已提交
4645
    - floating-point numbers are converted to a string using "%g" format
N
cleanup  
Niels 已提交
4646

N
Niels 已提交
4647 4648 4649 4650
    @param[out] o              stream to write to
    @param[in] pretty_print    whether the output shall be pretty-printed
    @param[in] indent_step     the indent level
    @param[in] current_indent  the current indent level (only used internally)
N
cleanup  
Niels 已提交
4651
    */
N
Niels 已提交
4652
    void dump(std::ostream& o, const bool pretty_print, const unsigned int indent_step,
N
Niels 已提交
4653
              const unsigned int current_indent = 0) const
N
cleanup  
Niels 已提交
4654
    {
N
Niels 已提交
4655
        // variable to hold indentation for recursive calls
N
Niels 已提交
4656
        unsigned int new_indent = current_indent;
N
Niels 已提交
4657

N
cleanup  
Niels 已提交
4658 4659 4660 4661 4662 4663
        switch (m_type)
        {
            case (value_t::object):
            {
                if (m_value.object->empty())
                {
N
Niels 已提交
4664 4665
                    o << "{}";
                    return;
N
cleanup  
Niels 已提交
4666 4667
                }

N
Niels 已提交
4668
                o << "{";
N
cleanup  
Niels 已提交
4669 4670

                // increase indentation
N
Niels 已提交
4671
                if (pretty_print)
N
cleanup  
Niels 已提交
4672
                {
N
Niels 已提交
4673
                    new_indent += indent_step;
N
Niels 已提交
4674
                    o << "\n";
N
cleanup  
Niels 已提交
4675 4676
                }

N
Niels 已提交
4677
                for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
N
cleanup  
Niels 已提交
4678
                {
N
Niels 已提交
4679
                    if (i != m_value.object->cbegin())
N
cleanup  
Niels 已提交
4680
                    {
N
Niels 已提交
4681
                        o << (pretty_print ? ",\n" : ",");
N
cleanup  
Niels 已提交
4682
                    }
N
Niels 已提交
4683 4684
                    o << string_t(new_indent, ' ') << "\"";
                    escape_string(o, i->first);
N
Niels 已提交
4685 4686
                    o << "\":" << (pretty_print ? " " : "");
                    i->second.dump(o, pretty_print, indent_step, new_indent);
N
cleanup  
Niels 已提交
4687 4688 4689
                }

                // decrease indentation
N
Niels 已提交
4690
                if (pretty_print)
N
cleanup  
Niels 已提交
4691
                {
N
Niels 已提交
4692
                    new_indent -= indent_step;
N
Niels 已提交
4693
                    o << "\n";
N
cleanup  
Niels 已提交
4694 4695
                }

N
Niels 已提交
4696 4697
                o << string_t(new_indent, ' ') + "}";
                return;
N
cleanup  
Niels 已提交
4698 4699 4700 4701 4702 4703
            }

            case (value_t::array):
            {
                if (m_value.array->empty())
                {
N
Niels 已提交
4704 4705
                    o << "[]";
                    return;
N
cleanup  
Niels 已提交
4706 4707
                }

N
Niels 已提交
4708
                o << "[";
N
cleanup  
Niels 已提交
4709 4710

                // increase indentation
N
Niels 已提交
4711
                if (pretty_print)
N
cleanup  
Niels 已提交
4712
                {
N
Niels 已提交
4713
                    new_indent += indent_step;
N
Niels 已提交
4714
                    o << "\n";
N
cleanup  
Niels 已提交
4715 4716
                }

N
Niels 已提交
4717
                for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
N
cleanup  
Niels 已提交
4718
                {
N
Niels 已提交
4719
                    if (i != m_value.array->cbegin())
N
cleanup  
Niels 已提交
4720
                    {
N
Niels 已提交
4721
                        o << (pretty_print ? ",\n" : ",");
N
cleanup  
Niels 已提交
4722
                    }
N
Niels 已提交
4723
                    o << string_t(new_indent, ' ');
N
Niels 已提交
4724
                    i->dump(o, pretty_print, indent_step, new_indent);
N
cleanup  
Niels 已提交
4725 4726 4727
                }

                // decrease indentation
N
Niels 已提交
4728
                if (pretty_print)
N
cleanup  
Niels 已提交
4729
                {
N
Niels 已提交
4730
                    new_indent -= indent_step;
N
Niels 已提交
4731
                    o << "\n";
N
cleanup  
Niels 已提交
4732 4733
                }

N
Niels 已提交
4734 4735
                o << string_t(new_indent, ' ') << "]";
                return;
N
cleanup  
Niels 已提交
4736 4737 4738 4739
            }

            case (value_t::string):
            {
N
Niels 已提交
4740 4741 4742 4743
                o << string_t("\"");
                escape_string(o, *m_value.string);
                o << "\"";
                return;
N
cleanup  
Niels 已提交
4744 4745 4746 4747
            }

            case (value_t::boolean):
            {
N
Niels 已提交
4748 4749
                o << (m_value.boolean ? "true" : "false");
                return;
N
cleanup  
Niels 已提交
4750 4751 4752 4753
            }

            case (value_t::number_integer):
            {
N
Niels 已提交
4754 4755
                o << m_value.number_integer;
                return;
N
cleanup  
Niels 已提交
4756 4757 4758 4759
            }

            case (value_t::number_float):
            {
N
Niels 已提交
4760
                // 15 digits of precision allows round-trip IEEE 754
N
Niels 已提交
4761 4762 4763
                // string->double->string; to be safe, we read this value from
                // std::numeric_limits<number_float_t>::digits10
                o << std::setprecision(std::numeric_limits<number_float_t>::digits10) << m_value.number_float;
N
Niels 已提交
4764
                return;
N
cleanup  
Niels 已提交
4765
            }
N
Niels 已提交
4766

N
Niels 已提交
4767 4768
            case (value_t::discarded):
            {
N
Niels 已提交
4769 4770
                o << "<discarded>";
                return;
N
Niels 已提交
4771
            }
N
Niels 已提交
4772

N
Niels 已提交
4773 4774
            default:
            {
N
Niels 已提交
4775 4776
                o << "null";
                return;
N
Niels 已提交
4777
            }
N
cleanup  
Niels 已提交
4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791
        }
    }

  private:
    //////////////////////
    // member variables //
    //////////////////////

    /// the type of the current element
    value_t m_type = value_t::null;

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

N
Niels 已提交
4792

N
Niels 已提交
4793
  private:
N
cleanup  
Niels 已提交
4794 4795 4796 4797
    ///////////////
    // iterators //
    ///////////////

4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853
    /*!
    @brief an iterator for primitive JSON types

    This class models an iterator for primitive JSON types (boolean, number,
    string). It's only purpose is to allow the iterator/const_iterator classes
    to "iterate" over primitive values. Internally, the iterator is modeled by
    a `difference_type` variable. Value begin_value (`0`) models the begin,
    end_value (`1`) models past the end.
    */
    class primitive_iterator_t
    {
      public:
        /// set iterator to a defined beginning
        void set_begin()
        {
            m_it = begin_value;
        }

        /// set iterator to a defined past the end
        void set_end()
        {
            m_it = end_value;
        }

        /// return whether the iterator can be dereferenced
        bool is_begin() const
        {
            return (m_it == begin_value);
        }

        /// return whether the iterator is at end
        bool is_end() const
        {
            return (m_it == end_value);
        }

        /// return reference to the value to change and compare
        operator difference_type& ()
        {
            return m_it;
        }

        /// return value to compare
        operator const difference_type () const
        {
            return m_it;
        }

      private:
        static constexpr difference_type begin_value = 0;
        static constexpr difference_type end_value = begin_value + 1;

        /// iterator as signed integer type
        difference_type m_it = std::numeric_limits<std::ptrdiff_t>::min();
    };

N
Niels 已提交
4854 4855 4856 4857
    /// an iterator value
    union internal_iterator
    {
        /// iterator for JSON objects
N
Niels 已提交
4858
        typename object_t::iterator object_iterator;
N
Niels 已提交
4859
        /// iterator for JSON arrays
N
Niels 已提交
4860
        typename array_t::iterator array_iterator;
N
Niels 已提交
4861
        /// generic iterator for all other types
4862
        primitive_iterator_t primitive_iterator;
N
Niels 已提交
4863

4864 4865
        // leave the union un-initialized
        internal_iterator() {}
N
Niels 已提交
4866 4867 4868
    };

  public:
N
Niels 已提交
4869 4870
    /// a const random access iterator for the basic_json class
    class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json>
N
cleanup  
Niels 已提交
4871
    {
4872 4873 4874
        // allow basic_json class to access m_it
        friend class basic_json;

N
cleanup  
Niels 已提交
4875 4876
      public:
        /// the type of the values when the iterator is dereferenced
N
Niels 已提交
4877
        using value_type = typename basic_json::value_type;
N
cleanup  
Niels 已提交
4878
        /// a type to represent differences between iterators
N
Niels 已提交
4879
        using difference_type = typename basic_json::difference_type;
N
cleanup  
Niels 已提交
4880
        /// defines a pointer to the type iterated over (value_type)
N
Niels 已提交
4881
        using pointer = typename basic_json::const_pointer;
N
cleanup  
Niels 已提交
4882
        /// defines a reference to the type iterated over (value_type)
N
Niels 已提交
4883
        using reference = typename basic_json::const_reference;
N
cleanup  
Niels 已提交
4884
        /// the category of the iterator
A
Alexandre Hamez 已提交
4885
        using iterator_category = std::bidirectional_iterator_tag;
N
cleanup  
Niels 已提交
4886

4887
        /// default constructor
N
Niels 已提交
4888
        const_iterator() = default;
4889

N
cleanup  
Niels 已提交
4890
        /// constructor for a given JSON instance
N
Niels 已提交
4891
        const_iterator(pointer object) : m_object(object)
N
cleanup  
Niels 已提交
4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    m_it.object_iterator = typename object_t::iterator();
                    break;
                }
                case (basic_json::value_t::array):
                {
                    m_it.array_iterator = typename array_t::iterator();
                    break;
                }
                default:
                {
4907
                    m_it.primitive_iterator = primitive_iterator_t();
N
cleanup  
Niels 已提交
4908 4909 4910 4911 4912
                    break;
                }
            }
        }

N
Niels 已提交
4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937
        /// copy constructor given a nonconst iterator
        const_iterator(const iterator& other) : m_object(other.m_object)
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    m_it.object_iterator = other.m_it.object_iterator;
                    break;
                }

                case (basic_json::value_t::array):
                {
                    m_it.array_iterator = other.m_it.array_iterator;
                    break;
                }

                default:
                {
                    m_it.primitive_iterator = other.m_it.primitive_iterator;
                    break;
                }
            }
        }

N
Niels 已提交
4938
        /// copy constructor
N
Niels 已提交
4939
        const_iterator(const const_iterator& other) noexcept
N
Niels 已提交
4940 4941 4942
            : m_object(other.m_object), m_it(other.m_it)
        {}

N
cleanup  
Niels 已提交
4943
        /// copy assignment
N
Niels 已提交
4944
        const_iterator& operator=(const_iterator other) noexcept(
N
Niels 已提交
4945 4946
            std::is_nothrow_move_constructible<pointer>::value and
            std::is_nothrow_move_assignable<pointer>::value and
N
Niels 已提交
4947 4948
            std::is_nothrow_move_constructible<internal_iterator>::value and
            std::is_nothrow_move_assignable<internal_iterator>::value
N
Niels 已提交
4949 4950 4951 4952
        )
        {
            std::swap(m_object, other.m_object);
            std::swap(m_it, other.m_it);
N
cleanup  
Niels 已提交
4953 4954 4955
            return *this;
        }

N
Niels 已提交
4956
      private:
N
cleanup  
Niels 已提交
4957
        /// set the iterator to the first value
N
Niels 已提交
4958
        void set_begin()
N
cleanup  
Niels 已提交
4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    m_it.object_iterator = m_object->m_value.object->begin();
                    break;
                }

                case (basic_json::value_t::array):
                {
                    m_it.array_iterator = m_object->m_value.array->begin();
                    break;
                }

                case (basic_json::value_t::null):
                {
N
Niels 已提交
4976
                    // set to end so begin()==end() is true: null is empty
4977
                    m_it.primitive_iterator.set_end();
N
cleanup  
Niels 已提交
4978 4979 4980 4981 4982
                    break;
                }

                default:
                {
4983
                    m_it.primitive_iterator.set_begin();
N
cleanup  
Niels 已提交
4984 4985 4986 4987 4988 4989
                    break;
                }
            }
        }

        /// set the iterator past the last value
N
Niels 已提交
4990
        void set_end()
N
cleanup  
Niels 已提交
4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    m_it.object_iterator = m_object->m_value.object->end();
                    break;
                }

                case (basic_json::value_t::array):
                {
                    m_it.array_iterator = m_object->m_value.array->end();
                    break;
                }

                default:
                {
5008
                    m_it.primitive_iterator.set_end();
N
cleanup  
Niels 已提交
5009 5010 5011 5012 5013
                    break;
                }
            }
        }

N
Niels 已提交
5014
      public:
N
cleanup  
Niels 已提交
5015
        /// return a reference to the value pointed to by the iterator
N
Niels 已提交
5016
        reference operator*() const
N
cleanup  
Niels 已提交
5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    return m_it.object_iterator->second;
                }

                case (basic_json::value_t::array):
                {
                    return *m_it.array_iterator;
                }

                case (basic_json::value_t::null):
                {
                    throw std::out_of_range("cannot get value");
                }

                default:
                {
5037
                    if (m_it.primitive_iterator.is_begin())
N
cleanup  
Niels 已提交
5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049
                    {
                        return *m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
                }
            }
        }

        /// dereference the iterator
N
Niels 已提交
5050
        pointer operator->() const
N
cleanup  
Niels 已提交
5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    return &(m_it.object_iterator->second);
                }

                case (basic_json::value_t::array):
                {
                    return &*m_it.array_iterator;
                }

                default:
                {
5066
                    if (m_it.primitive_iterator.is_begin())
N
cleanup  
Niels 已提交
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078
                    {
                        return m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
                }
            }
        }

        /// post-increment (it++)
N
Niels 已提交
5079
        const_iterator operator++(int)
N
cleanup  
Niels 已提交
5080
        {
N
Niels 已提交
5081
            auto result = *this;
N
Niels 已提交
5082
            ++(*this);
N
cleanup  
Niels 已提交
5083 5084 5085 5086 5087

            return result;
        }

        /// pre-increment (++it)
N
Niels 已提交
5088
        const_iterator& operator++()
N
cleanup  
Niels 已提交
5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    ++m_it.object_iterator;
                    break;
                }

                case (basic_json::value_t::array):
                {
                    ++m_it.array_iterator;
                    break;
                }

                default:
                {
5106
                    ++m_it.primitive_iterator;
N
cleanup  
Niels 已提交
5107 5108 5109 5110 5111 5112 5113 5114
                    break;
                }
            }

            return *this;
        }

        /// post-decrement (it--)
N
Niels 已提交
5115
        const_iterator operator--(int)
N
cleanup  
Niels 已提交
5116
        {
N
Niels 已提交
5117
            auto result = *this;
N
Niels 已提交
5118
            --(*this);
N
cleanup  
Niels 已提交
5119 5120 5121 5122 5123

            return result;
        }

        /// pre-decrement (--it)
N
Niels 已提交
5124
        const_iterator& operator--()
N
cleanup  
Niels 已提交
5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    --m_it.object_iterator;
                    break;
                }

                case (basic_json::value_t::array):
                {
                    --m_it.array_iterator;
                    break;
                }

                default:
                {
5142
                    --m_it.primitive_iterator;
N
cleanup  
Niels 已提交
5143 5144 5145 5146 5147 5148 5149 5150
                    break;
                }
            }

            return *this;
        }

        /// comparison: equal
N
Niels 已提交
5151
        bool operator==(const const_iterator& other) const
N
cleanup  
Niels 已提交
5152
        {
N
Niels 已提交
5153 5154
            // if objects are not the same, the comparison is undefined
            if (m_object != other.m_object)
N
cleanup  
Niels 已提交
5155
            {
N
Niels 已提交
5156
                throw std::domain_error("cannot compare iterators of different containers");
N
cleanup  
Niels 已提交
5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172
            }

            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    return (m_it.object_iterator == other.m_it.object_iterator);
                }

                case (basic_json::value_t::array):
                {
                    return (m_it.array_iterator == other.m_it.array_iterator);
                }

                default:
                {
5173
                    return (m_it.primitive_iterator == other.m_it.primitive_iterator);
N
cleanup  
Niels 已提交
5174 5175 5176 5177 5178
                }
            }
        }

        /// comparison: not equal
N
Niels 已提交
5179
        bool operator!=(const const_iterator& other) const
N
cleanup  
Niels 已提交
5180 5181 5182 5183
        {
            return not operator==(other);
        }

N
Niels 已提交
5184
        /// comparison: smaller
N
Niels 已提交
5185
        bool operator<(const const_iterator& other) const
N
Niels 已提交
5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206
        {
            // if objects are not the same, the comparison is undefined
            if (m_object != other.m_object)
            {
                throw std::domain_error("cannot compare iterators of different containers");
            }

            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    throw std::domain_error("cannot use operator< for object iterators");
                }

                case (basic_json::value_t::array):
                {
                    return (m_it.array_iterator < other.m_it.array_iterator);
                }

                default:
                {
5207
                    return (m_it.primitive_iterator < other.m_it.primitive_iterator);
N
Niels 已提交
5208 5209 5210 5211 5212
                }
            }
        }

        /// comparison: less than or equal
N
Niels 已提交
5213
        bool operator<=(const const_iterator& other) const
N
Niels 已提交
5214 5215 5216 5217 5218
        {
            return not other.operator < (*this);
        }

        /// comparison: greater than
N
Niels 已提交
5219
        bool operator>(const const_iterator& other) const
N
Niels 已提交
5220 5221 5222 5223 5224
        {
            return not operator<=(other);
        }

        /// comparison: greater than or equal
N
Niels 已提交
5225
        bool operator>=(const const_iterator& other) const
N
Niels 已提交
5226 5227 5228 5229 5230
        {
            return not operator<(other);
        }

        /// add to iterator
N
Niels 已提交
5231
        const_iterator& operator+=(difference_type i)
N
Niels 已提交
5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    throw std::domain_error("cannot use operator+= for object iterators");
                }

                case (basic_json::value_t::array):
                {
                    m_it.array_iterator += i;
                    break;
                }

                default:
                {
5248
                    m_it.primitive_iterator += i;
N
Niels 已提交
5249 5250 5251 5252 5253 5254 5255 5256
                    break;
                }
            }

            return *this;
        }

        /// subtract from iterator
N
Niels 已提交
5257
        const_iterator& operator-=(difference_type i)
N
Niels 已提交
5258 5259 5260 5261 5262
        {
            return operator+=(-i);
        }

        /// add to iterator
N
Niels 已提交
5263
        const_iterator operator+(difference_type i)
N
Niels 已提交
5264 5265 5266 5267 5268 5269 5270
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
5271
        const_iterator operator-(difference_type i)
N
Niels 已提交
5272 5273 5274 5275 5276 5277 5278
        {
            auto result = *this;
            result -= i;
            return result;
        }

        /// return difference
N
Niels 已提交
5279
        difference_type operator-(const const_iterator& other) const
N
Niels 已提交
5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    throw std::domain_error("cannot use operator- for object iterators");
                }

                case (basic_json::value_t::array):
                {
                    return m_it.array_iterator - other.m_it.array_iterator;
                }

                default:
                {
5295
                    return m_it.primitive_iterator - other.m_it.primitive_iterator;
N
Niels 已提交
5296 5297 5298 5299 5300
                }
            }
        }

        /// access to successor
N
Niels 已提交
5301
        reference operator[](difference_type n) const
N
Niels 已提交
5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    throw std::domain_error("cannot use operator[] for object iterators");
                }

                case (basic_json::value_t::array):
                {
                    return *(m_it.array_iterator + n);
                }

                case (basic_json::value_t::null):
                {
                    throw std::out_of_range("cannot get value");
                }

                default:
                {
5322
                    if (m_it.primitive_iterator == -n)
N
Niels 已提交
5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333
                    {
                        return *m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
                }
            }
        }

5334
        /// return the key of an object iterator
5335
        typename object_t::key_type key() const
N
Niels 已提交
5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350
        {
            switch (m_object->m_type)
            {
                case (basic_json::value_t::object):
                {
                    return m_it.object_iterator->first;
                }

                default:
                {
                    throw std::domain_error("cannot use key() for non-object iterators");
                }
            }
        }

N
Niels 已提交
5351 5352
        /// return the value of an iterator
        reference value() const
N
Niels 已提交
5353 5354 5355 5356
        {
            return operator*();
        }

N
cleanup  
Niels 已提交
5357 5358 5359 5360
      private:
        /// associated JSON instance
        pointer m_object = nullptr;
        /// the actual iterator of the associated instance
N
Niels 已提交
5361
        internal_iterator m_it = internal_iterator();
N
cleanup  
Niels 已提交
5362 5363
    };

N
Niels 已提交
5364 5365
    /// a random access iterator for the basic_json class
    class iterator : public const_iterator
N
cleanup  
Niels 已提交
5366 5367
    {
      public:
N
Niels 已提交
5368 5369 5370
        using base_iterator = const_iterator;
        using pointer = typename basic_json::pointer;
        using reference = typename basic_json::reference;
N
cleanup  
Niels 已提交
5371

5372
        /// default constructor
N
Niels 已提交
5373
        iterator() = default;
5374

N
cleanup  
Niels 已提交
5375
        /// constructor for a given JSON instance
N
Niels 已提交
5376 5377
        iterator(pointer object) noexcept : base_iterator(object)
        {}
N
cleanup  
Niels 已提交
5378

N
Niels 已提交
5379
        /// copy constructor
N
Niels 已提交
5380 5381
        iterator(const iterator& other) noexcept
            : base_iterator(other)
N
Niels 已提交
5382 5383
        {}

N
cleanup  
Niels 已提交
5384
        /// copy assignment
N
Niels 已提交
5385
        iterator& operator=(iterator other) noexcept(
N
Niels 已提交
5386 5387
            std::is_nothrow_move_constructible<pointer>::value and
            std::is_nothrow_move_assignable<pointer>::value and
N
Niels 已提交
5388 5389
            std::is_nothrow_move_constructible<internal_iterator>::value and
            std::is_nothrow_move_assignable<internal_iterator>::value
N
Niels 已提交
5390 5391
        )
        {
N
Niels 已提交
5392
            base_iterator::operator=(other);
N
cleanup  
Niels 已提交
5393 5394 5395
            return *this;
        }

N
Niels 已提交
5396 5397
        /// return a reference to the value pointed to by the iterator
        reference operator*()
N
cleanup  
Niels 已提交
5398
        {
N
Niels 已提交
5399 5400
            return const_cast<reference>(base_iterator::operator*());
        }
N
cleanup  
Niels 已提交
5401

N
Niels 已提交
5402 5403 5404 5405 5406
        /// dereference the iterator
        pointer operator->()
        {
            return const_cast<pointer>(base_iterator::operator->());
        }
N
cleanup  
Niels 已提交
5407

N
Niels 已提交
5408 5409 5410 5411 5412 5413 5414
        /// post-increment (it++)
        iterator operator++(int)
        {
            iterator result = *this;
            base_iterator::operator++();
            return result;
        }
N
cleanup  
Niels 已提交
5415

N
Niels 已提交
5416 5417 5418 5419 5420
        /// pre-increment (++it)
        iterator& operator++()
        {
            base_iterator::operator++();
            return *this;
N
cleanup  
Niels 已提交
5421 5422
        }

N
Niels 已提交
5423 5424
        /// post-decrement (it--)
        iterator operator--(int)
N
cleanup  
Niels 已提交
5425
        {
N
Niels 已提交
5426 5427 5428 5429
            iterator result = *this;
            base_iterator::operator--();
            return result;
        }
N
cleanup  
Niels 已提交
5430

N
Niels 已提交
5431 5432 5433 5434 5435 5436
        /// pre-decrement (--it)
        iterator& operator--()
        {
            base_iterator::operator--();
            return *this;
        }
N
Niels 已提交
5437 5438

        /// add to iterator
N
Niels 已提交
5439
        iterator& operator+=(difference_type i)
N
Niels 已提交
5440
        {
N
Niels 已提交
5441
            base_iterator::operator+=(i);
N
Niels 已提交
5442 5443 5444 5445
            return *this;
        }

        /// subtract from iterator
N
Niels 已提交
5446
        iterator& operator-=(difference_type i)
N
Niels 已提交
5447
        {
N
Niels 已提交
5448 5449
            base_iterator::operator-=(i);
            return *this;
N
Niels 已提交
5450 5451 5452
        }

        /// add to iterator
N
Niels 已提交
5453
        iterator operator+(difference_type i)
N
Niels 已提交
5454 5455 5456 5457 5458 5459 5460
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
5461
        iterator operator-(difference_type i)
N
Niels 已提交
5462 5463 5464 5465 5466 5467
        {
            auto result = *this;
            result -= i;
            return result;
        }

N
Niels 已提交
5468
        difference_type operator-(const iterator& other) const
N
Niels 已提交
5469
        {
N
Niels 已提交
5470
            return base_iterator::operator-(other);
N
Niels 已提交
5471 5472 5473
        }

        /// access to successor
5474
        reference operator[](difference_type n) const
N
Niels 已提交
5475
        {
N
Niels 已提交
5476
            return const_cast<reference>(base_iterator::operator[](n));
N
Niels 已提交
5477 5478
        }

5479
        /// return the value of an iterator
5480
        reference value() const
N
Niels 已提交
5481
        {
N
Niels 已提交
5482
            return const_cast<reference>(base_iterator::value());
N
Niels 已提交
5483
        }
N
cleanup  
Niels 已提交
5484
    };
N
Niels 已提交
5485

N
Niels 已提交
5486 5487 5488
    /// a template for a reverse iterator class
    template<typename Base>
    class json_reverse_iterator : public std::reverse_iterator<Base>
5489 5490
    {
      public:
5491
        /// shortcut to the reverse iterator adaptor
N
Niels 已提交
5492 5493
        using base_iterator = std::reverse_iterator<Base>;
        using reference = typename Base::reference;
5494

5495
        /// create reverse iterator from iterator
N
Niels 已提交
5496
        json_reverse_iterator(const typename base_iterator::iterator_type& it)
5497 5498 5499
            : base_iterator(it) {}

        /// create reverse iterator from base class
N
Niels 已提交
5500
        json_reverse_iterator(const base_iterator& it) : base_iterator(it) {}
5501 5502

        /// post-increment (it++)
N
Niels 已提交
5503
        json_reverse_iterator operator++(int)
5504 5505 5506 5507 5508
        {
            return base_iterator::operator++(1);
        }

        /// pre-increment (++it)
N
Niels 已提交
5509
        json_reverse_iterator& operator++()
5510 5511 5512 5513 5514 5515
        {
            base_iterator::operator++();
            return *this;
        }

        /// post-decrement (it--)
N
Niels 已提交
5516
        json_reverse_iterator operator--(int)
5517 5518 5519 5520 5521
        {
            return base_iterator::operator--(1);
        }

        /// pre-decrement (--it)
N
Niels 已提交
5522
        json_reverse_iterator& operator--()
5523 5524 5525 5526 5527 5528
        {
            base_iterator::operator--();
            return *this;
        }

        /// add to iterator
N
Niels 已提交
5529
        json_reverse_iterator& operator+=(difference_type i)
5530 5531 5532 5533 5534 5535
        {
            base_iterator::operator+=(i);
            return *this;
        }

        /// add to iterator
N
Niels 已提交
5536
        json_reverse_iterator operator+(difference_type i) const
5537 5538 5539 5540 5541 5542 5543
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
5544
        json_reverse_iterator operator-(difference_type i) const
5545 5546 5547 5548 5549 5550 5551
        {
            auto result = *this;
            result -= i;
            return result;
        }

        /// return difference
N
Niels 已提交
5552
        difference_type operator-(const json_reverse_iterator& other) const
5553 5554 5555 5556 5557 5558 5559 5560 5561
        {
            return this->base() - other.base();
        }

        /// access to successor
        reference operator[](difference_type n) const
        {
            return *(this->operator+(n));
        }
N
Niels 已提交
5562

5563
        /// return the key of an object iterator
5564
        typename object_t::key_type key() const
5565
        {
N
Niels 已提交
5566 5567
            auto it = --this->base();
            return it.key();
5568 5569 5570
        }

        /// return the value of an iterator
5571
        reference value() const
5572
        {
N
Niels 已提交
5573 5574
            auto it = --this->base();
            return it.operator * ();
5575 5576 5577
        }
    };

N
Niels 已提交
5578
  private:
N
Niels 已提交
5579 5580 5581
    //////////////////////
    // lexer and parser //
    //////////////////////
N
Niels 已提交
5582

N
Niels 已提交
5583 5584 5585 5586 5587
    /*!
    @brief lexical analysis

    This class organizes the lexical analysis during JSON deserialization. The
    core of it is a scanner generated by re2c <http://re2c.org> that processes
5588
    a buffer and recognizes tokens according to RFC 7159.
N
Niels 已提交
5589
    */
N
Niels 已提交
5590
    class lexer
N
Niels 已提交
5591
    {
N
Niels 已提交
5592
      public:
N
Niels 已提交
5593 5594 5595
        /// token types for the parser
        enum class token_type
        {
N
Niels 已提交
5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609
            uninitialized,    ///< indicating the scanner is uninitialized
            literal_true,     ///< the "true" literal
            literal_false,    ///< the "false" literal
            literal_null,     ///< the "null" literal
            value_string,     ///< a string - use get_string() for actual value
            value_number,     ///< a number - use get_number() for actual value
            begin_array,      ///< the character for array begin "["
            begin_object,     ///< the character for object begin "{"
            end_array,        ///< the character for array end "]"
            end_object,       ///< the character for object end "}"
            name_separator,   ///< the name separator ":"
            value_separator,  ///< the value separator ","
            parse_error,      ///< indicating a parse error
            end_of_input      ///< indicating the end of the input buffer
N
Niels 已提交
5610 5611
        };

N
Niels 已提交
5612
        /// the char type to use in the lexer
N
Niels 已提交
5613
        using lexer_char_t = unsigned char;
N
Niels 已提交
5614

N
Niels 已提交
5615
        /// constructor with a given buffer
N
Niels 已提交
5616
        explicit lexer(const string_t& s) noexcept
N
Niels 已提交
5617
            : m_stream(nullptr), m_buffer(s)
N
Niels 已提交
5618
        {
5619
            m_content = reinterpret_cast<const lexer_char_t*>(s.c_str());
N
Niels 已提交
5620
            m_start = m_cursor = m_content;
N
Niels 已提交
5621
            m_limit = m_content + s.size();
N
Niels 已提交
5622
        }
N
Niels 已提交
5623
        explicit lexer(std::istream* s) noexcept
N
Niels 已提交
5624
            : m_stream(s), m_buffer()
5625
        {
5626 5627
            getline(*m_stream, m_buffer);
            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
N
Niels 已提交
5628
            m_start = m_cursor = m_content;
5629
            m_limit = m_content + m_buffer.size();
N
Niels 已提交
5630 5631
        }

N
Niels 已提交
5632
        /// default constructor
5633
        lexer() = default;
N
Niels 已提交
5634

N
Niels 已提交
5635 5636 5637 5638
        // switch of unwanted functions
        lexer(const lexer&) = delete;
        lexer operator=(const lexer&) = delete;

N
Niels 已提交
5639 5640 5641
        /*!
        @brief create a string from a Unicode code point

N
Niels 已提交
5642 5643
        @param[in] codepoint1  the code point (can be high surrogate)
        @param[in] codepoint2  the code point (can be low surrogate or 0)
N
Niels 已提交
5644
        @return string representation of the code point
N
Niels 已提交
5645 5646
        @throw std::out_of_range if code point is >0x10ffff
        @throw std::invalid_argument if the low surrogate is invalid
N
Niels 已提交
5647 5648 5649

        @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
        */
5650
        static string_t to_unicode(const std::size_t codepoint1,
N
Niels 已提交
5651
                                   const std::size_t codepoint2 = 0)
N
Niels 已提交
5652
        {
N
Niels 已提交
5653
            string_t result;
N
Niels 已提交
5654

N
Niels 已提交
5655
            // calculate the codepoint from the given code points
N
Niels 已提交
5656
            std::size_t codepoint = codepoint1;
N
Niels 已提交
5657 5658

            // check if codepoint1 is a high surrogate
N
Niels 已提交
5659 5660
            if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
            {
N
Niels 已提交
5661
                // check if codepoint2 is a low surrogate
N
Niels 已提交
5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679
                if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
                {
                    codepoint =
                        // high surrogate occupies the most significant 22 bits
                        (codepoint1 << 10)
                        // low surrogate occupies the least significant 15 bits
                        + codepoint2
                        // there is still the 0xD800, 0xDC00 and 0x10000 noise
                        // in the result so we have to substract with:
                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
                        - 0x35FDC00;
                }
                else
                {
                    throw std::invalid_argument("missing or wrong low surrogate");
                }
            }

N
Niels 已提交
5680
            if (codepoint < 0x80)
N
Niels 已提交
5681
            {
N
Niels 已提交
5682
                // 1-byte characters: 0xxxxxxx (ASCII)
N
Niels 已提交
5683
                result.append(1, static_cast<typename string_t::value_type>(codepoint));
N
Niels 已提交
5684 5685 5686 5687
            }
            else if (codepoint <= 0x7ff)
            {
                // 2-byte characters: 110xxxxx 10xxxxxx
N
Niels 已提交
5688 5689
                result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
N
Niels 已提交
5690 5691 5692 5693
            }
            else if (codepoint <= 0xffff)
            {
                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
N
Niels 已提交
5694 5695 5696
                result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
N
Niels 已提交
5697 5698 5699 5700
            }
            else if (codepoint <= 0x10ffff)
            {
                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
N
Niels 已提交
5701 5702 5703 5704
                result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
N
Niels 已提交
5705 5706 5707
            }
            else
            {
N
Niels 已提交
5708
                throw std::out_of_range("code points above 0x10FFFF are invalid");
N
Niels 已提交
5709 5710 5711 5712 5713
            }

            return result;
        }

N
Niels 已提交
5714
        /// return name of values of type token_type
N
Niels 已提交
5715
        static std::string token_type_name(token_type t)
N
cleanup  
Niels 已提交
5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744
        {
            switch (t)
            {
                case (token_type::uninitialized):
                    return "<uninitialized>";
                case (token_type::literal_true):
                    return "true literal";
                case (token_type::literal_false):
                    return "false literal";
                case (token_type::literal_null):
                    return "null literal";
                case (token_type::value_string):
                    return "string literal";
                case (token_type::value_number):
                    return "number literal";
                case (token_type::begin_array):
                    return "[";
                case (token_type::begin_object):
                    return "{";
                case (token_type::end_array):
                    return "]";
                case (token_type::end_object):
                    return "}";
                case (token_type::name_separator):
                    return ":";
                case (token_type::value_separator):
                    return ",";
                case (token_type::end_of_input):
                    return "<end of input>";
N
Niels 已提交
5745 5746
                default:
                    return "<parse error>";
N
cleanup  
Niels 已提交
5747 5748 5749
            }
        }

N
fixes  
Niels 已提交
5750 5751
        /*!
        This function implements a scanner for JSON. It is specified using
5752 5753 5754 5755 5756
        regular expressions that try to follow RFC 7159 as close as possible.
        These regular expressions are then translated into a deterministic
        finite automaton (DFA) by the tool re2c <http://re2c.org>. As a result,
        the translated code for this function consists of a large block of code
        with goto jumps.
N
fixes  
Niels 已提交
5757 5758 5759

        @return the class of the next token read from the buffer
        */
5760
        token_type scan() noexcept
N
Niels 已提交
5761
        {
N
cleanup  
Niels 已提交
5762
            // pointer for backtracking information
5763
            m_marker = nullptr;
N
Niels 已提交
5764 5765 5766 5767 5768 5769 5770 5771 5772

            // remember the begin of the token
            m_start = m_cursor;

            /*!re2c
                re2c:define:YYCTYPE  = lexer_char_t;
                re2c:define:YYCURSOR = m_cursor;
                re2c:define:YYLIMIT  = m_limit;
                re2c:define:YYMARKER = m_marker;
N
Niels 已提交
5773
                re2c:define:YYFILL   = "yyfill(); // LCOV_EXCL_LINE";
5774
                re2c:yyfill:parameter = 0;
N
Niels 已提交
5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812
                re2c:indent:string   = "    ";
                re2c:indent:top      = 1;
                re2c:labelprefix     = "basic_json_parser_";

                // whitespace
                ws = [ \t\n\r]+;
                ws   { return scan(); }

                // structural characters
                "[" { return token_type::begin_array; }
                "]" { return token_type::end_array; }
                "{" { return token_type::begin_object; }
                "}" { return token_type::end_object; }
                "," { return token_type::value_separator; }
                ":" { return token_type::name_separator; }

                // literal names
                "null"  { return token_type::literal_null; }
                "true"  { return token_type::literal_true; }
                "false" { return token_type::literal_false; }

                // number
                decimal_point = [.];
                digit         = [0-9];
                digit_1_9     = [1-9];
                e             = [eE];
                minus         = [-];
                plus          = [+];
                zero          = [0];
                exp           = e (minus|plus)? digit+;
                frac          = decimal_point digit+;
                int           = (zero|digit_1_9 digit*);
                number        = minus? int frac? exp?;
                number        { return token_type::value_number; }

                // string
                quotation_mark  = [\"];
                escape          = [\\];
N
Niels 已提交
5813
                unescaped       = [^\"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F];
N
Niels 已提交
5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826
                single_escaped  = [\"\\/bfnrt];
                unicode_escaped = [u][0-9a-fA-F]{4};
                escaped         = escape (single_escaped | unicode_escaped);
                char            = unescaped | escaped;
                string          = quotation_mark char* quotation_mark;
                string          { return token_type::value_string; }

                // end of file
                '\000'         { return token_type::end_of_input; }

                // anything else is an error
                .              { return token_type::parse_error; }
             */
5827

N
Niels 已提交
5828 5829
        }

5830
        /// append data from the stream to the internal buffer
5831
        void yyfill() noexcept
5832
        {
N
Niels 已提交
5833 5834 5835 5836
            if (not m_stream or not * m_stream)
            {
                return;
            }
5837

N
Niels 已提交
5838 5839 5840
            const ssize_t offset_start = m_start - m_content;
            const ssize_t offset_marker = m_marker - m_start;
            const ssize_t offset_cursor = m_cursor - m_start;
5841

N
Niels 已提交
5842
            m_buffer.erase(0, static_cast<size_t>(offset_start));
5843 5844
            std::string line;
            std::getline(*m_stream, line);
N
Niels 已提交
5845
            m_buffer += "\n" + line; // add line with newline symbol
5846

5847 5848 5849 5850 5851
            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
            m_start  = m_content;
            m_marker = m_start + offset_marker;
            m_cursor = m_start + offset_cursor;
            m_limit  = m_start + m_buffer.size() - 1;
N
Niels 已提交
5852 5853
        }

N
Niels 已提交
5854
        /// return string representation of last read token
5855
        string_t get_token() const noexcept
N
Niels 已提交
5856
        {
N
Niels 已提交
5857 5858
            return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
                            static_cast<size_t>(m_cursor - m_start));
N
Niels 已提交
5859 5860 5861
        }

        /*!
N
Niels 已提交
5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877
        @brief return string value for string tokens

        The function iterates the characters between the opening and closing
        quotes of the string value. The complete string is the range
        [m_start,m_cursor). Consequently, we iterate from m_start+1 to
        m_cursor-1.

        We differentiate two cases:

        1. Escaped characters. In this case, a new character is constructed
           according to the nature of the escape. Some escapes create new
           characters (e.g., @c "\\n" is replaced by @c "\n"), some are copied
           as is (e.g., @c "\\\\"). Furthermore, Unicode escapes of the shape
           @c "\\uxxxx" need special care. In this case, to_unicode takes care
           of the construction of the values.
        2. Unescaped characters are copied as is.
N
Niels 已提交
5878 5879

        @return string value of current token without opening and closing quotes
N
Niels 已提交
5880
        @throw std::out_of_range if to_unicode fails
N
Niels 已提交
5881
        */
5882
        string_t get_string() const
N
Niels 已提交
5883
        {
N
Niels 已提交
5884
            string_t result;
N
Niels 已提交
5885 5886 5887
            result.reserve(static_cast<size_t>(m_cursor - m_start - 2));

            // iterate the result between the quotes
N
Niels 已提交
5888
            for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
N
Niels 已提交
5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925
            {
                // process escaped characters
                if (*i == '\\')
                {
                    // read next character
                    ++i;

                    switch (*i)
                    {
                        // the default escapes
                        case 't':
                        {
                            result += "\t";
                            break;
                        }
                        case 'b':
                        {
                            result += "\b";
                            break;
                        }
                        case 'f':
                        {
                            result += "\f";
                            break;
                        }
                        case 'n':
                        {
                            result += "\n";
                            break;
                        }
                        case 'r':
                        {
                            result += "\r";
                            break;
                        }
                        case '\\':
                        {
N
Niels 已提交
5926
                            result += "\\";
N
Niels 已提交
5927 5928 5929 5930
                            break;
                        }
                        case '/':
                        {
N
Niels 已提交
5931
                            result += "/";
N
Niels 已提交
5932 5933 5934 5935
                            break;
                        }
                        case '"':
                        {
N
Niels 已提交
5936
                            result += "\"";
N
Niels 已提交
5937 5938 5939 5940 5941 5942
                            break;
                        }

                        // unicode
                        case 'u':
                        {
N
Niels 已提交
5943
                            // get code xxxx from uxxxx
N
Niels 已提交
5944 5945
                            auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
                                                          4).c_str(), nullptr, 16);
N
Niels 已提交
5946

N
Niels 已提交
5947
                            // check if codepoint is a high surrogate
N
Niels 已提交
5948 5949
                            if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
                            {
N
Niels 已提交
5950
                                // make sure there is a subsequent unicode
N
Niels 已提交
5951
                                if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
N
Niels 已提交
5952 5953 5954 5955
                                {
                                    throw std::invalid_argument("missing low surrogate");
                                }

N
Niels 已提交
5956
                                // get code yyyy from uxxxx\uyyyy
N
Niels 已提交
5957 5958
                                auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
                                                               (i + 7), 4).c_str(), nullptr, 16);
N
Niels 已提交
5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969
                                result += to_unicode(codepoint, codepoint2);
                                // skip the next 11 characters (xxxx\uyyyy)
                                i += 11;
                            }
                            else
                            {
                                // add unicode character(s)
                                result += to_unicode(codepoint);
                                // skip the next four characters (xxxx)
                                i += 4;
                            }
N
Niels 已提交
5970 5971 5972 5973 5974 5975 5976 5977
                            break;
                        }
                    }
                }
                else
                {
                    // all other characters are just copied to the end of the
                    // string
N
Niels 已提交
5978
                    result.append(1, static_cast<typename string_t::value_type>(*i));
N
Niels 已提交
5979 5980 5981 5982
                }
            }

            return result;
N
Niels 已提交
5983 5984
        }

N
Niels 已提交
5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999
        /*!
        @brief return number value for number tokens

        This function translates the last token into a floating point number.
        The pointer m_begin points to the beginning of the parsed number. We
        pass this pointer to std::strtod which sets endptr to the first
        character past the converted number. If this pointer is not the same as
        m_cursor, then either more or less characters have been used during the
        comparison. This can happen for inputs like "01" which will be treated
        like number 0 followed by number 1.

        @return the result of the number conversion or NAN if the conversion
        read past the current token. The latter case needs to be treated by the
        caller function.

N
Niels 已提交
6000
        @throw std::range_error if passed value is out of range
N
Niels 已提交
6001
        */
N
Niels 已提交
6002
        long double get_number() const
N
Niels 已提交
6003 6004
        {
            // conversion
N
Niels 已提交
6005
            typename string_t::value_type* endptr;
N
Niels 已提交
6006 6007
            const auto float_val = std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start),
                                                &endptr);
N
Niels 已提交
6008

N
Niels 已提交
6009 6010
            // return float_val if the whole number was translated and NAN
            // otherwise
N
Niels 已提交
6011
            return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN;
N
Niels 已提交
6012 6013 6014
        }

      private:
6015 6016
        /// optional input stream
        std::istream* m_stream;
N
fixes  
Niels 已提交
6017
        /// the buffer
6018 6019
        string_t m_buffer;
        /// the buffer pointer
N
Niels 已提交
6020
        const lexer_char_t* m_content = nullptr;
6021
        /// pointer to the beginning of the current symbol
N
Niels 已提交
6022
        const lexer_char_t* m_start = nullptr;
6023 6024
        /// pointer for backtracking information
        const lexer_char_t* m_marker = nullptr;
N
fixes  
Niels 已提交
6025
        /// pointer to the current symbol
N
Niels 已提交
6026
        const lexer_char_t* m_cursor = nullptr;
N
fixes  
Niels 已提交
6027
        /// pointer to the end of the buffer
N
Niels 已提交
6028
        const lexer_char_t* m_limit = nullptr;
N
Niels 已提交
6029 6030
    };

N
Niels 已提交
6031 6032 6033
    /*!
    @brief syntax analysis
    */
N
Niels 已提交
6034 6035
    class parser
    {
N
Niels 已提交
6036 6037
      public:
        /// constructor for strings
N
Niels 已提交
6038 6039
        parser(const string_t& s, parser_callback_t cb = nullptr)
            : callback(cb), m_lexer(s)
N
Niels 已提交
6040 6041 6042 6043 6044 6045
        {
            // read first token
            get_token();
        }

        /// a parser reading from an input stream
N
Niels 已提交
6046 6047
        parser(std::istream& _is, parser_callback_t cb = nullptr)
            : callback(cb), m_lexer(&_is)
N
Niels 已提交
6048 6049 6050 6051 6052
        {
            // read first token
            get_token();
        }

N
Niels 已提交
6053
        /// public parser interface
6054
        basic_json parse()
N
Niels 已提交
6055
        {
N
Niels 已提交
6056
            basic_json result = parse_internal(true);
N
Niels 已提交
6057 6058 6059

            expect(lexer::token_type::end_of_input);

N
Niels 已提交
6060 6061 6062
            // return parser result and replace it with null in case the
            // top-level value was discarded by the callback function
            return result.is_discarded() ? basic_json() : result;
N
Niels 已提交
6063 6064 6065 6066
        }

      private:
        /// the actual parser
6067
        basic_json parse_internal(bool keep)
N
Niels 已提交
6068
        {
N
Niels 已提交
6069 6070
            auto result = basic_json(value_t::discarded);

N
Niels 已提交
6071 6072
            switch (last_token)
            {
N
Niels 已提交
6073
                case (lexer::token_type::begin_object):
N
Niels 已提交
6074
                {
6075
                    if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result))))
N
Niels 已提交
6076 6077
                    {
                        // explicitly set result to object to cope with {}
N
Niels 已提交
6078 6079
                        result.m_type = value_t::object;
                        result.m_value = json_value(value_t::object);
N
Niels 已提交
6080
                    }
N
Niels 已提交
6081 6082 6083 6084 6085

                    // read next token
                    get_token();

                    // closing } -> we are done
N
Niels 已提交
6086
                    if (last_token == lexer::token_type::end_object)
N
Niels 已提交
6087
                    {
N
Niels 已提交
6088
                        get_token();
6089
                        if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
N
Niels 已提交
6090 6091 6092
                        {
                            result = basic_json(value_t::discarded);
                        }
N
Niels 已提交
6093
                        return result;
N
Niels 已提交
6094 6095
                    }

N
Niels 已提交
6096 6097 6098
                    // no comma is expected here
                    unexpect(lexer::token_type::value_separator);

N
Niels 已提交
6099 6100 6101
                    // otherwise: parse key-value pairs
                    do
                    {
N
Niels 已提交
6102 6103 6104 6105 6106 6107
                        // ugly, but could be fixed with loop reorganization
                        if (last_token == lexer::token_type::value_separator)
                        {
                            get_token();
                        }

N
Niels 已提交
6108
                        // store key
N
Niels 已提交
6109 6110
                        expect(lexer::token_type::value_string);
                        const auto key = m_lexer.get_string();
N
Niels 已提交
6111

N
Niels 已提交
6112 6113 6114
                        bool keep_tag = false;
                        if (keep)
                        {
N
Niels 已提交
6115 6116 6117 6118 6119 6120 6121 6122 6123
                            if (callback)
                            {
                                basic_json k(key);
                                keep_tag = callback(depth, parse_event_t::key, k);
                            }
                            else
                            {
                                keep_tag = true;
                            }
N
Niels 已提交
6124 6125
                        }

N
Niels 已提交
6126 6127
                        // parse separator (:)
                        get_token();
N
Niels 已提交
6128
                        expect(lexer::token_type::name_separator);
N
Niels 已提交
6129

6130
                        // parse and add value
N
Niels 已提交
6131
                        get_token();
N
Niels 已提交
6132 6133 6134
                        auto value = parse_internal(keep);
                        if (keep and keep_tag and not value.is_discarded())
                        {
6135
                            result[key] = std::move(value);
N
Niels 已提交
6136
                        }
N
Niels 已提交
6137
                    }
N
Niels 已提交
6138
                    while (last_token == lexer::token_type::value_separator);
N
Niels 已提交
6139 6140

                    // closing }
N
Niels 已提交
6141
                    expect(lexer::token_type::end_object);
N
Niels 已提交
6142
                    get_token();
6143
                    if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
N
Niels 已提交
6144 6145 6146
                    {
                        result = basic_json(value_t::discarded);
                    }
N
Niels 已提交
6147 6148

                    return result;
N
Niels 已提交
6149 6150
                }

N
Niels 已提交
6151
                case (lexer::token_type::begin_array):
N
Niels 已提交
6152
                {
6153
                    if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
N
Niels 已提交
6154 6155
                    {
                        // explicitly set result to object to cope with []
N
Niels 已提交
6156 6157
                        result.m_type = value_t::array;
                        result.m_value = json_value(value_t::array);
N
Niels 已提交
6158
                    }
N
Niels 已提交
6159 6160 6161 6162 6163

                    // read next token
                    get_token();

                    // closing ] -> we are done
N
Niels 已提交
6164
                    if (last_token == lexer::token_type::end_array)
N
Niels 已提交
6165
                    {
N
Niels 已提交
6166
                        get_token();
6167
                        if (callback and not callback(--depth, parse_event_t::array_end, result))
N
Niels 已提交
6168 6169 6170
                        {
                            result = basic_json(value_t::discarded);
                        }
N
Niels 已提交
6171
                        return result;
N
Niels 已提交
6172 6173
                    }

N
Niels 已提交
6174 6175 6176
                    // no comma is expected here
                    unexpect(lexer::token_type::value_separator);

N
Niels 已提交
6177 6178 6179
                    // otherwise: parse values
                    do
                    {
N
Niels 已提交
6180 6181 6182 6183 6184
                        // ugly, but could be fixed with loop reorganization
                        if (last_token == lexer::token_type::value_separator)
                        {
                            get_token();
                        }
N
Niels 已提交
6185

N
Niels 已提交
6186 6187 6188 6189
                        // parse value
                        auto value = parse_internal(keep);
                        if (keep and not value.is_discarded())
                        {
6190
                            result.push_back(std::move(value));
N
Niels 已提交
6191
                        }
N
Niels 已提交
6192
                    }
N
Niels 已提交
6193
                    while (last_token == lexer::token_type::value_separator);
N
Niels 已提交
6194 6195

                    // closing ]
N
Niels 已提交
6196
                    expect(lexer::token_type::end_array);
N
Niels 已提交
6197
                    get_token();
6198
                    if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
N
Niels 已提交
6199 6200 6201
                    {
                        result = basic_json(value_t::discarded);
                    }
N
Niels 已提交
6202 6203

                    return result;
N
Niels 已提交
6204 6205
                }

N
Niels 已提交
6206
                case (lexer::token_type::literal_null):
N
Niels 已提交
6207
                {
N
Niels 已提交
6208
                    get_token();
N
Niels 已提交
6209
                    result.m_type = value_t::null;
N
Niels 已提交
6210
                    break;
N
Niels 已提交
6211 6212
                }

N
Niels 已提交
6213
                case (lexer::token_type::value_string):
N
Niels 已提交
6214
                {
N
Niels 已提交
6215
                    const auto s = m_lexer.get_string();
N
Niels 已提交
6216
                    get_token();
N
Niels 已提交
6217 6218
                    result = basic_json(s);
                    break;
N
Niels 已提交
6219 6220
                }

N
Niels 已提交
6221
                case (lexer::token_type::literal_true):
N
Niels 已提交
6222
                {
N
Niels 已提交
6223
                    get_token();
N
Niels 已提交
6224 6225
                    result.m_type = value_t::boolean;
                    result.m_value = true;
N
Niels 已提交
6226
                    break;
N
Niels 已提交
6227 6228
                }

N
Niels 已提交
6229
                case (lexer::token_type::literal_false):
N
Niels 已提交
6230
                {
N
Niels 已提交
6231
                    get_token();
N
Niels 已提交
6232 6233
                    result.m_type = value_t::boolean;
                    result.m_value = false;
N
Niels 已提交
6234
                    break;
N
Niels 已提交
6235 6236
                }

N
Niels 已提交
6237
                case (lexer::token_type::value_number):
N
Niels 已提交
6238
                {
N
Niels 已提交
6239
                    auto float_val = m_lexer.get_number();
N
Niels 已提交
6240

N
Niels 已提交
6241 6242
                    // NAN is returned if token could not be translated
                    // completely
N
Niels 已提交
6243
                    if (std::isnan(float_val))
N
Niels 已提交
6244 6245
                    {
                        throw std::invalid_argument(std::string("parse error - ") +
N
Niels 已提交
6246
                                                    m_lexer.get_token() + " is not a number");
N
Niels 已提交
6247 6248
                    }

N
Niels 已提交
6249 6250
                    get_token();

N
Niels 已提交
6251
                    // check if conversion loses precision
N
Niels 已提交
6252
                    const auto int_val = static_cast<number_integer_t>(float_val);
N
Niels 已提交
6253
                    if (approx(float_val, static_cast<long double>(int_val)))
N
Niels 已提交
6254 6255
                    {
                        // we basic_json not lose precision -> return int
N
Niels 已提交
6256 6257
                        result.m_type = value_t::number_integer;
                        result.m_value = int_val;
N
Niels 已提交
6258 6259 6260 6261
                    }
                    else
                    {
                        // we would lose precision -> returnfloat
N
Niels 已提交
6262
                        result.m_type = value_t::number_float;
N
Niels 已提交
6263
                        result.m_value = static_cast<number_float_t>(float_val);
N
Niels 已提交
6264
                    }
N
Niels 已提交
6265
                    break;
N
Niels 已提交
6266 6267 6268 6269
                }

                default:
                {
N
Niels 已提交
6270 6271
                    // the last token was unexpected
                    unexpect(last_token);
N
Niels 已提交
6272 6273
                }
            }
N
Niels 已提交
6274

6275
            if (keep and callback and not callback(depth, parse_event_t::value, result))
N
Niels 已提交
6276 6277 6278 6279
            {
                result = basic_json(value_t::discarded);
            }
            return result;
N
Niels 已提交
6280 6281
        }

N
Niels 已提交
6282
        /// get next token from lexer
6283
        typename lexer::token_type get_token()
N
Niels 已提交
6284
        {
N
Niels 已提交
6285 6286
            last_token = m_lexer.scan();
            return last_token;
N
Niels 已提交
6287 6288
        }

6289
        void expect(typename lexer::token_type t) const
N
Niels 已提交
6290 6291 6292 6293
        {
            if (t != last_token)
            {
                std::string error_msg = "parse error - unexpected \'";
N
Niels 已提交
6294
                error_msg += m_lexer.get_token();
N
cleanup  
Niels 已提交
6295 6296
                error_msg += "\' (" + lexer::token_type_name(last_token);
                error_msg += "); expected " + lexer::token_type_name(t);
N
Niels 已提交
6297 6298 6299 6300
                throw std::invalid_argument(error_msg);
            }
        }

6301
        void unexpect(typename lexer::token_type t) const
N
Niels 已提交
6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312
        {
            if (t == last_token)
            {
                std::string error_msg = "parse error - unexpected \'";
                error_msg += m_lexer.get_token();
                error_msg += "\' (";
                error_msg += lexer::token_type_name(last_token) + ")";
                throw std::invalid_argument(error_msg);
            }
        }

N
Niels 已提交
6313
      private:
N
Niels 已提交
6314
        /// current level of recursion
N
Niels 已提交
6315 6316 6317
        int depth = 0;
        /// callback function
        parser_callback_t callback;
N
Niels 已提交
6318
        /// the type of the last read token
N
Niels 已提交
6319
        typename lexer::token_type last_token = lexer::token_type::uninitialized;
N
Niels 已提交
6320
        /// the lexer
N
Niels 已提交
6321
        lexer m_lexer;
N
Niels 已提交
6322
    };
N
cleanup  
Niels 已提交
6323 6324 6325 6326 6327 6328 6329
};


/////////////
// presets //
/////////////

N
Niels 已提交
6330 6331 6332 6333 6334 6335
/*!
@brief default JSON class

This type is the default specialization of the @ref basic_json class which uses
the standard template types.
*/
N
cleanup  
Niels 已提交
6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346
using json = basic_json<>;
}


/////////////////////////
// nonmember functions //
/////////////////////////

// specialization of std::swap, and std::hash
namespace std
{
N
Niels 已提交
6347 6348 6349 6350
/*!
@brief exchanges the values of two JSON objects
@ingroup container
*/
N
cleanup  
Niels 已提交
6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364
template <>
inline void swap(nlohmann::json& j1,
                 nlohmann::json& j2) noexcept(
                     is_nothrow_move_constructible<nlohmann::json>::value and
                     is_nothrow_move_assignable<nlohmann::json>::value
                 )
{
    j1.swap(j2);
}

/// hash value for JSON objects
template <>
struct hash<nlohmann::json>
{
N
Niels 已提交
6365
    /// return a hash value for a JSON object
6366
    std::size_t operator()(const nlohmann::json& j) const
N
cleanup  
Niels 已提交
6367 6368
    {
        // a naive hashing via the string representation
N
Niels 已提交
6369 6370
        const auto& h = hash<nlohmann::json::string_t>();
        return h(j.dump());
N
cleanup  
Niels 已提交
6371 6372 6373 6374
    }
};
}

N
Niels 已提交
6375
/*!
N
Niels 已提交
6376 6377
@brief user-defined string literal for JSON values

N
Niels 已提交
6378 6379 6380 6381
This operator implements a user-defined string literal for JSON objects. It can
be used by adding \p "_json" to a string literal and returns a JSON object if
no parse error occurred.

N
Niels 已提交
6382
@param[in] s  a string representation of a JSON object
N
Niels 已提交
6383 6384
@return a JSON object
*/
N
Niels 已提交
6385
inline nlohmann::json operator "" _json(const char* s, std::size_t)
N
Niels 已提交
6386
{
N
Niels 已提交
6387 6388
    return nlohmann::json::parse(reinterpret_cast<nlohmann::json::string_t::value_type*>
                                 (const_cast<char*>(s)));
N
Niels 已提交
6389 6390
}

N
cleanup  
Niels 已提交
6391
#endif