json.hpp.re2c 207.9 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 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
@copyright The code is licensed under the [MIT
           License](http://opensource.org/licenses/MIT):
           <br>
           Copyright &copy; 2013-2015 Niels Lohmann.
           <br>
           Permission is hereby granted, free of charge, to any person
           obtaining a copy of this software and associated documentation files
           (the "Software"), to deal in the Software without restriction,
           including without limitation the rights to use, copy, modify, merge,
           publish, distribute, sublicense, and/or sell copies of the Software,
           and to permit persons to whom the Software is furnished to do so,
           subject to the following conditions:
           <br>
           The above copyright notice and this permission notice shall be
           included in all copies or substantial portions of the Software.
           <br>
           THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
           EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
           MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
           NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
           BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
           ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
           CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
           SOFTWARE.

@author [Niels Lohmann](http://nlohmann.me)
N
Niels 已提交
35
@see https://github.com/nlohmann/json to download the source code
N
Niels 已提交
36 37
*/

N
Niels 已提交
38 39
#ifndef NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_HPP
N
cleanup  
Niels 已提交
40 41

#include <algorithm>
42
#include <array>
N
Niels 已提交
43
#include <ciso646>
N
Niels 已提交
44
#include <cmath>
N
Niels 已提交
45
#include <cstdio>
N
cleanup  
Niels 已提交
46 47
#include <functional>
#include <initializer_list>
N
Niels 已提交
48
#include <iomanip>
N
cleanup  
Niels 已提交
49 50 51 52 53
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
N
Niels 已提交
54
#include <sstream>
N
cleanup  
Niels 已提交
55 56 57 58 59
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

N
Niels 已提交
60 61 62 63 64 65 66
// enable ssize_t on MinGW
#ifdef __GNUC__
    #ifdef __MINGW32__
        #include <sys/types.h>
    #endif
#endif

N
Niels 已提交
67 68
// enable ssize_t for MSVC
#ifdef _MSC_VER
N
Niels 已提交
69
    #include <basetsd.h>
N
Niels 已提交
70 71 72
    using ssize_t = SSIZE_T;
#endif

N
cleanup  
Niels 已提交
73
/*!
N
Niels 已提交
74
@brief namespace for Niels Lohmann
N
cleanup  
Niels 已提交
75 76 77 78 79
@see https://github.com/nlohmann
*/
namespace nlohmann
{

N
Niels 已提交
80

81 82 83 84
/*!
@brief unnamed namespace with internal helper functions
*/
namespace
N
Niels 已提交
85
{
86 87 88 89
/*!
@brief Helper to determine whether there's a key_type for T.
@sa http://stackoverflow.com/a/7728728/266378
*/
N
Niels 已提交
90
template<typename T>
N
Niels 已提交
91
struct has_mapped_type
N
Niels 已提交
92 93
{
  private:
N
Niels 已提交
94
    template<typename C> static char test(typename C::mapped_type*);
N
Niels 已提交
95 96 97 98
    template<typename C> static int  test(...);
  public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
99 100 101 102 103 104 105

/// "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 已提交
106
}
N
Niels 已提交
107

N
cleanup  
Niels 已提交
108
/*!
N
Niels 已提交
109
@brief a class to store JSON values
N
cleanup  
Niels 已提交
110

N
Niels 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124
@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 已提交
125

N
Niels 已提交
126 127
@requirement The class satisfies the following concept requirements:
- Basic
N
Niels 已提交
128 129 130 131 132 133 134 135 136 137 138 139
 - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
   JSON values can be default constructed. The result will be a JSON null value.
 - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
   A JSON value can be constructed from an rvalue argument.
 - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
   A JSON value can be copy-constrcuted from an lvalue expression.
 - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
   A JSON value van be assigned from an rvalue argument.
 - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
   A JSON value can be copy-assigned from an lvalue expression.
 - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
   JSON values can be destructed.
N
Niels 已提交
140
- Layout
N
Niels 已提交
141 142 143 144 145
 - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
   JSON values have
   [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
   All non-static data members are private and standard layout types, the class
   has no virtual functions or (virtual) base classes.
N
Niels 已提交
146
- Library-wide
N
Niels 已提交
147 148 149 150 151 152 153 154 155 156 157 158
 - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
   JSON values can be compared with `==`, see @ref
   operator==(const_reference,const_reference).
 - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
   JSON values can be compared with `<`, see @ref
   operator<(const_reference,const_reference).
 - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
   other compatible types, using unqualified function call @ref swap().
 - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
   JSON values can be compared against `std::nullptr_t` objects which are used
   to model the `null` value.
N
Niels 已提交
159
- Container
N
Niels 已提交
160 161 162 163 164
 - [Container](http://en.cppreference.com/w/cpp/concept/Container):
   JSON values can be used like STL containers and provide iterator access.
 - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
   JSON values can be used like STL containers and provide reverse iterator
   access.
N
Niels 已提交
165

N
Niels 已提交
166
@internal
N
Niels 已提交
167
@note ObjectType trick from http://stackoverflow.com/a/9860911
N
Niels 已提交
168
@endinternal
N
Niels 已提交
169

N
Niels 已提交
170
@see RFC 7159 <http://rfc7159.net/rfc7159>
N
cleanup  
Niels 已提交
171 172 173 174 175 176 177
*/
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 已提交
178
    class NumberFloatType = double,
N
Niels 已提交
179
    template<typename U> class AllocatorType = std::allocator
N
cleanup  
Niels 已提交
180 181 182
    >
class basic_json
{
183 184
  private:
    /// workaround type for MSVC
N
Niels 已提交
185 186 187 188 189 190 191
    using basic_json_t = basic_json<ObjectType,
          ArrayType,
          StringType,
          BooleanType,
          NumberIntegerType,
          NumberFloatType,
          AllocatorType>;
192 193 194

  public:

N
cleanup  
Niels 已提交
195 196 197 198
    /////////////////////
    // container types //
    /////////////////////

N
Niels 已提交
199 200 201
    /// @name container types
    /// @{

N
Niels 已提交
202
    /// the type of elements in a basic_json container
N
cleanup  
Niels 已提交
203
    using value_type = basic_json;
N
Niels 已提交
204

N
Niels 已提交
205
    /// the type of an element reference
N
Niels 已提交
206
    using reference = value_type&;
N
Niels 已提交
207

N
Niels 已提交
208
    /// the type of an element const reference
N
Niels 已提交
209
    using const_reference = const value_type&;
N
Niels 已提交
210

N
Niels 已提交
211
    /// a type to represent differences between iterators
N
Niels 已提交
212 213
    using difference_type = std::ptrdiff_t;

N
Niels 已提交
214
    /// a type to represent container sizes
N
Niels 已提交
215 216 217
    using size_type = std::size_t;

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

N
cleanup  
Niels 已提交
220
    /// the type of an element pointer
N
Niels 已提交
221
    using pointer = typename std::allocator_traits<allocator_type>::pointer;
N
cleanup  
Niels 已提交
222
    /// the type of an element const pointer
N
Niels 已提交
223
    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
N
Niels 已提交
224

N
Niels 已提交
225 226 227
    // forward declaration
    template<typename Base> class json_reverse_iterator;

N
Niels 已提交
228 229 230 231 232
    /// 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 已提交
233
    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
N
Niels 已提交
234
    /// a const reverse iterator for a basic_json container
N
Niels 已提交
235
    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
N
Niels 已提交
236

N
Niels 已提交
237 238 239
    /// @}


N
Niels 已提交
240 241 242
    /*!
    @brief returns the allocator associated with the container
    */
243
    static allocator_type get_allocator()
N
Niels 已提交
244 245 246 247 248
    {
        return allocator_type();
    }


N
cleanup  
Niels 已提交
249 250 251 252
    ///////////////////////////
    // JSON value data types //
    ///////////////////////////

N
Niels 已提交
253 254 255
    /// @name JSON value data types
    /// @{

N
Niels 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 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 312 313 314 315 316 317 318 319 320 321
    /*!
    @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 已提交
322 323 324 325 326
    using object_t = ObjectType<StringType,
          basic_json,
          std::less<StringType>,
          AllocatorType<std::pair<const StringType,
          basic_json>>>;
N
Niels 已提交
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 356 357 358 359 360 361 362 363 364

    /*!
    @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 已提交
365
    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
N
Niels 已提交
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 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

    /*!
    @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 已提交
409
    using string_t = StringType;
N
Niels 已提交
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

    /*!
    @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 已提交
433
    using boolean_t = BooleanType;
N
Niels 已提交
434 435 436 437 438 439 440 441 442 443 444 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

    /*!
    @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 已提交
497
    using number_integer_t = NumberIntegerType;
N
Niels 已提交
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556

    /*!
    @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 已提交
557 558
    using number_float_t = NumberFloatType;

N
Niels 已提交
559 560
    /// @}

N
cleanup  
Niels 已提交
561

N
Niels 已提交
562 563 564
    ///////////////////////////
    // JSON type enumeration //
    ///////////////////////////
N
Niels 已提交
565

N
Niels 已提交
566
    /*!
N
Niels 已提交
567
    @brief the JSON type enumeration
N
Niels 已提交
568

N
Niels 已提交
569 570 571
    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 已提交
572
    */
N
Niels 已提交
573 574 575 576 577 578 579 580 581
    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)
N
Niels 已提交
582
        discarded       ///< discarded by the the parser callback function
N
Niels 已提交
583 584
    };

N
Niels 已提交
585

N
Niels 已提交
586
  private:
N
cleanup  
Niels 已提交
587 588 589 590 591 592 593 594 595 596 597 598 599
    ////////////////////////
    // 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 已提交
600
        /// boolean
N
cleanup  
Niels 已提交
601 602 603
        boolean_t boolean;
        /// number (integer)
        number_integer_t number_integer;
N
Niels 已提交
604
        /// number (floating-point)
N
cleanup  
Niels 已提交
605 606 607
        number_float_t number_float;

        /// default constructor (for null values)
608
        json_value() noexcept = default;
N
cleanup  
Niels 已提交
609
        /// constructor for booleans
610
        json_value(boolean_t v) noexcept : boolean(v) {}
N
cleanup  
Niels 已提交
611
        /// constructor for numbers (integer)
612
        json_value(number_integer_t v) noexcept : number_integer(v) {}
N
Niels 已提交
613
        /// constructor for numbers (floating-point)
614
        json_value(number_float_t v) noexcept : number_float(v) {}
N
Niels 已提交
615
        /// constructor for empty values of a given type
616
        json_value(value_t t)
N
Niels 已提交
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
        {
            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 已提交
633

N
Niels 已提交
634 635 636 637 638 639 640
                case (value_t::array):
                {
                    AllocatorType<array_t> alloc;
                    array = alloc.allocate(1);
                    alloc.construct(array);
                    break;
                }
N
cleanup  
Niels 已提交
641

N
Niels 已提交
642 643 644 645 646 647 648
                case (value_t::string):
                {
                    AllocatorType<string_t> alloc;
                    string = alloc.allocate(1);
                    alloc.construct(string, "");
                    break;
                }
N
cleanup  
Niels 已提交
649

N
Niels 已提交
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
                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 已提交
669 670

        /// constructor for strings
671
        json_value(const string_t& value)
N
Niels 已提交
672 673 674 675 676 677 678
        {
            AllocatorType<string_t> alloc;
            string = alloc.allocate(1);
            alloc.construct(string, value);
        }

        /// constructor for objects
679
        json_value(const object_t& value)
N
Niels 已提交
680 681 682 683 684 685 686
        {
            AllocatorType<object_t> alloc;
            object = alloc.allocate(1);
            alloc.construct(object, value);
        }

        /// constructor for arrays
687
        json_value(const array_t& value)
N
Niels 已提交
688 689 690 691 692
        {
            AllocatorType<array_t> alloc;
            array = alloc.allocate(1);
            alloc.construct(array, value);
        }
N
cleanup  
Niels 已提交
693 694
    };

N
Niels 已提交
695 696

  public:
N
Niels 已提交
697 698 699 700
    //////////////////////////
    // JSON parser callback //
    //////////////////////////

N
Niels 已提交
701 702 703 704 705 706
    /*!
    @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 已提交
707 708
    enum class parse_event_t : uint8_t
    {
N
Niels 已提交
709 710 711 712 713 714 715 716 717 718 719 720
        /// 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 已提交
721 722
    };

N
Niels 已提交
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
    /*!
    @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 已提交
772

N
cleanup  
Niels 已提交
773 774 775 776 777

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

N
Niels 已提交
778 779 780
    /*!
    @brief create an empty value with a given type

N
Niels 已提交
781 782 783 784 785
    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 已提交
786 787 788 789 790 791
    null        | `null`
    boolean     | `false`
    string      | `""`
    number      | `0`
    object      | `{}`
    array       | `[]`
N
Niels 已提交
792

N
Niels 已提交
793
    @param[in] value  the type of the value to create
N
Niels 已提交
794 795 796

    @complexity Constant.

N
Niels 已提交
797
    @throw std::bad_alloc if allocation for object, array, or string value
N
Niels 已提交
798
    fails
N
Niels 已提交
799 800 801

    @liveexample{The following code shows the constructor for different @ref
    value_t values,basic_json__value_t}
N
Niels 已提交
802
    */
803
    basic_json(const value_t value)
N
Niels 已提交
804 805
        : m_type(value), m_value(value)
    {}
N
cleanup  
Niels 已提交
806

N
Niels 已提交
807 808
    /*!
    @brief create a null object (implicitly)
N
Niels 已提交
809 810 811 812 813 814 815 816 817 818 819 820 821 822

    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 已提交
823
    */
824
    basic_json() noexcept = default;
N
cleanup  
Niels 已提交
825

N
Niels 已提交
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
    /*!
    @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()
    */
842
    basic_json(std::nullptr_t) noexcept
N
Niels 已提交
843
        : basic_json(value_t::null)
N
cleanup  
Niels 已提交
844 845
    {}

N
Niels 已提交
846 847 848 849 850
    /*!
    @brief create an object (explicit)

    Create an object JSON value with a given content.

N
Niels 已提交
851
    @param[in] value  a value for the object
N
Niels 已提交
852 853 854

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

N
Niels 已提交
855
    @throw std::bad_alloc if allocation for object value fails
N
Niels 已提交
856 857 858 859 860 861

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

    @sa basic_json(const CompatibleObjectType&)
    */
862
    basic_json(const object_t& value)
N
Niels 已提交
863 864
        : m_type(value_t::object), m_value(value)
    {}
N
cleanup  
Niels 已提交
865

N
Niels 已提交
866 867 868 869 870 871 872 873 874 875
    /*!
    @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 已提交
876
    @param[in] value  a value for the object
N
Niels 已提交
877 878 879

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

N
Niels 已提交
880
    @throw std::bad_alloc if allocation for object value fails
N
Niels 已提交
881 882 883 884 885 886 887

    @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 已提交
888
              std::enable_if<
N
Niels 已提交
889 890
                  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 已提交
891
              = 0>
N
Niels 已提交
892
    basic_json(const CompatibleObjectType& value)
N
Niels 已提交
893 894
        : m_type(value_t::object)
    {
N
Niels 已提交
895
        AllocatorType<object_t> alloc;
N
Niels 已提交
896
        m_value.object = alloc.allocate(1);
897 898 899
        using std::begin;
        using std::end;
        alloc.construct(m_value.object, begin(value), end(value));
N
Niels 已提交
900
    }
N
cleanup  
Niels 已提交
901

N
Niels 已提交
902 903 904 905 906
    /*!
    @brief create an array (explicit)

    Create an array JSON value with a given content.

N
Niels 已提交
907
    @param[in] value  a value for the array
N
Niels 已提交
908 909 910

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

N
Niels 已提交
911
    @throw std::bad_alloc if allocation for array value fails
N
Niels 已提交
912 913 914 915 916 917

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

    @sa basic_json(const CompatibleArrayType&)
    */
918
    basic_json(const array_t& value)
N
Niels 已提交
919 920
        : m_type(value_t::array), m_value(value)
    {}
N
cleanup  
Niels 已提交
921

N
Niels 已提交
922 923 924 925 926 927 928 929 930 931
    /*!
    @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 已提交
932
    @param[in] value  a value for the array
N
Niels 已提交
933 934 935

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

N
Niels 已提交
936
    @throw std::bad_alloc if allocation for array value fails
N
Niels 已提交
937 938 939 940 941 942 943

    @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 已提交
944
              std::enable_if<
N
Niels 已提交
945 946 947 948
                  not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
                  not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
                  not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
                  not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
N
Niels 已提交
949 950 951
                  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 已提交
952
              = 0>
N
Niels 已提交
953
    basic_json(const CompatibleArrayType& value)
N
Niels 已提交
954 955
        : m_type(value_t::array)
    {
N
Niels 已提交
956
        AllocatorType<array_t> alloc;
N
Niels 已提交
957
        m_value.array = alloc.allocate(1);
958 959 960
        using std::begin;
        using std::end;
        alloc.construct(m_value.array, begin(value), end(value));
N
Niels 已提交
961
    }
N
cleanup  
Niels 已提交
962

N
Niels 已提交
963 964 965 966 967 968 969 970 971
    /*!
    @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 已提交
972
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
973 974 975 976 977 978 979

    @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&)
    */
980
    basic_json(const string_t& value)
N
Niels 已提交
981 982
        : m_type(value_t::string), m_value(value)
    {}
N
cleanup  
Niels 已提交
983

N
Niels 已提交
984 985 986
    /*!
    @brief create a string (explicit)

N
Niels 已提交
987
    Create a string JSON value with a given content.
N
Niels 已提交
988 989 990 991 992

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

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

N
Niels 已提交
993
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
994 995 996 997 998 999 1000

    @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&)
    */
1001
    basic_json(const typename string_t::value_type* value)
N
Niels 已提交
1002 1003
        : basic_json(string_t(value))
    {}
N
cleanup  
Niels 已提交
1004

N
Niels 已提交
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    /*!
    @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 已提交
1017
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
1018 1019 1020 1021 1022 1023

    @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 已提交
1024
    template <class CompatibleStringType, typename
N
cleanup  
Niels 已提交
1025
              std::enable_if<
N
Niels 已提交
1026
                  std::is_constructible<string_t, CompatibleStringType>::value, int>::type
N
cleanup  
Niels 已提交
1027
              = 0>
N
Niels 已提交
1028
    basic_json(const CompatibleStringType& value)
N
cleanup  
Niels 已提交
1029 1030 1031
        : basic_json(string_t(value))
    {}

N
Niels 已提交
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    /*!
    @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}
    */
1044
    basic_json(boolean_t value)
N
cleanup  
Niels 已提交
1045 1046 1047
        : m_type(value_t::boolean), m_value(value)
    {}

N
Niels 已提交
1048 1049 1050
    /*!
    @brief create an integer number (explicit)

N
Niels 已提交
1051 1052 1053 1054 1055
    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 已提交
1056
    @param[in] value  an integer to create a JSON number from
N
Niels 已提交
1057

N
Niels 已提交
1058 1059 1060 1061 1062 1063
    @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 已提交
1064 1065
    @liveexample{The example below shows the construction of a JSON integer
    number value.,basic_json__number_integer_t}
N
Niels 已提交
1066 1067

    @sa basic_json(const int)
N
Niels 已提交
1068 1069 1070 1071 1072 1073 1074
    */
    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 已提交
1075 1076 1077
        : m_type(value_t::number_integer), m_value(value)
    {}

N
Niels 已提交
1078
    /*!
N
Niels 已提交
1079 1080
    @brief create an integer number from an enum type (explicit)

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

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

N
Niels 已提交
1085 1086 1087 1088 1089 1090 1091 1092 1093
    @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 已提交
1094
    number value from an anonymous enum.,basic_json__const_int}
N
Niels 已提交
1095 1096

    @sa basic_json(const number_integer_t)
N
Niels 已提交
1097 1098 1099 1100
    */
    basic_json(const int value)
        : m_type(value_t::number_integer),
          m_value(static_cast<number_integer_t>(value))
N
Niels 已提交
1101 1102
    {}

N
Niels 已提交
1103 1104 1105
    /*!
    @brief create an integer number (implicit)

N
Niels 已提交
1106
    Create an integer number JSON value with a given content. This constructor
N
Niels 已提交
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
    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 已提交
1125
             std::enable_if<
N
Niels 已提交
1126 1127
                 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
N
cleanup  
Niels 已提交
1128
             = 0>
N
Niels 已提交
1129
    basic_json(const CompatibleNumberIntegerType value) noexcept
N
Niels 已提交
1130 1131
        : m_type(value_t::number_integer),
          m_value(static_cast<number_integer_t>(value))
N
cleanup  
Niels 已提交
1132 1133
    {}

N
Niels 已提交
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
    /*!
    @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 已提交
1148
    @complexity Constant.
N
Niels 已提交
1149 1150 1151 1152

    @liveexample{The following example creates several floating-point
    values.,basic_json__number_float_t}
    */
N
Niels 已提交
1153
    basic_json(const number_float_t value)
N
cleanup  
Niels 已提交
1154
        : m_type(value_t::number_float), m_value(value)
N
Niels 已提交
1155 1156 1157 1158 1159 1160 1161 1162
    {
        // replace infinity and NAN by null
        if (not std::isfinite(value))
        {
            m_type = value_t::null;
            m_value = json_value();
        }
    }
N
cleanup  
Niels 已提交
1163

N
Niels 已提交
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    /*!
    @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 已提交
1191
    template<typename CompatibleNumberFloatType, typename = typename
N
cleanup  
Niels 已提交
1192
             std::enable_if<
N
Niels 已提交
1193 1194
                 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
                 std::is_floating_point<CompatibleNumberFloatType>::value>::type
N
cleanup  
Niels 已提交
1195
             >
N
Niels 已提交
1196
    basic_json(const CompatibleNumberFloatType value) noexcept
N
Niels 已提交
1197 1198
        : basic_json(number_float_t(value))
    {}
N
cleanup  
Niels 已提交
1199

N
Niels 已提交
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
    /*!
    @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 已提交
1226 1227
    With the rules described above, the following JSON values cannot be
    expressed by an initializer list:
N
Niels 已提交
1228

N
Niels 已提交
1229 1230 1231 1232 1233
    - 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 已提交
1234 1235 1236 1237 1238

    @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 已提交
1239
    @param[in] init  initializer list with JSON values
N
Niels 已提交
1240

N
Niels 已提交
1241 1242 1243
    @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 已提交
1244 1245
    used by the functions @ref array(std::initializer_list<basic_json>) and
    @ref object(std::initializer_list<basic_json>).
N
Niels 已提交
1246

N
Niels 已提交
1247
    @param[in] manual_type internal parameter; when @a type_deduction is set to
N
Niels 已提交
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
    `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 已提交
1261 1262 1263 1264
    @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 已提交
1265
    */
N
Niels 已提交
1266 1267
    basic_json(std::initializer_list<basic_json> init,
               bool type_deduction = true,
N
Niels 已提交
1268
               value_t manual_type = value_t::array)
N
cleanup  
Niels 已提交
1269 1270 1271 1272
    {
        // the initializer list could describe an object
        bool is_object = true;

N
Niels 已提交
1273 1274
        // check if each element is an array with two elements whose first element
        // is a string
N
Niels 已提交
1275
        for (const auto& element : init)
N
cleanup  
Niels 已提交
1276
        {
N
Niels 已提交
1277 1278
            if (element.m_type != value_t::array or element.size() != 2
                    or element[0].m_type != value_t::string)
N
cleanup  
Niels 已提交
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
            {
                // 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 已提交
1299
                throw std::domain_error("cannot create object from initializer list");
N
cleanup  
Niels 已提交
1300 1301 1302 1303 1304 1305 1306
            }
        }

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

N
Niels 已提交
1309
            for (auto& element : init)
N
cleanup  
Niels 已提交
1310 1311 1312 1313 1314 1315 1316 1317
            {
                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 已提交
1318
            AllocatorType<array_t> alloc;
N
Niels 已提交
1319
            m_value.array = alloc.allocate(1);
N
Niels 已提交
1320
            alloc.construct(m_value.array, std::move(init));
N
cleanup  
Niels 已提交
1321 1322 1323
        }
    }

N
Niels 已提交
1324 1325 1326 1327 1328 1329 1330 1331 1332
    /*!
    @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 已提交
1333 1334
    basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
    are:
N
Niels 已提交
1335 1336 1337 1338 1339 1340
    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 已提交
1341
    @param[in] init  initializer list with JSON values to create an array from
N
Niels 已提交
1342 1343 1344 1345 1346 1347 1348 1349 1350
    (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 已提交
1351 1352 1353 1354
    @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 已提交
1355
    */
N
Niels 已提交
1356 1357
    static basic_json array(std::initializer_list<basic_json> init =
                                std::initializer_list<basic_json>())
N
cleanup  
Niels 已提交
1358
    {
N
Niels 已提交
1359
        return basic_json(init, false, value_t::array);
N
cleanup  
Niels 已提交
1360 1361
    }

N
Niels 已提交
1362 1363 1364 1365 1366 1367 1368 1369
    /*!
    @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 已提交
1370 1371 1372 1373 1374
    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 已提交
1375

N
Niels 已提交
1376
    @param[in] init  initializer list to create an object from (optional)
N
Niels 已提交
1377 1378 1379 1380

    @return JSON object value

    @throw std::domain_error if @a init is not a pair whose first elements are
N
Niels 已提交
1381 1382
    strings; thrown by @ref basic_json(std::initializer_list<basic_json>, bool,
    value_t)
N
Niels 已提交
1383 1384 1385 1386 1387 1388

    @complexity Linear in the size of @a init.

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

N
Niels 已提交
1389 1390 1391 1392
    @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 已提交
1393
    */
N
Niels 已提交
1394 1395
    static basic_json object(std::initializer_list<basic_json> init =
                                 std::initializer_list<basic_json>())
N
cleanup  
Niels 已提交
1396
    {
N
Niels 已提交
1397
        return basic_json(init, false, value_t::object);
N
cleanup  
Niels 已提交
1398 1399
    }

N
Niels 已提交
1400 1401 1402 1403 1404 1405 1406
    /*!
    @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 已提交
1407 1408
    @param[in] count  the number of JSON copies of @a value to create
    @param[in] value  the JSON value to copy
N
Niels 已提交
1409 1410 1411 1412 1413 1414 1415 1416

    @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 已提交
1417 1418 1419 1420
        : m_type(value_t::array)
    {
        AllocatorType<array_t> alloc;
        m_value.array = alloc.allocate(1);
N
Niels 已提交
1421
        alloc.construct(m_value.array, count, value);
N
Niels 已提交
1422
    }
N
Niels 已提交
1423

N
Niels 已提交
1424 1425 1426 1427 1428
    /*!
    @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 已提交
1429
    - In case of primitive types (number, boolean, or string), @a first must
N
Niels 已提交
1430 1431
      be `begin()` and @a last must be `end()`. In this case, the value is
      copied. Otherwise, std::out_of_range is thrown.
N
Niels 已提交
1432
    - In case of structured types (array, object), the constructor behaves
N
Niels 已提交
1433
      as similar versions for `std::vector`.
N
Niels 已提交
1434
    - In case of a null type, std::domain_error is thrown.
N
Niels 已提交
1435 1436 1437 1438 1439 1440 1441 1442 1443

    @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 已提交
1444
    @throw std::out_of_range if iterators are for a primitive type (number,
N
Niels 已提交
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
    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 已提交
1455
              std::enable_if<
N
Niels 已提交
1456 1457
                  std::is_same<InputIT, typename basic_json_t::iterator>::value or
                  std::is_same<InputIT, typename basic_json_t::const_iterator>::value
N
Niels 已提交
1458 1459
                  , int>::type
              = 0>
N
Niels 已提交
1460
    basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
N
Niels 已提交
1461 1462
    {
        // make sure iterator fits the current value
N
Niels 已提交
1463
        if (first.m_object != last.m_object)
N
Niels 已提交
1464
        {
N
Niels 已提交
1465
            throw std::domain_error("iterators are not compatible");
N
Niels 已提交
1466 1467
        }

N
Niels 已提交
1468
        // check if iterator range is complete for primitive values
N
Niels 已提交
1469 1470 1471 1472 1473 1474 1475
        switch (m_type)
        {
            case value_t::number_integer:
            case value_t::number_float:
            case value_t::boolean:
            case value_t::string:
            {
1476
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
N
Niels 已提交
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
                {
                    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 已提交
1511
                m_value = *first.m_object->m_value.string;
N
Niels 已提交
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
                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 已提交
1533
                throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
N
Niels 已提交
1534 1535 1536 1537
            }
        }
    }

N
cleanup  
Niels 已提交
1538 1539 1540 1541
    ///////////////////////////////////////
    // other constructors and destructor //
    ///////////////////////////////////////

N
Niels 已提交
1542 1543
    /*!
    @brief copy constructor
N
Niels 已提交
1544

N
Niels 已提交
1545 1546
    Creates a copy of a given JSON value.

N
Niels 已提交
1547
    @param[in] other  the JSON value to copy
N
Niels 已提交
1548 1549 1550 1551 1552 1553 1554

    @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 已提交
1555
    @throw std::bad_alloc if allocation for object, array, or string fails.
N
Niels 已提交
1556 1557

    @liveexample{The following code shows an example for the copy
N
Niels 已提交
1558
    constructor.,basic_json__basic_json}
N
Niels 已提交
1559
    */
1560
    basic_json(const basic_json& other)
N
cleanup  
Niels 已提交
1561 1562 1563 1564 1565
        : m_type(other.m_type)
    {
        switch (m_type)
        {
            case (value_t::null):
N
Niels 已提交
1566
            case (value_t::discarded):
N
cleanup  
Niels 已提交
1567 1568 1569
            {
                break;
            }
N
Niels 已提交
1570

N
cleanup  
Niels 已提交
1571 1572
            case (value_t::object):
            {
N
Niels 已提交
1573
                m_value = *other.m_value.object;
N
cleanup  
Niels 已提交
1574 1575
                break;
            }
N
Niels 已提交
1576

N
cleanup  
Niels 已提交
1577 1578
            case (value_t::array):
            {
N
Niels 已提交
1579
                m_value = *other.m_value.array;
N
cleanup  
Niels 已提交
1580 1581
                break;
            }
N
Niels 已提交
1582

N
cleanup  
Niels 已提交
1583 1584
            case (value_t::string):
            {
N
Niels 已提交
1585
                m_value = *other.m_value.string;
N
cleanup  
Niels 已提交
1586 1587
                break;
            }
N
Niels 已提交
1588

N
cleanup  
Niels 已提交
1589 1590
            case (value_t::boolean):
            {
N
Niels 已提交
1591
                m_value = other.m_value.boolean;
N
cleanup  
Niels 已提交
1592 1593
                break;
            }
N
Niels 已提交
1594

N
cleanup  
Niels 已提交
1595 1596
            case (value_t::number_integer):
            {
N
Niels 已提交
1597
                m_value = other.m_value.number_integer;
N
cleanup  
Niels 已提交
1598 1599
                break;
            }
N
Niels 已提交
1600

N
cleanup  
Niels 已提交
1601 1602
            case (value_t::number_float):
            {
N
Niels 已提交
1603
                m_value = other.m_value.number_float;
N
cleanup  
Niels 已提交
1604 1605 1606 1607 1608
                break;
            }
        }
    }

N
Niels 已提交
1609 1610 1611 1612 1613 1614 1615
    /*!
    @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 已提交
1616
    @param[in,out] other  value to move to this object
N
Niels 已提交
1617 1618 1619 1620 1621 1622 1623 1624

    @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}
    */
1625
    basic_json(basic_json&& other) noexcept
N
cleanup  
Niels 已提交
1626 1627 1628
        : m_type(std::move(other.m_type)),
          m_value(std::move(other.m_value))
    {
N
Niels 已提交
1629
        // invalidate payload
N
cleanup  
Niels 已提交
1630 1631 1632 1633
        other.m_type = value_t::null;
        other.m_value = {};
    }

N
Niels 已提交
1634 1635
    /*!
    @brief copy assignment
N
Niels 已提交
1636

N
Niels 已提交
1637 1638 1639 1640
    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 已提交
1641
    @param[in] other  value to copy from
N
Niels 已提交
1642 1643 1644 1645 1646 1647

    @complexity Linear.

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

N
Niels 已提交
1648 1649 1650 1651
    @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 已提交
1652
    */
1653
    reference& operator=(basic_json other) noexcept (
N
Niels 已提交
1654 1655 1656 1657 1658
        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 已提交
1659
    {
N
Niels 已提交
1660
        using std::swap;
N
cleanup  
Niels 已提交
1661 1662 1663 1664 1665
        std::swap(m_type, other.m_type);
        std::swap(m_value, other.m_value);
        return *this;
    }

N
Niels 已提交
1666 1667
    /*!
    @brief destructor
N
Niels 已提交
1668

N
Niels 已提交
1669
    Destroys the JSON value and frees all allocated memory.
N
Niels 已提交
1670 1671 1672 1673 1674 1675

    @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 已提交
1676
    */
N
Niels 已提交
1677
    ~basic_json()
N
cleanup  
Niels 已提交
1678 1679 1680 1681 1682
    {
        switch (m_type)
        {
            case (value_t::object):
            {
N
Niels 已提交
1683
                AllocatorType<object_t> alloc;
N
Niels 已提交
1684 1685
                alloc.destroy(m_value.object);
                alloc.deallocate(m_value.object, 1);
N
cleanup  
Niels 已提交
1686 1687 1688
                m_value.object = nullptr;
                break;
            }
N
Niels 已提交
1689

N
cleanup  
Niels 已提交
1690 1691
            case (value_t::array):
            {
N
Niels 已提交
1692
                AllocatorType<array_t> alloc;
N
Niels 已提交
1693 1694
                alloc.destroy(m_value.array);
                alloc.deallocate(m_value.array, 1);
N
cleanup  
Niels 已提交
1695 1696 1697
                m_value.array = nullptr;
                break;
            }
N
Niels 已提交
1698

N
cleanup  
Niels 已提交
1699 1700
            case (value_t::string):
            {
N
Niels 已提交
1701
                AllocatorType<string_t> alloc;
N
Niels 已提交
1702
                alloc.destroy(m_value.string);
N
Niels 已提交
1703
                alloc.deallocate(m_value.string, 1);
N
cleanup  
Niels 已提交
1704 1705 1706
                m_value.string = nullptr;
                break;
            }
N
Niels 已提交
1707 1708

            default:
N
cleanup  
Niels 已提交
1709
            {
N
Niels 已提交
1710
                // all other types need no specific destructor
N
cleanup  
Niels 已提交
1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
                break;
            }
        }
    }


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

N
Niels 已提交
1722 1723 1724
    /// @name object inspection
    /// @{

N
cleanup  
Niels 已提交
1725
    /*!
N
Niels 已提交
1726 1727
    @brief serialization

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

N
Niels 已提交
1732
    @param[in] indent if indent is nonnegative, then array elements and object
N
Niels 已提交
1733 1734 1735
    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 已提交
1736

N
Niels 已提交
1737 1738 1739 1740 1741 1742 1743
    @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 已提交
1744 1745
    @see https://docs.python.org/2/library/json.html#json.dump
    */
N
Niels 已提交
1746
    string_t dump(const int indent = -1) const
N
cleanup  
Niels 已提交
1747
    {
N
Niels 已提交
1748 1749
        std::stringstream ss;

N
cleanup  
Niels 已提交
1750 1751
        if (indent >= 0)
        {
N
Niels 已提交
1752
            dump(ss, true, static_cast<unsigned int>(indent));
N
cleanup  
Niels 已提交
1753 1754 1755
        }
        else
        {
N
Niels 已提交
1756
            dump(ss, false, 0);
N
cleanup  
Niels 已提交
1757
        }
N
Niels 已提交
1758 1759

        return ss.str();
N
cleanup  
Niels 已提交
1760 1761
    }

N
Niels 已提交
1762 1763 1764 1765 1766 1767 1768
    /*!
    @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 已提交
1769 1770 1771 1772 1773

    @complexity Constant.

    @liveexample{The following code exemplifies @ref type() for all JSON
    types.,type}
N
Niels 已提交
1774
    */
1775
    value_t type() const noexcept
N
cleanup  
Niels 已提交
1776 1777 1778 1779
    {
        return m_type;
    }

N
Niels 已提交
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816
    /*!
    @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 已提交
1817 1818 1819 1820 1821
    /*!
    @brief return whether value is null

    This function returns true iff the JSON value is null.

N
Niels 已提交
1822
    @return `true` if type is null, `false` otherwise.
N
Niels 已提交
1823 1824 1825 1826

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_null for all JSON
N
Niels 已提交
1827
    types.,is_null}
N
Niels 已提交
1828
    */
1829
    bool is_null() const noexcept
N
Niels 已提交
1830 1831 1832 1833
    {
        return m_type == value_t::null;
    }

N
Niels 已提交
1834 1835 1836 1837 1838
    /*!
    @brief return whether value is a boolean

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

N
Niels 已提交
1839
    @return `true` if type is boolean, `false` otherwise.
N
Niels 已提交
1840 1841 1842 1843

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_boolean for all JSON
N
Niels 已提交
1844
    types.,is_boolean}
N
Niels 已提交
1845
    */
1846
    bool is_boolean() const noexcept
N
Niels 已提交
1847 1848 1849 1850
    {
        return m_type == value_t::boolean;
    }

N
Niels 已提交
1851 1852 1853 1854 1855 1856
    /*!
    @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 已提交
1857
    @return `true` if type is number, `false` otherwise.
N
Niels 已提交
1858 1859 1860 1861

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number for all JSON
N
Niels 已提交
1862
    types.,is_number}
N
Niels 已提交
1863
    */
1864
    bool is_number() const noexcept
N
Niels 已提交
1865
    {
N
Niels 已提交
1866
        return is_number_integer() or is_number_float();
N
Niels 已提交
1867 1868
    }

N
Niels 已提交
1869 1870 1871 1872 1873 1874
    /*!
    @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 已提交
1875
    @return `true` if type is an integer number, `false` otherwise.
N
Niels 已提交
1876 1877 1878 1879

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number_integer for all
N
Niels 已提交
1880
    JSON types.,is_number_integer}
N
Niels 已提交
1881
    */
N
Niels 已提交
1882 1883 1884 1885 1886
    bool is_number_integer() const noexcept
    {
        return m_type == value_t::number_integer;
    }

N
Niels 已提交
1887 1888 1889 1890 1891 1892
    /*!
    @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 已提交
1893
    @return `true` if type is a floating-point number, `false` otherwise.
N
Niels 已提交
1894 1895 1896 1897

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number_float for all
N
Niels 已提交
1898
    JSON types.,is_number_float}
N
Niels 已提交
1899
    */
N
Niels 已提交
1900 1901 1902 1903 1904
    bool is_number_float() const noexcept
    {
        return m_type == value_t::number_float;
    }

N
Niels 已提交
1905 1906 1907 1908 1909
    /*!
    @brief return whether value is an object

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

N
Niels 已提交
1910
    @return `true` if type is object, `false` otherwise.
N
Niels 已提交
1911 1912 1913 1914

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_object for all JSON
N
Niels 已提交
1915
    types.,is_object}
N
Niels 已提交
1916
    */
1917
    bool is_object() const noexcept
N
Niels 已提交
1918 1919 1920 1921
    {
        return m_type == value_t::object;
    }

N
Niels 已提交
1922 1923 1924 1925 1926
    /*!
    @brief return whether value is an array

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

N
Niels 已提交
1927
    @return `true` if type is array, `false` otherwise.
N
Niels 已提交
1928 1929 1930 1931

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_array for all JSON
N
Niels 已提交
1932
    types.,is_array}
N
Niels 已提交
1933
    */
1934
    bool is_array() const noexcept
N
Niels 已提交
1935 1936 1937 1938
    {
        return m_type == value_t::array;
    }

N
Niels 已提交
1939 1940 1941 1942 1943
    /*!
    @brief return whether value is a string

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

N
Niels 已提交
1944
    @return `true` if type is string, `false` otherwise.
N
Niels 已提交
1945 1946 1947 1948

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_string for all JSON
N
Niels 已提交
1949
    types.,is_string}
N
Niels 已提交
1950
    */
1951
    bool is_string() const noexcept
N
Niels 已提交
1952 1953 1954 1955
    {
        return m_type == value_t::string;
    }

N
Niels 已提交
1956 1957 1958 1959 1960 1961
    /*!
    @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 已提交
1962 1963 1964 1965
    @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 已提交
1966 1967 1968 1969
    @return `true` if type is discarded, `false` otherwise.

    @complexity Constant.

N
Niels 已提交
1970 1971
    @liveexample{The following code exemplifies @ref is_discarded for all JSON
    types.,is_discarded}
N
Niels 已提交
1972
    */
1973
    bool is_discarded() const noexcept
N
Niels 已提交
1974 1975 1976 1977
    {
        return m_type == value_t::discarded;
    }

N
Niels 已提交
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
    /*!
    @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}
    */
1991
    operator value_t() const noexcept
N
Niels 已提交
1992 1993 1994 1995
    {
        return m_type;
    }

N
Niels 已提交
1996 1997
    /// @}

N
Niels 已提交
1998
  private:
N
Niels 已提交
1999 2000 2001
    //////////////////
    // value access //
    //////////////////
N
cleanup  
Niels 已提交
2002

N
Niels 已提交
2003
    /// get an object (explicit)
N
cleanup  
Niels 已提交
2004 2005
    template <class T, typename
              std::enable_if<
N
Niels 已提交
2006
                  std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
N
Niels 已提交
2007
                  std::is_convertible<basic_json_t, typename T::mapped_type>::value
N
Niels 已提交
2008
                  , int>::type = 0>
2009
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2010 2011 2012 2013
    {
        switch (m_type)
        {
            case (value_t::object):
N
Niels 已提交
2014
            {
N
cleanup  
Niels 已提交
2015
                return T(m_value.object->begin(), m_value.object->end());
N
Niels 已提交
2016
            }
N
cleanup  
Niels 已提交
2017
            default:
N
Niels 已提交
2018
            {
N
Niels 已提交
2019
                throw std::domain_error("type must be object, but is " + type_name());
N
Niels 已提交
2020 2021 2022 2023 2024
            }
        }
    }

    /// get an object (explicit)
2025
    object_t get_impl(object_t*) const
N
Niels 已提交
2026 2027 2028 2029 2030 2031 2032 2033 2034
    {
        switch (m_type)
        {
            case (value_t::object):
            {
                return *(m_value.object);
            }
            default:
            {
N
Niels 已提交
2035
                throw std::domain_error("type must be object, but is " + type_name());
N
Niels 已提交
2036
            }
N
cleanup  
Niels 已提交
2037 2038 2039
        }
    }

N
Niels 已提交
2040
    /// get an array (explicit)
N
cleanup  
Niels 已提交
2041 2042
    template <class T, typename
              std::enable_if<
N
Niels 已提交
2043 2044
                  std::is_convertible<basic_json_t, typename T::value_type>::value and
                  not std::is_same<basic_json_t, typename T::value_type>::value and
N
Niels 已提交
2045 2046
                  not std::is_arithmetic<T>::value and
                  not std::is_convertible<std::string, T>::value and
2047
                  not has_mapped_type<T>::value
N
Niels 已提交
2048
                  , int>::type = 0>
2049
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2050 2051 2052 2053
    {
        switch (m_type)
        {
            case (value_t::array):
N
Niels 已提交
2054 2055 2056 2057 2058 2059 2060 2061 2062
            {
                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 已提交
2063
            default:
N
Niels 已提交
2064
            {
N
Niels 已提交
2065
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2066
            }
N
cleanup  
Niels 已提交
2067 2068 2069
        }
    }

N
Niels 已提交
2070 2071
    /// get an array (explicit)
    template <class T, typename
N
cleanup  
Niels 已提交
2072
              std::enable_if<
N
Niels 已提交
2073 2074
                  std::is_convertible<basic_json_t, T>::value and
                  not std::is_same<basic_json_t, T>::value
N
Niels 已提交
2075
                  , int>::type = 0>
2076
    std::vector<T> get_impl(std::vector<T>*) const
N
cleanup  
Niels 已提交
2077 2078 2079
    {
        switch (m_type)
        {
N
Niels 已提交
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090
            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 已提交
2091
            default:
N
Niels 已提交
2092
            {
N
Niels 已提交
2093
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2094
            }
N
cleanup  
Niels 已提交
2095 2096 2097
        }
    }

N
Niels 已提交
2098 2099 2100 2101
    /// get an array (explicit)
    template <class T, typename
              std::enable_if<
                  std::is_same<basic_json, typename T::value_type>::value and
2102
                  not has_mapped_type<T>::value
N
Niels 已提交
2103
                  , int>::type = 0>
2104
    T get_impl(T*) const
N
Niels 已提交
2105 2106 2107 2108 2109 2110 2111 2112 2113
    {
        switch (m_type)
        {
            case (value_t::array):
            {
                return T(m_value.array->begin(), m_value.array->end());
            }
            default:
            {
N
Niels 已提交
2114
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2115 2116 2117 2118
            }
        }
    }

N
Niels 已提交
2119
    /// get an array (explicit)
2120
    array_t get_impl(array_t*) const
N
Niels 已提交
2121 2122 2123 2124 2125 2126 2127 2128 2129
    {
        switch (m_type)
        {
            case (value_t::array):
            {
                return *(m_value.array);
            }
            default:
            {
N
Niels 已提交
2130
                throw std::domain_error("type must be array, but is " + type_name());
N
Niels 已提交
2131 2132 2133 2134 2135
            }
        }
    }

    /// get a string (explicit)
N
cleanup  
Niels 已提交
2136 2137
    template <typename T, typename
              std::enable_if<
N
Niels 已提交
2138 2139
                  std::is_convertible<string_t, T>::value
                  , int>::type = 0>
2140
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2141 2142 2143
    {
        switch (m_type)
        {
N
Niels 已提交
2144 2145 2146 2147
            case (value_t::string):
            {
                return *m_value.string;
            }
N
cleanup  
Niels 已提交
2148
            default:
N
Niels 已提交
2149
            {
N
Niels 已提交
2150
                throw std::domain_error("type must be string, but is " + type_name());
N
Niels 已提交
2151
            }
N
cleanup  
Niels 已提交
2152 2153 2154
        }
    }

N
Niels 已提交
2155
    /// get a number (explicit)
N
cleanup  
Niels 已提交
2156 2157
    template<typename T, typename
             std::enable_if<
N
Niels 已提交
2158 2159
                 std::is_arithmetic<T>::value
                 , int>::type = 0>
2160
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2161 2162 2163 2164
    {
        switch (m_type)
        {
            case (value_t::number_integer):
N
Niels 已提交
2165
            {
N
cleanup  
Niels 已提交
2166
                return static_cast<T>(m_value.number_integer);
N
Niels 已提交
2167
            }
N
cleanup  
Niels 已提交
2168
            case (value_t::number_float):
N
Niels 已提交
2169
            {
N
cleanup  
Niels 已提交
2170
                return static_cast<T>(m_value.number_float);
N
Niels 已提交
2171
            }
N
cleanup  
Niels 已提交
2172
            default:
N
Niels 已提交
2173
            {
N
Niels 已提交
2174
                throw std::domain_error("type must be number, but is " + type_name());
N
Niels 已提交
2175 2176 2177 2178 2179
            }
        }
    }

    /// get a boolean (explicit)
2180
    boolean_t get_impl(boolean_t*) const
N
Niels 已提交
2181 2182 2183 2184 2185 2186 2187 2188 2189
    {
        switch (m_type)
        {
            case (value_t::boolean):
            {
                return m_value.boolean;
            }
            default:
            {
N
Niels 已提交
2190
                throw std::domain_error("type must be boolean, but is " + type_name());
N
Niels 已提交
2191
            }
N
cleanup  
Niels 已提交
2192 2193 2194
        }
    }

N
Niels 已提交
2195
    /// get a pointer to the value (object)
N
Niels 已提交
2196 2197 2198 2199 2200 2201 2202
    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 已提交
2203 2204 2205 2206 2207
    {
        return is_object() ? m_value.object : nullptr;
    }

    /// get a pointer to the value (array)
N
Niels 已提交
2208
    array_t* get_impl_ptr(array_t*) noexcept
N
Niels 已提交
2209 2210 2211 2212
    {
        return is_array() ? m_value.array : nullptr;
    }

N
Niels 已提交
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224
    /// 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 已提交
2225
    /// get a pointer to the value (string)
N
Niels 已提交
2226
    const string_t* get_impl_ptr(const string_t*) const noexcept
N
Niels 已提交
2227 2228 2229 2230 2231
    {
        return is_string() ? m_value.string : nullptr;
    }

    /// get a pointer to the value (boolean)
N
Niels 已提交
2232 2233 2234 2235 2236 2237 2238
    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 已提交
2239 2240 2241 2242 2243
    {
        return is_boolean() ? &m_value.boolean : nullptr;
    }

    /// get a pointer to the value (integer number)
N
Niels 已提交
2244
    number_integer_t* get_impl_ptr(number_integer_t*) noexcept
N
Niels 已提交
2245 2246 2247 2248
    {
        return is_number_integer() ? &m_value.number_integer : nullptr;
    }

N
Niels 已提交
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260
    /// 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 已提交
2261
    /// get a pointer to the value (floating-point number)
N
Niels 已提交
2262
    const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
N
Niels 已提交
2263 2264 2265 2266
    {
        return is_number_float() ? &m_value.number_float : nullptr;
    }

N
Niels 已提交
2267
  public:
N
Niels 已提交
2268 2269 2270 2271

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

N
Niels 已提交
2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307
    /*!
    @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 已提交
2308
    {
N
Niels 已提交
2309
        return get_impl(static_cast<ValueType*>(nullptr));
N
Niels 已提交
2310 2311
    }

N
Niels 已提交
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
    /*!
    @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 已提交
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355
    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 已提交
2356 2357 2358 2359 2360 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
    {
        // 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 已提交
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403
    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 已提交
2404
    {
N
Niels 已提交
2405 2406
        // delegate the call to get_impl_ptr<>() const
        return get_impl_ptr(static_cast<const PointerType>(nullptr));
N
Niels 已提交
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437
    }

    /*!
    @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 已提交
2438
    {
N
Niels 已提交
2439 2440
        // delegate the call to get<>() const
        return get<ValueType>();
N
cleanup  
Niels 已提交
2441 2442
    }

N
Niels 已提交
2443 2444
    /// @}

N
cleanup  
Niels 已提交
2445 2446 2447 2448 2449

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

N
Niels 已提交
2450 2451 2452
    /// @name element access
    /// @{

N
Niels 已提交
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471
    /*!
    @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}
    */
2472
    reference at(size_type idx)
N
cleanup  
Niels 已提交
2473 2474 2475 2476
    {
        // at only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
2477
            throw std::domain_error("cannot use at() with " + type_name());
N
cleanup  
Niels 已提交
2478 2479
        }

2480
        return m_value.array->at(idx);
N
cleanup  
Niels 已提交
2481 2482
    }

N
Niels 已提交
2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501
    /*!
    @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}
    */
2502
    const_reference at(size_type idx) const
N
cleanup  
Niels 已提交
2503 2504 2505 2506
    {
        // at only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
2507
            throw std::domain_error("cannot use at() with " + type_name());
N
cleanup  
Niels 已提交
2508 2509
        }

2510 2511 2512
        return m_value.array->at(idx);
    }

N
Niels 已提交
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
    /*!
    @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}
    */
2532
    reference at(const typename object_t::key_type& key)
2533 2534 2535 2536
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2537
            throw std::domain_error("cannot use at() with " + type_name());
2538 2539 2540 2541 2542
        }

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

N
Niels 已提交
2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
    /*!
    @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}
    */
2562
    const_reference at(const typename object_t::key_type& key) const
2563 2564 2565 2566
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2567
            throw std::domain_error("cannot use at() with " + type_name());
2568 2569 2570
        }

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

N
Niels 已提交
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594
    /*!
    @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}
    */
2595
    reference operator[](size_type idx)
N
cleanup  
Niels 已提交
2596
    {
N
Niels 已提交
2597 2598 2599 2600
        // implicitly convert null to object
        if (m_type == value_t::null)
        {
            m_type = value_t::array;
N
Niels 已提交
2601
            AllocatorType<array_t> alloc;
N
Niels 已提交
2602 2603 2604 2605 2606
            m_value.array = alloc.allocate(1);
            alloc.construct(m_value.array);
        }

        // [] only works for arrays
N
cleanup  
Niels 已提交
2607 2608
        if (m_type != value_t::array)
        {
N
Niels 已提交
2609
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2610 2611
        }

2612
        for (size_t i = m_value.array->size(); i <= idx; ++i)
N
Niels 已提交
2613 2614 2615 2616
        {
            m_value.array->push_back(basic_json());
        }

2617
        return m_value.array->operator[](idx);
N
cleanup  
Niels 已提交
2618 2619
    }

N
Niels 已提交
2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635
    /*!
    @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}
    */
2636
    const_reference operator[](size_type idx) const
N
cleanup  
Niels 已提交
2637 2638 2639 2640
    {
        // at only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
2641
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2642 2643
        }

2644
        return m_value.array->operator[](idx);
N
cleanup  
Niels 已提交
2645 2646
    }

N
Niels 已提交
2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666
    /*!
    @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}
    */
2667
    reference operator[](const typename object_t::key_type& key)
N
cleanup  
Niels 已提交
2668
    {
N
Niels 已提交
2669 2670 2671 2672
        // implicitly convert null to object
        if (m_type == value_t::null)
        {
            m_type = value_t::object;
N
Niels 已提交
2673
            AllocatorType<object_t> alloc;
N
Niels 已提交
2674 2675 2676 2677
            m_value.object = alloc.allocate(1);
            alloc.construct(m_value.object);
        }

N
Niels 已提交
2678
        // [] only works for objects
N
cleanup  
Niels 已提交
2679 2680
        if (m_type != value_t::object)
        {
N
Niels 已提交
2681
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2682 2683 2684 2685 2686
        }

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

N
Niels 已提交
2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
    /*!
    @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}
    */
2703
    const_reference operator[](const typename object_t::key_type& key) const
2704 2705 2706 2707
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2708
            throw std::domain_error("cannot use operator[] with " + type_name());
2709 2710 2711 2712 2713
        }

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

N
Niels 已提交
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735
    /*!
    @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 已提交
2736
    template<typename T, std::size_t n>
2737
    reference operator[](const T (&key)[n])
N
cleanup  
Niels 已提交
2738
    {
N
Niels 已提交
2739 2740 2741 2742
        // implicitly convert null to object
        if (m_type == value_t::null)
        {
            m_type = value_t::object;
N
Niels 已提交
2743
            m_value = value_t::object;
N
Niels 已提交
2744 2745
        }

N
cleanup  
Niels 已提交
2746 2747 2748
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2749
            throw std::domain_error("cannot use operator[] with " + type_name());
N
cleanup  
Niels 已提交
2750 2751 2752 2753 2754
        }

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

N
Niels 已提交
2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772
    /*!
    @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 已提交
2773
    template<typename T, std::size_t n>
2774
    const_reference operator[](const T (&key)[n]) const
2775 2776 2777 2778
    {
        // at only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
2779
            throw std::domain_error("cannot use operator[] with " + type_name());
2780 2781 2782 2783 2784
        }

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

N
Niels 已提交
2785 2786 2787 2788 2789 2790
    /*!
    @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 已提交
2791
    @return In case of a structured type (array or object), a reference to the
N
Niels 已提交
2792 2793 2794 2795 2796 2797 2798
    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 已提交
2799
    @throw std::out_of_range when called on null value
N
Niels 已提交
2800 2801 2802

    @liveexample{The following code shows an example for @ref front.,front}
    */
2803
    reference front()
N
Niels 已提交
2804 2805 2806 2807
    {
        return *begin();
    }

N
Niels 已提交
2808 2809 2810
    /*!
    @copydoc basic_json::front()
    */
2811
    const_reference front() const
N
Niels 已提交
2812 2813 2814 2815
    {
        return *cbegin();
    }

N
Niels 已提交
2816 2817 2818 2819 2820 2821 2822
    /*!
    @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 已提交
2823
    @return In case of a structured type (array or object), a reference to the
N
Niels 已提交
2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834
    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}
    */
2835
    reference back()
N
Niels 已提交
2836 2837 2838 2839 2840 2841
    {
        auto tmp = end();
        --tmp;
        return *tmp;
    }

N
Niels 已提交
2842 2843 2844
    /*!
    @copydoc basic_json::back()
    */
2845
    const_reference back() const
N
Niels 已提交
2846 2847 2848 2849 2850 2851
    {
        auto tmp = cend();
        --tmp;
        return *tmp;
    }

N
Niels 已提交
2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885
    /*!
    @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
2886
              std::enable_if<
N
Niels 已提交
2887 2888
                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
2889 2890
                  , int>::type
              = 0>
N
Niels 已提交
2891
    InteratorType erase(InteratorType pos)
2892 2893
    {
        // make sure iterator fits the current value
N
Niels 已提交
2894
        if (this != pos.m_object)
2895
        {
N
Niels 已提交
2896
            throw std::domain_error("iterator does not fit current value");
2897 2898
        }

N
Niels 已提交
2899
        InteratorType result = end();
2900 2901 2902 2903 2904 2905 2906 2907

        switch (m_type)
        {
            case value_t::number_integer:
            case value_t::number_float:
            case value_t::boolean:
            case value_t::string:
            {
2908
                if (not pos.m_it.primitive_iterator.is_begin())
2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936
                {
                    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 已提交
2937
                throw std::domain_error("cannot use erase() with " + type_name());
2938 2939 2940 2941 2942 2943
            }
        }

        return result;
    }

N
Niels 已提交
2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978
    /*!
    @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
2979
              std::enable_if<
N
Niels 已提交
2980 2981
                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
2982 2983
                  , int>::type
              = 0>
N
Niels 已提交
2984
    InteratorType erase(InteratorType first, InteratorType last)
2985 2986
    {
        // make sure iterator fits the current value
N
Niels 已提交
2987
        if (this != first.m_object or this != last.m_object)
2988
        {
N
Niels 已提交
2989
            throw std::domain_error("iterators do not fit current value");
2990 2991
        }

N
Niels 已提交
2992
        InteratorType result = end();
2993 2994 2995 2996 2997 2998 2999 3000

        switch (m_type)
        {
            case value_t::number_integer:
            case value_t::number_float:
            case value_t::boolean:
            case value_t::string:
            {
3001
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031
                {
                    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 已提交
3032
                throw std::domain_error("cannot use erase with " + type_name());
3033 3034 3035 3036 3037 3038
            }
        }

        return result;
    }

N
Niels 已提交
3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055
    /*!
    @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}
    */
3056
    size_type erase(const typename object_t::key_type& key)
3057
    {
N
Niels 已提交
3058
        // this erase only works for objects
3059 3060
        if (m_type != value_t::object)
        {
N
Niels 已提交
3061
            throw std::domain_error("cannot use erase() with " + type_name());
3062 3063 3064 3065 3066
        }

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

N
Niels 已提交
3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080
    /*!
    @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}
    */
3081
    void erase(const size_type idx)
N
Niels 已提交
3082 3083 3084 3085
    {
        // this erase only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
3086
            throw std::domain_error("cannot use erase() with " + type_name());
N
Niels 已提交
3087 3088
        }

N
Niels 已提交
3089
        if (idx >= size())
N
Niels 已提交
3090 3091 3092 3093
        {
            throw std::out_of_range("index out of range");
        }

N
Niels 已提交
3094
        m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
N
Niels 已提交
3095 3096
    }

N
Niels 已提交
3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111
    /*!
    @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}
    */
3112
    iterator find(typename object_t::key_type key)
N
Niels 已提交
3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123
    {
        auto result = end();

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

        return result;
    }

N
Niels 已提交
3124 3125 3126 3127
    /*!
    @brief find an element in a JSON object
    @copydoc find(typename object_t::key_type)
    */
3128
    const_iterator find(typename object_t::key_type key) const
N
Niels 已提交
3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139
    {
        auto result = cend();

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

        return result;
    }

N
Niels 已提交
3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155
    /*!
    @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}
    */
3156
    size_type count(typename object_t::key_type key) const
3157 3158 3159 3160 3161
    {
        // return 0 for all nonobject types
        return (m_type == value_t::object) ? m_value.object->count(key) : 0;
    }

N
Niels 已提交
3162 3163
    /// @}

N
Niels 已提交
3164

N
cleanup  
Niels 已提交
3165 3166 3167 3168
    ///////////////
    // iterators //
    ///////////////

N
Niels 已提交
3169 3170 3171
    /// @name iterators
    /// @{

N
Niels 已提交
3172 3173
    /*!
    @brief returns an iterator to the first element
N
Niels 已提交
3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186

    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 已提交
3187
    */
N
Niels 已提交
3188
    iterator begin()
N
cleanup  
Niels 已提交
3189 3190 3191 3192 3193 3194
    {
        iterator result(this);
        result.set_begin();
        return result;
    }

N
Niels 已提交
3195
    /*!
N
Niels 已提交
3196
    @copydoc basic_json::cbegin()
N
Niels 已提交
3197
    */
N
Niels 已提交
3198
    const_iterator begin() const
N
cleanup  
Niels 已提交
3199
    {
N
Niels 已提交
3200
        return cbegin();
N
cleanup  
Niels 已提交
3201 3202
    }

N
Niels 已提交
3203 3204
    /*!
    @brief returns a const iterator to the first element
N
Niels 已提交
3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218

    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 已提交
3219
    */
N
Niels 已提交
3220
    const_iterator cbegin() const
N
cleanup  
Niels 已提交
3221 3222 3223 3224 3225 3226
    {
        const_iterator result(this);
        result.set_begin();
        return result;
    }

N
Niels 已提交
3227 3228
    /*!
    @brief returns an iterator to one past the last element
N
Niels 已提交
3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241

    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 已提交
3242
    */
N
Niels 已提交
3243
    iterator end()
N
cleanup  
Niels 已提交
3244 3245 3246 3247 3248 3249
    {
        iterator result(this);
        result.set_end();
        return result;
    }

N
Niels 已提交
3250
    /*!
N
Niels 已提交
3251
    @copydoc basic_json::cend()
N
Niels 已提交
3252
    */
N
Niels 已提交
3253
    const_iterator end() const
N
cleanup  
Niels 已提交
3254
    {
N
Niels 已提交
3255
        return cend();
N
cleanup  
Niels 已提交
3256 3257
    }

N
Niels 已提交
3258 3259
    /*!
    @brief returns a const iterator to one past the last element
N
Niels 已提交
3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273

    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 已提交
3274
    */
N
Niels 已提交
3275
    const_iterator cend() const
N
cleanup  
Niels 已提交
3276 3277 3278 3279 3280 3281
    {
        const_iterator result(this);
        result.set_end();
        return result;
    }

N
Niels 已提交
3282
    /*!
N
Niels 已提交
3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295
    @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 已提交
3296
    */
N
Niels 已提交
3297
    reverse_iterator rbegin()
N
Niels 已提交
3298 3299 3300 3301
    {
        return reverse_iterator(end());
    }

N
Niels 已提交
3302
    /*!
N
Niels 已提交
3303
    @copydoc basic_json::crbegin()
N
Niels 已提交
3304
    */
N
Niels 已提交
3305
    const_reverse_iterator rbegin() const
N
Niels 已提交
3306
    {
N
Niels 已提交
3307
        return crbegin();
N
Niels 已提交
3308 3309
    }

N
Niels 已提交
3310
    /*!
N
Niels 已提交
3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324
    @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 已提交
3325
    */
N
Niels 已提交
3326
    reverse_iterator rend()
N
Niels 已提交
3327 3328 3329 3330
    {
        return reverse_iterator(begin());
    }

N
Niels 已提交
3331
    /*!
N
Niels 已提交
3332
    @copydoc basic_json::crend()
N
Niels 已提交
3333
    */
N
Niels 已提交
3334
    const_reverse_iterator rend() const
N
Niels 已提交
3335
    {
N
Niels 已提交
3336
        return crend();
N
Niels 已提交
3337 3338
    }

N
Niels 已提交
3339
    /*!
N
Niels 已提交
3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353
    @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 已提交
3354
    */
N
Niels 已提交
3355
    const_reverse_iterator crbegin() const
N
Niels 已提交
3356 3357 3358 3359
    {
        return const_reverse_iterator(cend());
    }

N
Niels 已提交
3360
    /*!
N
Niels 已提交
3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374
    @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 已提交
3375
    */
N
Niels 已提交
3376
    const_reverse_iterator crend() const
N
Niels 已提交
3377 3378 3379 3380
    {
        return const_reverse_iterator(cbegin());
    }

N
Niels 已提交
3381 3382
    /// @}

N
cleanup  
Niels 已提交
3383 3384 3385 3386 3387

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

N
Niels 已提交
3388 3389 3390
    /// @name capacity
    /// @{

N
Niels 已提交
3391 3392
    /*!
    @brief checks whether the container is empty
N
Niels 已提交
3393 3394 3395

    Checks if a JSON value has no elements.

N
Niels 已提交
3396
    @return The return value depends on the different types and is
N
Niels 已提交
3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416
            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 已提交
3417
    */
3418
    bool empty() const noexcept
N
cleanup  
Niels 已提交
3419 3420 3421 3422 3423 3424 3425
    {
        switch (m_type)
        {
            case (value_t::null):
            {
                return true;
            }
N
Niels 已提交
3426

N
cleanup  
Niels 已提交
3427 3428 3429 3430
            case (value_t::array):
            {
                return m_value.array->empty();
            }
N
Niels 已提交
3431

N
cleanup  
Niels 已提交
3432 3433 3434 3435
            case (value_t::object):
            {
                return m_value.object->empty();
            }
N
Niels 已提交
3436

N
Niels 已提交
3437 3438 3439 3440 3441 3442
            default:
            {
                // all other types are nonempty
                return false;
            }
        }
N
cleanup  
Niels 已提交
3443 3444
    }

N
Niels 已提交
3445 3446
    /*!
    @brief returns the number of elements
N
Niels 已提交
3447 3448 3449

    Returns the number of elements in a JSON value.

N
Niels 已提交
3450
    @return The return value depends on the different types and is
N
Niels 已提交
3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470
            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 已提交
3471
    */
3472
    size_type size() const noexcept
N
cleanup  
Niels 已提交
3473 3474 3475 3476 3477 3478 3479
    {
        switch (m_type)
        {
            case (value_t::null):
            {
                return 0;
            }
N
Niels 已提交
3480

N
cleanup  
Niels 已提交
3481 3482 3483 3484
            case (value_t::array):
            {
                return m_value.array->size();
            }
N
Niels 已提交
3485

N
cleanup  
Niels 已提交
3486 3487 3488 3489
            case (value_t::object):
            {
                return m_value.object->size();
            }
N
Niels 已提交
3490

N
Niels 已提交
3491 3492 3493 3494 3495 3496
            default:
            {
                // all other types have size 1
                return 1;
            }
        }
N
cleanup  
Niels 已提交
3497 3498
    }

N
Niels 已提交
3499 3500
    /*!
    @brief returns the maximum possible number of elements
N
Niels 已提交
3501 3502 3503 3504 3505

    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 已提交
3506
    @return The return value depends on the different types and is
N
Niels 已提交
3507 3508 3509
            defined as follows:
            Value type  | return value
            ----------- | -------------
3510 3511 3512 3513
            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 已提交
3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527
            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 已提交
3528
    */
3529
    size_type max_size() const noexcept
N
cleanup  
Niels 已提交
3530 3531 3532 3533 3534 3535 3536
    {
        switch (m_type)
        {
            case (value_t::array):
            {
                return m_value.array->max_size();
            }
N
Niels 已提交
3537

N
cleanup  
Niels 已提交
3538 3539 3540 3541
            case (value_t::object):
            {
                return m_value.object->max_size();
            }
N
Niels 已提交
3542

N
Niels 已提交
3543 3544
            default:
            {
3545 3546
                // all other types have max_size() == size()
                return size();
N
Niels 已提交
3547 3548
            }
        }
N
cleanup  
Niels 已提交
3549 3550
    }

N
Niels 已提交
3551 3552
    /// @}

N
cleanup  
Niels 已提交
3553 3554 3555 3556 3557

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

N
Niels 已提交
3558 3559 3560
    /// @name modifiers
    /// @{

N
Niels 已提交
3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581
    /*!
    @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 已提交
3582
    JSON types.,clear}
N
Niels 已提交
3583
    */
3584
    void clear() noexcept
N
cleanup  
Niels 已提交
3585 3586 3587 3588
    {
        switch (m_type)
        {
            case (value_t::null):
N
Niels 已提交
3589
            case (value_t::discarded):
N
cleanup  
Niels 已提交
3590 3591 3592
            {
                break;
            }
N
Niels 已提交
3593

N
cleanup  
Niels 已提交
3594 3595
            case (value_t::number_integer):
            {
N
Niels 已提交
3596
                m_value.number_integer = 0;
N
cleanup  
Niels 已提交
3597 3598
                break;
            }
N
Niels 已提交
3599

N
cleanup  
Niels 已提交
3600 3601
            case (value_t::number_float):
            {
N
Niels 已提交
3602
                m_value.number_float = 0.0;
N
cleanup  
Niels 已提交
3603 3604
                break;
            }
N
Niels 已提交
3605

N
cleanup  
Niels 已提交
3606 3607
            case (value_t::boolean):
            {
N
Niels 已提交
3608
                m_value.boolean = false;
N
cleanup  
Niels 已提交
3609 3610
                break;
            }
N
Niels 已提交
3611

N
cleanup  
Niels 已提交
3612 3613 3614 3615 3616
            case (value_t::string):
            {
                m_value.string->clear();
                break;
            }
N
Niels 已提交
3617

N
cleanup  
Niels 已提交
3618 3619 3620 3621 3622
            case (value_t::array):
            {
                m_value.array->clear();
                break;
            }
N
Niels 已提交
3623

N
cleanup  
Niels 已提交
3624 3625 3626 3627 3628 3629 3630 3631
            case (value_t::object):
            {
                m_value.object->clear();
                break;
            }
        }
    }

3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
    /*!
    @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}
    */
3649
    void push_back(basic_json&& value)
N
cleanup  
Niels 已提交
3650 3651 3652 3653
    {
        // push_back only works for null objects or arrays
        if (not(m_type == value_t::null or m_type == value_t::array))
        {
N
Niels 已提交
3654
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
3655 3656 3657 3658 3659 3660
        }

        // transform null object into an array
        if (m_type == value_t::null)
        {
            m_type = value_t::array;
N
Niels 已提交
3661
            m_value = value_t::array;
N
cleanup  
Niels 已提交
3662 3663 3664 3665 3666 3667 3668 3669
        }

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

3670 3671 3672 3673
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
3674
    reference operator+=(basic_json&& value)
N
Niels 已提交
3675 3676 3677 3678 3679
    {
        push_back(std::move(value));
        return *this;
    }

3680 3681 3682 3683
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
3684
    void push_back(const basic_json& value)
N
cleanup  
Niels 已提交
3685 3686 3687 3688
    {
        // push_back only works for null objects or arrays
        if (not(m_type == value_t::null or m_type == value_t::array))
        {
N
Niels 已提交
3689
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
3690 3691 3692 3693 3694 3695
        }

        // transform null object into an array
        if (m_type == value_t::null)
        {
            m_type = value_t::array;
N
Niels 已提交
3696
            m_value = value_t::array;
N
cleanup  
Niels 已提交
3697 3698 3699 3700 3701 3702
        }

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

3703 3704 3705 3706
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
3707
    reference operator+=(const basic_json& value)
N
cleanup  
Niels 已提交
3708 3709 3710 3711 3712
    {
        push_back(value);
        return *this;
    }

3713 3714 3715 3716 3717 3718 3719
    /*!
    @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 已提交
3720
    @param[in] value the value to add to the JSON object
3721 3722 3723 3724 3725 3726 3727 3728 3729 3730

    @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}
    */
3731
    void push_back(const typename object_t::value_type& value)
N
cleanup  
Niels 已提交
3732 3733 3734 3735
    {
        // push_back only works for null objects or objects
        if (not(m_type == value_t::null or m_type == value_t::object))
        {
N
Niels 已提交
3736
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
3737 3738 3739 3740 3741 3742
        }

        // transform null object into an object
        if (m_type == value_t::null)
        {
            m_type = value_t::object;
N
Niels 已提交
3743
            m_value = value_t::object;
N
cleanup  
Niels 已提交
3744 3745 3746 3747 3748 3749
        }

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

3750 3751 3752 3753
    /*!
    @brief add an object to an object
    @copydoc push_back(const typename object_t::value_type&)
    */
3754
    reference operator+=(const typename object_t::value_type& value)
N
cleanup  
Niels 已提交
3755 3756 3757 3758 3759
    {
        push_back(value);
        return operator[](value.first);
    }

N
Niels 已提交
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 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901
    /*!
    @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 已提交
3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940
    /*!
    @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 已提交
3941 3942
    /*!
    @brief exchanges the values
N
Niels 已提交
3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954

    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 已提交
3955
    */
3956
    void swap(reference other) noexcept (
N
Niels 已提交
3957 3958 3959 3960 3961
        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 已提交
3962 3963 3964 3965 3966
    {
        std::swap(m_type, other.m_type);
        std::swap(m_value, other.m_value);
    }

N
Niels 已提交
3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983
    /*!
    @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}
    */
3984
    void swap(array_t& other)
N
cleanup  
Niels 已提交
3985 3986 3987 3988
    {
        // swap only works for arrays
        if (m_type != value_t::array)
        {
N
Niels 已提交
3989
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
3990 3991 3992 3993 3994 3995
        }

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

3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012
    /*!
    @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}
    */
4013
    void swap(object_t& other)
N
cleanup  
Niels 已提交
4014 4015 4016 4017
    {
        // swap only works for objects
        if (m_type != value_t::object)
        {
N
Niels 已提交
4018
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
4019 4020
        }

4021
        // swap objects
N
cleanup  
Niels 已提交
4022 4023 4024
        std::swap(*(m_value.object), other);
    }

4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041
    /*!
    @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}
    */
4042
    void swap(string_t& other)
N
cleanup  
Niels 已提交
4043 4044 4045 4046
    {
        // swap only works for strings
        if (m_type != value_t::string)
        {
N
Niels 已提交
4047
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
4048 4049
        }

4050
        // swap strings
N
cleanup  
Niels 已提交
4051 4052 4053
        std::swap(*(m_value.string), other);
    }

N
Niels 已提交
4054 4055
    /// @}

N
cleanup  
Niels 已提交
4056 4057 4058 4059 4060

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

N
Niels 已提交
4061 4062 4063
    /// @name lexicographical comparison operators
    /// @{

N
Niels 已提交
4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094
  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 已提交
4095 4096
    /*!
    @brief comparison: equal
N
Niels 已提交
4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112

    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.

4113 4114
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__equal}
N
Niels 已提交
4115
    */
N
Niels 已提交
4116
    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4117
    {
F
Florian Weber 已提交
4118 4119
        const auto lhs_type = lhs.type();
        const auto rhs_type = rhs.type();
N
Niels 已提交
4120

F
Florian Weber 已提交
4121
        if (lhs_type == rhs_type)
N
cleanup  
Niels 已提交
4122
        {
F
Florian Weber 已提交
4123
            switch (lhs_type)
N
cleanup  
Niels 已提交
4124
            {
F
Florian Weber 已提交
4125
                case (value_t::array):
N
cleanup  
Niels 已提交
4126
                    return *lhs.m_value.array == *rhs.m_value.array;
F
Florian Weber 已提交
4127
                case (value_t::object):
N
cleanup  
Niels 已提交
4128
                    return *lhs.m_value.object == *rhs.m_value.object;
F
Florian Weber 已提交
4129
                case (value_t::null):
N
cleanup  
Niels 已提交
4130
                    return true;
F
Florian Weber 已提交
4131
                case (value_t::string):
N
cleanup  
Niels 已提交
4132
                    return *lhs.m_value.string == *rhs.m_value.string;
F
Florian Weber 已提交
4133
                case (value_t::boolean):
N
cleanup  
Niels 已提交
4134
                    return lhs.m_value.boolean == rhs.m_value.boolean;
F
Florian Weber 已提交
4135
                case (value_t::number_integer):
N
cleanup  
Niels 已提交
4136
                    return lhs.m_value.number_integer == rhs.m_value.number_integer;
F
Florian Weber 已提交
4137
                case (value_t::number_float):
4138
                    return approx(lhs.m_value.number_float, rhs.m_value.number_float);
N
Niels 已提交
4139 4140
                case (value_t::discarded):
                    return false;
N
cleanup  
Niels 已提交
4141 4142
            }
        }
F
Florian Weber 已提交
4143 4144
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
        {
4145 4146
            return approx(static_cast<number_float_t>(lhs.m_value.number_integer),
                          rhs.m_value.number_float);
F
Florian Weber 已提交
4147 4148 4149 4150 4151 4152
        }
        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 已提交
4153 4154 4155
        return false;
    }

N
Niels 已提交
4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185
    /*!
    @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 已提交
4186 4187
    /*!
    @brief comparison: not equal
N
Niels 已提交
4188 4189 4190 4191 4192 4193 4194 4195 4196

    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.

4197 4198
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__notequal}
N
Niels 已提交
4199
    */
N
Niels 已提交
4200
    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4201 4202 4203 4204
    {
        return not (lhs == rhs);
    }

N
Niels 已提交
4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234
    /*!
    @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 已提交
4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253
    /*!
    @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.

4254 4255
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__less}
N
Niels 已提交
4256
    */
N
Niels 已提交
4257
    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4258
    {
F
Florian Weber 已提交
4259 4260
        const auto lhs_type = lhs.type();
        const auto rhs_type = rhs.type();
N
Niels 已提交
4261

F
Florian Weber 已提交
4262
        if (lhs_type == rhs_type)
N
cleanup  
Niels 已提交
4263
        {
F
Florian Weber 已提交
4264
            switch (lhs_type)
N
cleanup  
Niels 已提交
4265
            {
F
Florian Weber 已提交
4266
                case (value_t::array):
N
cleanup  
Niels 已提交
4267
                    return *lhs.m_value.array < *rhs.m_value.array;
F
Florian Weber 已提交
4268
                case (value_t::object):
N
cleanup  
Niels 已提交
4269
                    return *lhs.m_value.object < *rhs.m_value.object;
F
Florian Weber 已提交
4270
                case (value_t::null):
N
cleanup  
Niels 已提交
4271
                    return false;
F
Florian Weber 已提交
4272
                case (value_t::string):
N
cleanup  
Niels 已提交
4273
                    return *lhs.m_value.string < *rhs.m_value.string;
F
Florian Weber 已提交
4274
                case (value_t::boolean):
N
cleanup  
Niels 已提交
4275
                    return lhs.m_value.boolean < rhs.m_value.boolean;
F
Florian Weber 已提交
4276
                case (value_t::number_integer):
N
cleanup  
Niels 已提交
4277
                    return lhs.m_value.number_integer < rhs.m_value.number_integer;
F
Florian Weber 已提交
4278
                case (value_t::number_float):
N
cleanup  
Niels 已提交
4279
                    return lhs.m_value.number_float < rhs.m_value.number_float;
N
Niels 已提交
4280 4281
                case (value_t::discarded):
                    return false;
N
cleanup  
Niels 已提交
4282 4283
            }
        }
F
Florian Weber 已提交
4284 4285
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
        {
4286 4287
            return static_cast<number_float_t>(lhs.m_value.number_integer) <
                   rhs.m_value.number_float;
F
Florian Weber 已提交
4288 4289 4290 4291 4292 4293
        }
        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 已提交
4294

N
Niels 已提交
4295
        // We only reach this line if we cannot compare values. In that case,
N
Niels 已提交
4296 4297 4298
        // we compare types. Note we have to call the operator explicitly,
        // because MSVC has problems otherwise.
        return operator<(lhs_type, rhs_type);
N
cleanup  
Niels 已提交
4299 4300
    }

N
Niels 已提交
4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312
    /*!
    @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.

4313 4314
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__greater}
N
Niels 已提交
4315
    */
N
Niels 已提交
4316
    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4317 4318 4319 4320
    {
        return not (rhs < lhs);
    }

N
Niels 已提交
4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332
    /*!
    @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.

4333 4334
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__lessequal}
N
Niels 已提交
4335
    */
N
Niels 已提交
4336
    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4337 4338 4339 4340
    {
        return not (lhs <= rhs);
    }

N
Niels 已提交
4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352
    /*!
    @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.

4353 4354
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__greaterequal}
N
Niels 已提交
4355
    */
N
Niels 已提交
4356
    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4357 4358 4359 4360
    {
        return not (lhs < rhs);
    }

N
Niels 已提交
4361 4362
    /// @}

N
cleanup  
Niels 已提交
4363 4364 4365 4366 4367

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

N
Niels 已提交
4368 4369 4370
    /// @name serialization
    /// @{

N
Niels 已提交
4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387
    /*!
    @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 已提交
4388 4389
    @liveexample{The example below shows the serialization with different
    parameters to `width` to adjust the indentation level.,operator_serialize}
N
Niels 已提交
4390
    */
N
cleanup  
Niels 已提交
4391 4392
    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
    {
N
Niels 已提交
4393
        // read width member and use it as indentation parameter if nonzero
N
Niels 已提交
4394 4395
        const bool pretty_print = (o.width() > 0);
        const auto indentation = (pretty_print ? o.width() : 0);
N
Niels 已提交
4396

N
Niels 已提交
4397 4398 4399 4400
        // reset width to 0 for subsequent calls to this stream
        o.width(0);

        // do the actual serialization
N
Niels 已提交
4401
        j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
N
cleanup  
Niels 已提交
4402 4403 4404
        return o;
    }

N
Niels 已提交
4405 4406 4407 4408
    /*!
    @brief serialize to stream
    @copydoc operator<<(std::ostream&, const basic_json&)
    */
N
cleanup  
Niels 已提交
4409 4410
    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
    {
A
Alexandre Hamez 已提交
4411
        return o << j;
N
cleanup  
Niels 已提交
4412 4413
    }

N
Niels 已提交
4414 4415
    /// @}

N
cleanup  
Niels 已提交
4416

N
Niels 已提交
4417 4418 4419 4420
    /////////////////////
    // deserialization //
    /////////////////////

N
Niels 已提交
4421 4422 4423
    /// @name deserialization
    /// @{

N
Niels 已提交
4424 4425 4426 4427
    /*!
    @brief deserialize from string

    @param[in] s  string to read a serialized JSON value from
N
Niels 已提交
4428 4429 4430
    @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 已提交
4431 4432 4433 4434 4435 4436 4437

    @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 已提交
4438 4439
    @liveexample{The example below demonstrates the parse function with and
    without callback function.,parse__string__parser_callback_t}
N
Niels 已提交
4440 4441 4442 4443

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

N
Niels 已提交
4449 4450 4451 4452
    /*!
    @brief deserialize from stream

    @param[in,out] i  stream to read a serialized JSON value from
N
Niels 已提交
4453 4454 4455
    @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 已提交
4456 4457 4458 4459 4460 4461 4462

    @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 已提交
4463 4464
    @liveexample{The example below demonstrates the parse function with and
    without callback function.,parse__istream__parser_callback_t}
N
Niels 已提交
4465 4466 4467 4468

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

N
Niels 已提交
4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493
    /*!
    @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 已提交
4494 4495 4496 4497 4498
    {
        j = parser(i).parse();
        return i;
    }

N
Niels 已提交
4499 4500 4501 4502 4503
    /*!
    @brief deserialize from stream
    @copydoc operator<<(basic_json&, std::istream&)
    */
    friend std::istream& operator>>(std::istream& i, basic_json& j)
N
Niels 已提交
4504 4505 4506 4507 4508
    {
        j = parser(i).parse();
        return i;
    }

N
Niels 已提交
4509 4510
    /// @}

N
Niels 已提交
4511

N
cleanup  
Niels 已提交
4512 4513 4514 4515 4516 4517
  private:
    ///////////////////////////
    // convenience functions //
    ///////////////////////////

    /// return the type as string
N
Niels 已提交
4518
    string_t type_name() const
N
cleanup  
Niels 已提交
4519 4520 4521 4522 4523 4524 4525
    {
        switch (m_type)
        {
            case (value_t::null):
            {
                return "null";
            }
N
Niels 已提交
4526

N
cleanup  
Niels 已提交
4527 4528 4529 4530
            case (value_t::object):
            {
                return "object";
            }
N
Niels 已提交
4531

N
cleanup  
Niels 已提交
4532 4533 4534 4535
            case (value_t::array):
            {
                return "array";
            }
N
Niels 已提交
4536

N
cleanup  
Niels 已提交
4537 4538 4539 4540
            case (value_t::string):
            {
                return "string";
            }
N
Niels 已提交
4541

N
cleanup  
Niels 已提交
4542 4543 4544 4545
            case (value_t::boolean):
            {
                return "boolean";
            }
N
Niels 已提交
4546

N
Niels 已提交
4547 4548 4549 4550 4551
            case (value_t::discarded):
            {
                return "discarded";
            }

N
Niels 已提交
4552
            default:
N
cleanup  
Niels 已提交
4553 4554 4555 4556 4557 4558
            {
                return "number";
            }
        }
    }

N
Niels 已提交
4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602
    /*!
    @brief calculates the extra space to escape a JSON string

    @param[in] s  the string to escape
    @return the number of characters required to escape string @a s

    @complexity Linear in the length of string @a s.
    */
    static std::size_t extra_space(const string_t& s) noexcept
    {
        std::size_t result = 0;

        for (const auto& c : s)
        {
            switch (c)
            {
                case '"':
                case '\\':
                case '\b':
                case '\f':
                case '\n':
                case '\r':
                case '\t':
                {
                    // from c (1 byte) to \x (2 bytes)
                    result += 1;
                    break;
                }

                default:
                {
                    if (c >= 0x00 and c <= 0x1f)
                    {
                        // from c (1 byte) to \uxxxx (6 bytes)
                        result += 5;
                    }
                    break;
                }
            }
        }

        return result;
    }

N
Niels 已提交
4603
    /*!
N
Niels 已提交
4604
    @brief escape a string
N
Niels 已提交
4605

N
Niels 已提交
4606 4607 4608 4609 4610
    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 已提交
4611
    @param[in] s  the string to escape
N
Niels 已提交
4612 4613 4614
    @return  the escaped string

    @complexity Linear in the length of string @a s.
N
Niels 已提交
4615
    */
N
Niels 已提交
4616
    static string_t escape_string(const string_t& s) noexcept
N
Niels 已提交
4617
    {
N
Niels 已提交
4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628
        const auto space = extra_space(s);
        if (space == 0)
        {
            return s;
        }

        // create a result string of necessary size
        string_t result(s.size() + space, '\\');
        std::size_t pos = 0;

        for (const auto& c : s)
N
Niels 已提交
4629 4630 4631
        {
            switch (c)
            {
N
Niels 已提交
4632
                // quotation mark (0x22)
N
Niels 已提交
4633 4634
                case '"':
                {
N
Niels 已提交
4635 4636
                    result[pos + 1] = '"';
                    pos += 2;
N
Niels 已提交
4637 4638
                    break;
                }
N
Niels 已提交
4639

N
Niels 已提交
4640
                // reverse solidus (0x5c)
N
Niels 已提交
4641 4642
                case '\\':
                {
N
Niels 已提交
4643 4644
                    // nothing to change
                    pos += 2;
N
Niels 已提交
4645 4646
                    break;
                }
N
Niels 已提交
4647

N
Niels 已提交
4648
                // backspace (0x08)
N
Niels 已提交
4649 4650
                case '\b':
                {
N
Niels 已提交
4651 4652
                    result[pos + 1] = 'b';
                    pos += 2;
N
Niels 已提交
4653 4654
                    break;
                }
N
Niels 已提交
4655

N
Niels 已提交
4656
                // formfeed (0x0c)
N
Niels 已提交
4657 4658
                case '\f':
                {
N
Niels 已提交
4659 4660
                    result[pos + 1] = 'f';
                    pos += 2;
N
Niels 已提交
4661 4662
                    break;
                }
N
Niels 已提交
4663

N
Niels 已提交
4664
                // newline (0x0a)
N
Niels 已提交
4665 4666
                case '\n':
                {
N
Niels 已提交
4667 4668
                    result[pos + 1] = 'n';
                    pos += 2;
N
Niels 已提交
4669 4670
                    break;
                }
N
Niels 已提交
4671

N
Niels 已提交
4672
                // carriage return (0x0d)
N
Niels 已提交
4673 4674
                case '\r':
                {
N
Niels 已提交
4675 4676
                    result[pos + 1] = 'r';
                    pos += 2;
N
Niels 已提交
4677 4678
                    break;
                }
N
Niels 已提交
4679

N
Niels 已提交
4680
                // horizontal tab (0x09)
N
Niels 已提交
4681 4682
                case '\t':
                {
N
Niels 已提交
4683 4684
                    result[pos + 1] = 't';
                    pos += 2;
N
Niels 已提交
4685 4686
                    break;
                }
N
Niels 已提交
4687

N
Niels 已提交
4688 4689
                default:
                {
4690
                    if (c >= 0x00 and c <= 0x1f)
N
Niels 已提交
4691
                    {
N
Niels 已提交
4692 4693 4694
                        // print character c as \uxxxx
                        sprintf(&result[pos + 1], "u%04x", int(c));
                        pos += 6;
N
Niels 已提交
4695 4696 4697 4698
                    }
                    else
                    {
                        // all other characters are added as-is
N
Niels 已提交
4699
                        result[pos++] = c;
N
Niels 已提交
4700 4701
                    }
                    break;
N
Niels 已提交
4702 4703 4704
                }
            }
        }
N
Niels 已提交
4705 4706

        return result;
N
Niels 已提交
4707 4708
    }

N
cleanup  
Niels 已提交
4709
    /*!
N
Niels 已提交
4710
    @brief internal implementation of the serialization function
N
Niels 已提交
4711

N
Niels 已提交
4712 4713 4714 4715
    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 已提交
4716

N
Niels 已提交
4717
    - strings and object keys are escaped using escape_string()
N
Niels 已提交
4718
    - integer numbers are converted implictly via operator<<
N
Niels 已提交
4719
    - floating-point numbers are converted to a string using "%g" format
N
cleanup  
Niels 已提交
4720

N
Niels 已提交
4721 4722 4723 4724
    @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 已提交
4725
    */
N
Niels 已提交
4726
    void dump(std::ostream& o, const bool pretty_print, const unsigned int indent_step,
N
Niels 已提交
4727
              const unsigned int current_indent = 0) const
N
cleanup  
Niels 已提交
4728
    {
N
Niels 已提交
4729
        // variable to hold indentation for recursive calls
N
Niels 已提交
4730
        unsigned int new_indent = current_indent;
N
Niels 已提交
4731

N
cleanup  
Niels 已提交
4732 4733 4734 4735 4736 4737
        switch (m_type)
        {
            case (value_t::object):
            {
                if (m_value.object->empty())
                {
N
Niels 已提交
4738 4739
                    o << "{}";
                    return;
N
cleanup  
Niels 已提交
4740 4741
                }

N
Niels 已提交
4742
                o << "{";
N
cleanup  
Niels 已提交
4743 4744

                // increase indentation
N
Niels 已提交
4745
                if (pretty_print)
N
cleanup  
Niels 已提交
4746
                {
N
Niels 已提交
4747
                    new_indent += indent_step;
N
Niels 已提交
4748
                    o << "\n";
N
cleanup  
Niels 已提交
4749 4750
                }

N
Niels 已提交
4751
                for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
N
cleanup  
Niels 已提交
4752
                {
N
Niels 已提交
4753
                    if (i != m_value.object->cbegin())
N
cleanup  
Niels 已提交
4754
                    {
N
Niels 已提交
4755
                        o << (pretty_print ? ",\n" : ",");
N
cleanup  
Niels 已提交
4756
                    }
N
Niels 已提交
4757 4758 4759
                    o << string_t(new_indent, ' ') << "\""
                      << escape_string(i->first) << "\":"
                      << (pretty_print ? " " : "");
N
Niels 已提交
4760
                    i->second.dump(o, pretty_print, indent_step, new_indent);
N
cleanup  
Niels 已提交
4761 4762 4763
                }

                // decrease indentation
N
Niels 已提交
4764
                if (pretty_print)
N
cleanup  
Niels 已提交
4765
                {
N
Niels 已提交
4766
                    new_indent -= indent_step;
N
Niels 已提交
4767
                    o << "\n";
N
cleanup  
Niels 已提交
4768 4769
                }

N
Niels 已提交
4770 4771
                o << string_t(new_indent, ' ') + "}";
                return;
N
cleanup  
Niels 已提交
4772 4773 4774 4775 4776 4777
            }

            case (value_t::array):
            {
                if (m_value.array->empty())
                {
N
Niels 已提交
4778 4779
                    o << "[]";
                    return;
N
cleanup  
Niels 已提交
4780 4781
                }

N
Niels 已提交
4782
                o << "[";
N
cleanup  
Niels 已提交
4783 4784

                // increase indentation
N
Niels 已提交
4785
                if (pretty_print)
N
cleanup  
Niels 已提交
4786
                {
N
Niels 已提交
4787
                    new_indent += indent_step;
N
Niels 已提交
4788
                    o << "\n";
N
cleanup  
Niels 已提交
4789 4790
                }

N
Niels 已提交
4791
                for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
N
cleanup  
Niels 已提交
4792
                {
N
Niels 已提交
4793
                    if (i != m_value.array->cbegin())
N
cleanup  
Niels 已提交
4794
                    {
N
Niels 已提交
4795
                        o << (pretty_print ? ",\n" : ",");
N
cleanup  
Niels 已提交
4796
                    }
N
Niels 已提交
4797
                    o << string_t(new_indent, ' ');
N
Niels 已提交
4798
                    i->dump(o, pretty_print, indent_step, new_indent);
N
cleanup  
Niels 已提交
4799 4800 4801
                }

                // decrease indentation
N
Niels 已提交
4802
                if (pretty_print)
N
cleanup  
Niels 已提交
4803
                {
N
Niels 已提交
4804
                    new_indent -= indent_step;
N
Niels 已提交
4805
                    o << "\n";
N
cleanup  
Niels 已提交
4806 4807
                }

N
Niels 已提交
4808 4809
                o << string_t(new_indent, ' ') << "]";
                return;
N
cleanup  
Niels 已提交
4810 4811 4812 4813
            }

            case (value_t::string):
            {
N
Niels 已提交
4814
                o << string_t("\"") << escape_string(*m_value.string) << "\"";
N
Niels 已提交
4815
                return;
N
cleanup  
Niels 已提交
4816 4817 4818 4819
            }

            case (value_t::boolean):
            {
N
Niels 已提交
4820 4821
                o << (m_value.boolean ? "true" : "false");
                return;
N
cleanup  
Niels 已提交
4822 4823 4824 4825
            }

            case (value_t::number_integer):
            {
N
Niels 已提交
4826 4827
                o << m_value.number_integer;
                return;
N
cleanup  
Niels 已提交
4828 4829 4830 4831
            }

            case (value_t::number_float):
            {
N
Niels 已提交
4832
                // 15 digits of precision allows round-trip IEEE 754
N
Niels 已提交
4833 4834 4835
                // 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 已提交
4836
                return;
N
cleanup  
Niels 已提交
4837
            }
N
Niels 已提交
4838

N
Niels 已提交
4839 4840
            case (value_t::discarded):
            {
N
Niels 已提交
4841 4842
                o << "<discarded>";
                return;
N
Niels 已提交
4843
            }
N
Niels 已提交
4844

N
Niels 已提交
4845 4846
            default:
            {
N
Niels 已提交
4847 4848
                o << "null";
                return;
N
Niels 已提交
4849
            }
N
cleanup  
Niels 已提交
4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863
        }
    }

  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 已提交
4864

N
Niels 已提交
4865
  private:
N
cleanup  
Niels 已提交
4866 4867 4868 4869
    ///////////////
    // iterators //
    ///////////////

4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912
    /*!
    @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
N
Niels 已提交
4913
        operator difference_type () const
4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925
        {
            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 已提交
4926 4927 4928 4929 4930 4931 4932 4933
    /*!
    @brief an iterator value

    @note This structure could easily be a union, but MSVC currently does not
    allow unions members with complex constructors, see
    https://github.com/nlohmann/json/pull/105.
    */
    struct internal_iterator
N
Niels 已提交
4934 4935
    {
        /// iterator for JSON objects
N
Niels 已提交
4936
        typename object_t::iterator object_iterator;
N
Niels 已提交
4937
        /// iterator for JSON arrays
N
Niels 已提交
4938
        typename array_t::iterator array_iterator;
N
Niels 已提交
4939
        /// generic iterator for all other types
N
Niels 已提交
4940 4941 4942 4943 4944 4945
        primitive_iterator_t primitive_iterator;

        /// create an uninitialized internal_iterator
        internal_iterator()
            : object_iterator(), array_iterator(), primitive_iterator()
        {}
N
Niels 已提交
4946 4947 4948
    };

  public:
N
Niels 已提交
4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959
    /*!
    @brief a const random access iterator for the @ref basic_json class

    This class implements a const iterator for the @ref basic_json class. From
    this class, the @ref iterator class is derived.

    @requirement The class satisfies the following concept requirements:
    - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
      The iterator that can be moved to point (forward and backward) to any
      element in constant time.
    */
N
Niels 已提交
4960
    class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json>
N
cleanup  
Niels 已提交
4961
    {
N
Niels 已提交
4962
        /// allow basic_json to access private members
4963 4964
        friend class basic_json;

N
cleanup  
Niels 已提交
4965 4966
      public:
        /// the type of the values when the iterator is dereferenced
N
Niels 已提交
4967
        using value_type = typename basic_json::value_type;
N
cleanup  
Niels 已提交
4968
        /// a type to represent differences between iterators
N
Niels 已提交
4969
        using difference_type = typename basic_json::difference_type;
N
cleanup  
Niels 已提交
4970
        /// defines a pointer to the type iterated over (value_type)
N
Niels 已提交
4971
        using pointer = typename basic_json::const_pointer;
N
cleanup  
Niels 已提交
4972
        /// defines a reference to the type iterated over (value_type)
N
Niels 已提交
4973
        using reference = typename basic_json::const_reference;
N
cleanup  
Niels 已提交
4974
        /// the category of the iterator
N
Niels 已提交
4975
        using iterator_category = std::bidirectional_iterator_tag;
N
cleanup  
Niels 已提交
4976

4977
        /// default constructor
N
Niels 已提交
4978
        const_iterator() = default;
4979

N
cleanup  
Niels 已提交
4980
        /// constructor for a given JSON instance
N
Niels 已提交
4981
        const_iterator(pointer object) : m_object(object)
N
cleanup  
Niels 已提交
4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996
        {
            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:
                {
4997
                    m_it.primitive_iterator = primitive_iterator_t();
N
cleanup  
Niels 已提交
4998 4999 5000 5001 5002
                    break;
                }
            }
        }

N
Niels 已提交
5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027
        /// 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 已提交
5028
        /// copy constructor
N
Niels 已提交
5029
        const_iterator(const const_iterator& other) noexcept
N
Niels 已提交
5030 5031 5032
            : m_object(other.m_object), m_it(other.m_it)
        {}

N
cleanup  
Niels 已提交
5033
        /// copy assignment
N
Niels 已提交
5034
        const_iterator& operator=(const_iterator other) noexcept(
N
Niels 已提交
5035 5036
            std::is_nothrow_move_constructible<pointer>::value and
            std::is_nothrow_move_assignable<pointer>::value and
N
Niels 已提交
5037 5038
            std::is_nothrow_move_constructible<internal_iterator>::value and
            std::is_nothrow_move_assignable<internal_iterator>::value
N
Niels 已提交
5039 5040 5041 5042
        )
        {
            std::swap(m_object, other.m_object);
            std::swap(m_it, other.m_it);
N
cleanup  
Niels 已提交
5043 5044 5045
            return *this;
        }

N
Niels 已提交
5046
      private:
N
cleanup  
Niels 已提交
5047
        /// set the iterator to the first value
N
Niels 已提交
5048
        void set_begin()
N
cleanup  
Niels 已提交
5049 5050 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):
                {
                    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 已提交
5066
                    // set to end so begin()==end() is true: null is empty
5067
                    m_it.primitive_iterator.set_end();
N
cleanup  
Niels 已提交
5068 5069 5070 5071 5072
                    break;
                }

                default:
                {
5073
                    m_it.primitive_iterator.set_begin();
N
cleanup  
Niels 已提交
5074 5075 5076 5077 5078 5079
                    break;
                }
            }
        }

        /// set the iterator past the last value
N
Niels 已提交
5080
        void set_end()
N
cleanup  
Niels 已提交
5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097
        {
            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:
                {
5098
                    m_it.primitive_iterator.set_end();
N
cleanup  
Niels 已提交
5099 5100 5101 5102 5103
                    break;
                }
            }
        }

N
Niels 已提交
5104
      public:
N
cleanup  
Niels 已提交
5105
        /// return a reference to the value pointed to by the iterator
N
Niels 已提交
5106
        reference operator*() const
N
cleanup  
Niels 已提交
5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126
        {
            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:
                {
5127
                    if (m_it.primitive_iterator.is_begin())
N
cleanup  
Niels 已提交
5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139
                    {
                        return *m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
                }
            }
        }

        /// dereference the iterator
N
Niels 已提交
5140
        pointer operator->() const
N
cleanup  
Niels 已提交
5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155
        {
            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:
                {
5156
                    if (m_it.primitive_iterator.is_begin())
N
cleanup  
Niels 已提交
5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168
                    {
                        return m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
                }
            }
        }

        /// post-increment (it++)
N
Niels 已提交
5169
        const_iterator operator++(int)
N
cleanup  
Niels 已提交
5170
        {
N
Niels 已提交
5171
            auto result = *this;
N
Niels 已提交
5172
            ++(*this);
N
cleanup  
Niels 已提交
5173 5174 5175 5176 5177

            return result;
        }

        /// pre-increment (++it)
N
Niels 已提交
5178
        const_iterator& operator++()
N
cleanup  
Niels 已提交
5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195
        {
            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:
                {
5196
                    ++m_it.primitive_iterator;
N
cleanup  
Niels 已提交
5197 5198 5199 5200 5201 5202 5203 5204
                    break;
                }
            }

            return *this;
        }

        /// post-decrement (it--)
N
Niels 已提交
5205
        const_iterator operator--(int)
N
cleanup  
Niels 已提交
5206
        {
N
Niels 已提交
5207
            auto result = *this;
N
Niels 已提交
5208
            --(*this);
N
cleanup  
Niels 已提交
5209 5210 5211 5212 5213

            return result;
        }

        /// pre-decrement (--it)
N
Niels 已提交
5214
        const_iterator& operator--()
N
cleanup  
Niels 已提交
5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231
        {
            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:
                {
5232
                    --m_it.primitive_iterator;
N
cleanup  
Niels 已提交
5233 5234 5235 5236 5237 5238 5239 5240
                    break;
                }
            }

            return *this;
        }

        /// comparison: equal
N
Niels 已提交
5241
        bool operator==(const const_iterator& other) const
N
cleanup  
Niels 已提交
5242
        {
N
Niels 已提交
5243 5244
            // if objects are not the same, the comparison is undefined
            if (m_object != other.m_object)
N
cleanup  
Niels 已提交
5245
            {
N
Niels 已提交
5246
                throw std::domain_error("cannot compare iterators of different containers");
N
cleanup  
Niels 已提交
5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262
            }

            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:
                {
5263
                    return (m_it.primitive_iterator == other.m_it.primitive_iterator);
N
cleanup  
Niels 已提交
5264 5265 5266 5267 5268
                }
            }
        }

        /// comparison: not equal
N
Niels 已提交
5269
        bool operator!=(const const_iterator& other) const
N
cleanup  
Niels 已提交
5270 5271 5272 5273
        {
            return not operator==(other);
        }

N
Niels 已提交
5274
        /// comparison: smaller
N
Niels 已提交
5275
        bool operator<(const const_iterator& other) const
N
Niels 已提交
5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296
        {
            // 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:
                {
5297
                    return (m_it.primitive_iterator < other.m_it.primitive_iterator);
N
Niels 已提交
5298 5299 5300 5301 5302
                }
            }
        }

        /// comparison: less than or equal
N
Niels 已提交
5303
        bool operator<=(const const_iterator& other) const
N
Niels 已提交
5304 5305 5306 5307 5308
        {
            return not other.operator < (*this);
        }

        /// comparison: greater than
N
Niels 已提交
5309
        bool operator>(const const_iterator& other) const
N
Niels 已提交
5310 5311 5312 5313 5314
        {
            return not operator<=(other);
        }

        /// comparison: greater than or equal
N
Niels 已提交
5315
        bool operator>=(const const_iterator& other) const
N
Niels 已提交
5316 5317 5318 5319 5320
        {
            return not operator<(other);
        }

        /// add to iterator
N
Niels 已提交
5321
        const_iterator& operator+=(difference_type i)
N
Niels 已提交
5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337
        {
            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:
                {
5338
                    m_it.primitive_iterator += i;
N
Niels 已提交
5339 5340 5341 5342 5343 5344 5345 5346
                    break;
                }
            }

            return *this;
        }

        /// subtract from iterator
N
Niels 已提交
5347
        const_iterator& operator-=(difference_type i)
N
Niels 已提交
5348 5349 5350 5351 5352
        {
            return operator+=(-i);
        }

        /// add to iterator
N
Niels 已提交
5353
        const_iterator operator+(difference_type i)
N
Niels 已提交
5354 5355 5356 5357 5358 5359 5360
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
5361
        const_iterator operator-(difference_type i)
N
Niels 已提交
5362 5363 5364 5365 5366 5367 5368
        {
            auto result = *this;
            result -= i;
            return result;
        }

        /// return difference
N
Niels 已提交
5369
        difference_type operator-(const const_iterator& other) const
N
Niels 已提交
5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384
        {
            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:
                {
5385
                    return m_it.primitive_iterator - other.m_it.primitive_iterator;
N
Niels 已提交
5386 5387 5388 5389 5390
                }
            }
        }

        /// access to successor
N
Niels 已提交
5391
        reference operator[](difference_type n) const
N
Niels 已提交
5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411
        {
            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:
                {
5412
                    if (m_it.primitive_iterator == -n)
N
Niels 已提交
5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423
                    {
                        return *m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
                }
            }
        }

5424
        /// return the key of an object iterator
5425
        typename object_t::key_type key() const
N
Niels 已提交
5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440
        {
            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 已提交
5441 5442
        /// return the value of an iterator
        reference value() const
N
Niels 已提交
5443 5444 5445 5446
        {
            return operator*();
        }

N
cleanup  
Niels 已提交
5447 5448 5449 5450
      private:
        /// associated JSON instance
        pointer m_object = nullptr;
        /// the actual iterator of the associated instance
N
Niels 已提交
5451
        internal_iterator m_it = internal_iterator();
N
cleanup  
Niels 已提交
5452 5453
    };

N
Niels 已提交
5454 5455 5456 5457 5458 5459 5460 5461 5462 5463
    /*!
    @brief a mutable random access iterator for the @ref basic_json class

    @requirement The class satisfies the following concept requirements:
    - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
      The iterator that can be moved to point (forward and backward) to any
      element in constant time.
    - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
      It is possible to write to the pointed-to element.
    */
N
Niels 已提交
5464
    class iterator : public const_iterator
N
cleanup  
Niels 已提交
5465 5466
    {
      public:
N
Niels 已提交
5467 5468 5469
        using base_iterator = const_iterator;
        using pointer = typename basic_json::pointer;
        using reference = typename basic_json::reference;
N
cleanup  
Niels 已提交
5470

5471
        /// default constructor
N
Niels 已提交
5472
        iterator() = default;
5473

N
cleanup  
Niels 已提交
5474
        /// constructor for a given JSON instance
N
Niels 已提交
5475 5476
        iterator(pointer object) noexcept : base_iterator(object)
        {}
N
cleanup  
Niels 已提交
5477

N
Niels 已提交
5478
        /// copy constructor
N
Niels 已提交
5479 5480
        iterator(const iterator& other) noexcept
            : base_iterator(other)
N
Niels 已提交
5481 5482
        {}

N
cleanup  
Niels 已提交
5483
        /// copy assignment
N
Niels 已提交
5484
        iterator& operator=(iterator other) noexcept(
N
Niels 已提交
5485 5486
            std::is_nothrow_move_constructible<pointer>::value and
            std::is_nothrow_move_assignable<pointer>::value and
N
Niels 已提交
5487 5488
            std::is_nothrow_move_constructible<internal_iterator>::value and
            std::is_nothrow_move_assignable<internal_iterator>::value
N
Niels 已提交
5489 5490
        )
        {
N
Niels 已提交
5491
            base_iterator::operator=(other);
N
cleanup  
Niels 已提交
5492 5493 5494
            return *this;
        }

N
Niels 已提交
5495 5496
        /// return a reference to the value pointed to by the iterator
        reference operator*()
N
cleanup  
Niels 已提交
5497
        {
N
Niels 已提交
5498 5499
            return const_cast<reference>(base_iterator::operator*());
        }
N
cleanup  
Niels 已提交
5500

N
Niels 已提交
5501 5502 5503 5504 5505
        /// dereference the iterator
        pointer operator->()
        {
            return const_cast<pointer>(base_iterator::operator->());
        }
N
cleanup  
Niels 已提交
5506

N
Niels 已提交
5507 5508 5509 5510 5511 5512 5513
        /// post-increment (it++)
        iterator operator++(int)
        {
            iterator result = *this;
            base_iterator::operator++();
            return result;
        }
N
cleanup  
Niels 已提交
5514

N
Niels 已提交
5515 5516 5517 5518 5519
        /// pre-increment (++it)
        iterator& operator++()
        {
            base_iterator::operator++();
            return *this;
N
cleanup  
Niels 已提交
5520 5521
        }

N
Niels 已提交
5522 5523
        /// post-decrement (it--)
        iterator operator--(int)
N
cleanup  
Niels 已提交
5524
        {
N
Niels 已提交
5525 5526 5527 5528
            iterator result = *this;
            base_iterator::operator--();
            return result;
        }
N
cleanup  
Niels 已提交
5529

N
Niels 已提交
5530 5531 5532 5533 5534 5535
        /// pre-decrement (--it)
        iterator& operator--()
        {
            base_iterator::operator--();
            return *this;
        }
N
Niels 已提交
5536 5537

        /// add to iterator
N
Niels 已提交
5538
        iterator& operator+=(difference_type i)
N
Niels 已提交
5539
        {
N
Niels 已提交
5540
            base_iterator::operator+=(i);
N
Niels 已提交
5541 5542 5543 5544
            return *this;
        }

        /// subtract from iterator
N
Niels 已提交
5545
        iterator& operator-=(difference_type i)
N
Niels 已提交
5546
        {
N
Niels 已提交
5547 5548
            base_iterator::operator-=(i);
            return *this;
N
Niels 已提交
5549 5550 5551
        }

        /// add to iterator
N
Niels 已提交
5552
        iterator operator+(difference_type i)
N
Niels 已提交
5553 5554 5555 5556 5557 5558 5559
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
5560
        iterator operator-(difference_type i)
N
Niels 已提交
5561 5562 5563 5564 5565 5566
        {
            auto result = *this;
            result -= i;
            return result;
        }

N
Niels 已提交
5567
        difference_type operator-(const iterator& other) const
N
Niels 已提交
5568
        {
N
Niels 已提交
5569
            return base_iterator::operator-(other);
N
Niels 已提交
5570 5571 5572
        }

        /// access to successor
5573
        reference operator[](difference_type n) const
N
Niels 已提交
5574
        {
N
Niels 已提交
5575
            return const_cast<reference>(base_iterator::operator[](n));
N
Niels 已提交
5576 5577
        }

5578
        /// return the value of an iterator
5579
        reference value() const
N
Niels 已提交
5580
        {
N
Niels 已提交
5581
            return const_cast<reference>(base_iterator::value());
N
Niels 已提交
5582
        }
N
cleanup  
Niels 已提交
5583
    };
N
Niels 已提交
5584

N
Niels 已提交
5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599
    /*!
    @brief a template for a reverse iterator class

    @tparam Base the base iterator type to reverse. Valid types are @ref
    iterator (to create @ref reverse_iterator) and @ref const_iterator (to
    create @ref const_reverse_iterator).

    @requirement The class satisfies the following concept requirements:
    - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
      The iterator that can be moved to point (forward and backward) to any
      element in constant time.
    - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
      It is possible to write to the pointed-to element (only if @a Base is
      @ref iterator).
    */
N
Niels 已提交
5600 5601
    template<typename Base>
    class json_reverse_iterator : public std::reverse_iterator<Base>
5602 5603
    {
      public:
5604
        /// shortcut to the reverse iterator adaptor
N
Niels 已提交
5605
        using base_iterator = std::reverse_iterator<Base>;
N
Niels 已提交
5606
        /// the reference type for the pointed-to element
N
Niels 已提交
5607
        using reference = typename Base::reference;
5608

5609
        /// create reverse iterator from iterator
N
Niels 已提交
5610
        json_reverse_iterator(const typename base_iterator::iterator_type& it)
5611 5612 5613
            : base_iterator(it) {}

        /// create reverse iterator from base class
N
Niels 已提交
5614
        json_reverse_iterator(const base_iterator& it) : base_iterator(it) {}
5615 5616

        /// post-increment (it++)
N
Niels 已提交
5617
        json_reverse_iterator operator++(int)
5618 5619 5620 5621 5622
        {
            return base_iterator::operator++(1);
        }

        /// pre-increment (++it)
N
Niels 已提交
5623
        json_reverse_iterator& operator++()
5624 5625 5626 5627 5628 5629
        {
            base_iterator::operator++();
            return *this;
        }

        /// post-decrement (it--)
N
Niels 已提交
5630
        json_reverse_iterator operator--(int)
5631 5632 5633 5634 5635
        {
            return base_iterator::operator--(1);
        }

        /// pre-decrement (--it)
N
Niels 已提交
5636
        json_reverse_iterator& operator--()
5637 5638 5639 5640 5641 5642
        {
            base_iterator::operator--();
            return *this;
        }

        /// add to iterator
N
Niels 已提交
5643
        json_reverse_iterator& operator+=(difference_type i)
5644 5645 5646 5647 5648 5649
        {
            base_iterator::operator+=(i);
            return *this;
        }

        /// add to iterator
N
Niels 已提交
5650
        json_reverse_iterator operator+(difference_type i) const
5651 5652 5653 5654 5655 5656 5657
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
5658
        json_reverse_iterator operator-(difference_type i) const
5659 5660 5661 5662 5663 5664 5665
        {
            auto result = *this;
            result -= i;
            return result;
        }

        /// return difference
N
Niels 已提交
5666
        difference_type operator-(const json_reverse_iterator& other) const
5667 5668 5669 5670 5671 5672 5673 5674 5675
        {
            return this->base() - other.base();
        }

        /// access to successor
        reference operator[](difference_type n) const
        {
            return *(this->operator+(n));
        }
N
Niels 已提交
5676

5677
        /// return the key of an object iterator
5678
        typename object_t::key_type key() const
5679
        {
N
Niels 已提交
5680 5681
            auto it = --this->base();
            return it.key();
5682 5683 5684
        }

        /// return the value of an iterator
5685
        reference value() const
5686
        {
N
Niels 已提交
5687 5688
            auto it = --this->base();
            return it.operator * ();
5689 5690 5691
        }
    };

N
Niels 已提交
5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 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 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754
    /*!
    @brief wrapper to access iterator member functions in range-based for

    This class allows to access @ref key() and @ref value() during range-based
    for loops. In these loops, a reference to the JSON values is returned, so
    there is no access to the underlying iterator.
    */
    class iterator_wrapper
    {
      private:
        /// the container to iterate
        basic_json& container;
        /// the type of the iterator to use while iteration
        using json_iterator = decltype(container.begin());

        /// internal iterator wrapper
        class iterator_wrapper_internal
        {
          private:
            /// the iterator
            json_iterator anchor;
            /// an index for arrays
            size_t array_index = 0;
            size_t container_size = 0;

            /// calculate a key for the iterator
            std::string calculate_key()
            {
                switch (anchor.m_object->type())
                {
                    /// use integer array index as key
                    case (value_t::array):
                    {
                        return std::to_string(array_index);
                    }

                    /// use key from the object
                    case (value_t::object):
                    {
                        return anchor.key();
                    }

                    /// use an empty key for all primitive types
                    default:
                    {
                        return "";
                    }
                }
            }

          public:
            /// construct wrapper given an iterator
            iterator_wrapper_internal(json_iterator i, size_t s)
                : anchor(i), container_size(s), first(calculate_key()), second(*i)
            {}

            /// dereference operator (needed for range-based for)
            iterator_wrapper_internal operator*()
            {
                return *this;
            }

            /// increment operator (needed for range-based for)
N
Niels 已提交
5755
            iterator_wrapper_internal& operator++()
N
Niels 已提交
5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 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 5813 5814 5815 5816 5817 5818
            {
                ++anchor;
                ++array_index;

                first = calculate_key();

                if (array_index < container_size)
                {
                    second = *anchor;
                }

                return *this;
            }

            /// inequality operator (needed for range-based for)
            bool operator!= (const iterator_wrapper_internal& o)
            {
                return anchor != o.anchor;
            }

            /// stream operator
            friend std::ostream& operator<<(std::ostream& o, const iterator_wrapper_internal& w)
            {
                return o << w.value();
            }

            /// return key of the iterator
            typename basic_json::string_t key() const
            {
                return first;
            }

            /// return value of the iterator
            basic_json value() const
            {
                return second;
            }

            /// public member to simulate std::map::iterator access
            typename basic_json::string_t first;
            /// public member to simulate std::map::iterator access
            basic_json& second;
        };

      public:
        /// construct iterator wrapper from a container
        iterator_wrapper(basic_json& cont)
            : container(cont)
        {}

        /// return iterator begin (needed for range-based for)
        iterator_wrapper_internal begin()
        {
            return iterator_wrapper_internal(container.begin(), container.size());
        }

        /// return iterator end (needed for range-based for)
        iterator_wrapper_internal end()
        {
            return iterator_wrapper_internal(container.end(), container.size());
        }
    };

N
Niels 已提交
5819
  private:
N
Niels 已提交
5820 5821 5822
    //////////////////////
    // lexer and parser //
    //////////////////////
N
Niels 已提交
5823

N
Niels 已提交
5824 5825 5826 5827 5828
    /*!
    @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
5829
    a buffer and recognizes tokens according to RFC 7159.
N
Niels 已提交
5830
    */
N
Niels 已提交
5831
    class lexer
N
Niels 已提交
5832
    {
N
Niels 已提交
5833
      public:
N
Niels 已提交
5834 5835 5836
        /// token types for the parser
        enum class token_type
        {
N
Niels 已提交
5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850
            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 已提交
5851 5852
        };

N
Niels 已提交
5853
        /// the char type to use in the lexer
N
Niels 已提交
5854
        using lexer_char_t = unsigned char;
N
Niels 已提交
5855

N
Niels 已提交
5856
        /// constructor with a given buffer
N
Niels 已提交
5857
        explicit lexer(const string_t& s) noexcept
N
Niels 已提交
5858
            : m_stream(nullptr), m_buffer(s)
N
Niels 已提交
5859
        {
5860
            m_content = reinterpret_cast<const lexer_char_t*>(s.c_str());
N
Niels 已提交
5861
            m_start = m_cursor = m_content;
N
Niels 已提交
5862
            m_limit = m_content + s.size();
N
Niels 已提交
5863
        }
N
Niels 已提交
5864
        explicit lexer(std::istream* s) noexcept
N
Niels 已提交
5865
            : m_stream(s), m_buffer()
5866
        {
5867 5868
            getline(*m_stream, m_buffer);
            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
N
Niels 已提交
5869
            m_start = m_cursor = m_content;
5870
            m_limit = m_content + m_buffer.size();
N
Niels 已提交
5871 5872
        }

N
Niels 已提交
5873
        /// default constructor
5874
        lexer() = default;
N
Niels 已提交
5875

N
Niels 已提交
5876 5877 5878 5879
        // switch of unwanted functions
        lexer(const lexer&) = delete;
        lexer operator=(const lexer&) = delete;

N
Niels 已提交
5880 5881 5882
        /*!
        @brief create a string from a Unicode code point

N
Niels 已提交
5883 5884
        @param[in] codepoint1  the code point (can be high surrogate)
        @param[in] codepoint2  the code point (can be low surrogate or 0)
N
Niels 已提交
5885
        @return string representation of the code point
N
Niels 已提交
5886 5887
        @throw std::out_of_range if code point is >0x10ffff
        @throw std::invalid_argument if the low surrogate is invalid
N
Niels 已提交
5888 5889 5890

        @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
        */
5891
        static string_t to_unicode(const std::size_t codepoint1,
N
Niels 已提交
5892
                                   const std::size_t codepoint2 = 0)
N
Niels 已提交
5893
        {
N
Niels 已提交
5894
            string_t result;
N
Niels 已提交
5895

N
Niels 已提交
5896
            // calculate the codepoint from the given code points
N
Niels 已提交
5897
            std::size_t codepoint = codepoint1;
N
Niels 已提交
5898 5899

            // check if codepoint1 is a high surrogate
N
Niels 已提交
5900 5901
            if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
            {
N
Niels 已提交
5902
                // check if codepoint2 is a low surrogate
N
Niels 已提交
5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920
                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 已提交
5921
            if (codepoint < 0x80)
N
Niels 已提交
5922
            {
N
Niels 已提交
5923
                // 1-byte characters: 0xxxxxxx (ASCII)
N
Niels 已提交
5924
                result.append(1, static_cast<typename string_t::value_type>(codepoint));
N
Niels 已提交
5925 5926 5927 5928
            }
            else if (codepoint <= 0x7ff)
            {
                // 2-byte characters: 110xxxxx 10xxxxxx
N
Niels 已提交
5929 5930
                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 已提交
5931 5932 5933 5934
            }
            else if (codepoint <= 0xffff)
            {
                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
N
Niels 已提交
5935 5936 5937
                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 已提交
5938 5939 5940 5941
            }
            else if (codepoint <= 0x10ffff)
            {
                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
N
Niels 已提交
5942 5943 5944 5945
                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 已提交
5946 5947 5948
            }
            else
            {
N
Niels 已提交
5949
                throw std::out_of_range("code points above 0x10FFFF are invalid");
N
Niels 已提交
5950 5951 5952 5953 5954
            }

            return result;
        }

N
Niels 已提交
5955
        /// return name of values of type token_type
N
Niels 已提交
5956
        static std::string token_type_name(token_type t)
N
cleanup  
Niels 已提交
5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985
        {
            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 已提交
5986 5987
                default:
                    return "<parse error>";
N
cleanup  
Niels 已提交
5988 5989 5990
            }
        }

N
fixes  
Niels 已提交
5991 5992
        /*!
        This function implements a scanner for JSON. It is specified using
5993 5994 5995 5996 5997
        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 已提交
5998 5999 6000

        @return the class of the next token read from the buffer
        */
6001
        token_type scan() noexcept
N
Niels 已提交
6002
        {
N
cleanup  
Niels 已提交
6003
            // pointer for backtracking information
6004
            m_marker = nullptr;
N
Niels 已提交
6005 6006 6007 6008 6009 6010 6011 6012 6013

            // 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 已提交
6014
                re2c:define:YYFILL   = "yyfill(); // LCOV_EXCL_LINE";
6015
                re2c:yyfill:parameter = 0;
N
Niels 已提交
6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053
                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 已提交
6054
                unescaped       = [^\"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F];
N
Niels 已提交
6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067
                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; }
             */
6068

N
Niels 已提交
6069 6070
        }

6071
        /// append data from the stream to the internal buffer
6072
        void yyfill() noexcept
6073
        {
N
Niels 已提交
6074 6075 6076 6077
            if (not m_stream or not * m_stream)
            {
                return;
            }
6078

N
Niels 已提交
6079 6080 6081
            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;
6082

N
Niels 已提交
6083
            m_buffer.erase(0, static_cast<size_t>(offset_start));
6084 6085
            std::string line;
            std::getline(*m_stream, line);
N
Niels 已提交
6086
            m_buffer += "\n" + line; // add line with newline symbol
6087

6088 6089 6090 6091 6092
            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 已提交
6093 6094
        }

N
Niels 已提交
6095
        /// return string representation of last read token
6096
        string_t get_token() const noexcept
N
Niels 已提交
6097
        {
N
Niels 已提交
6098 6099
            return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
                            static_cast<size_t>(m_cursor - m_start));
N
Niels 已提交
6100 6101 6102
        }

        /*!
N
Niels 已提交
6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118
        @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 已提交
6119 6120

        @return string value of current token without opening and closing quotes
N
Niels 已提交
6121
        @throw std::out_of_range if to_unicode fails
N
Niels 已提交
6122
        */
6123
        string_t get_string() const
N
Niels 已提交
6124
        {
N
Niels 已提交
6125
            string_t result;
N
Niels 已提交
6126 6127 6128
            result.reserve(static_cast<size_t>(m_cursor - m_start - 2));

            // iterate the result between the quotes
N
Niels 已提交
6129
            for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
N
Niels 已提交
6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166
            {
                // 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 已提交
6167
                            result += "\\";
N
Niels 已提交
6168 6169 6170 6171
                            break;
                        }
                        case '/':
                        {
N
Niels 已提交
6172
                            result += "/";
N
Niels 已提交
6173 6174 6175 6176
                            break;
                        }
                        case '"':
                        {
N
Niels 已提交
6177
                            result += "\"";
N
Niels 已提交
6178 6179 6180 6181 6182 6183
                            break;
                        }

                        // unicode
                        case 'u':
                        {
N
Niels 已提交
6184
                            // get code xxxx from uxxxx
N
Niels 已提交
6185 6186
                            auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
                                                          4).c_str(), nullptr, 16);
N
Niels 已提交
6187

N
Niels 已提交
6188
                            // check if codepoint is a high surrogate
N
Niels 已提交
6189 6190
                            if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
                            {
N
Niels 已提交
6191
                                // make sure there is a subsequent unicode
N
Niels 已提交
6192
                                if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
N
Niels 已提交
6193 6194 6195 6196
                                {
                                    throw std::invalid_argument("missing low surrogate");
                                }

N
Niels 已提交
6197
                                // get code yyyy from uxxxx\uyyyy
N
Niels 已提交
6198 6199
                                auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
                                                               (i + 7), 4).c_str(), nullptr, 16);
N
Niels 已提交
6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210
                                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 已提交
6211 6212 6213 6214 6215 6216 6217 6218
                            break;
                        }
                    }
                }
                else
                {
                    // all other characters are just copied to the end of the
                    // string
N
Niels 已提交
6219
                    result.append(1, static_cast<typename string_t::value_type>(*i));
N
Niels 已提交
6220 6221 6222 6223
                }
            }

            return result;
N
Niels 已提交
6224 6225
        }

N
Niels 已提交
6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240
        /*!
        @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 已提交
6241
        @throw std::range_error if passed value is out of range
N
Niels 已提交
6242
        */
N
Niels 已提交
6243
        long double get_number() const
N
Niels 已提交
6244
        {
N
Niels 已提交
6245 6246 6247 6248 6249 6250 6251 6252
            // conversion
            typename string_t::value_type* endptr;
            const auto float_val = std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start),
                                                &endptr);

            // return float_val if the whole number was translated and NAN
            // otherwise
            return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN;
N
Niels 已提交
6253 6254 6255
        }

      private:
6256 6257
        /// optional input stream
        std::istream* m_stream;
N
fixes  
Niels 已提交
6258
        /// the buffer
6259 6260
        string_t m_buffer;
        /// the buffer pointer
N
Niels 已提交
6261
        const lexer_char_t* m_content = nullptr;
6262
        /// pointer to the beginning of the current symbol
N
Niels 已提交
6263
        const lexer_char_t* m_start = nullptr;
6264 6265
        /// pointer for backtracking information
        const lexer_char_t* m_marker = nullptr;
N
fixes  
Niels 已提交
6266
        /// pointer to the current symbol
N
Niels 已提交
6267
        const lexer_char_t* m_cursor = nullptr;
N
fixes  
Niels 已提交
6268
        /// pointer to the end of the buffer
N
Niels 已提交
6269
        const lexer_char_t* m_limit = nullptr;
N
Niels 已提交
6270 6271
    };

N
Niels 已提交
6272 6273 6274
    /*!
    @brief syntax analysis
    */
N
Niels 已提交
6275 6276
    class parser
    {
N
Niels 已提交
6277 6278
      public:
        /// constructor for strings
N
Niels 已提交
6279 6280
        parser(const string_t& s, parser_callback_t cb = nullptr)
            : callback(cb), m_lexer(s)
N
Niels 已提交
6281 6282 6283 6284 6285 6286
        {
            // read first token
            get_token();
        }

        /// a parser reading from an input stream
N
Niels 已提交
6287 6288
        parser(std::istream& _is, parser_callback_t cb = nullptr)
            : callback(cb), m_lexer(&_is)
N
Niels 已提交
6289 6290 6291 6292 6293
        {
            // read first token
            get_token();
        }

N
Niels 已提交
6294
        /// public parser interface
6295
        basic_json parse()
N
Niels 已提交
6296
        {
N
Niels 已提交
6297
            basic_json result = parse_internal(true);
N
Niels 已提交
6298 6299 6300

            expect(lexer::token_type::end_of_input);

N
Niels 已提交
6301 6302 6303
            // 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 已提交
6304 6305 6306 6307
        }

      private:
        /// the actual parser
6308
        basic_json parse_internal(bool keep)
N
Niels 已提交
6309
        {
N
Niels 已提交
6310 6311
            auto result = basic_json(value_t::discarded);

N
Niels 已提交
6312 6313
            switch (last_token)
            {
N
Niels 已提交
6314
                case (lexer::token_type::begin_object):
N
Niels 已提交
6315
                {
6316
                    if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result))))
N
Niels 已提交
6317 6318
                    {
                        // explicitly set result to object to cope with {}
N
Niels 已提交
6319 6320
                        result.m_type = value_t::object;
                        result.m_value = json_value(value_t::object);
N
Niels 已提交
6321
                    }
N
Niels 已提交
6322 6323 6324 6325 6326

                    // read next token
                    get_token();

                    // closing } -> we are done
N
Niels 已提交
6327
                    if (last_token == lexer::token_type::end_object)
N
Niels 已提交
6328
                    {
N
Niels 已提交
6329
                        get_token();
6330
                        if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
N
Niels 已提交
6331 6332 6333
                        {
                            result = basic_json(value_t::discarded);
                        }
N
Niels 已提交
6334
                        return result;
N
Niels 已提交
6335 6336
                    }

N
Niels 已提交
6337 6338 6339
                    // no comma is expected here
                    unexpect(lexer::token_type::value_separator);

N
Niels 已提交
6340 6341 6342
                    // otherwise: parse key-value pairs
                    do
                    {
N
Niels 已提交
6343 6344 6345 6346 6347 6348
                        // ugly, but could be fixed with loop reorganization
                        if (last_token == lexer::token_type::value_separator)
                        {
                            get_token();
                        }

N
Niels 已提交
6349
                        // store key
N
Niels 已提交
6350 6351
                        expect(lexer::token_type::value_string);
                        const auto key = m_lexer.get_string();
N
Niels 已提交
6352

N
Niels 已提交
6353 6354 6355
                        bool keep_tag = false;
                        if (keep)
                        {
N
Niels 已提交
6356 6357 6358 6359 6360 6361 6362 6363 6364
                            if (callback)
                            {
                                basic_json k(key);
                                keep_tag = callback(depth, parse_event_t::key, k);
                            }
                            else
                            {
                                keep_tag = true;
                            }
N
Niels 已提交
6365 6366
                        }

N
Niels 已提交
6367 6368
                        // parse separator (:)
                        get_token();
N
Niels 已提交
6369
                        expect(lexer::token_type::name_separator);
N
Niels 已提交
6370

6371
                        // parse and add value
N
Niels 已提交
6372
                        get_token();
N
Niels 已提交
6373 6374 6375
                        auto value = parse_internal(keep);
                        if (keep and keep_tag and not value.is_discarded())
                        {
6376
                            result[key] = std::move(value);
N
Niels 已提交
6377
                        }
N
Niels 已提交
6378
                    }
N
Niels 已提交
6379
                    while (last_token == lexer::token_type::value_separator);
N
Niels 已提交
6380 6381

                    // closing }
N
Niels 已提交
6382
                    expect(lexer::token_type::end_object);
N
Niels 已提交
6383
                    get_token();
6384
                    if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
N
Niels 已提交
6385 6386 6387
                    {
                        result = basic_json(value_t::discarded);
                    }
N
Niels 已提交
6388 6389

                    return result;
N
Niels 已提交
6390 6391
                }

N
Niels 已提交
6392
                case (lexer::token_type::begin_array):
N
Niels 已提交
6393
                {
6394
                    if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
N
Niels 已提交
6395 6396
                    {
                        // explicitly set result to object to cope with []
N
Niels 已提交
6397 6398
                        result.m_type = value_t::array;
                        result.m_value = json_value(value_t::array);
N
Niels 已提交
6399
                    }
N
Niels 已提交
6400 6401 6402 6403 6404

                    // read next token
                    get_token();

                    // closing ] -> we are done
N
Niels 已提交
6405
                    if (last_token == lexer::token_type::end_array)
N
Niels 已提交
6406
                    {
N
Niels 已提交
6407
                        get_token();
6408
                        if (callback and not callback(--depth, parse_event_t::array_end, result))
N
Niels 已提交
6409 6410 6411
                        {
                            result = basic_json(value_t::discarded);
                        }
N
Niels 已提交
6412
                        return result;
N
Niels 已提交
6413 6414
                    }

N
Niels 已提交
6415 6416 6417
                    // no comma is expected here
                    unexpect(lexer::token_type::value_separator);

N
Niels 已提交
6418 6419 6420
                    // otherwise: parse values
                    do
                    {
N
Niels 已提交
6421 6422 6423 6424 6425
                        // ugly, but could be fixed with loop reorganization
                        if (last_token == lexer::token_type::value_separator)
                        {
                            get_token();
                        }
N
Niels 已提交
6426

N
Niels 已提交
6427 6428 6429 6430
                        // parse value
                        auto value = parse_internal(keep);
                        if (keep and not value.is_discarded())
                        {
6431
                            result.push_back(std::move(value));
N
Niels 已提交
6432
                        }
N
Niels 已提交
6433
                    }
N
Niels 已提交
6434
                    while (last_token == lexer::token_type::value_separator);
N
Niels 已提交
6435 6436

                    // closing ]
N
Niels 已提交
6437
                    expect(lexer::token_type::end_array);
N
Niels 已提交
6438
                    get_token();
6439
                    if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
N
Niels 已提交
6440 6441 6442
                    {
                        result = basic_json(value_t::discarded);
                    }
N
Niels 已提交
6443 6444

                    return result;
N
Niels 已提交
6445 6446
                }

N
Niels 已提交
6447
                case (lexer::token_type::literal_null):
N
Niels 已提交
6448
                {
N
Niels 已提交
6449
                    get_token();
N
Niels 已提交
6450
                    result.m_type = value_t::null;
N
Niels 已提交
6451
                    break;
N
Niels 已提交
6452 6453
                }

N
Niels 已提交
6454
                case (lexer::token_type::value_string):
N
Niels 已提交
6455
                {
N
Niels 已提交
6456
                    const auto s = m_lexer.get_string();
N
Niels 已提交
6457
                    get_token();
N
Niels 已提交
6458 6459
                    result = basic_json(s);
                    break;
N
Niels 已提交
6460 6461
                }

N
Niels 已提交
6462
                case (lexer::token_type::literal_true):
N
Niels 已提交
6463
                {
N
Niels 已提交
6464
                    get_token();
N
Niels 已提交
6465 6466
                    result.m_type = value_t::boolean;
                    result.m_value = true;
N
Niels 已提交
6467
                    break;
N
Niels 已提交
6468 6469
                }

N
Niels 已提交
6470
                case (lexer::token_type::literal_false):
N
Niels 已提交
6471
                {
N
Niels 已提交
6472
                    get_token();
N
Niels 已提交
6473 6474
                    result.m_type = value_t::boolean;
                    result.m_value = false;
N
Niels 已提交
6475
                    break;
N
Niels 已提交
6476 6477
                }

N
Niels 已提交
6478
                case (lexer::token_type::value_number):
N
Niels 已提交
6479
                {
N
Niels 已提交
6480
                    auto float_val = m_lexer.get_number();
N
Niels 已提交
6481

N
Niels 已提交
6482 6483
                    // NAN is returned if token could not be translated
                    // completely
N
Niels 已提交
6484
                    if (std::isnan(float_val))
N
Niels 已提交
6485 6486
                    {
                        throw std::invalid_argument(std::string("parse error - ") +
N
Niels 已提交
6487
                                                    m_lexer.get_token() + " is not a number");
N
Niels 已提交
6488 6489
                    }

N
Niels 已提交
6490 6491
                    get_token();

N
Niels 已提交
6492
                    // check if conversion loses precision
N
Niels 已提交
6493
                    const auto int_val = static_cast<number_integer_t>(float_val);
N
Niels 已提交
6494
                    if (approx(float_val, static_cast<long double>(int_val)))
N
Niels 已提交
6495 6496
                    {
                        // we basic_json not lose precision -> return int
N
Niels 已提交
6497 6498
                        result.m_type = value_t::number_integer;
                        result.m_value = int_val;
N
Niels 已提交
6499 6500 6501 6502
                    }
                    else
                    {
                        // we would lose precision -> returnfloat
N
Niels 已提交
6503
                        result.m_type = value_t::number_float;
N
Niels 已提交
6504
                        result.m_value = static_cast<number_float_t>(float_val);
N
Niels 已提交
6505
                    }
N
Niels 已提交
6506
                    break;
N
Niels 已提交
6507 6508 6509 6510
                }

                default:
                {
N
Niels 已提交
6511 6512
                    // the last token was unexpected
                    unexpect(last_token);
N
Niels 已提交
6513 6514
                }
            }
N
Niels 已提交
6515

6516
            if (keep and callback and not callback(depth, parse_event_t::value, result))
N
Niels 已提交
6517 6518 6519 6520
            {
                result = basic_json(value_t::discarded);
            }
            return result;
N
Niels 已提交
6521 6522
        }

N
Niels 已提交
6523
        /// get next token from lexer
6524
        typename lexer::token_type get_token()
N
Niels 已提交
6525
        {
N
Niels 已提交
6526 6527
            last_token = m_lexer.scan();
            return last_token;
N
Niels 已提交
6528 6529
        }

6530
        void expect(typename lexer::token_type t) const
N
Niels 已提交
6531 6532 6533 6534
        {
            if (t != last_token)
            {
                std::string error_msg = "parse error - unexpected \'";
N
Niels 已提交
6535
                error_msg += m_lexer.get_token();
N
cleanup  
Niels 已提交
6536 6537
                error_msg += "\' (" + lexer::token_type_name(last_token);
                error_msg += "); expected " + lexer::token_type_name(t);
N
Niels 已提交
6538 6539 6540 6541
                throw std::invalid_argument(error_msg);
            }
        }

6542
        void unexpect(typename lexer::token_type t) const
N
Niels 已提交
6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553
        {
            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 已提交
6554
      private:
N
Niels 已提交
6555
        /// current level of recursion
N
Niels 已提交
6556 6557 6558
        int depth = 0;
        /// callback function
        parser_callback_t callback;
N
Niels 已提交
6559
        /// the type of the last read token
N
Niels 已提交
6560
        typename lexer::token_type last_token = lexer::token_type::uninitialized;
N
Niels 已提交
6561
        /// the lexer
N
Niels 已提交
6562
        lexer m_lexer;
N
Niels 已提交
6563
    };
N
cleanup  
Niels 已提交
6564 6565 6566 6567 6568 6569 6570
};


/////////////
// presets //
/////////////

N
Niels 已提交
6571 6572 6573 6574 6575 6576
/*!
@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 已提交
6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587
using json = basic_json<>;
}


/////////////////////////
// nonmember functions //
/////////////////////////

// specialization of std::swap, and std::hash
namespace std
{
N
Niels 已提交
6588 6589 6590
/*!
@brief exchanges the values of two JSON objects
*/
N
cleanup  
Niels 已提交
6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604
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 已提交
6605
    /// return a hash value for a JSON object
6606
    std::size_t operator()(const nlohmann::json& j) const
N
cleanup  
Niels 已提交
6607 6608
    {
        // a naive hashing via the string representation
N
Niels 已提交
6609 6610
        const auto& h = hash<nlohmann::json::string_t>();
        return h(j.dump());
N
cleanup  
Niels 已提交
6611 6612 6613 6614
    }
};
}

N
Niels 已提交
6615
/*!
N
Niels 已提交
6616 6617
@brief user-defined string literal for JSON values

N
Niels 已提交
6618 6619 6620 6621
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 已提交
6622
@param[in] s  a string representation of a JSON object
N
Niels 已提交
6623 6624
@return a JSON object
*/
N
Niels 已提交
6625
inline nlohmann::json operator "" _json(const char* s, std::size_t)
N
Niels 已提交
6626
{
N
Niels 已提交
6627 6628
    return nlohmann::json::parse(reinterpret_cast<nlohmann::json::string_t::value_type*>
                                 (const_cast<char*>(s)));
N
Niels 已提交
6629 6630
}

N
cleanup  
Niels 已提交
6631
#endif