json.hpp.re2c 233.7 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
@copyright The code is licensed under the [MIT
N
Niels 已提交
10 11
  License](http://opensource.org/licenses/MIT):
  <br>
N
Niels 已提交
12
  Copyright &copy; 2013-2016 Niels Lohmann.
N
Niels 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
  <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.
N
Niels 已提交
31 32

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

N
Niels 已提交
35
@version 1.0.0
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 <cassert>
N
Niels 已提交
44
#include <ciso646>
N
Niels 已提交
45
#include <cmath>
N
Niels 已提交
46
#include <cstddef>
N
Niels 已提交
47
#include <cstdio>
N
Niels 已提交
48
#include <cstdlib>
N
cleanup  
Niels 已提交
49 50
#include <functional>
#include <initializer_list>
N
Niels 已提交
51
#include <iomanip>
N
cleanup  
Niels 已提交
52 53 54 55 56
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
N
Niels 已提交
57
#include <sstream>
N
Niels 已提交
58
#include <stdexcept>
N
cleanup  
Niels 已提交
59 60 61 62 63
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

N
Niels 已提交
64 65 66 67 68 69 70
// enable ssize_t on MinGW
#ifdef __GNUC__
    #ifdef __MINGW32__
        #include <sys/types.h>
    #endif
#endif

71 72 73 74 75 76
// disable float-equal warnings on GCC/clang
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wfloat-equal"
#endif

N
Niels 已提交
77 78
// enable ssize_t for MSVC
#ifdef _MSC_VER
N
Niels 已提交
79
    #include <basetsd.h>
N
Niels 已提交
80 81 82
    using ssize_t = SSIZE_T;
#endif

N
cleanup  
Niels 已提交
83
/*!
N
Niels 已提交
84
@brief namespace for Niels Lohmann
N
cleanup  
Niels 已提交
85
@see https://github.com/nlohmann
N
Niels 已提交
86
@since version 1.0.0
N
cleanup  
Niels 已提交
87 88 89 90
*/
namespace nlohmann
{

N
Niels 已提交
91

92 93
/*!
@brief unnamed namespace with internal helper functions
N
Niels 已提交
94
@since version 1.0.0
95 96
*/
namespace
N
Niels 已提交
97
{
98 99 100 101
/*!
@brief Helper to determine whether there's a key_type for T.
@sa http://stackoverflow.com/a/7728728/266378
*/
N
Niels 已提交
102
template<typename T>
N
Niels 已提交
103
struct has_mapped_type
N
Niels 已提交
104 105
{
  private:
N
Niels 已提交
106
    template<typename C> static char test(typename C::mapped_type*);
N
Niels 已提交
107
    template<typename C> static char (&test(...))[2];
N
Niels 已提交
108
  public:
N
Niels 已提交
109
    static constexpr bool value = sizeof(test<T>(0)) == 1;
N
Niels 已提交
110
};
111

N
Niels 已提交
112
}
N
Niels 已提交
113

N
cleanup  
Niels 已提交
114
/*!
N
Niels 已提交
115
@brief a class to store JSON values
N
cleanup  
Niels 已提交
116

N
Niels 已提交
117 118 119 120 121 122 123 124 125 126 127 128 129 130
@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 已提交
131

N
Niels 已提交
132 133
@requirement The class satisfies the following concept requirements:
- Basic
N
Niels 已提交
134 135 136 137 138
 - [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):
N
Niels 已提交
139
   A JSON value can be copy-constructed from an lvalue expression.
N
Niels 已提交
140 141 142 143 144 145
 - [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 已提交
146
- Layout
N
Niels 已提交
147 148 149 150 151
 - [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 已提交
152
- Library-wide
N
Niels 已提交
153 154 155 156 157 158 159 160 161 162 163 164
 - [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 已提交
165
- Container
N
Niels 已提交
166 167 168 169 170
 - [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 已提交
171

N
Niels 已提交
172
@internal
N
Niels 已提交
173
@note ObjectType trick from http://stackoverflow.com/a/9860911
N
Niels 已提交
174
@endinternal
N
Niels 已提交
175

N
Niels 已提交
176
@see RFC 7159 <http://rfc7159.net/rfc7159>
N
Niels 已提交
177

N
Niels 已提交
178
@since version 1.0.0
N
Niels 已提交
179 180

@nosubgrouping
N
cleanup  
Niels 已提交
181 182 183 184 185 186 187
*/
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 已提交
188
    class NumberFloatType = double,
N
Niels 已提交
189
    template<typename U> class AllocatorType = std::allocator
N
cleanup  
Niels 已提交
190 191 192
    >
class basic_json
{
193 194
  private:
    /// workaround type for MSVC
N
Niels 已提交
195 196 197 198 199 200 201
    using basic_json_t = basic_json<ObjectType,
          ArrayType,
          StringType,
          BooleanType,
          NumberIntegerType,
          NumberFloatType,
          AllocatorType>;
202 203 204

  public:

N
cleanup  
Niels 已提交
205 206 207 208
    /////////////////////
    // container types //
    /////////////////////

N
Niels 已提交
209 210 211
    /// @name container types
    /// @{

N
Niels 已提交
212
    /// the type of elements in a basic_json container
N
cleanup  
Niels 已提交
213
    using value_type = basic_json;
N
Niels 已提交
214

N
Niels 已提交
215
    /// the type of an element reference
N
Niels 已提交
216
    using reference = value_type&;
N
Niels 已提交
217

N
Niels 已提交
218
    /// the type of an element const reference
N
Niels 已提交
219
    using const_reference = const value_type&;
N
Niels 已提交
220

N
Niels 已提交
221
    /// a type to represent differences between iterators
N
Niels 已提交
222 223
    using difference_type = std::ptrdiff_t;

N
Niels 已提交
224
    /// a type to represent container sizes
N
Niels 已提交
225 226 227
    using size_type = std::size_t;

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

N
cleanup  
Niels 已提交
230
    /// the type of an element pointer
N
Niels 已提交
231
    using pointer = typename std::allocator_traits<allocator_type>::pointer;
N
cleanup  
Niels 已提交
232
    /// the type of an element const pointer
N
Niels 已提交
233
    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
N
Niels 已提交
234

N
Niels 已提交
235 236 237
    // forward declaration
    template<typename Base> class json_reverse_iterator;

N
Niels 已提交
238 239 240 241 242
    /// 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 已提交
243
    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
N
Niels 已提交
244
    /// a const reverse iterator for a basic_json container
N
Niels 已提交
245
    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
N
Niels 已提交
246

N
Niels 已提交
247 248 249
    /// @}


N
Niels 已提交
250 251 252
    /*!
    @brief returns the allocator associated with the container
    */
253
    static allocator_type get_allocator()
N
Niels 已提交
254 255 256 257 258
    {
        return allocator_type();
    }


N
cleanup  
Niels 已提交
259 260 261 262
    ///////////////////////////
    // JSON value data types //
    ///////////////////////////

N
Niels 已提交
263 264 265
    /// @name JSON value data types
    /// @{

N
Niels 已提交
266 267 268 269 270 271 272 273
    /*!
    @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.

N
Niels 已提交
274 275 276 277 278 279 280 281 282 283
    To store objects in C++, a type is defined by the template parameters
    described below.

    @tparam ObjectType  the container to store objects (e.g., `std::map` or
    `std::unordered_map`)
    @tparam StringType the type of the keys or names (e.g., `std::string`). The
    comparison function `std::less<StringType>` is used to order elements
    inside the container.
    @tparam AllocatorType the allocator to use for objects (e.g.,
    `std::allocator`)
N
Niels 已提交
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 322 323 324 325 326 327 328 329 330 331 332

    #### 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

333
    Objects are stored as pointers in a @ref basic_json type. That is, for any
N
Niels 已提交
334 335
    access to object values, a pointer of type `object_t*` must be dereferenced.

336 337
    @sa @ref array_t -- type for an array value

N
Niels 已提交
338
    @since version 1.0.0
N
Niels 已提交
339
    */
N
Niels 已提交
340 341 342 343 344
    using object_t = ObjectType<StringType,
          basic_json,
          std::less<StringType>,
          AllocatorType<std::pair<const StringType,
          basic_json>>>;
N
Niels 已提交
345 346 347 348 349 350 351

    /*!
    @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.

N
Niels 已提交
352 353 354 355 356 357
    To store objects in C++, a type is defined by the template parameters
    explained below.

    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or
    `std::list`)
    @tparam AllocatorType  allocator to use for arrays (e.g., `std::allocator`)
N
Niels 已提交
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382

    #### 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

383
    Arrays are stored as pointers in a @ref basic_json type. That is, for any
N
Niels 已提交
384
    access to array values, a pointer of type `array_t*` must be dereferenced.
385 386 387

    @sa @ref object_t -- type for an object value

N
Niels 已提交
388
    @since version 1.0.0
N
Niels 已提交
389
    */
N
Niels 已提交
390
    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
N
Niels 已提交
391 392 393 394 395 396 397

    /*!
    @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.

N
Niels 已提交
398 399 400
    To store objects in C++, a type is defined by the template parameter
    described below. Unicode values are split by the JSON class into byte-sized
    characters during deserialization.
N
Niels 已提交
401

N
Niels 已提交
402 403
    @tparam StringType  the container to store strings (e.g., `std::string`).
    Note this container is used for keys/names in objects, see @ref object_t.
N
Niels 已提交
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430

    #### 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

431 432
    String values are stored as pointers in a @ref basic_json type. That is,
    for any access to string values, a pointer of type `string_t*` must be
N
Niels 已提交
433
    dereferenced.
434

N
Niels 已提交
435
    @since version 1.0.0
N
Niels 已提交
436
    */
N
cleanup  
Niels 已提交
437
    using string_t = StringType;
N
Niels 已提交
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

    /*!
    @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

459 460
    Boolean values are stored directly inside a @ref basic_json type.

N
Niels 已提交
461
    @since version 1.0.0
N
Niels 已提交
462
    */
N
cleanup  
Niels 已提交
463
    using boolean_t = BooleanType;
N
Niels 已提交
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524

    /*!
    @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

525 526 527 528
    Integer number values are stored directly inside a @ref basic_json type.

    @sa @ref number_float_t -- type for number values (floating-point)

N
Niels 已提交
529
    @since version 1.0.0
N
Niels 已提交
530
    */
N
cleanup  
Niels 已提交
531
    using number_integer_t = NumberIntegerType;
N
Niels 已提交
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 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583

    /*!
    @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
N
Niels 已提交
584
    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
N
Niels 已提交
585 586 587 588
    will be stored as NaN internally and be serialized to `null`.

    #### Storage

589 590 591 592 593
    Floating-point number values are stored directly inside a @ref basic_json
    type.

    @sa @ref number_integer_t -- type for number values (integer)

N
Niels 已提交
594
    @since version 1.0.0
N
Niels 已提交
595
    */
N
cleanup  
Niels 已提交
596 597
    using number_float_t = NumberFloatType;

N
Niels 已提交
598 599
    /// @}

N
cleanup  
Niels 已提交
600

N
Niels 已提交
601 602 603
    ///////////////////////////
    // JSON type enumeration //
    ///////////////////////////
N
Niels 已提交
604

N
Niels 已提交
605
    /*!
N
Niels 已提交
606
    @brief the JSON type enumeration
N
Niels 已提交
607

N
Niels 已提交
608
    This enumeration collects the different JSON types. It is internally used
609 610 611 612
    to distinguish the stored values, and the functions @ref is_null(), @ref
    is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref
    is_number(), and @ref is_discarded() rely on it.

N
Niels 已提交
613
    @since version 1.0.0
N
Niels 已提交
614
    */
N
Niels 已提交
615 616 617 618 619 620 621 622 623
    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 已提交
624
        discarded       ///< discarded by the the parser callback function
N
Niels 已提交
625 626
    };

N
Niels 已提交
627

N
Niels 已提交
628
  private:
629 630
    /// helper for exception-safe object creation
    template<typename T, typename... Args>
N
Cleanup  
Niels 已提交
631
    static T* create(Args&& ... args)
632 633
    {
        AllocatorType<T> alloc;
N
cleanup  
Niels 已提交
634
        auto deleter = [&](T * object)
N
Cleanup  
Niels 已提交
635 636 637
        {
            alloc.deallocate(object, 1);
        };
638 639 640 641 642
        std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
        alloc.construct(object.get(), std::forward<Args>(args)...);
        return object.release();
    }

N
cleanup  
Niels 已提交
643 644 645 646
    ////////////////////////
    // JSON value storage //
    ////////////////////////

647 648 649 650 651
    /*!
    @brief a JSON value

    The actual storage for a JSON value of the @ref basic_json class.

N
Niels 已提交
652
    @since version 1.0.0
653
    */
N
cleanup  
Niels 已提交
654 655 656 657 658 659 660 661
    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 已提交
662
        /// boolean
N
cleanup  
Niels 已提交
663 664 665
        boolean_t boolean;
        /// number (integer)
        number_integer_t number_integer;
N
Niels 已提交
666
        /// number (floating-point)
N
cleanup  
Niels 已提交
667 668 669
        number_float_t number_float;

        /// default constructor (for null values)
670
        json_value() noexcept = default;
N
cleanup  
Niels 已提交
671
        /// constructor for booleans
672
        json_value(boolean_t v) noexcept : boolean(v) {}
N
cleanup  
Niels 已提交
673
        /// constructor for numbers (integer)
674
        json_value(number_integer_t v) noexcept : number_integer(v) {}
N
Niels 已提交
675
        /// constructor for numbers (floating-point)
676
        json_value(number_float_t v) noexcept : number_float(v) {}
N
Niels 已提交
677
        /// constructor for empty values of a given type
678
        json_value(value_t t)
N
Niels 已提交
679 680 681
        {
            switch (t)
            {
682
                case value_t::object:
N
Niels 已提交
683
                {
684
                    object = create<object_t>();
N
Niels 已提交
685 686
                    break;
                }
N
cleanup  
Niels 已提交
687

688
                case value_t::array:
N
Niels 已提交
689
                {
690
                    array = create<array_t>();
N
Niels 已提交
691 692
                    break;
                }
N
cleanup  
Niels 已提交
693

694
                case value_t::string:
N
Niels 已提交
695
                {
696
                    string = create<string_t>("");
N
Niels 已提交
697 698
                    break;
                }
N
cleanup  
Niels 已提交
699

700
                case value_t::boolean:
N
Niels 已提交
701 702 703 704 705
                {
                    boolean = boolean_t(false);
                    break;
                }

706
                case value_t::number_integer:
N
Niels 已提交
707 708 709 710 711
                {
                    number_integer = number_integer_t(0);
                    break;
                }

712
                case value_t::number_float:
N
Niels 已提交
713 714 715 716
                {
                    number_float = number_float_t(0.0);
                    break;
                }
717 718 719 720 721

                default:
                {
                    break;
                }
N
Niels 已提交
722 723
            }
        }
N
Niels 已提交
724 725

        /// constructor for strings
726
        json_value(const string_t& value)
N
Niels 已提交
727
        {
728
            string = create<string_t>(value);
N
Niels 已提交
729 730 731
        }

        /// constructor for objects
732
        json_value(const object_t& value)
N
Niels 已提交
733
        {
734
            object = create<object_t>(value);
N
Niels 已提交
735 736 737
        }

        /// constructor for arrays
738
        json_value(const array_t& value)
N
Niels 已提交
739
        {
740
            array = create<array_t>(value);
N
Niels 已提交
741
        }
N
cleanup  
Niels 已提交
742 743
    };

N
Niels 已提交
744 745

  public:
N
Niels 已提交
746 747 748 749
    //////////////////////////
    // JSON parser callback //
    //////////////////////////

N
Niels 已提交
750 751 752 753 754
    /*!
    @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.
755

N
Niels 已提交
756
    @since version 1.0.0
N
Niels 已提交
757
    */
N
Niels 已提交
758 759
    enum class parse_event_t : uint8_t
    {
N
Niels 已提交
760 761 762 763 764 765 766 767 768 769 770 771
        /// 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 已提交
772 773
    };

N
Niels 已提交
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
    /*!
    @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

N
Niels 已提交
798 799
    Discarding a value (i.e., returning `false`) has different effects
    depending on the context in which function was called:
N
Niels 已提交
800 801 802 803 804 805

    - 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.

N
Niels 已提交
806
    @param[in] depth  the depth of the recursion during parsing
N
Niels 已提交
807

N
Niels 已提交
808
    @param[in] event  an event of type parse_event_t indicating the context in
N
Niels 已提交
809 810 811 812 813 814 815 816 817 818 819
    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
820

N
Niels 已提交
821
    @since version 1.0.0
N
Niels 已提交
822
    */
823
    using parser_callback_t = std::function<bool(int depth, parse_event_t event, basic_json& parsed)>;
N
Niels 已提交
824

N
cleanup  
Niels 已提交
825 826 827 828 829

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

N
Niels 已提交
830 831 832
    /// @name constructors and destructors
    /// @{

N
Niels 已提交
833 834 835
    /*!
    @brief create an empty value with a given type

N
Niels 已提交
836 837 838 839 840
    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 已提交
841 842 843 844 845 846
    null        | `null`
    boolean     | `false`
    string      | `""`
    number      | `0`
    object      | `{}`
    array       | `[]`
N
Niels 已提交
847

848
    @param[in] value_type  the type of the value to create
N
Niels 已提交
849 850 851

    @complexity Constant.

N
Niels 已提交
852
    @throw std::bad_alloc if allocation for object, array, or string value
N
Niels 已提交
853
    fails
N
Niels 已提交
854 855 856

    @liveexample{The following code shows the constructor for different @ref
    value_t values,basic_json__value_t}
857 858 859 860 861 862

    @sa @ref basic_json(std::nullptr_t) -- create a `null` value
    @sa @ref basic_json(boolean_t value) -- create a boolean value
    @sa @ref basic_json(const string_t&) -- create a string value
    @sa @ref basic_json(const object_t&) -- create a object value
    @sa @ref basic_json(const array_t&) -- create a array value
N
Niels 已提交
863 864 865 866
    @sa @ref basic_json(const number_float_t) -- create a number
    (floating-point) value
    @sa @ref basic_json(const number_integer_t) -- create a number (integer)
    value
867

N
Niels 已提交
868
    @since version 1.0.0
N
Niels 已提交
869
    */
870 871
    basic_json(const value_t value_type)
        : m_type(value_type), m_value(value_type)
N
Niels 已提交
872
    {}
N
cleanup  
Niels 已提交
873

N
Niels 已提交
874 875
    /*!
    @brief create a null object (implicitly)
N
Niels 已提交
876 877 878 879 880 881 882 883 884 885 886 887 888

    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}

889 890
    @sa @ref basic_json(std::nullptr_t) -- create a `null` value

N
Niels 已提交
891
    @since version 1.0.0
N
Niels 已提交
892
    */
893
    basic_json() noexcept = default;
N
cleanup  
Niels 已提交
894

N
Niels 已提交
895 896 897 898 899 900
    /*!
    @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.
N
Niels 已提交
901
    The passed null pointer itself is not read -- it is only used to choose the
N
Niels 已提交
902 903 904 905 906 907 908
    right constructor.

    @complexity Constant.

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

909 910 911
    @sa @ref basic_json() -- default constructor (implicitly creating a `null`
    value)

N
Niels 已提交
912
    @since version 1.0.0
N
Niels 已提交
913
    */
914
    basic_json(std::nullptr_t) noexcept
N
Niels 已提交
915
        : basic_json(value_t::null)
N
cleanup  
Niels 已提交
916 917
    {}

N
Niels 已提交
918 919 920 921 922
    /*!
    @brief create an object (explicit)

    Create an object JSON value with a given content.

923
    @param[in] val  a value for the object
N
Niels 已提交
924

925
    @complexity Linear in the size of the passed @a val.
N
Niels 已提交
926

N
Niels 已提交
927
    @throw std::bad_alloc if allocation for object value fails
N
Niels 已提交
928 929 930 931

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

932 933 934
    @sa @ref basic_json(const CompatibleObjectType&) -- create an object value
    from a compatible STL container

N
Niels 已提交
935
    @since version 1.0.0
N
Niels 已提交
936
    */
937 938
    basic_json(const object_t& val)
        : m_type(value_t::object), m_value(val)
N
Niels 已提交
939
    {}
N
cleanup  
Niels 已提交
940

N
Niels 已提交
941 942 943 944 945 946 947 948 949 950
    /*!
    @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

951
    @param[in] val  a value for the object
N
Niels 已提交
952

953
    @complexity Linear in the size of the passed @a val.
N
Niels 已提交
954

N
Niels 已提交
955
    @throw std::bad_alloc if allocation for object value fails
N
Niels 已提交
956 957 958 959

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

960 961
    @sa @ref basic_json(const object_t&) -- create an object value

N
Niels 已提交
962
    @since version 1.0.0
N
Niels 已提交
963 964
    */
    template <class CompatibleObjectType, typename
N
cleanup  
Niels 已提交
965
              std::enable_if<
N
Niels 已提交
966 967
                  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 已提交
968
              = 0>
969
    basic_json(const CompatibleObjectType& val)
N
Niels 已提交
970 971
        : m_type(value_t::object)
    {
972 973
        using std::begin;
        using std::end;
974
        m_value.object = create<object_t>(begin(val), end(val));
N
Niels 已提交
975
    }
N
cleanup  
Niels 已提交
976

N
Niels 已提交
977 978 979 980 981
    /*!
    @brief create an array (explicit)

    Create an array JSON value with a given content.

982
    @param[in] val  a value for the array
N
Niels 已提交
983

984
    @complexity Linear in the size of the passed @a val.
N
Niels 已提交
985

N
Niels 已提交
986
    @throw std::bad_alloc if allocation for array value fails
N
Niels 已提交
987 988 989 990

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

991 992 993
    @sa @ref basic_json(const CompatibleArrayType&) -- create an array value
    from a compatible STL containers

N
Niels 已提交
994
    @since version 1.0.0
N
Niels 已提交
995
    */
996 997
    basic_json(const array_t& val)
        : m_type(value_t::array), m_value(val)
N
Niels 已提交
998
    {}
N
cleanup  
Niels 已提交
999

N
Niels 已提交
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
    /*!
    @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

1010
    @param[in] val  a value for the array
N
Niels 已提交
1011

1012
    @complexity Linear in the size of the passed @a val.
N
Niels 已提交
1013

N
Niels 已提交
1014
    @throw std::bad_alloc if allocation for array value fails
N
Niels 已提交
1015 1016 1017 1018

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

1019 1020
    @sa @ref basic_json(const array_t&) -- create an array value

N
Niels 已提交
1021
    @since version 1.0.0
N
Niels 已提交
1022 1023
    */
    template <class CompatibleArrayType, typename
N
cleanup  
Niels 已提交
1024
              std::enable_if<
N
Niels 已提交
1025 1026 1027 1028
                  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 已提交
1029 1030 1031
                  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 已提交
1032
              = 0>
1033
    basic_json(const CompatibleArrayType& val)
N
Niels 已提交
1034 1035
        : m_type(value_t::array)
    {
1036 1037
        using std::begin;
        using std::end;
1038
        m_value.array = create<array_t>(begin(val), end(val));
N
Niels 已提交
1039
    }
N
cleanup  
Niels 已提交
1040

N
Niels 已提交
1041 1042 1043 1044 1045
    /*!
    @brief create a string (explicit)

    Create an string JSON value with a given content.

1046
    @param[in] val  a value for the string
N
Niels 已提交
1047

1048
    @complexity Linear in the size of the passed @a val.
N
Niels 已提交
1049

N
Niels 已提交
1050
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
1051 1052 1053 1054

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

1055 1056 1057 1058 1059
    @sa @ref basic_json(const typename string_t::value_type*) -- create a
    string value from a character pointer
    @sa @ref basic_json(const CompatibleStringType&) -- create a string value
    from a compatible string container

N
Niels 已提交
1060
    @since version 1.0.0
N
Niels 已提交
1061
    */
1062 1063
    basic_json(const string_t& val)
        : m_type(value_t::string), m_value(val)
N
Niels 已提交
1064
    {}
N
cleanup  
Niels 已提交
1065

N
Niels 已提交
1066 1067 1068
    /*!
    @brief create a string (explicit)

N
Niels 已提交
1069
    Create a string JSON value with a given content.
N
Niels 已提交
1070

1071
    @param[in] val  a literal value for the string
N
Niels 已提交
1072

1073
    @complexity Linear in the size of the passed @a val.
N
Niels 已提交
1074

N
Niels 已提交
1075
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
1076 1077 1078 1079

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

1080 1081 1082 1083
    @sa @ref basic_json(const string_t&) -- create a string value
    @sa @ref basic_json(const CompatibleStringType&) -- create a string value
    from a compatible string container

N
Niels 已提交
1084
    @since version 1.0.0
N
Niels 已提交
1085
    */
1086 1087
    basic_json(const typename string_t::value_type* val)
        : basic_json(string_t(val))
N
Niels 已提交
1088
    {}
N
cleanup  
Niels 已提交
1089

N
Niels 已提交
1090 1091 1092 1093 1094
    /*!
    @brief create a string (implicit)

    Create a string JSON value with a given content.

1095
    @param[in] val  a value for the string
N
Niels 已提交
1096 1097 1098 1099

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

1100
    @complexity Linear in the size of the passed @a val.
N
Niels 已提交
1101

N
Niels 已提交
1102
    @throw std::bad_alloc if allocation for string value fails
N
Niels 已提交
1103 1104 1105 1106

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

1107 1108 1109 1110
    @sa @ref basic_json(const string_t&) -- create a string value
    @sa @ref basic_json(const typename string_t::value_type*) -- create a
    string value from a character pointer

N
Niels 已提交
1111
    @since version 1.0.0
N
Niels 已提交
1112
    */
N
Niels 已提交
1113
    template <class CompatibleStringType, typename
N
cleanup  
Niels 已提交
1114
              std::enable_if<
N
Niels 已提交
1115
                  std::is_constructible<string_t, CompatibleStringType>::value, int>::type
N
cleanup  
Niels 已提交
1116
              = 0>
1117 1118
    basic_json(const CompatibleStringType& val)
        : basic_json(string_t(val))
N
cleanup  
Niels 已提交
1119 1120
    {}

N
Niels 已提交
1121 1122 1123 1124 1125
    /*!
    @brief create a boolean (explicit)

    Creates a JSON boolean type from a given value.

1126
    @param[in] val  a boolean value to store
N
Niels 已提交
1127 1128 1129 1130 1131

    @complexity Constant.

    @liveexample{The example below demonstrates boolean
    values.,basic_json__boolean_t}
1132

N
Niels 已提交
1133
    @since version 1.0.0
N
Niels 已提交
1134
    */
1135 1136
    basic_json(boolean_t val)
        : m_type(value_t::boolean), m_value(val)
N
cleanup  
Niels 已提交
1137 1138
    {}

N
Niels 已提交
1139 1140 1141
    /*!
    @brief create an integer number (explicit)

N
Niels 已提交
1142
    Create an integer number JSON value with a given content.
N
Niels 已提交
1143 1144 1145 1146

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

1147
    @param[in] val  an integer to create a JSON number from
N
Niels 已提交
1148

N
Niels 已提交
1149 1150 1151 1152 1153 1154
    @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 已提交
1155 1156
    @liveexample{The example below shows the construction of a JSON integer
    number value.,basic_json__number_integer_t}
N
Niels 已提交
1157

1158 1159 1160 1161
    @sa @ref basic_json(const int) -- create a number value (integer)
    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
    value (integer) from a compatible number type

N
Niels 已提交
1162
    @since version 1.0.0
N
Niels 已提交
1163 1164 1165 1166 1167 1168
    */
    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>
1169 1170
    basic_json(const number_integer_t val)
        : m_type(value_t::number_integer), m_value(val)
N
cleanup  
Niels 已提交
1171 1172
    {}

N
Niels 已提交
1173
    /*!
N
Niels 已提交
1174 1175
    @brief create an integer number from an enum type (explicit)

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

1178
    @param[in] val  an integer to create a JSON number from
N
Niels 已提交
1179

N
Niels 已提交
1180 1181 1182 1183 1184 1185 1186 1187 1188
    @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 已提交
1189
    number value from an anonymous enum.,basic_json__const_int}
N
Niels 已提交
1190

1191 1192 1193 1194 1195
    @sa @ref basic_json(const number_integer_t) -- create a number value
    (integer)
    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
    value (integer) from a compatible number type

N
Niels 已提交
1196
    @since version 1.0.0
N
Niels 已提交
1197
    */
1198
    basic_json(const int val)
N
Niels 已提交
1199
        : m_type(value_t::number_integer),
1200
          m_value(static_cast<number_integer_t>(val))
N
Niels 已提交
1201 1202
    {}

N
Niels 已提交
1203 1204 1205
    /*!
    @brief create an integer number (implicit)

N
Niels 已提交
1206
    Create an integer number JSON value with a given content. This constructor
N
Niels 已提交
1207 1208 1209 1210 1211 1212 1213
    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.

1214
    @param[in] val  an integer to create a JSON number from
N
Niels 已提交
1215 1216 1217 1218 1219 1220 1221

    @complexity Constant.

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

1222 1223 1224 1225
    @sa @ref basic_json(const number_integer_t) -- create a number value
    (integer)
    @sa @ref basic_json(const int) -- create a number value (integer)

N
Niels 已提交
1226
    @since version 1.0.0
N
Niels 已提交
1227 1228
    */
    template<typename CompatibleNumberIntegerType, typename
N
cleanup  
Niels 已提交
1229
             std::enable_if<
N
Niels 已提交
1230 1231
                 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
N
cleanup  
Niels 已提交
1232
             = 0>
1233
    basic_json(const CompatibleNumberIntegerType val) noexcept
N
Niels 已提交
1234
        : m_type(value_t::number_integer),
1235
          m_value(static_cast<number_integer_t>(val))
N
cleanup  
Niels 已提交
1236 1237
    {}

N
Niels 已提交
1238 1239 1240 1241 1242
    /*!
    @brief create a floating-point number (explicit)

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

1243
    @param[in] val  a floating-point value to create a JSON number from
N
Niels 已提交
1244 1245 1246 1247 1248

    @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.
1249
    In case the parameter @a val is not a number, a JSON null value is
N
Niels 已提交
1250 1251
    created instead.

N
Niels 已提交
1252
    @complexity Constant.
N
Niels 已提交
1253 1254 1255

    @liveexample{The following example creates several floating-point
    values.,basic_json__number_float_t}
1256 1257 1258 1259

    @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number
    value (floating-point) from a compatible number type

N
Niels 已提交
1260
    @since version 1.0.0
N
Niels 已提交
1261
    */
1262 1263
    basic_json(const number_float_t val)
        : m_type(value_t::number_float), m_value(val)
N
Niels 已提交
1264 1265
    {
        // replace infinity and NAN by null
1266
        if (not std::isfinite(val))
N
Niels 已提交
1267 1268 1269 1270 1271
        {
            m_type = value_t::null;
            m_value = json_value();
        }
    }
N
cleanup  
Niels 已提交
1272

N
Niels 已提交
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
    /*!
    @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.

1283
    @param[in] val  a floating-point to create a JSON number from
N
Niels 已提交
1284 1285 1286 1287 1288

    @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.
1289
    In case the parameter @a val is not a number, a JSON null value is
N
Niels 已提交
1290 1291 1292 1293 1294 1295 1296 1297
    created instead.

    @complexity Constant.

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

1298 1299 1300
    @sa @ref basic_json(const number_float_t) -- create a number value
    (floating-point)

N
Niels 已提交
1301
    @since version 1.0.0
N
Niels 已提交
1302
    */
N
Niels 已提交
1303
    template<typename CompatibleNumberFloatType, typename = typename
N
cleanup  
Niels 已提交
1304
             std::enable_if<
N
Niels 已提交
1305 1306
                 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
                 std::is_floating_point<CompatibleNumberFloatType>::value>::type
N
cleanup  
Niels 已提交
1307
             >
1308 1309
    basic_json(const CompatibleNumberFloatType val) noexcept
        : basic_json(number_float_t(val))
N
Niels 已提交
1310
    {}
N
cleanup  
Niels 已提交
1311

N
Niels 已提交
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
    /*!
    @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
N
Niels 已提交
1327
    JSON values. The rationale is as follows:
N
Niels 已提交
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337

    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 已提交
1338 1339
    With the rules described above, the following JSON values cannot be
    expressed by an initializer list:
N
Niels 已提交
1340

N
Niels 已提交
1341 1342 1343 1344 1345
    - 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 已提交
1346 1347 1348 1349 1350

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

N
Niels 已提交
1353 1354 1355
    @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 已提交
1356 1357
    used by the functions @ref array(std::initializer_list<basic_json>) and
    @ref object(std::initializer_list<basic_json>).
N
Niels 已提交
1358

N
Niels 已提交
1359
    @param[in] manual_type internal parameter; when @a type_deduction is set to
N
Niels 已提交
1360 1361 1362 1363 1364 1365
    `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
N
Niels 已提交
1366 1367
    whose first element is a string; example: `"cannot create object from
    initializer list"`
N
Niels 已提交
1368 1369 1370 1371 1372 1373

    @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 已提交
1374
    @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
1375
    value from an initializer list
N
Niels 已提交
1376
    @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
1377 1378
    value from an initializer list

N
Niels 已提交
1379
    @since version 1.0.0
N
Niels 已提交
1380
    */
N
Niels 已提交
1381 1382
    basic_json(std::initializer_list<basic_json> init,
               bool type_deduction = true,
N
Niels 已提交
1383
               value_t manual_type = value_t::array)
N
cleanup  
Niels 已提交
1384 1385
    {
        // the initializer list could describe an object
1386
        bool is_an_object = true;
N
cleanup  
Niels 已提交
1387

N
Niels 已提交
1388 1389
        // check if each element is an array with two elements whose first
        // element is a string
N
Niels 已提交
1390
        for (const auto& element : init)
N
cleanup  
Niels 已提交
1391
        {
N
cleanup  
Niels 已提交
1392 1393
            if (not element.is_array() or element.size() != 2
                    or not element[0].is_string())
N
cleanup  
Niels 已提交
1394 1395 1396
            {
                // we found an element that makes it impossible to use the
                // initializer list as object
1397
                is_an_object = false;
N
cleanup  
Niels 已提交
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
                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)
            {
1408
                is_an_object = false;
N
cleanup  
Niels 已提交
1409 1410 1411
            }

            // if object is wanted but impossible, throw an exception
1412
            if (manual_type == value_t::object and not is_an_object)
N
cleanup  
Niels 已提交
1413
            {
N
Niels 已提交
1414
                throw std::domain_error("cannot create object from initializer list");
N
cleanup  
Niels 已提交
1415 1416 1417
            }
        }

1418
        if (is_an_object)
N
cleanup  
Niels 已提交
1419 1420 1421
        {
            // the initializer list is a list of pairs -> create object
            m_type = value_t::object;
N
Niels 已提交
1422
            m_value = value_t::object;
N
Niels 已提交
1423

N
Niels 已提交
1424 1425
            assert(m_value.object != nullptr);

N
Niels 已提交
1426
            for (auto& element : init)
N
cleanup  
Niels 已提交
1427 1428 1429 1430 1431 1432 1433 1434
            {
                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;
1435
            m_value.array = create<array_t>(std::move(init));
N
cleanup  
Niels 已提交
1436 1437 1438
        }
    }

N
Niels 已提交
1439 1440 1441 1442 1443 1444 1445 1446 1447
    /*!
    @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 已提交
1448 1449
    basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
    are:
N
Niels 已提交
1450
    1. creating an array whose elements are all pairs whose first element is a
N
Niels 已提交
1451
    string -- in this case, the initializer list constructor would create an
N
Niels 已提交
1452
    object, taking the first elements as keys
N
Niels 已提交
1453
    2. creating an empty array -- passing the empty initializer list to the
N
Niels 已提交
1454 1455
    initializer list constructor yields an empty object

N
Niels 已提交
1456
    @param[in] init  initializer list with JSON values to create an array from
N
Niels 已提交
1457 1458 1459 1460 1461 1462 1463 1464 1465
    (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}

1466 1467 1468 1469 1470
    @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
    create a JSON value from an initializer list
    @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
    value from an initializer list

N
Niels 已提交
1471
    @since version 1.0.0
N
Niels 已提交
1472
    */
N
Niels 已提交
1473 1474
    static basic_json array(std::initializer_list<basic_json> init =
                                std::initializer_list<basic_json>())
N
cleanup  
Niels 已提交
1475
    {
N
Niels 已提交
1476
        return basic_json(init, false, value_t::array);
N
cleanup  
Niels 已提交
1477 1478
    }

N
Niels 已提交
1479 1480 1481 1482
    /*!
    @brief explicitly create an object from an initializer list

    Creates a JSON object value from a given initializer list. The initializer
N
Niels 已提交
1483
    lists elements must be pairs, and their first elements must be strings. If
N
Niels 已提交
1484 1485 1486
    the initializer list is empty, the empty object `{}` is created.

    @note This function is only added for symmetry reasons. In contrast to the
1487 1488 1489 1490 1491
    related function @ref 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 已提交
1492

N
Niels 已提交
1493
    @param[in] init  initializer list to create an object from (optional)
N
Niels 已提交
1494 1495 1496 1497

    @return JSON object value

    @throw std::domain_error if @a init is not a pair whose first elements are
1498 1499
    strings; thrown by
    @ref basic_json(std::initializer_list<basic_json>, bool, value_t)
N
Niels 已提交
1500 1501 1502 1503 1504 1505

    @complexity Linear in the size of @a init.

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

1506 1507 1508 1509 1510
    @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
    create a JSON value from an initializer list
    @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
    value from an initializer list

N
Niels 已提交
1511
    @since version 1.0.0
N
Niels 已提交
1512
    */
N
Niels 已提交
1513 1514
    static basic_json object(std::initializer_list<basic_json> init =
                                 std::initializer_list<basic_json>())
N
cleanup  
Niels 已提交
1515
    {
N
Niels 已提交
1516
        return basic_json(init, false, value_t::object);
N
cleanup  
Niels 已提交
1517 1518
    }

N
Niels 已提交
1519 1520 1521
    /*!
    @brief construct an array with count copies of given value

1522 1523 1524
    Constructs a JSON array value by creating @a cnt copies of a passed
    value. In case @a cnt is `0`, an empty array is created. As postcondition,
    `std::distance(begin(),end()) == cnt` holds.
N
Niels 已提交
1525

1526 1527
    @param[in] cnt  the number of JSON copies of @a val to create
    @param[in] val  the JSON value to copy
N
Niels 已提交
1528

1529
    @complexity Linear in @a cnt.
N
Niels 已提交
1530 1531 1532 1533

    @liveexample{The following code shows examples for the @ref
    basic_json(size_type\, const basic_json&)
    constructor.,basic_json__size_type_basic_json}
1534

N
Niels 已提交
1535
    @since version 1.0.0
N
Niels 已提交
1536
    */
1537
    basic_json(size_type cnt, const basic_json& val)
N
Niels 已提交
1538 1539
        : m_type(value_t::array)
    {
1540
        m_value.array = create<array_t>(cnt, val);
N
Niels 已提交
1541
    }
N
Niels 已提交
1542

N
Niels 已提交
1543 1544 1545 1546 1547
    /*!
    @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 已提交
1548
    - In case of primitive types (number, boolean, or string), @a first must
N
Niels 已提交
1549 1550
      be `begin()` and @a last must be `end()`. In this case, the value is
      copied. Otherwise, std::out_of_range is thrown.
N
Niels 已提交
1551
    - In case of structured types (array, object), the constructor behaves
N
Niels 已提交
1552
      as similar versions for `std::vector`.
N
Niels 已提交
1553
    - In case of a null type, std::domain_error is thrown.
N
Niels 已提交
1554 1555 1556 1557 1558 1559 1560 1561

    @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
N
Niels 已提交
1562
    belong to the same JSON value; example: `"iterators are not compatible"`
N
Niels 已提交
1563
    @throw std::out_of_range if iterators are for a primitive type (number,
N
Niels 已提交
1564 1565
    boolean, or string) where an out of range error can be detected easily;
    example: `"iterators out of range"`
N
Niels 已提交
1566
    @throw std::bad_alloc if allocation for object, array, or string fails
N
Niels 已提交
1567 1568
    @throw std::domain_error if called with a null value; example: `"cannot use
    construct with iterators from null"`
N
Niels 已提交
1569 1570 1571 1572 1573

    @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}
1574

N
Niels 已提交
1575
    @since version 1.0.0
N
Niels 已提交
1576 1577
    */
    template <class InputIT, typename
N
Niels 已提交
1578
              std::enable_if<
N
Niels 已提交
1579 1580
                  std::is_same<InputIT, typename basic_json_t::iterator>::value or
                  std::is_same<InputIT, typename basic_json_t::const_iterator>::value
N
Niels 已提交
1581 1582
                  , int>::type
              = 0>
N
Niels 已提交
1583
    basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
N
Niels 已提交
1584 1585
    {
        // make sure iterator fits the current value
N
Niels 已提交
1586
        if (first.m_object != last.m_object)
N
Niels 已提交
1587
        {
N
Niels 已提交
1588
            throw std::domain_error("iterators are not compatible");
N
Niels 已提交
1589 1590
        }

N
Niels 已提交
1591
        // check if iterator range is complete for primitive values
N
Niels 已提交
1592 1593 1594
        switch (m_type)
        {
            case value_t::boolean:
1595 1596
            case value_t::number_float:
            case value_t::number_integer:
N
Niels 已提交
1597 1598
            case value_t::string:
            {
1599
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
N
Niels 已提交
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
                {
                    throw std::out_of_range("iterators out of range");
                }
                break;
            }

            default:
            {
                break;
            }
        }

        switch (m_type)
        {
            case value_t::number_integer:
            {
N
Niels 已提交
1616
                assert(first.m_object != nullptr);
N
Niels 已提交
1617 1618 1619 1620 1621 1622
                m_value.number_integer = first.m_object->m_value.number_integer;
                break;
            }

            case value_t::number_float:
            {
N
Niels 已提交
1623
                assert(first.m_object != nullptr);
N
Niels 已提交
1624 1625 1626 1627 1628 1629
                m_value.number_float = first.m_object->m_value.number_float;
                break;
            }

            case value_t::boolean:
            {
N
Niels 已提交
1630
                assert(first.m_object != nullptr);
N
Niels 已提交
1631 1632 1633 1634 1635 1636
                m_value.boolean = first.m_object->m_value.boolean;
                break;
            }

            case value_t::string:
            {
N
Niels 已提交
1637
                assert(first.m_object != nullptr);
N
Niels 已提交
1638
                m_value = *first.m_object->m_value.string;
N
Niels 已提交
1639 1640 1641 1642 1643
                break;
            }

            case value_t::object:
            {
1644
                m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
N
Niels 已提交
1645 1646 1647 1648 1649
                break;
            }

            case value_t::array:
            {
1650
                m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
N
Niels 已提交
1651 1652 1653 1654 1655
                break;
            }

            default:
            {
N
Niels 已提交
1656
                assert(first.m_object != nullptr);
N
Niels 已提交
1657
                throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
N
Niels 已提交
1658 1659 1660 1661
            }
        }
    }

N
cleanup  
Niels 已提交
1662 1663 1664 1665
    ///////////////////////////////////////
    // other constructors and destructor //
    ///////////////////////////////////////

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

N
Niels 已提交
1669 1670
    Creates a copy of a given JSON value.

N
Niels 已提交
1671
    @param[in] other  the JSON value to copy
N
Niels 已提交
1672 1673 1674 1675 1676 1677 1678

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

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

N
Niels 已提交
1684
    @since version 1.0.0
N
Niels 已提交
1685
    */
1686
    basic_json(const basic_json& other)
N
cleanup  
Niels 已提交
1687 1688 1689 1690
        : m_type(other.m_type)
    {
        switch (m_type)
        {
1691
            case value_t::object:
N
cleanup  
Niels 已提交
1692
            {
N
Niels 已提交
1693
                assert(other.m_value.object != nullptr);
N
Niels 已提交
1694
                m_value = *other.m_value.object;
N
cleanup  
Niels 已提交
1695 1696
                break;
            }
N
Niels 已提交
1697

1698
            case value_t::array:
N
cleanup  
Niels 已提交
1699
            {
N
Niels 已提交
1700
                assert(other.m_value.array != nullptr);
N
Niels 已提交
1701
                m_value = *other.m_value.array;
N
cleanup  
Niels 已提交
1702 1703
                break;
            }
N
Niels 已提交
1704

1705
            case value_t::string:
N
cleanup  
Niels 已提交
1706
            {
N
Niels 已提交
1707
                assert(other.m_value.string != nullptr);
N
Niels 已提交
1708
                m_value = *other.m_value.string;
N
cleanup  
Niels 已提交
1709 1710
                break;
            }
N
Niels 已提交
1711

1712
            case value_t::boolean:
N
cleanup  
Niels 已提交
1713
            {
N
Niels 已提交
1714
                m_value = other.m_value.boolean;
N
cleanup  
Niels 已提交
1715 1716
                break;
            }
N
Niels 已提交
1717

1718
            case value_t::number_integer:
N
cleanup  
Niels 已提交
1719
            {
N
Niels 已提交
1720
                m_value = other.m_value.number_integer;
N
cleanup  
Niels 已提交
1721 1722
                break;
            }
N
Niels 已提交
1723

1724
            case value_t::number_float:
N
cleanup  
Niels 已提交
1725
            {
N
Niels 已提交
1726
                m_value = other.m_value.number_float;
N
cleanup  
Niels 已提交
1727 1728
                break;
            }
1729 1730 1731 1732 1733

            default:
            {
                break;
            }
N
cleanup  
Niels 已提交
1734 1735 1736
        }
    }

N
Niels 已提交
1737 1738 1739 1740 1741 1742 1743
    /*!
    @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 已提交
1744
    @param[in,out] other  value to move to this object
N
Niels 已提交
1745 1746 1747 1748 1749 1750 1751

    @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}
1752

N
Niels 已提交
1753
    @since version 1.0.0
N
Niels 已提交
1754
    */
1755
    basic_json(basic_json&& other) noexcept
N
cleanup  
Niels 已提交
1756 1757 1758
        : m_type(std::move(other.m_type)),
          m_value(std::move(other.m_value))
    {
N
Niels 已提交
1759
        // invalidate payload
N
cleanup  
Niels 已提交
1760 1761 1762 1763
        other.m_type = value_t::null;
        other.m_value = {};
    }

N
Niels 已提交
1764 1765
    /*!
    @brief copy assignment
N
Niels 已提交
1766

N
Niels 已提交
1767 1768 1769 1770
    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 已提交
1771
    @param[in] other  value to copy from
N
Niels 已提交
1772 1773 1774 1775 1776 1777

    @complexity Linear.

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

N
Niels 已提交
1778 1779 1780 1781
    @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 已提交
1782

N
Niels 已提交
1783
    @since version 1.0.0
N
Niels 已提交
1784
    */
1785
    reference& operator=(basic_json other) noexcept (
N
Niels 已提交
1786 1787 1788 1789 1790
        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 已提交
1791
    {
N
Niels 已提交
1792
        using std::swap;
C
Colin Hirsch 已提交
1793 1794
        swap(m_type, other.m_type);
        swap(m_value, other.m_value);
N
cleanup  
Niels 已提交
1795 1796 1797
        return *this;
    }

N
Niels 已提交
1798 1799
    /*!
    @brief destructor
N
Niels 已提交
1800

N
Niels 已提交
1801
    Destroys the JSON value and frees all allocated memory.
N
Niels 已提交
1802 1803 1804 1805 1806 1807

    @complexity Linear.

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

N
Niels 已提交
1809
    @since version 1.0.0
N
Niels 已提交
1810
    */
N
Niels 已提交
1811
    ~basic_json()
N
cleanup  
Niels 已提交
1812 1813 1814
    {
        switch (m_type)
        {
1815
            case value_t::object:
N
cleanup  
Niels 已提交
1816
            {
N
Niels 已提交
1817
                AllocatorType<object_t> alloc;
N
Niels 已提交
1818 1819
                alloc.destroy(m_value.object);
                alloc.deallocate(m_value.object, 1);
N
cleanup  
Niels 已提交
1820 1821
                break;
            }
N
Niels 已提交
1822

1823
            case value_t::array:
N
cleanup  
Niels 已提交
1824
            {
N
Niels 已提交
1825
                AllocatorType<array_t> alloc;
N
Niels 已提交
1826 1827
                alloc.destroy(m_value.array);
                alloc.deallocate(m_value.array, 1);
N
cleanup  
Niels 已提交
1828 1829
                break;
            }
N
Niels 已提交
1830

1831
            case value_t::string:
N
cleanup  
Niels 已提交
1832
            {
N
Niels 已提交
1833
                AllocatorType<string_t> alloc;
N
Niels 已提交
1834
                alloc.destroy(m_value.string);
N
Niels 已提交
1835
                alloc.deallocate(m_value.string, 1);
N
cleanup  
Niels 已提交
1836 1837
                break;
            }
N
Niels 已提交
1838 1839

            default:
N
cleanup  
Niels 已提交
1840
            {
N
Niels 已提交
1841
                // all other types need no specific destructor
N
cleanup  
Niels 已提交
1842 1843 1844 1845 1846
                break;
            }
        }
    }

N
Niels 已提交
1847
    /// @}
N
cleanup  
Niels 已提交
1848 1849 1850 1851 1852 1853

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

N
Niels 已提交
1854 1855 1856
    /// @name object inspection
    /// @{

N
cleanup  
Niels 已提交
1857
    /*!
N
Niels 已提交
1858 1859
    @brief serialization

N
Niels 已提交
1860
    Serialization function for JSON values. The function tries to mimic
N
Niels 已提交
1861 1862
    Python's @p json.dumps() function, and currently supports its @p indent
    parameter.
N
cleanup  
Niels 已提交
1863

N
Niels 已提交
1864
    @param[in] indent if indent is nonnegative, then array elements and object
N
Niels 已提交
1865 1866 1867
    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 已提交
1868

N
Niels 已提交
1869 1870 1871 1872 1873
    @return string containing the serialization of the JSON value

    @complexity Linear.

    @liveexample{The following example shows the effect of different @a indent
N
Niels 已提交
1874
    parameters to the result of the serialization.,dump}
N
Niels 已提交
1875

N
cleanup  
Niels 已提交
1876
    @see https://docs.python.org/2/library/json.html#json.dump
N
Niels 已提交
1877

N
Niels 已提交
1878
    @since version 1.0.0
N
cleanup  
Niels 已提交
1879
    */
N
Niels 已提交
1880
    string_t dump(const int indent = -1) const
N
cleanup  
Niels 已提交
1881
    {
N
Niels 已提交
1882 1883
        std::stringstream ss;

N
cleanup  
Niels 已提交
1884 1885
        if (indent >= 0)
        {
N
Niels 已提交
1886
            dump(ss, true, static_cast<unsigned int>(indent));
N
cleanup  
Niels 已提交
1887 1888 1889
        }
        else
        {
N
Niels 已提交
1890
            dump(ss, false, 0);
N
cleanup  
Niels 已提交
1891
        }
N
Niels 已提交
1892 1893

        return ss.str();
N
cleanup  
Niels 已提交
1894 1895
    }

N
Niels 已提交
1896 1897 1898 1899 1900 1901 1902
    /*!
    @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 已提交
1903 1904 1905 1906 1907

    @complexity Constant.

    @liveexample{The following code exemplifies @ref type() for all JSON
    types.,type}
N
Niels 已提交
1908

N
Niels 已提交
1909
    @since version 1.0.0
N
Niels 已提交
1910
    */
1911
    value_t type() const noexcept
N
cleanup  
Niels 已提交
1912 1913 1914 1915
    {
        return m_type;
    }

N
Niels 已提交
1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928
    /*!
    @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}
N
Niels 已提交
1929

N
Niels 已提交
1930
    @since version 1.0.0
N
Niels 已提交
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948
    */
    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}
N
Niels 已提交
1949

N
Niels 已提交
1950
    @since version 1.0.0
N
Niels 已提交
1951 1952 1953 1954 1955 1956
    */
    bool is_structured() const noexcept
    {
        return is_array() or is_object();
    }

N
Niels 已提交
1957 1958 1959 1960 1961
    /*!
    @brief return whether value is null

    This function returns true iff the JSON value is null.

N
Niels 已提交
1962
    @return `true` if type is null, `false` otherwise.
N
Niels 已提交
1963 1964 1965 1966

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_null for all JSON
N
Niels 已提交
1967
    types.,is_null}
N
Niels 已提交
1968

N
Niels 已提交
1969
    @since version 1.0.0
N
Niels 已提交
1970
    */
1971
    bool is_null() const noexcept
N
Niels 已提交
1972 1973 1974 1975
    {
        return m_type == value_t::null;
    }

N
Niels 已提交
1976 1977 1978 1979 1980
    /*!
    @brief return whether value is a boolean

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

N
Niels 已提交
1981
    @return `true` if type is boolean, `false` otherwise.
N
Niels 已提交
1982 1983 1984 1985

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_boolean for all JSON
N
Niels 已提交
1986
    types.,is_boolean}
N
Niels 已提交
1987

N
Niels 已提交
1988
    @since version 1.0.0
N
Niels 已提交
1989
    */
1990
    bool is_boolean() const noexcept
N
Niels 已提交
1991 1992 1993 1994
    {
        return m_type == value_t::boolean;
    }

N
Niels 已提交
1995 1996 1997 1998 1999 2000
    /*!
    @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 已提交
2001 2002
    @return `true` if type is number (regardless whether integer or
    floating-type), `false` otherwise.
N
Niels 已提交
2003 2004 2005 2006

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number for all JSON
N
Niels 已提交
2007
    types.,is_number}
N
Niels 已提交
2008 2009 2010 2011

    @sa @ref is_number_integer() -- check if value is an integer number
    @sa @ref is_number_float() -- check if value is a floating-point number

N
Niels 已提交
2012
    @since version 1.0.0
N
Niels 已提交
2013
    */
2014
    bool is_number() const noexcept
N
Niels 已提交
2015
    {
N
Niels 已提交
2016
        return is_number_integer() or is_number_float();
N
Niels 已提交
2017 2018
    }

N
Niels 已提交
2019 2020 2021 2022 2023 2024
    /*!
    @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 已提交
2025
    @return `true` if type is an integer number, `false` otherwise.
N
Niels 已提交
2026 2027 2028 2029

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number_integer for all
N
Niels 已提交
2030
    JSON types.,is_number_integer}
N
Niels 已提交
2031 2032 2033 2034

    @sa @ref is_number() -- check if value is a number
    @sa @ref is_number_float() -- check if value is a floating-point number

N
Niels 已提交
2035
    @since version 1.0.0
N
Niels 已提交
2036
    */
N
Niels 已提交
2037 2038 2039 2040 2041
    bool is_number_integer() const noexcept
    {
        return m_type == value_t::number_integer;
    }

N
Niels 已提交
2042 2043 2044 2045 2046 2047
    /*!
    @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 已提交
2048
    @return `true` if type is a floating-point number, `false` otherwise.
N
Niels 已提交
2049 2050 2051 2052

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_number_float for all
N
Niels 已提交
2053
    JSON types.,is_number_float}
N
Niels 已提交
2054 2055 2056 2057

    @sa @ref is_number() -- check if value is number
    @sa @ref is_number_integer() -- check if value is an integer number

N
Niels 已提交
2058
    @since version 1.0.0
N
Niels 已提交
2059
    */
N
Niels 已提交
2060 2061 2062 2063 2064
    bool is_number_float() const noexcept
    {
        return m_type == value_t::number_float;
    }

N
Niels 已提交
2065 2066 2067 2068 2069
    /*!
    @brief return whether value is an object

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

N
Niels 已提交
2070
    @return `true` if type is object, `false` otherwise.
N
Niels 已提交
2071 2072 2073 2074

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_object for all JSON
N
Niels 已提交
2075
    types.,is_object}
N
Niels 已提交
2076

N
Niels 已提交
2077
    @since version 1.0.0
N
Niels 已提交
2078
    */
2079
    bool is_object() const noexcept
N
Niels 已提交
2080 2081 2082 2083
    {
        return m_type == value_t::object;
    }

N
Niels 已提交
2084 2085 2086 2087 2088
    /*!
    @brief return whether value is an array

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

N
Niels 已提交
2089
    @return `true` if type is array, `false` otherwise.
N
Niels 已提交
2090 2091 2092 2093

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_array for all JSON
N
Niels 已提交
2094
    types.,is_array}
N
Niels 已提交
2095

N
Niels 已提交
2096
    @since version 1.0.0
N
Niels 已提交
2097
    */
2098
    bool is_array() const noexcept
N
Niels 已提交
2099 2100 2101 2102
    {
        return m_type == value_t::array;
    }

N
Niels 已提交
2103 2104 2105 2106 2107
    /*!
    @brief return whether value is a string

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

N
Niels 已提交
2108
    @return `true` if type is string, `false` otherwise.
N
Niels 已提交
2109 2110 2111 2112

    @complexity Constant.

    @liveexample{The following code exemplifies @ref is_string for all JSON
N
Niels 已提交
2113
    types.,is_string}
N
Niels 已提交
2114

N
Niels 已提交
2115
    @since version 1.0.0
N
Niels 已提交
2116
    */
2117
    bool is_string() const noexcept
N
Niels 已提交
2118 2119 2120 2121
    {
        return m_type == value_t::string;
    }

N
Niels 已提交
2122 2123 2124 2125 2126 2127
    /*!
    @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 已提交
2128 2129 2130 2131
    @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 已提交
2132 2133 2134 2135
    @return `true` if type is discarded, `false` otherwise.

    @complexity Constant.

N
Niels 已提交
2136 2137
    @liveexample{The following code exemplifies @ref is_discarded for all JSON
    types.,is_discarded}
N
Niels 已提交
2138

N
Niels 已提交
2139
    @since version 1.0.0
N
Niels 已提交
2140
    */
2141
    bool is_discarded() const noexcept
N
Niels 已提交
2142 2143 2144 2145
    {
        return m_type == value_t::discarded;
    }

N
Niels 已提交
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157
    /*!
    @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}
N
Niels 已提交
2158

N
Niels 已提交
2159
    @since version 1.0.0
N
Niels 已提交
2160
    */
2161
    operator value_t() const noexcept
N
Niels 已提交
2162 2163 2164 2165
    {
        return m_type;
    }

N
Niels 已提交
2166 2167
    /// @}

N
Niels 已提交
2168
  private:
N
Niels 已提交
2169 2170 2171
    //////////////////
    // value access //
    //////////////////
N
cleanup  
Niels 已提交
2172

N
Niels 已提交
2173
    /// get an object (explicit)
N
cleanup  
Niels 已提交
2174 2175
    template <class T, typename
              std::enable_if<
N
Niels 已提交
2176
                  std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
N
Niels 已提交
2177
                  std::is_convertible<basic_json_t, typename T::mapped_type>::value
N
Niels 已提交
2178
                  , int>::type = 0>
2179
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2180
    {
2181 2182
        if (is_object())
        {
N
Niels 已提交
2183
            assert(m_value.object != nullptr);
2184 2185 2186 2187 2188 2189
            return T(m_value.object->begin(), m_value.object->end());
        }
        else
        {
            throw std::domain_error("type must be object, but is " + type_name());
        }
N
Niels 已提交
2190 2191 2192
    }

    /// get an object (explicit)
2193
    object_t get_impl(object_t*) const
N
Niels 已提交
2194
    {
2195 2196
        if (is_object())
        {
N
Niels 已提交
2197
            assert(m_value.object != nullptr);
2198 2199 2200 2201 2202 2203
            return *(m_value.object);
        }
        else
        {
            throw std::domain_error("type must be object, but is " + type_name());
        }
N
cleanup  
Niels 已提交
2204 2205
    }

N
Niels 已提交
2206
    /// get an array (explicit)
N
cleanup  
Niels 已提交
2207 2208
    template <class T, typename
              std::enable_if<
N
Niels 已提交
2209 2210
                  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 已提交
2211 2212
                  not std::is_arithmetic<T>::value and
                  not std::is_convertible<std::string, T>::value and
2213
                  not has_mapped_type<T>::value
N
Niels 已提交
2214
                  , int>::type = 0>
2215
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2216
    {
N
cleanup  
Niels 已提交
2217
        if (is_array())
N
cleanup  
Niels 已提交
2218
        {
2219
            T to_vector;
N
Niels 已提交
2220
            assert(m_value.array != nullptr);
2221 2222
            std::transform(m_value.array->begin(), m_value.array->end(),
                           std::inserter(to_vector, to_vector.end()), [](basic_json i)
N
Niels 已提交
2223
            {
2224 2225 2226 2227 2228 2229 2230
                return i.get<typename T::value_type>();
            });
            return to_vector;
        }
        else
        {
            throw std::domain_error("type must be array, but is " + type_name());
N
cleanup  
Niels 已提交
2231 2232 2233
        }
    }

N
Niels 已提交
2234 2235
    /// get an array (explicit)
    template <class T, typename
N
cleanup  
Niels 已提交
2236
              std::enable_if<
N
Niels 已提交
2237 2238
                  std::is_convertible<basic_json_t, T>::value and
                  not std::is_same<basic_json_t, T>::value
N
Niels 已提交
2239
                  , int>::type = 0>
2240
    std::vector<T> get_impl(std::vector<T>*) const
N
cleanup  
Niels 已提交
2241
    {
N
cleanup  
Niels 已提交
2242
        if (is_array())
N
cleanup  
Niels 已提交
2243
        {
2244
            std::vector<T> to_vector;
N
Niels 已提交
2245
            assert(m_value.array != nullptr);
2246 2247 2248
            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)
N
Niels 已提交
2249
            {
2250 2251 2252 2253 2254 2255 2256
                return i.get<T>();
            });
            return to_vector;
        }
        else
        {
            throw std::domain_error("type must be array, but is " + type_name());
N
cleanup  
Niels 已提交
2257 2258 2259
        }
    }

N
Niels 已提交
2260 2261 2262 2263
    /// get an array (explicit)
    template <class T, typename
              std::enable_if<
                  std::is_same<basic_json, typename T::value_type>::value and
2264
                  not has_mapped_type<T>::value
N
Niels 已提交
2265
                  , int>::type = 0>
2266
    T get_impl(T*) const
N
Niels 已提交
2267
    {
2268 2269
        if (is_array())
        {
N
Niels 已提交
2270
            assert(m_value.array != nullptr);
2271 2272 2273 2274 2275 2276
            return T(m_value.array->begin(), m_value.array->end());
        }
        else
        {
            throw std::domain_error("type must be array, but is " + type_name());
        }
N
Niels 已提交
2277 2278
    }

N
Niels 已提交
2279
    /// get an array (explicit)
2280
    array_t get_impl(array_t*) const
N
Niels 已提交
2281
    {
2282 2283
        if (is_array())
        {
N
Niels 已提交
2284
            assert(m_value.array != nullptr);
2285 2286 2287 2288 2289 2290
            return *(m_value.array);
        }
        else
        {
            throw std::domain_error("type must be array, but is " + type_name());
        }
N
Niels 已提交
2291 2292 2293
    }

    /// get a string (explicit)
N
cleanup  
Niels 已提交
2294 2295
    template <typename T, typename
              std::enable_if<
N
Niels 已提交
2296 2297
                  std::is_convertible<string_t, T>::value
                  , int>::type = 0>
2298
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2299
    {
2300 2301
        if (is_string())
        {
N
Niels 已提交
2302
            assert(m_value.string != nullptr);
2303 2304 2305 2306 2307 2308
            return *m_value.string;
        }
        else
        {
            throw std::domain_error("type must be string, but is " + type_name());
        }
N
cleanup  
Niels 已提交
2309 2310
    }

N
Niels 已提交
2311
    /// get a number (explicit)
N
cleanup  
Niels 已提交
2312 2313
    template<typename T, typename
             std::enable_if<
N
Niels 已提交
2314 2315
                 std::is_arithmetic<T>::value
                 , int>::type = 0>
2316
    T get_impl(T*) const
N
cleanup  
Niels 已提交
2317 2318 2319
    {
        switch (m_type)
        {
2320
            case value_t::number_integer:
N
Niels 已提交
2321
            {
N
cleanup  
Niels 已提交
2322
                return static_cast<T>(m_value.number_integer);
N
Niels 已提交
2323
            }
2324 2325

            case value_t::number_float:
N
Niels 已提交
2326
            {
N
cleanup  
Niels 已提交
2327
                return static_cast<T>(m_value.number_float);
N
Niels 已提交
2328
            }
2329

N
cleanup  
Niels 已提交
2330
            default:
N
Niels 已提交
2331
            {
N
Niels 已提交
2332
                throw std::domain_error("type must be number, but is " + type_name());
N
Niels 已提交
2333 2334 2335 2336 2337
            }
        }
    }

    /// get a boolean (explicit)
2338
    boolean_t get_impl(boolean_t*) const
N
Niels 已提交
2339
    {
2340 2341 2342 2343 2344 2345 2346 2347
        if (is_boolean())
        {
            return m_value.boolean;
        }
        else
        {
            throw std::domain_error("type must be boolean, but is " + type_name());
        }
N
cleanup  
Niels 已提交
2348 2349
    }

N
Niels 已提交
2350
    /// get a pointer to the value (object)
N
Niels 已提交
2351 2352 2353 2354 2355 2356 2357
    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 已提交
2358 2359 2360 2361 2362
    {
        return is_object() ? m_value.object : nullptr;
    }

    /// get a pointer to the value (array)
N
Niels 已提交
2363
    array_t* get_impl_ptr(array_t*) noexcept
N
Niels 已提交
2364 2365 2366 2367
    {
        return is_array() ? m_value.array : nullptr;
    }

N
Niels 已提交
2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379
    /// 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 已提交
2380
    /// get a pointer to the value (string)
N
Niels 已提交
2381
    const string_t* get_impl_ptr(const string_t*) const noexcept
N
Niels 已提交
2382 2383 2384 2385 2386
    {
        return is_string() ? m_value.string : nullptr;
    }

    /// get a pointer to the value (boolean)
N
Niels 已提交
2387 2388 2389 2390 2391 2392 2393
    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 已提交
2394 2395 2396 2397 2398
    {
        return is_boolean() ? &m_value.boolean : nullptr;
    }

    /// get a pointer to the value (integer number)
N
Niels 已提交
2399
    number_integer_t* get_impl_ptr(number_integer_t*) noexcept
N
Niels 已提交
2400 2401 2402 2403
    {
        return is_number_integer() ? &m_value.number_integer : nullptr;
    }

N
Niels 已提交
2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
    /// 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 已提交
2416
    /// get a pointer to the value (floating-point number)
N
Niels 已提交
2417
    const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
N
Niels 已提交
2418 2419 2420 2421
    {
        return is_number_float() ? &m_value.number_float : nullptr;
    }

N
Niels 已提交
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433
    /*!
    @brief helper function to implement get_ref()

    This funcion helps to implement get_ref() without code duplication for
    const and non-const overloads

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

    @throw std::domain_error if ReferenceType does not match underlying value
    type of the current JSON
    */
    template<typename ReferenceType, typename ThisType>
D
dariomt 已提交
2434 2435 2436
    static ReferenceType get_ref_impl(ThisType& obj)
    {
        // delegate the call to get_ptr<>()
N
Niels 已提交
2437
        using PointerType = typename std::add_pointer<ReferenceType>::type;
2438
        auto ptr = obj.template get_ptr<PointerType>();
N
Niels 已提交
2439 2440 2441 2442 2443 2444 2445 2446 2447 2448

        if (ptr != nullptr)
        {
            return *ptr;
        }
        else
        {
            throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
                                    obj.type_name());
        }
D
dariomt 已提交
2449 2450
    }

N
Niels 已提交
2451
  public:
N
Niels 已提交
2452 2453 2454 2455

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

N
Niels 已提交
2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467
    /*!
    @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
N
Niels 已提交
2468
    to JSON; example: `"type must be object, but is null"`
N
Niels 已提交
2469 2470 2471

    @complexity Linear in the size of the JSON value.

N
Niels 已提交
2472
    @liveexample{The example below shows several conversions from JSON values
N
Niels 已提交
2473 2474 2475
    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++
N
Niels 已提交
2476
    associative containers such as `std::unordered_map<std::string\,
N
Niels 已提交
2477 2478 2479 2480 2481 2482 2483 2484 2485
    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
N
Niels 已提交
2486

N
Niels 已提交
2487
    @since version 1.0.0
N
Niels 已提交
2488 2489 2490 2491 2492 2493
    */
    template<typename ValueType, typename
             std::enable_if<
                 not std::is_pointer<ValueType>::value
                 , int>::type = 0>
    ValueType get() const
N
Niels 已提交
2494
    {
N
Niels 已提交
2495
        return get_impl(static_cast<ValueType*>(nullptr));
N
Niels 已提交
2496 2497
    }

N
Niels 已提交
2498 2499 2500 2501 2502 2503
    /*!
    @brief get a pointer value (explicit)

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

N
Niels 已提交
2504
    @warning The pointer becomes invalid if the underlying JSON object changes.
N
Niels 已提交
2505 2506 2507 2508 2509

    @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.

N
Niels 已提交
2510 2511
    @return pointer to the internally stored JSON value if the requested
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
N
Niels 已提交
2512 2513 2514 2515 2516 2517 2518 2519 2520

    @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
N
Niels 已提交
2521

N
Niels 已提交
2522
    @since version 1.0.0
N
Niels 已提交
2523 2524 2525 2526 2527
    */
    template<typename PointerType, typename
             std::enable_if<
                 std::is_pointer<PointerType>::value
                 , int>::type = 0>
N
Niels 已提交
2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542
    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 已提交
2543 2544 2545 2546 2547 2548 2549 2550
    {
        // delegate the call to get_ptr
        return get_ptr<PointerType>();
    }

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

N
Niels 已提交
2551
    Implicit pointer access to the internally stored JSON value. No copies are
N
Niels 已提交
2552 2553 2554 2555 2556 2557 2558 2559 2560
    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.

N
Niels 已提交
2561 2562
    @return pointer to the internally stored JSON value if the requested
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
N
Niels 已提交
2563 2564 2565 2566 2567 2568 2569

    @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}
N
Niels 已提交
2570

N
Niels 已提交
2571
    @since version 1.0.0
N
Niels 已提交
2572 2573 2574 2575 2576
    */
    template<typename PointerType, typename
             std::enable_if<
                 std::is_pointer<PointerType>::value
                 , int>::type = 0>
N
Niels 已提交
2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589
    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
N
Niels 已提交
2590
                 and std::is_const<typename std::remove_pointer<PointerType>::type>::value
N
Niels 已提交
2591 2592
                 , int>::type = 0>
    const PointerType get_ptr() const noexcept
N
Niels 已提交
2593
    {
N
Niels 已提交
2594 2595
        // delegate the call to get_impl_ptr<>() const
        return get_impl_ptr(static_cast<const PointerType>(nullptr));
N
Niels 已提交
2596 2597
    }

N
Niels 已提交
2598
    /*!
D
dariomt 已提交
2599 2600 2601 2602 2603 2604 2605 2606
    @brief get a reference value (implicit)

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

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

N
Niels 已提交
2607 2608 2609
    @tparam ReferenceType reference type; must be a reference to @ref array_t,
    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
    @ref number_float_t.
D
dariomt 已提交
2610

N
Niels 已提交
2611 2612 2613
    @return reference to the internally stored JSON value if the requested
    reference type @a ReferenceType fits to the JSON value; throws
    std::domain_error otherwise
D
dariomt 已提交
2614

N
Niels 已提交
2615 2616
    @throw std::domain_error in case passed type @a ReferenceType is
    incompatible with the stored JSON value
D
dariomt 已提交
2617 2618

    @complexity Constant.
N
Niels 已提交
2619 2620 2621 2622

    @liveexample{The example shows several calls to `get_ref()`.,get_ref}

    @since version 1.0.1
D
dariomt 已提交
2623 2624 2625 2626 2627 2628 2629
    */
    template<typename ReferenceType, typename
             std::enable_if<
                 std::is_reference<ReferenceType>::value
                 , int>::type = 0>
    ReferenceType get_ref()
    {
N
Niels 已提交
2630 2631
        // delegate call to get_ref_impl
        return get_ref_impl<ReferenceType>(*this);
D
dariomt 已提交
2632 2633 2634 2635 2636 2637 2638 2639 2640
    }

    /*!
    @brief get a reference value (implicit)
    @copydoc get_ref()
    */
    template<typename ReferenceType, typename
             std::enable_if<
                 std::is_reference<ReferenceType>::value
N
Niels 已提交
2641
                 and std::is_const<typename std::remove_reference<ReferenceType>::type>::value
D
dariomt 已提交
2642 2643 2644
                 , int>::type = 0>
    ReferenceType get_ref() const
    {
N
Niels 已提交
2645 2646
        // delegate call to get_ref_impl
        return get_ref_impl<ReferenceType>(*this);
D
dariomt 已提交
2647 2648
    }

N
Niels 已提交
2649 2650 2651
    /*!
    @brief get a value (implicit)

N
Niels 已提交
2652
    Implicit type conversion between the JSON value and a compatible value. The
N
Niels 已提交
2653 2654 2655 2656
    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
N
Niels 已提交
2657 2658 2659
    `std::vector` types for JSON arrays. The character type of @ref string_t
    as well as an initializer list of this type is excluded to avoid
    ambiguities as these types implicitly convert to `std::string`.
N
Niels 已提交
2660 2661 2662 2663 2664 2665 2666 2667

    @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.

N
Niels 已提交
2668
    @liveexample{The example below shows several conversions from JSON values
N
Niels 已提交
2669 2670 2671
    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++
N
Niels 已提交
2672
    associative containers such as `std::unordered_map<std::string\,
N
Niels 已提交
2673
    json>`.,operator__ValueType}
N
Niels 已提交
2674

N
Niels 已提交
2675
    @since version 1.0.0
N
Niels 已提交
2676
    */
N
Niels 已提交
2677 2678 2679 2680
    template < typename ValueType, typename
               std::enable_if <
                   not std::is_pointer<ValueType>::value
                   and not std::is_same<ValueType, typename string_t::value_type>::value
2681
#ifndef _MSC_VER  // Fix for issue #167 operator<< abiguity under VS2015
N
Niels 已提交
2682
                   and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
2683
#endif
N
Niels 已提交
2684
                   , int >::type = 0 >
N
Niels 已提交
2685
    operator ValueType() const
N
cleanup  
Niels 已提交
2686
    {
N
Niels 已提交
2687 2688
        // delegate the call to get<>() const
        return get<ValueType>();
N
cleanup  
Niels 已提交
2689 2690
    }

N
Niels 已提交
2691 2692
    /// @}

N
cleanup  
Niels 已提交
2693 2694 2695 2696 2697

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

N
Niels 已提交
2698 2699 2700
    /// @name element access
    /// @{

N
Niels 已提交
2701 2702 2703 2704 2705 2706 2707 2708 2709 2710
    /*!
    @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

N
Niels 已提交
2711 2712
    @throw std::domain_error if the JSON value is not an array; example:
    `"cannot use at() with string"`
N
Niels 已提交
2713
    @throw std::out_of_range if the index @a idx is out of range of the array;
N
Niels 已提交
2714
    that is, `idx >= size()`; example: `"array index 7 is out of range"`
N
Niels 已提交
2715 2716 2717 2718 2719

    @complexity Constant.

    @liveexample{The example below shows how array elements can be read and
    written using at.,at__size_type}
N
Niels 已提交
2720

N
Niels 已提交
2721
    @since version 1.0.0
N
Niels 已提交
2722
    */
2723
    reference at(size_type idx)
N
cleanup  
Niels 已提交
2724 2725
    {
        // at only works for arrays
2726 2727
        if (is_array())
        {
N
Niels 已提交
2728 2729
            try
            {
N
Niels 已提交
2730
                assert(m_value.array != nullptr);
N
Niels 已提交
2731 2732
                return m_value.array->at(idx);
            }
2733
            catch (std::out_of_range&)
N
Niels 已提交
2734 2735 2736 2737
            {
                // create better exception explanation
                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
            }
2738 2739 2740 2741 2742
        }
        else
        {
            throw std::domain_error("cannot use at() with " + type_name());
        }
N
cleanup  
Niels 已提交
2743 2744
    }

N
Niels 已提交
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754
    /*!
    @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

N
Niels 已提交
2755 2756
    @throw std::domain_error if the JSON value is not an array; example:
    `"cannot use at() with string"`
N
Niels 已提交
2757
    @throw std::out_of_range if the index @a idx is out of range of the array;
N
Niels 已提交
2758
    that is, `idx >= size()`; example: `"array index 7 is out of range"`
N
Niels 已提交
2759 2760 2761 2762 2763

    @complexity Constant.

    @liveexample{The example below shows how array elements can be read using
    at.,at__size_type_const}
N
Niels 已提交
2764

N
Niels 已提交
2765
    @since version 1.0.0
N
Niels 已提交
2766
    */
2767
    const_reference at(size_type idx) const
N
cleanup  
Niels 已提交
2768 2769
    {
        // at only works for arrays
2770 2771
        if (is_array())
        {
N
Niels 已提交
2772 2773
            try
            {
N
Niels 已提交
2774
                assert(m_value.array != nullptr);
N
Niels 已提交
2775 2776
                return m_value.array->at(idx);
            }
2777
            catch (std::out_of_range&)
N
Niels 已提交
2778 2779 2780 2781
            {
                // create better exception explanation
                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
            }
2782 2783 2784 2785 2786
        }
        else
        {
            throw std::domain_error("cannot use at() with " + type_name());
        }
2787 2788
    }

N
Niels 已提交
2789 2790 2791 2792 2793 2794 2795 2796 2797 2798
    /*!
    @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

N
Niels 已提交
2799 2800
    @throw std::domain_error if the JSON value is not an object; example:
    `"cannot use at() with boolean"`
N
Niels 已提交
2801
    @throw std::out_of_range if the key @a key is is not stored in the object;
N
Niels 已提交
2802
    that is, `find(key) == end()`; example: `"key "the fast" not found"`
N
Niels 已提交
2803 2804 2805 2806 2807

    @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}
N
Niels 已提交
2808 2809 2810 2811

    @sa @ref operator[](const typename object_t::key_type&) for unchecked
    access by reference
    @sa @ref value() for access by value with a default value
N
Niels 已提交
2812

N
Niels 已提交
2813
    @since version 1.0.0
N
Niels 已提交
2814
    */
2815
    reference at(const typename object_t::key_type& key)
2816 2817
    {
        // at only works for objects
2818 2819
        if (is_object())
        {
N
Niels 已提交
2820 2821
            try
            {
N
Niels 已提交
2822
                assert(m_value.object != nullptr);
N
Niels 已提交
2823 2824
                return m_value.object->at(key);
            }
2825
            catch (std::out_of_range&)
N
Niels 已提交
2826 2827 2828 2829
            {
                // create better exception explanation
                throw std::out_of_range("key '" + key + "' not found");
            }
2830 2831 2832 2833 2834
        }
        else
        {
            throw std::domain_error("cannot use at() with " + type_name());
        }
2835 2836
    }

N
Niels 已提交
2837 2838 2839 2840 2841 2842 2843 2844 2845 2846
    /*!
    @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

N
Niels 已提交
2847 2848
    @throw std::domain_error if the JSON value is not an object; example:
    `"cannot use at() with boolean"`
N
Niels 已提交
2849
    @throw std::out_of_range if the key @a key is is not stored in the object;
N
Niels 已提交
2850
    that is, `find(key) == end()`; example: `"key "the fast" not found"`
N
Niels 已提交
2851 2852 2853 2854 2855

    @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}
N
Niels 已提交
2856 2857 2858 2859

    @sa @ref operator[](const typename object_t::key_type&) for unchecked
    access by reference
    @sa @ref value() for access by value with a default value
N
Niels 已提交
2860

N
Niels 已提交
2861
    @since version 1.0.0
N
Niels 已提交
2862
    */
2863
    const_reference at(const typename object_t::key_type& key) const
2864 2865
    {
        // at only works for objects
2866 2867
        if (is_object())
        {
N
Niels 已提交
2868 2869
            try
            {
N
Niels 已提交
2870
                assert(m_value.object != nullptr);
N
Niels 已提交
2871 2872
                return m_value.object->at(key);
            }
2873
            catch (std::out_of_range&)
N
Niels 已提交
2874 2875 2876 2877
            {
                // create better exception explanation
                throw std::out_of_range("key '" + key + "' not found");
            }
2878 2879 2880 2881 2882
        }
        else
        {
            throw std::domain_error("cannot use at() with " + type_name());
        }
N
cleanup  
Niels 已提交
2883 2884
    }

N
Niels 已提交
2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897
    /*!
    @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

N
Niels 已提交
2898 2899
    @throw std::domain_error if JSON is not an array or null; example: `"cannot
    use operator[] with null"`
N
Niels 已提交
2900 2901 2902 2903 2904 2905 2906

    @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}
N
Niels 已提交
2907

N
Niels 已提交
2908
    @since version 1.0.0
N
Niels 已提交
2909
    */
2910
    reference operator[](size_type idx)
N
cleanup  
Niels 已提交
2911
    {
N
Niels 已提交
2912
        // implicitly convert null to object
N
cleanup  
Niels 已提交
2913
        if (is_null())
N
Niels 已提交
2914 2915
        {
            m_type = value_t::array;
2916
            m_value.array = create<array_t>();
N
Niels 已提交
2917 2918 2919
        }

        // [] only works for arrays
N
cleanup  
Niels 已提交
2920
        if (is_array())
N
cleanup  
Niels 已提交
2921
        {
N
Niels 已提交
2922
            assert(m_value.array != nullptr);
N
cleanup  
Niels 已提交
2923 2924 2925 2926
            for (size_t i = m_value.array->size(); i <= idx; ++i)
            {
                m_value.array->push_back(basic_json());
            }
N
cleanup  
Niels 已提交
2927

N
cleanup  
Niels 已提交
2928 2929 2930
            return m_value.array->operator[](idx);
        }
        else
N
Niels 已提交
2931
        {
N
cleanup  
Niels 已提交
2932
            throw std::domain_error("cannot use operator[] with " + type_name());
N
Niels 已提交
2933
        }
N
cleanup  
Niels 已提交
2934 2935
    }

N
Niels 已提交
2936 2937 2938 2939 2940 2941 2942 2943 2944
    /*!
    @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

N
Niels 已提交
2945 2946
    @throw std::domain_error if JSON is not an array; example: `"cannot use
    operator[] with null"`
N
Niels 已提交
2947 2948 2949 2950 2951

    @complexity Constant.

    @liveexample{The example below shows how array elements can be read using
    the [] operator.,operatorarray__size_type_const}
N
Niels 已提交
2952

N
Niels 已提交
2953
    @since version 1.0.0
N
Niels 已提交
2954
    */
2955
    const_reference operator[](size_type idx) const
N
cleanup  
Niels 已提交
2956 2957
    {
        // at only works for arrays
2958 2959
        if (is_array())
        {
N
Niels 已提交
2960
            assert(m_value.array != nullptr);
2961 2962 2963 2964 2965 2966
            return m_value.array->operator[](idx);
        }
        else
        {
            throw std::domain_error("cannot use operator[] with " + type_name());
        }
N
cleanup  
Niels 已提交
2967 2968
    }

N
Niels 已提交
2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981
    /*!
    @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

N
Niels 已提交
2982 2983
    @throw std::domain_error if JSON is not an object or null; example:
    `"cannot use operator[] with null"`
N
Niels 已提交
2984 2985 2986 2987 2988

    @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 已提交
2989 2990 2991 2992

    @sa @ref at(const typename object_t::key_type&) for access by reference
    with range checking
    @sa @ref value() for access by value with a default value
N
Niels 已提交
2993

N
Niels 已提交
2994
    @since version 1.0.0
N
Niels 已提交
2995
    */
2996
    reference operator[](const typename object_t::key_type& key)
N
cleanup  
Niels 已提交
2997
    {
N
Niels 已提交
2998
        // implicitly convert null to object
N
cleanup  
Niels 已提交
2999
        if (is_null())
N
Niels 已提交
3000 3001
        {
            m_type = value_t::object;
3002
            m_value.object = create<object_t>();
N
Niels 已提交
3003 3004
        }

N
Niels 已提交
3005
        // [] only works for objects
3006 3007
        if (is_object())
        {
N
Niels 已提交
3008
            assert(m_value.object != nullptr);
3009 3010 3011 3012 3013 3014
            return m_value.object->operator[](key);
        }
        else
        {
            throw std::domain_error("cannot use operator[] with " + type_name());
        }
N
cleanup  
Niels 已提交
3015 3016
    }

3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029
    /*!
    @brief read-only access specified object element

    Returns a const reference to the element at with specified key @a key. No
    bounds checking is performed.

    @warning If the element with key @a key does not exist, the behavior is
    undefined.

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

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

N
Niels 已提交
3030 3031
    @throw std::domain_error if JSON is not an object; example: `"cannot use
    operator[] with null"`
3032 3033 3034 3035 3036 3037 3038 3039 3040 3041

    @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}

    @sa @ref at(const typename object_t::key_type&) for access by reference
    with range checking
    @sa @ref value() for access by value with a default value

N
Niels 已提交
3042
    @since version 1.0.0
3043 3044 3045 3046 3047 3048
    */
    const_reference operator[](const typename object_t::key_type& key) const
    {
        // [] only works for objects
        if (is_object())
        {
N
Niels 已提交
3049 3050
            assert(m_value.object != nullptr);
            assert(m_value.object->find(key) != m_value.object->end());
3051 3052 3053 3054 3055 3056 3057 3058
            return m_value.object->find(key)->second;
        }
        else
        {
            throw std::domain_error("cannot use operator[] with " + type_name());
        }
    }

N
Niels 已提交
3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071
    /*!
    @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

N
Niels 已提交
3072 3073
    @throw std::domain_error if JSON is not an object or null; example:
    `"cannot use operator[] with null"`
N
Niels 已提交
3074 3075 3076 3077 3078

    @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 已提交
3079 3080 3081 3082

    @sa @ref at(const typename object_t::key_type&) for access by reference
    with range checking
    @sa @ref value() for access by value with a default value
N
Niels 已提交
3083

N
Niels 已提交
3084
    @since version 1.0.0
N
Niels 已提交
3085
    */
N
Niels 已提交
3086
    template<typename T, std::size_t n>
N
Niels 已提交
3087
    reference operator[](T * (&key)[n])
3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121
    {
        return operator[](static_cast<const T>(key));
    }

    /*!
    @brief read-only access specified object element

    Returns a const reference to the element at with specified key @a key. No
    bounds checking is performed.

    @warning If the element with key @a key does not exist, the behavior is
    undefined.

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

    @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; example: `"cannot use
    operator[] with 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}

    @sa @ref at(const typename object_t::key_type&) for access by reference
    with range checking
    @sa @ref value() for access by value with a default value

    @since version 1.0.0
    */
    template<typename T, std::size_t n>
N
Niels 已提交
3122
    const_reference operator[](T * (&key)[n]) const
3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155
    {
        return operator[](static_cast<const T>(key));
    }

    /*!
    @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; example:
    `"cannot use operator[] with 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}

    @sa @ref at(const typename object_t::key_type&) for access by reference
    with range checking
    @sa @ref value() for access by value with a default value

    @since version 1.0.1
    */
    template<typename T>
    reference operator[](T* key)
N
cleanup  
Niels 已提交
3156
    {
N
Niels 已提交
3157
        // implicitly convert null to object
N
cleanup  
Niels 已提交
3158
        if (is_null())
N
Niels 已提交
3159 3160
        {
            m_type = value_t::object;
N
Niels 已提交
3161
            m_value = value_t::object;
N
Niels 已提交
3162 3163
        }

N
cleanup  
Niels 已提交
3164
        // at only works for objects
3165 3166
        if (is_object())
        {
N
Niels 已提交
3167
            assert(m_value.object != nullptr);
3168 3169 3170 3171 3172 3173
            return m_value.object->operator[](key);
        }
        else
        {
            throw std::domain_error("cannot use operator[] with " + type_name());
        }
N
cleanup  
Niels 已提交
3174 3175
    }

3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188
    /*!
    @brief read-only access specified object element

    Returns a const reference to the element at with specified key @a key. No
    bounds checking is performed.

    @warning If the element with key @a key does not exist, the behavior is
    undefined.

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

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

N
Niels 已提交
3189 3190
    @throw std::domain_error if JSON is not an object; example: `"cannot use
    operator[] with null"`
3191 3192 3193 3194 3195 3196 3197 3198 3199 3200

    @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}

    @sa @ref at(const typename object_t::key_type&) for access by reference
    with range checking
    @sa @ref value() for access by value with a default value

3201
    @since version 1.0.1
3202
    */
3203 3204
    template<typename T>
    const_reference operator[](T* key) const
3205 3206 3207 3208
    {
        // at only works for objects
        if (is_object())
        {
N
Niels 已提交
3209 3210
            assert(m_value.object != nullptr);
            assert(m_value.object->find(key) != m_value.object->end());
3211 3212 3213 3214 3215 3216 3217 3218
            return m_value.object->find(key)->second;
        }
        else
        {
            throw std::domain_error("cannot use operator[] with " + type_name());
        }
    }

N
Niels 已提交
3219 3220 3221 3222 3223 3224 3225
    /*!
    @brief access specified object element with default value

    Returns either a copy of an object's element at the specified key @a key or
    a given default value if no element with key @a key exists.

    The function is basically equivalent to executing
3226
    @code {.cpp}
N
Niels 已提交
3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251
    try {
        return at(key);
    } catch(std::out_of_range) {
        return default_value;
    }
    @endcode

    @note Unlike @ref at(const typename object_t::key_type&), this function
    does not throw if the given key @a key was not found.

    @note Unlike @ref operator[](const typename object_t::key_type& key), this
    function does not implicitly add an element to the position defined by @a
    key. This function is furthermore also applicable to const objects.

    @param[in] key  key of the element to access
    @param[in] default_value  the value to return if @a key is not found

    @tparam ValueType type compatible to JSON values, for instance `int` for
    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
    JSON arrays. Note the type of the expected value at @a key and the default
    value @a default_value must be compatible.

    @return copy of the element at key @a key or @a default_value if @a key
    is not found

N
Niels 已提交
3252 3253
    @throw std::domain_error if JSON is not an object; example: `"cannot use
    value() with null"`
N
Niels 已提交
3254 3255 3256 3257 3258 3259 3260 3261 3262 3263

    @complexity Logarithmic in the size of the container.

    @liveexample{The example below shows how object elements can be queried
    with a default value.,basic_json__value}

    @sa @ref at(const typename object_t::key_type&) for access by reference
    with range checking
    @sa @ref operator[](const typename object_t::key_type&) for unchecked
    access by reference
N
Niels 已提交
3264

N
Niels 已提交
3265
    @since version 1.0.0
N
Niels 已提交
3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293
    */
    template <class ValueType, typename
              std::enable_if<
                  std::is_convertible<basic_json_t, ValueType>::value
                  , int>::type = 0>
    ValueType value(const typename object_t::key_type& key, ValueType default_value) const
    {
        // at only works for objects
        if (is_object())
        {
            // if key is found, return value and given default value otherwise
            const auto it = find(key);
            if (it != end())
            {
                return *it;
            }
            else
            {
                return default_value;
            }
        }
        else
        {
            throw std::domain_error("cannot use value() with " + type_name());
        }
    }

    /*!
N
Niels 已提交
3294
    @brief overload for a default value of type const char*
N
Niels 已提交
3295 3296 3297 3298 3299 3300 3301
    @copydoc basic_json::value()
    */
    string_t value(const typename object_t::key_type& key, const char* default_value) const
    {
        return value(key, string_t(default_value));
    }

N
Niels 已提交
3302 3303 3304 3305 3306 3307
    /*!
    @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 已提交
3308
    @return In case of a structured type (array or object), a reference to the
N
Niels 已提交
3309 3310 3311 3312 3313 3314 3315
    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 已提交
3316
    @throw std::out_of_range when called on null value
N
Niels 已提交
3317 3318

    @liveexample{The following code shows an example for @ref front.,front}
N
Niels 已提交
3319

N
Niels 已提交
3320
    @since version 1.0.0
N
Niels 已提交
3321
    */
3322
    reference front()
N
Niels 已提交
3323 3324 3325 3326
    {
        return *begin();
    }

N
Niels 已提交
3327 3328 3329
    /*!
    @copydoc basic_json::front()
    */
3330
    const_reference front() const
N
Niels 已提交
3331 3332 3333 3334
    {
        return *cbegin();
    }

N
Niels 已提交
3335 3336 3337 3338 3339 3340 3341
    /*!
    @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 已提交
3342
    @return In case of a structured type (array or object), a reference to the
N
Niels 已提交
3343 3344 3345 3346 3347 3348 3349 3350 3351 3352
    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}
N
Niels 已提交
3353

N
Niels 已提交
3354
    @since version 1.0.0
N
Niels 已提交
3355
    */
3356
    reference back()
N
Niels 已提交
3357 3358 3359 3360 3361 3362
    {
        auto tmp = end();
        --tmp;
        return *tmp;
    }

N
Niels 已提交
3363 3364 3365
    /*!
    @copydoc basic_json::back()
    */
3366
    const_reference back() const
N
Niels 已提交
3367 3368 3369 3370 3371 3372
    {
        auto tmp = cend();
        --tmp;
        return *tmp;
    }

N
Niels 已提交
3373 3374 3375 3376 3377 3378
    /*!
    @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
N
Niels 已提交
3379
    end() iterator (which is valid, but is not dereferenceable) cannot be used
N
Niels 已提交
3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390
    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

N
Niels 已提交
3391 3392
    @throw std::domain_error if called on a `null` value; example: `"cannot use
    erase() with null"`
N
Niels 已提交
3393
    @throw std::domain_error if called on an iterator which does not belong to
N
Niels 已提交
3394
    the current JSON value; example: `"iterator does not fit current value"`
N
Niels 已提交
3395
    @throw std::out_of_range if called on a primitive type with invalid
N
Niels 已提交
3396 3397
    iterator (i.e., any iterator which is not end()); example: `"iterator out
    of range"`
N
Niels 已提交
3398 3399 3400 3401 3402 3403 3404 3405 3406

    @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}
N
Niels 已提交
3407 3408 3409

    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
    given range
N
Niels 已提交
3410
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
N
Niels 已提交
3411 3412 3413 3414
    from an object at the given key
    @sa @ref erase(const size_type) -- removes the element from an array at the
    given index

N
Niels 已提交
3415
    @since version 1.0.0
N
Niels 已提交
3416 3417
    */
    template <class InteratorType, typename
3418
              std::enable_if<
N
Niels 已提交
3419 3420
                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
3421 3422
                  , int>::type
              = 0>
N
Niels 已提交
3423
    InteratorType erase(InteratorType pos)
3424 3425
    {
        // make sure iterator fits the current value
N
Niels 已提交
3426
        if (this != pos.m_object)
3427
        {
N
Niels 已提交
3428
            throw std::domain_error("iterator does not fit current value");
3429 3430
        }

N
Niels 已提交
3431
        InteratorType result = end();
3432 3433 3434 3435

        switch (m_type)
        {
            case value_t::boolean:
3436 3437
            case value_t::number_float:
            case value_t::number_integer:
3438 3439
            case value_t::string:
            {
3440
                if (not pos.m_it.primitive_iterator.is_begin())
3441 3442 3443 3444
                {
                    throw std::out_of_range("iterator out of range");
                }

N
cleanup  
Niels 已提交
3445
                if (is_string())
3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456
                {
                    delete m_value.string;
                    m_value.string = nullptr;
                }

                m_type = value_t::null;
                break;
            }

            case value_t::object:
            {
N
Niels 已提交
3457
                assert(m_value.object != nullptr);
3458 3459 3460 3461 3462 3463
                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
                break;
            }

            case value_t::array:
            {
N
Niels 已提交
3464
                assert(m_value.array != nullptr);
3465 3466 3467 3468 3469 3470
                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
                break;
            }

            default:
            {
N
Niels 已提交
3471
                throw std::domain_error("cannot use erase() with " + type_name());
3472 3473 3474 3475 3476 3477
            }
        }

        return result;
    }

N
Niels 已提交
3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495
    /*!
    @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

N
Niels 已提交
3496 3497
    @throw std::domain_error if called on a `null` value; example: `"cannot use
    erase() with null"`
N
Niels 已提交
3498
    @throw std::domain_error if called on iterators which does not belong to
N
Niels 已提交
3499
    the current JSON value; example: `"iterators do not fit current value"`
N
Niels 已提交
3500
    @throw std::out_of_range if called on a primitive type with invalid
N
Niels 已提交
3501 3502
    iterators (i.e., if `first != begin()` and `last != end()`); example:
    `"iterators out of range"`
N
Niels 已提交
3503 3504 3505 3506 3507 3508 3509 3510 3511 3512

    @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}
N
Niels 已提交
3513 3514

    @sa @ref erase(InteratorType) -- removes the element at a given position
N
Niels 已提交
3515
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
N
Niels 已提交
3516 3517 3518 3519
    from an object at the given key
    @sa @ref erase(const size_type) -- removes the element from an array at the
    given index

N
Niels 已提交
3520
    @since version 1.0.0
N
Niels 已提交
3521 3522
    */
    template <class InteratorType, typename
3523
              std::enable_if<
N
Niels 已提交
3524 3525
                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
3526 3527
                  , int>::type
              = 0>
N
Niels 已提交
3528
    InteratorType erase(InteratorType first, InteratorType last)
3529 3530
    {
        // make sure iterator fits the current value
N
Niels 已提交
3531
        if (this != first.m_object or this != last.m_object)
3532
        {
N
Niels 已提交
3533
            throw std::domain_error("iterators do not fit current value");
3534 3535
        }

N
Niels 已提交
3536
        InteratorType result = end();
3537 3538 3539 3540

        switch (m_type)
        {
            case value_t::boolean:
3541 3542
            case value_t::number_float:
            case value_t::number_integer:
3543 3544
            case value_t::string:
            {
3545
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
3546 3547 3548 3549
                {
                    throw std::out_of_range("iterators out of range");
                }

N
cleanup  
Niels 已提交
3550
                if (is_string())
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561
                {
                    delete m_value.string;
                    m_value.string = nullptr;
                }

                m_type = value_t::null;
                break;
            }

            case value_t::object:
            {
N
Niels 已提交
3562
                assert(m_value.object != nullptr);
3563 3564 3565 3566 3567 3568 3569
                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
                                              last.m_it.object_iterator);
                break;
            }

            case value_t::array:
            {
N
Niels 已提交
3570
                assert(m_value.array != nullptr);
3571 3572 3573 3574 3575 3576 3577
                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
                                             last.m_it.array_iterator);
                break;
            }

            default:
            {
N
Niels 已提交
3578
                throw std::domain_error("cannot use erase() with " + type_name());
3579 3580 3581 3582 3583 3584
            }
        }

        return result;
    }

N
Niels 已提交
3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595
    /*!
    @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).

N
Niels 已提交
3596 3597
    @throw std::domain_error when called on a type other than JSON object;
    example: `"cannot use erase() with null"`
N
Niels 已提交
3598 3599 3600 3601

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

    @liveexample{The example shows the effect of erase.,erase__key_type}
N
Niels 已提交
3602 3603 3604 3605 3606 3607 3608

    @sa @ref erase(InteratorType) -- removes the element at a given position
    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
    given range
    @sa @ref erase(const size_type) -- removes the element from an array at the
    given index

N
Niels 已提交
3609
    @since version 1.0.0
N
Niels 已提交
3610
    */
3611
    size_type erase(const typename object_t::key_type& key)
3612
    {
N
Niels 已提交
3613
        // this erase only works for objects
3614 3615
        if (is_object())
        {
N
Niels 已提交
3616
            assert(m_value.object != nullptr);
3617 3618 3619 3620 3621 3622
            return m_value.object->erase(key);
        }
        else
        {
            throw std::domain_error("cannot use erase() with " + type_name());
        }
3623 3624
    }

N
Niels 已提交
3625 3626 3627 3628 3629 3630 3631
    /*!
    @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

N
Niels 已提交
3632 3633 3634 3635
    @throw std::domain_error when called on a type other than JSON array;
    example: `"cannot use erase() with null"`
    @throw std::out_of_range when `idx >= size()`; example: `"index out of
    range"`
N
Niels 已提交
3636 3637 3638 3639

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

    @liveexample{The example shows the effect of erase.,erase__size_type}
N
Niels 已提交
3640 3641 3642 3643

    @sa @ref erase(InteratorType) -- removes the element at a given position
    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
    given range
N
Niels 已提交
3644
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
N
Niels 已提交
3645 3646
    from an object at the given key

N
Niels 已提交
3647
    @since version 1.0.0
N
Niels 已提交
3648
    */
3649
    void erase(const size_type idx)
N
Niels 已提交
3650 3651
    {
        // this erase only works for arrays
N
cleanup  
Niels 已提交
3652
        if (is_array())
N
Niels 已提交
3653
        {
N
cleanup  
Niels 已提交
3654 3655 3656 3657
            if (idx >= size())
            {
                throw std::out_of_range("index out of range");
            }
N
Niels 已提交
3658

N
Niels 已提交
3659
            assert(m_value.array != nullptr);
N
cleanup  
Niels 已提交
3660 3661 3662
            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
        }
        else
N
Niels 已提交
3663
        {
N
cleanup  
Niels 已提交
3664
            throw std::domain_error("cannot use erase() with " + type_name());
N
Niels 已提交
3665 3666 3667
        }
    }

N
Niels 已提交
3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681
    /*!
    @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}
N
Niels 已提交
3682

N
Niels 已提交
3683
    @since version 1.0.0
N
Niels 已提交
3684
    */
3685
    iterator find(typename object_t::key_type key)
N
Niels 已提交
3686 3687 3688
    {
        auto result = end();

N
cleanup  
Niels 已提交
3689
        if (is_object())
N
Niels 已提交
3690
        {
N
Niels 已提交
3691
            assert(m_value.object != nullptr);
N
Niels 已提交
3692 3693 3694 3695 3696 3697
            result.m_it.object_iterator = m_value.object->find(key);
        }

        return result;
    }

N
Niels 已提交
3698 3699 3700 3701
    /*!
    @brief find an element in a JSON object
    @copydoc find(typename object_t::key_type)
    */
3702
    const_iterator find(typename object_t::key_type key) const
N
Niels 已提交
3703 3704 3705
    {
        auto result = cend();

N
cleanup  
Niels 已提交
3706
        if (is_object())
N
Niels 已提交
3707
        {
N
Niels 已提交
3708
            assert(m_value.object != nullptr);
N
Niels 已提交
3709 3710 3711 3712 3713 3714
            result.m_it.object_iterator = m_value.object->find(key);
        }

        return result;
    }

N
Niels 已提交
3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729
    /*!
    @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}
N
Niels 已提交
3730

N
Niels 已提交
3731
    @since version 1.0.0
N
Niels 已提交
3732
    */
3733
    size_type count(typename object_t::key_type key) const
3734 3735
    {
        // return 0 for all nonobject types
N
Niels 已提交
3736
        assert(not is_object() or m_value.object != nullptr);
N
Niels 已提交
3737
        return is_object() ? m_value.object->count(key) : 0;
3738 3739
    }

N
Niels 已提交
3740 3741
    /// @}

N
Niels 已提交
3742

N
cleanup  
Niels 已提交
3743 3744 3745 3746
    ///////////////
    // iterators //
    ///////////////

N
Niels 已提交
3747 3748 3749
    /// @name iterators
    /// @{

N
Niels 已提交
3750 3751
    /*!
    @brief returns an iterator to the first element
N
Niels 已提交
3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764

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

N
Niels 已提交
3766
    @since version 1.0.0
N
Niels 已提交
3767
    */
N
Niels 已提交
3768
    iterator begin()
N
cleanup  
Niels 已提交
3769 3770 3771 3772 3773 3774
    {
        iterator result(this);
        result.set_begin();
        return result;
    }

N
Niels 已提交
3775
    /*!
N
Niels 已提交
3776
    @copydoc basic_json::cbegin()
N
Niels 已提交
3777
    */
N
Niels 已提交
3778
    const_iterator begin() const
N
cleanup  
Niels 已提交
3779
    {
N
Niels 已提交
3780
        return cbegin();
N
cleanup  
Niels 已提交
3781 3782
    }

N
Niels 已提交
3783 3784
    /*!
    @brief returns a const iterator to the first element
N
Niels 已提交
3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798

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

N
Niels 已提交
3800
    @since version 1.0.0
N
Niels 已提交
3801
    */
N
Niels 已提交
3802
    const_iterator cbegin() const
N
cleanup  
Niels 已提交
3803 3804 3805 3806 3807 3808
    {
        const_iterator result(this);
        result.set_begin();
        return result;
    }

N
Niels 已提交
3809 3810
    /*!
    @brief returns an iterator to one past the last element
N
Niels 已提交
3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823

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

N
Niels 已提交
3825
    @since version 1.0.0
N
Niels 已提交
3826
    */
N
Niels 已提交
3827
    iterator end()
N
cleanup  
Niels 已提交
3828 3829 3830 3831 3832 3833
    {
        iterator result(this);
        result.set_end();
        return result;
    }

N
Niels 已提交
3834
    /*!
N
Niels 已提交
3835
    @copydoc basic_json::cend()
N
Niels 已提交
3836
    */
N
Niels 已提交
3837
    const_iterator end() const
N
cleanup  
Niels 已提交
3838
    {
N
Niels 已提交
3839
        return cend();
N
cleanup  
Niels 已提交
3840 3841
    }

N
Niels 已提交
3842 3843
    /*!
    @brief returns a const iterator to one past the last element
N
Niels 已提交
3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857

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

N
Niels 已提交
3859
    @since version 1.0.0
N
Niels 已提交
3860
    */
N
Niels 已提交
3861
    const_iterator cend() const
N
cleanup  
Niels 已提交
3862 3863 3864 3865 3866 3867
    {
        const_iterator result(this);
        result.set_end();
        return result;
    }

N
Niels 已提交
3868
    /*!
N
Niels 已提交
3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881
    @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 已提交
3882

N
Niels 已提交
3883
    @since version 1.0.0
N
Niels 已提交
3884
    */
N
Niels 已提交
3885
    reverse_iterator rbegin()
N
Niels 已提交
3886 3887 3888 3889
    {
        return reverse_iterator(end());
    }

N
Niels 已提交
3890
    /*!
N
Niels 已提交
3891
    @copydoc basic_json::crbegin()
N
Niels 已提交
3892
    */
N
Niels 已提交
3893
    const_reverse_iterator rbegin() const
N
Niels 已提交
3894
    {
N
Niels 已提交
3895
        return crbegin();
N
Niels 已提交
3896 3897
    }

N
Niels 已提交
3898
    /*!
N
Niels 已提交
3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912
    @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 已提交
3913

N
Niels 已提交
3914
    @since version 1.0.0
N
Niels 已提交
3915
    */
N
Niels 已提交
3916
    reverse_iterator rend()
N
Niels 已提交
3917 3918 3919 3920
    {
        return reverse_iterator(begin());
    }

N
Niels 已提交
3921
    /*!
N
Niels 已提交
3922
    @copydoc basic_json::crend()
N
Niels 已提交
3923
    */
N
Niels 已提交
3924
    const_reverse_iterator rend() const
N
Niels 已提交
3925
    {
N
Niels 已提交
3926
        return crend();
N
Niels 已提交
3927 3928
    }

N
Niels 已提交
3929
    /*!
N
Niels 已提交
3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943
    @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 已提交
3944

N
Niels 已提交
3945
    @since version 1.0.0
N
Niels 已提交
3946
    */
N
Niels 已提交
3947
    const_reverse_iterator crbegin() const
N
Niels 已提交
3948 3949 3950 3951
    {
        return const_reverse_iterator(cend());
    }

N
Niels 已提交
3952
    /*!
N
Niels 已提交
3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966
    @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 已提交
3967

N
Niels 已提交
3968
    @since version 1.0.0
N
Niels 已提交
3969
    */
N
Niels 已提交
3970
    const_reverse_iterator crend() const
N
Niels 已提交
3971 3972 3973 3974
    {
        return const_reverse_iterator(cbegin());
    }

N
cleanup  
Niels 已提交
3975 3976 3977 3978 3979 3980 3981 3982
  private:
    // forward declaration
    template<typename IteratorType> class iteration_proxy;

  public:
    /*!
    @brief wrapper to access iterator member functions in range-based for

N
Niels 已提交
3983
    This function allows to access @ref iterator::key() and @ref
N
cleanup  
Niels 已提交
3984 3985 3986
    iterator::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.
N
cleanup  
Niels 已提交
3987 3988 3989

    @note The name of this function is not yet final and may change in the
    future.
N
cleanup  
Niels 已提交
3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003
    */
    static iteration_proxy<iterator> iterator_wrapper(reference cont)
    {
        return iteration_proxy<iterator>(cont);
    }

    /*!
    @copydoc iterator_wrapper(reference)
    */
    static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont)
    {
        return iteration_proxy<const_iterator>(cont);
    }

N
Niels 已提交
4004 4005
    /// @}

N
cleanup  
Niels 已提交
4006 4007 4008 4009 4010

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

N
Niels 已提交
4011 4012 4013
    /// @name capacity
    /// @{

N
Niels 已提交
4014 4015
    /*!
    @brief checks whether the container is empty
N
Niels 已提交
4016 4017 4018

    Checks if a JSON value has no elements.

N
Niels 已提交
4019
    @return The return value depends on the different types and is
N
Niels 已提交
4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030
            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
N
Niels 已提交
4031 4032
    Container concept; that is, their empty() functions have constant
    complexity.
N
Niels 已提交
4033 4034 4035 4036 4037 4038 4039

    @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 已提交
4040

N
Niels 已提交
4041
    @since version 1.0.0
N
Niels 已提交
4042
    */
4043
    bool empty() const noexcept
N
cleanup  
Niels 已提交
4044 4045 4046
    {
        switch (m_type)
        {
4047
            case value_t::null:
N
cleanup  
Niels 已提交
4048
            {
N
Niels 已提交
4049
                // null values are empty
N
cleanup  
Niels 已提交
4050 4051
                return true;
            }
N
Niels 已提交
4052

4053
            case value_t::array:
N
cleanup  
Niels 已提交
4054
            {
N
Niels 已提交
4055
                assert(m_value.array != nullptr);
N
cleanup  
Niels 已提交
4056 4057
                return m_value.array->empty();
            }
N
Niels 已提交
4058

4059
            case value_t::object:
N
cleanup  
Niels 已提交
4060
            {
N
Niels 已提交
4061
                assert(m_value.object != nullptr);
N
cleanup  
Niels 已提交
4062 4063
                return m_value.object->empty();
            }
N
Niels 已提交
4064

N
Niels 已提交
4065 4066 4067 4068 4069 4070
            default:
            {
                // all other types are nonempty
                return false;
            }
        }
N
cleanup  
Niels 已提交
4071 4072
    }

N
Niels 已提交
4073 4074
    /*!
    @brief returns the number of elements
N
Niels 已提交
4075 4076 4077

    Returns the number of elements in a JSON value.

N
Niels 已提交
4078
    @return The return value depends on the different types and is
N
Niels 已提交
4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089
            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
N
Niels 已提交
4090
    Container concept; that is, their size() functions have constant complexity.
N
Niels 已提交
4091 4092 4093 4094 4095 4096 4097

    @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 已提交
4098

N
Niels 已提交
4099
    @since version 1.0.0
N
Niels 已提交
4100
    */
4101
    size_type size() const noexcept
N
cleanup  
Niels 已提交
4102 4103 4104
    {
        switch (m_type)
        {
4105
            case value_t::null:
N
cleanup  
Niels 已提交
4106
            {
N
Niels 已提交
4107
                // null values are empty
N
cleanup  
Niels 已提交
4108 4109
                return 0;
            }
N
Niels 已提交
4110

4111
            case value_t::array:
N
cleanup  
Niels 已提交
4112
            {
N
Niels 已提交
4113
                assert(m_value.array != nullptr);
N
cleanup  
Niels 已提交
4114 4115
                return m_value.array->size();
            }
N
Niels 已提交
4116

4117
            case value_t::object:
N
cleanup  
Niels 已提交
4118
            {
N
Niels 已提交
4119
                assert(m_value.object != nullptr);
N
cleanup  
Niels 已提交
4120 4121
                return m_value.object->size();
            }
N
Niels 已提交
4122

N
Niels 已提交
4123 4124 4125 4126 4127 4128
            default:
            {
                // all other types have size 1
                return 1;
            }
        }
N
cleanup  
Niels 已提交
4129 4130
    }

N
Niels 已提交
4131 4132
    /*!
    @brief returns the maximum possible number of elements
N
Niels 已提交
4133 4134 4135 4136 4137

    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 已提交
4138
    @return The return value depends on the different types and is
N
Niels 已提交
4139 4140 4141
            defined as follows:
            Value type  | return value
            ----------- | -------------
4142 4143 4144 4145
            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 已提交
4146 4147 4148 4149
            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
N
Niels 已提交
4150 4151
    Container concept; that is, their max_size() functions have constant
    complexity.
N
Niels 已提交
4152 4153 4154 4155 4156 4157 4158 4159

    @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 已提交
4160

N
Niels 已提交
4161
    @since version 1.0.0
N
Niels 已提交
4162
    */
4163
    size_type max_size() const noexcept
N
cleanup  
Niels 已提交
4164 4165 4166
    {
        switch (m_type)
        {
4167
            case value_t::array:
N
cleanup  
Niels 已提交
4168
            {
N
Niels 已提交
4169
                assert(m_value.array != nullptr);
N
cleanup  
Niels 已提交
4170 4171
                return m_value.array->max_size();
            }
N
Niels 已提交
4172

4173
            case value_t::object:
N
cleanup  
Niels 已提交
4174
            {
N
Niels 已提交
4175
                assert(m_value.object != nullptr);
N
cleanup  
Niels 已提交
4176 4177
                return m_value.object->max_size();
            }
N
Niels 已提交
4178

N
Niels 已提交
4179 4180
            default:
            {
4181 4182
                // all other types have max_size() == size()
                return size();
N
Niels 已提交
4183 4184
            }
        }
N
cleanup  
Niels 已提交
4185 4186
    }

N
Niels 已提交
4187 4188
    /// @}

N
cleanup  
Niels 已提交
4189 4190 4191 4192 4193

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

N
Niels 已提交
4194 4195 4196
    /// @name modifiers
    /// @{

N
Niels 已提交
4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217
    /*!
    @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 已提交
4218
    JSON types.,clear}
N
Niels 已提交
4219

N
Niels 已提交
4220
    @since version 1.0.0
N
Niels 已提交
4221
    */
4222
    void clear() noexcept
N
cleanup  
Niels 已提交
4223 4224 4225
    {
        switch (m_type)
        {
4226
            case value_t::number_integer:
N
cleanup  
Niels 已提交
4227
            {
N
Niels 已提交
4228
                m_value.number_integer = 0;
N
cleanup  
Niels 已提交
4229 4230
                break;
            }
N
Niels 已提交
4231

4232
            case value_t::number_float:
N
cleanup  
Niels 已提交
4233
            {
N
Niels 已提交
4234
                m_value.number_float = 0.0;
N
cleanup  
Niels 已提交
4235 4236
                break;
            }
N
Niels 已提交
4237

4238
            case value_t::boolean:
N
cleanup  
Niels 已提交
4239
            {
N
Niels 已提交
4240
                m_value.boolean = false;
N
cleanup  
Niels 已提交
4241 4242
                break;
            }
N
Niels 已提交
4243

4244
            case value_t::string:
N
cleanup  
Niels 已提交
4245
            {
N
Niels 已提交
4246
                assert(m_value.string != nullptr);
N
cleanup  
Niels 已提交
4247 4248 4249
                m_value.string->clear();
                break;
            }
N
Niels 已提交
4250

4251
            case value_t::array:
N
cleanup  
Niels 已提交
4252
            {
N
Niels 已提交
4253
                assert(m_value.array != nullptr);
N
cleanup  
Niels 已提交
4254 4255 4256
                m_value.array->clear();
                break;
            }
N
Niels 已提交
4257

4258
            case value_t::object:
N
cleanup  
Niels 已提交
4259
            {
N
Niels 已提交
4260
                assert(m_value.object != nullptr);
N
cleanup  
Niels 已提交
4261 4262 4263
                m_value.object->clear();
                break;
            }
4264 4265 4266 4267 4268

            default:
            {
                break;
            }
N
cleanup  
Niels 已提交
4269 4270 4271
        }
    }

4272 4273 4274
    /*!
    @brief add an object to an array

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

4279
    @param val the value to add to the JSON array
4280

N
Niels 已提交
4281 4282
    @throw std::domain_error when called on a type other than JSON array or
    null; example: `"cannot use push_back() with number"`
4283 4284 4285 4286 4287 4288

    @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}
N
Niels 已提交
4289

N
Niels 已提交
4290
    @since version 1.0.0
4291
    */
4292
    void push_back(basic_json&& val)
N
cleanup  
Niels 已提交
4293 4294
    {
        // push_back only works for null objects or arrays
N
cleanup  
Niels 已提交
4295
        if (not(is_null() or is_array()))
N
cleanup  
Niels 已提交
4296
        {
N
Niels 已提交
4297
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
4298 4299 4300
        }

        // transform null object into an array
N
cleanup  
Niels 已提交
4301
        if (is_null())
N
cleanup  
Niels 已提交
4302 4303
        {
            m_type = value_t::array;
N
Niels 已提交
4304
            m_value = value_t::array;
N
cleanup  
Niels 已提交
4305 4306 4307
        }

        // add element to array (move semantics)
N
Niels 已提交
4308
        assert(m_value.array != nullptr);
4309
        m_value.array->push_back(std::move(val));
N
cleanup  
Niels 已提交
4310
        // invalidate object
4311
        val.m_type = value_t::null;
N
cleanup  
Niels 已提交
4312 4313
    }

4314 4315 4316 4317
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
4318
    reference operator+=(basic_json&& val)
N
Niels 已提交
4319
    {
4320
        push_back(std::move(val));
N
Niels 已提交
4321 4322 4323
        return *this;
    }

4324 4325 4326 4327
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
4328
    void push_back(const basic_json& val)
N
cleanup  
Niels 已提交
4329 4330
    {
        // push_back only works for null objects or arrays
N
cleanup  
Niels 已提交
4331
        if (not(is_null() or is_array()))
N
cleanup  
Niels 已提交
4332
        {
N
Niels 已提交
4333
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
4334 4335 4336
        }

        // transform null object into an array
N
cleanup  
Niels 已提交
4337
        if (is_null())
N
cleanup  
Niels 已提交
4338 4339
        {
            m_type = value_t::array;
N
Niels 已提交
4340
            m_value = value_t::array;
N
cleanup  
Niels 已提交
4341 4342 4343
        }

        // add element to array
N
Niels 已提交
4344
        assert(m_value.array != nullptr);
4345
        m_value.array->push_back(val);
N
cleanup  
Niels 已提交
4346 4347
    }

4348 4349 4350 4351
    /*!
    @brief add an object to an array
    @copydoc push_back(basic_json&&)
    */
4352
    reference operator+=(const basic_json& val)
N
cleanup  
Niels 已提交
4353
    {
4354
        push_back(val);
N
cleanup  
Niels 已提交
4355 4356 4357
        return *this;
    }

4358 4359 4360
    /*!
    @brief add an object to an object

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

4365
    @param[in] val the value to add to the JSON object
4366 4367

    @throw std::domain_error when called on a type other than JSON object or
N
Niels 已提交
4368
    null; example: `"cannot use push_back() with number"`
4369 4370 4371 4372 4373 4374

    @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}
N
Niels 已提交
4375

N
Niels 已提交
4376
    @since version 1.0.0
4377
    */
4378
    void push_back(const typename object_t::value_type& val)
N
cleanup  
Niels 已提交
4379 4380
    {
        // push_back only works for null objects or objects
N
cleanup  
Niels 已提交
4381
        if (not(is_null() or is_object()))
N
cleanup  
Niels 已提交
4382
        {
N
Niels 已提交
4383
            throw std::domain_error("cannot use push_back() with " + type_name());
N
cleanup  
Niels 已提交
4384 4385 4386
        }

        // transform null object into an object
N
cleanup  
Niels 已提交
4387
        if (is_null())
N
cleanup  
Niels 已提交
4388 4389
        {
            m_type = value_t::object;
N
Niels 已提交
4390
            m_value = value_t::object;
N
cleanup  
Niels 已提交
4391 4392 4393
        }

        // add element to array
N
Niels 已提交
4394
        assert(m_value.object != nullptr);
4395
        m_value.object->insert(val);
N
cleanup  
Niels 已提交
4396 4397
    }

4398 4399 4400 4401
    /*!
    @brief add an object to an object
    @copydoc push_back(const typename object_t::value_type&)
    */
4402
    reference operator+=(const typename object_t::value_type& val)
N
cleanup  
Niels 已提交
4403
    {
4404 4405
        push_back(val);
        return operator[](val.first);
N
cleanup  
Niels 已提交
4406 4407
    }

N
Niels 已提交
4408 4409 4410
    /*!
    @brief inserts element

4411
    Inserts element @a val before iterator @a pos.
N
Niels 已提交
4412 4413 4414

    @param[in] pos iterator before which the content will be inserted; may be
    the end() iterator
4415 4416
    @param[in] val element to insert
    @return iterator pointing to the inserted @a val.
N
Niels 已提交
4417

N
Niels 已提交
4418 4419
    @throw std::domain_error if called on JSON values other than arrays;
    example: `"cannot use insert() with string"`
N
Niels 已提交
4420 4421
    @throw std::domain_error if @a pos is not an iterator of *this; example:
    `"iterator does not fit current value"`
N
Niels 已提交
4422 4423 4424 4425 4426

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

    @liveexample{The example shows how insert is used.,insert}
N
Niels 已提交
4427

N
Niels 已提交
4428
    @since version 1.0.0
N
Niels 已提交
4429
    */
4430
    iterator insert(const_iterator pos, const basic_json& val)
N
Niels 已提交
4431 4432
    {
        // insert only works for arrays
N
cleanup  
Niels 已提交
4433
        if (is_array())
N
Niels 已提交
4434
        {
N
cleanup  
Niels 已提交
4435 4436 4437 4438 4439
            // check if iterator pos fits to this JSON value
            if (pos.m_object != this)
            {
                throw std::domain_error("iterator does not fit current value");
            }
N
Niels 已提交
4440

N
cleanup  
Niels 已提交
4441 4442
            // insert to array and return iterator
            iterator result(this);
N
Niels 已提交
4443
            assert(m_value.array != nullptr);
4444
            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
N
cleanup  
Niels 已提交
4445 4446 4447
            return result;
        }
        else
N
Niels 已提交
4448
        {
N
cleanup  
Niels 已提交
4449
            throw std::domain_error("cannot use insert() with " + type_name());
N
Niels 已提交
4450 4451 4452 4453 4454 4455 4456
        }
    }

    /*!
    @brief inserts element
    @copydoc insert(const_iterator, const basic_json&)
    */
4457
    iterator insert(const_iterator pos, basic_json&& val)
N
Niels 已提交
4458
    {
4459
        return insert(pos, val);
N
Niels 已提交
4460 4461 4462 4463 4464
    }

    /*!
    @brief inserts elements

4465
    Inserts @a cnt copies of @a val before iterator @a pos.
N
Niels 已提交
4466 4467 4468

    @param[in] pos iterator before which the content will be inserted; may be
    the end() iterator
4469 4470
    @param[in] cnt number of copies of @a val to insert
    @param[in] val element to insert
N
Niels 已提交
4471
    @return iterator pointing to the first element inserted, or @a pos if
4472
    `cnt==0`
N
Niels 已提交
4473

N
Niels 已提交
4474 4475
    @throw std::domain_error if called on JSON values other than arrays;
    example: `"cannot use insert() with string"`
N
Niels 已提交
4476 4477
    @throw std::domain_error if @a pos is not an iterator of *this; example:
    `"iterator does not fit current value"`
N
Niels 已提交
4478

4479
    @complexity Linear in @a cnt plus linear in the distance between @a pos
N
Niels 已提交
4480 4481 4482
    and end of the container.

    @liveexample{The example shows how insert is used.,insert__count}
N
Niels 已提交
4483

N
Niels 已提交
4484
    @since version 1.0.0
N
Niels 已提交
4485
    */
4486
    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
N
Niels 已提交
4487 4488
    {
        // insert only works for arrays
N
cleanup  
Niels 已提交
4489
        if (is_array())
N
Niels 已提交
4490
        {
N
cleanup  
Niels 已提交
4491 4492 4493 4494 4495
            // check if iterator pos fits to this JSON value
            if (pos.m_object != this)
            {
                throw std::domain_error("iterator does not fit current value");
            }
N
Niels 已提交
4496

N
cleanup  
Niels 已提交
4497 4498
            // insert to array and return iterator
            iterator result(this);
N
Niels 已提交
4499
            assert(m_value.array != nullptr);
4500
            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
N
cleanup  
Niels 已提交
4501 4502 4503
            return result;
        }
        else
N
Niels 已提交
4504
        {
N
cleanup  
Niels 已提交
4505
            throw std::domain_error("cannot use insert() with " + type_name());
N
Niels 已提交
4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518
        }
    }

    /*!
    @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

N
Niels 已提交
4519 4520
    @throw std::domain_error if called on JSON values other than arrays;
    example: `"cannot use insert() with string"`
N
Niels 已提交
4521 4522
    @throw std::domain_error if @a pos is not an iterator of *this; example:
    `"iterator does not fit current value"`
N
Niels 已提交
4523
    @throw std::domain_error if @a first and @a last do not belong to the same
N
Niels 已提交
4524
    JSON value; example: `"iterators do not fit"`
N
Niels 已提交
4525
    @throw std::domain_error if @a first or @a last are iterators into
N
Niels 已提交
4526 4527 4528
    container for which insert is called; example: `"passed iterators may not
    belong to container"`

N
Niels 已提交
4529 4530 4531 4532 4533 4534 4535
    @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}
N
Niels 已提交
4536

N
Niels 已提交
4537
    @since version 1.0.0
N
Niels 已提交
4538 4539 4540 4541
    */
    iterator insert(const_iterator pos, const_iterator first, const_iterator last)
    {
        // insert only works for arrays
N
cleanup  
Niels 已提交
4542
        if (not is_array())
N
Niels 已提交
4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554
        {
            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)
        {
N
Niels 已提交
4555
            throw std::domain_error("iterators do not fit");
N
Niels 已提交
4556 4557 4558 4559 4560 4561 4562 4563 4564
        }

        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);
N
Niels 已提交
4565
        assert(m_value.array != nullptr);
N
Niels 已提交
4566 4567 4568 4569
        result.m_it.array_iterator = m_value.array->insert(
                                         pos.m_it.array_iterator,
                                         first.m_it.array_iterator,
                                         last.m_it.array_iterator);
N
Niels 已提交
4570 4571 4572
        return result;
    }

N
Niels 已提交
4573 4574 4575 4576 4577 4578 4579 4580 4581
    /*!
    @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

N
Niels 已提交
4582 4583
    @throw std::domain_error if called on JSON values other than arrays;
    example: `"cannot use insert() with string"`
N
Niels 已提交
4584 4585
    @throw std::domain_error if @a pos is not an iterator of *this; example:
    `"iterator does not fit current value"`
N
Niels 已提交
4586

N
Niels 已提交
4587 4588 4589 4590 4591 4592 4593
    @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}
N
Niels 已提交
4594

N
Niels 已提交
4595
    @since version 1.0.0
N
Niels 已提交
4596 4597 4598 4599
    */
    iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
    {
        // insert only works for arrays
N
cleanup  
Niels 已提交
4600
        if (not is_array())
N
Niels 已提交
4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612
        {
            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);
N
Niels 已提交
4613
        assert(m_value.array != nullptr);
N
Niels 已提交
4614 4615 4616 4617
        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
        return result;
    }

N
Niels 已提交
4618 4619
    /*!
    @brief exchanges the values
N
Niels 已提交
4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631

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

N
Niels 已提交
4633
    @since version 1.0.0
N
Niels 已提交
4634
    */
4635
    void swap(reference other) noexcept (
N
Niels 已提交
4636 4637 4638 4639 4640
        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 已提交
4641 4642 4643 4644 4645
    {
        std::swap(m_type, other.m_type);
        std::swap(m_value, other.m_value);
    }

N
Niels 已提交
4646 4647 4648 4649 4650 4651 4652 4653 4654 4655
    /*!
    @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

N
Niels 已提交
4656 4657
    @throw std::domain_error when JSON value is not an array; example: `"cannot
    use swap() with string"`
N
Niels 已提交
4658 4659 4660 4661 4662

    @complexity Constant.

    @liveexample{The example below shows how JSON values can be
    swapped.,swap__array_t}
N
Niels 已提交
4663

N
Niels 已提交
4664
    @since version 1.0.0
N
Niels 已提交
4665
    */
4666
    void swap(array_t& other)
N
cleanup  
Niels 已提交
4667 4668
    {
        // swap only works for arrays
N
cleanup  
Niels 已提交
4669 4670
        if (is_array())
        {
N
Niels 已提交
4671
            assert(m_value.array != nullptr);
N
cleanup  
Niels 已提交
4672 4673 4674
            std::swap(*(m_value.array), other);
        }
        else
N
cleanup  
Niels 已提交
4675
        {
N
Niels 已提交
4676
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
4677 4678 4679
        }
    }

4680 4681 4682 4683 4684 4685 4686 4687 4688 4689
    /*!
    @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

N
Niels 已提交
4690 4691
    @throw std::domain_error when JSON value is not an object; example:
    `"cannot use swap() with string"`
4692 4693 4694 4695 4696

    @complexity Constant.

    @liveexample{The example below shows how JSON values can be
    swapped.,swap__object_t}
N
Niels 已提交
4697

N
Niels 已提交
4698
    @since version 1.0.0
4699
    */
4700
    void swap(object_t& other)
N
cleanup  
Niels 已提交
4701 4702
    {
        // swap only works for objects
N
cleanup  
Niels 已提交
4703 4704
        if (is_object())
        {
N
Niels 已提交
4705
            assert(m_value.object != nullptr);
N
cleanup  
Niels 已提交
4706 4707 4708
            std::swap(*(m_value.object), other);
        }
        else
N
cleanup  
Niels 已提交
4709
        {
N
Niels 已提交
4710
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
4711 4712 4713
        }
    }

4714 4715 4716 4717 4718 4719 4720 4721 4722 4723
    /*!
    @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

N
Niels 已提交
4724 4725
    @throw std::domain_error when JSON value is not a string; example: `"cannot
    use swap() with boolean"`
4726 4727 4728 4729 4730

    @complexity Constant.

    @liveexample{The example below shows how JSON values can be
    swapped.,swap__string_t}
N
Niels 已提交
4731

N
Niels 已提交
4732
    @since version 1.0.0
4733
    */
4734
    void swap(string_t& other)
N
cleanup  
Niels 已提交
4735 4736
    {
        // swap only works for strings
N
cleanup  
Niels 已提交
4737 4738
        if (is_string())
        {
N
Niels 已提交
4739
            assert(m_value.string != nullptr);
N
cleanup  
Niels 已提交
4740 4741 4742
            std::swap(*(m_value.string), other);
        }
        else
N
cleanup  
Niels 已提交
4743
        {
N
Niels 已提交
4744
            throw std::domain_error("cannot use swap() with " + type_name());
N
cleanup  
Niels 已提交
4745 4746 4747
        }
    }

N
Niels 已提交
4748 4749
    /// @}

N
cleanup  
Niels 已提交
4750 4751 4752 4753 4754

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

N
Niels 已提交
4755 4756 4757
    /// @name lexicographical comparison operators
    /// @{

N
Niels 已提交
4758 4759 4760 4761 4762 4763 4764
  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
N
Niels 已提交
4765

N
Niels 已提交
4766
    @since version 1.0.0
N
Niels 已提交
4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790
    */
    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 已提交
4791 4792
    /*!
    @brief comparison: equal
N
Niels 已提交
4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808

    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.

4809 4810
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__equal}
N
Niels 已提交
4811

N
Niels 已提交
4812
    @since version 1.0.0
N
Niels 已提交
4813
    */
N
Niels 已提交
4814
    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4815
    {
F
Florian Weber 已提交
4816 4817
        const auto lhs_type = lhs.type();
        const auto rhs_type = rhs.type();
N
Niels 已提交
4818

F
Florian Weber 已提交
4819
        if (lhs_type == rhs_type)
N
cleanup  
Niels 已提交
4820
        {
F
Florian Weber 已提交
4821
            switch (lhs_type)
N
cleanup  
Niels 已提交
4822
            {
4823
                case value_t::array:
N
Niels 已提交
4824 4825 4826
                {
                    assert(lhs.m_value.array != nullptr);
                    assert(rhs.m_value.array != nullptr);
N
cleanup  
Niels 已提交
4827
                    return *lhs.m_value.array == *rhs.m_value.array;
N
Niels 已提交
4828
                }
4829
                case value_t::object:
N
Niels 已提交
4830 4831 4832
                {
                    assert(lhs.m_value.object != nullptr);
                    assert(rhs.m_value.object != nullptr);
N
cleanup  
Niels 已提交
4833
                    return *lhs.m_value.object == *rhs.m_value.object;
N
Niels 已提交
4834
                }
4835
                case value_t::null:
N
Niels 已提交
4836
                {
N
cleanup  
Niels 已提交
4837
                    return true;
N
Niels 已提交
4838
                }
4839
                case value_t::string:
N
Niels 已提交
4840 4841 4842
                {
                    assert(lhs.m_value.string != nullptr);
                    assert(rhs.m_value.string != nullptr);
N
cleanup  
Niels 已提交
4843
                    return *lhs.m_value.string == *rhs.m_value.string;
N
Niels 已提交
4844
                }
4845
                case value_t::boolean:
N
Niels 已提交
4846
                {
N
cleanup  
Niels 已提交
4847
                    return lhs.m_value.boolean == rhs.m_value.boolean;
N
Niels 已提交
4848
                }
4849
                case value_t::number_integer:
N
Niels 已提交
4850
                {
N
cleanup  
Niels 已提交
4851
                    return lhs.m_value.number_integer == rhs.m_value.number_integer;
N
Niels 已提交
4852
                }
4853
                case value_t::number_float:
N
Niels 已提交
4854
                {
4855
                    return lhs.m_value.number_float == rhs.m_value.number_float;
N
Niels 已提交
4856
                }
4857
                default:
N
Niels 已提交
4858
                {
N
Niels 已提交
4859
                    return false;
N
Niels 已提交
4860
                }
N
cleanup  
Niels 已提交
4861 4862
            }
        }
F
Florian Weber 已提交
4863 4864
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
        {
N
Niels 已提交
4865
            return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
F
Florian Weber 已提交
4866 4867 4868
        }
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
        {
4869
            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
F
Florian Weber 已提交
4870
        }
N
cleanup  
Niels 已提交
4871 4872 4873
        return false;
    }

N
Niels 已提交
4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888
    /*!
    @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}
N
Niels 已提交
4889

N
Niels 已提交
4890
    @since version 1.0.0
N
Niels 已提交
4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905
    */
    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 已提交
4906 4907
    /*!
    @brief comparison: not equal
N
Niels 已提交
4908 4909 4910 4911 4912 4913 4914 4915 4916

    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.

4917 4918
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__notequal}
N
Niels 已提交
4919

N
Niels 已提交
4920
    @since version 1.0.0
N
Niels 已提交
4921
    */
N
Niels 已提交
4922
    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4923 4924 4925 4926
    {
        return not (lhs == rhs);
    }

N
Niels 已提交
4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941
    /*!
    @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}
N
Niels 已提交
4942

N
Niels 已提交
4943
    @since version 1.0.0
N
Niels 已提交
4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958
    */
    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 已提交
4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977
    /*!
    @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.

4978 4979
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__less}
N
Niels 已提交
4980

N
Niels 已提交
4981
    @since version 1.0.0
N
Niels 已提交
4982
    */
N
Niels 已提交
4983
    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
4984
    {
F
Florian Weber 已提交
4985 4986
        const auto lhs_type = lhs.type();
        const auto rhs_type = rhs.type();
N
Niels 已提交
4987

F
Florian Weber 已提交
4988
        if (lhs_type == rhs_type)
N
cleanup  
Niels 已提交
4989
        {
F
Florian Weber 已提交
4990
            switch (lhs_type)
N
cleanup  
Niels 已提交
4991
            {
4992
                case value_t::array:
N
Niels 已提交
4993 4994 4995
                {
                    assert(lhs.m_value.array != nullptr);
                    assert(rhs.m_value.array != nullptr);
N
cleanup  
Niels 已提交
4996
                    return *lhs.m_value.array < *rhs.m_value.array;
N
Niels 已提交
4997
                }
4998
                case value_t::object:
N
Niels 已提交
4999 5000 5001
                {
                    assert(lhs.m_value.object != nullptr);
                    assert(rhs.m_value.object != nullptr);
N
cleanup  
Niels 已提交
5002
                    return *lhs.m_value.object < *rhs.m_value.object;
N
Niels 已提交
5003
                }
5004
                case value_t::null:
N
Niels 已提交
5005
                {
N
cleanup  
Niels 已提交
5006
                    return false;
N
Niels 已提交
5007
                }
5008
                case value_t::string:
N
Niels 已提交
5009 5010 5011
                {
                    assert(lhs.m_value.string != nullptr);
                    assert(rhs.m_value.string != nullptr);
N
cleanup  
Niels 已提交
5012
                    return *lhs.m_value.string < *rhs.m_value.string;
N
Niels 已提交
5013
                }
5014
                case value_t::boolean:
N
Niels 已提交
5015
                {
N
cleanup  
Niels 已提交
5016
                    return lhs.m_value.boolean < rhs.m_value.boolean;
N
Niels 已提交
5017
                }
5018
                case value_t::number_integer:
N
Niels 已提交
5019
                {
N
cleanup  
Niels 已提交
5020
                    return lhs.m_value.number_integer < rhs.m_value.number_integer;
N
Niels 已提交
5021
                }
5022
                case value_t::number_float:
N
Niels 已提交
5023
                {
N
cleanup  
Niels 已提交
5024
                    return lhs.m_value.number_float < rhs.m_value.number_float;
N
Niels 已提交
5025
                }
5026
                default:
N
Niels 已提交
5027
                {
N
Niels 已提交
5028
                    return false;
N
Niels 已提交
5029
                }
N
cleanup  
Niels 已提交
5030 5031
            }
        }
F
Florian Weber 已提交
5032 5033
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
        {
5034 5035
            return static_cast<number_float_t>(lhs.m_value.number_integer) <
                   rhs.m_value.number_float;
F
Florian Weber 已提交
5036 5037 5038 5039 5040 5041
        }
        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 已提交
5042

N
Niels 已提交
5043
        // We only reach this line if we cannot compare values. In that case,
N
Niels 已提交
5044 5045 5046
        // 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 已提交
5047 5048
    }

N
Niels 已提交
5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060
    /*!
    @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.

5061 5062
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__greater}
N
Niels 已提交
5063

N
Niels 已提交
5064
    @since version 1.0.0
N
Niels 已提交
5065
    */
N
Niels 已提交
5066
    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
5067 5068 5069 5070
    {
        return not (rhs < lhs);
    }

N
Niels 已提交
5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082
    /*!
    @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.

5083 5084
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__lessequal}
N
Niels 已提交
5085

N
Niels 已提交
5086
    @since version 1.0.0
N
Niels 已提交
5087
    */
N
Niels 已提交
5088
    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
5089 5090 5091 5092
    {
        return not (lhs <= rhs);
    }

N
Niels 已提交
5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104
    /*!
    @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.

5105 5106
    @liveexample{The example demonstrates comparing several JSON
    types.,operator__greaterequal}
N
Niels 已提交
5107

N
Niels 已提交
5108
    @since version 1.0.0
N
Niels 已提交
5109
    */
N
Niels 已提交
5110
    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
N
cleanup  
Niels 已提交
5111 5112 5113 5114
    {
        return not (lhs < rhs);
    }

N
Niels 已提交
5115 5116
    /// @}

N
cleanup  
Niels 已提交
5117 5118 5119 5120 5121

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

N
Niels 已提交
5122 5123 5124
    /// @name serialization
    /// @{

N
Niels 已提交
5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141
    /*!
    @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 已提交
5142 5143
    @liveexample{The example below shows the serialization with different
    parameters to `width` to adjust the indentation level.,operator_serialize}
N
Niels 已提交
5144

N
Niels 已提交
5145
    @since version 1.0.0
N
Niels 已提交
5146
    */
N
cleanup  
Niels 已提交
5147 5148
    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
    {
N
Niels 已提交
5149
        // read width member and use it as indentation parameter if nonzero
N
Niels 已提交
5150 5151
        const bool pretty_print = (o.width() > 0);
        const auto indentation = (pretty_print ? o.width() : 0);
N
Niels 已提交
5152

N
Niels 已提交
5153 5154 5155 5156
        // reset width to 0 for subsequent calls to this stream
        o.width(0);

        // do the actual serialization
N
Niels 已提交
5157
        j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
N
cleanup  
Niels 已提交
5158 5159 5160
        return o;
    }

N
Niels 已提交
5161 5162 5163 5164
    /*!
    @brief serialize to stream
    @copydoc operator<<(std::ostream&, const basic_json&)
    */
N
cleanup  
Niels 已提交
5165 5166
    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
    {
A
Alexandre Hamez 已提交
5167
        return o << j;
N
cleanup  
Niels 已提交
5168 5169
    }

N
Niels 已提交
5170 5171
    /// @}

N
cleanup  
Niels 已提交
5172

N
Niels 已提交
5173 5174 5175 5176
    /////////////////////
    // deserialization //
    /////////////////////

N
Niels 已提交
5177 5178 5179
    /// @name deserialization
    /// @{

N
Niels 已提交
5180 5181 5182 5183
    /*!
    @brief deserialize from string

    @param[in] s  string to read a serialized JSON value from
N
Niels 已提交
5184 5185 5186
    @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 已提交
5187 5188 5189 5190 5191 5192 5193

    @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 已提交
5194 5195
    @note A UTF-8 byte order mark is silently ignored.

N
Niels 已提交
5196 5197
    @liveexample{The example below demonstrates the parse function with and
    without callback function.,parse__string__parser_callback_t}
N
Niels 已提交
5198

N
Niels 已提交
5199 5200 5201
    @sa @ref parse(std::istream&, parser_callback_t) for a version that reads
    from an input stream

N
Niels 已提交
5202
    @since version 1.0.0
N
Niels 已提交
5203
    */
5204
    static basic_json parse(const string_t& s, parser_callback_t cb = nullptr)
N
Niels 已提交
5205
    {
N
Niels 已提交
5206
        return parser(s, cb).parse();
N
Niels 已提交
5207 5208
    }

N
Niels 已提交
5209 5210 5211 5212
    /*!
    @brief deserialize from stream

    @param[in,out] i  stream to read a serialized JSON value from
N
Niels 已提交
5213 5214 5215
    @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 已提交
5216 5217 5218 5219 5220 5221 5222

    @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 已提交
5223 5224
    @note A UTF-8 byte order mark is silently ignored.

N
Niels 已提交
5225 5226
    @liveexample{The example below demonstrates the parse function with and
    without callback function.,parse__istream__parser_callback_t}
N
Niels 已提交
5227

N
Niels 已提交
5228
    @sa @ref parse(const string_t&, parser_callback_t) for a version that reads
N
Niels 已提交
5229
    from a string
N
Niels 已提交
5230

N
Niels 已提交
5231
    @since version 1.0.0
N
Niels 已提交
5232
    */
5233
    static basic_json parse(std::istream& i, parser_callback_t cb = nullptr)
A
Aaron Burghardt 已提交
5234
    {
N
Niels 已提交
5235
        return parser(i, cb).parse();
N
Niels 已提交
5236 5237
    }

N
Niels 已提交
5238 5239 5240
    /*!
    @copydoc parse(std::istream&, parser_callback_t)
    */
5241 5242 5243 5244 5245
    static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr)
    {
        return parser(i, cb).parse();
    }

N
Niels 已提交
5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258
    /*!
    @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.

N
Niels 已提交
5259 5260
    @note A UTF-8 byte order mark is silently ignored.

N
Niels 已提交
5261 5262 5263 5264 5265
    @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
N
Niels 已提交
5266

N
Niels 已提交
5267
    @since version 1.0.0
N
Niels 已提交
5268 5269
    */
    friend std::istream& operator<<(basic_json& j, std::istream& i)
N
Niels 已提交
5270 5271 5272 5273 5274
    {
        j = parser(i).parse();
        return i;
    }

N
Niels 已提交
5275 5276 5277 5278 5279
    /*!
    @brief deserialize from stream
    @copydoc operator<<(basic_json&, std::istream&)
    */
    friend std::istream& operator>>(std::istream& i, basic_json& j)
N
Niels 已提交
5280 5281 5282 5283 5284
    {
        j = parser(i).parse();
        return i;
    }

N
Niels 已提交
5285 5286
    /// @}

N
Niels 已提交
5287

N
cleanup  
Niels 已提交
5288 5289 5290 5291 5292 5293
  private:
    ///////////////////////////
    // convenience functions //
    ///////////////////////////

    /// return the type as string
N
Niels 已提交
5294
    string_t type_name() const
N
cleanup  
Niels 已提交
5295 5296 5297
    {
        switch (m_type)
        {
5298
            case value_t::null:
N
cleanup  
Niels 已提交
5299
                return "null";
5300
            case value_t::object:
N
cleanup  
Niels 已提交
5301
                return "object";
5302
            case value_t::array:
N
cleanup  
Niels 已提交
5303
                return "array";
5304
            case value_t::string:
N
cleanup  
Niels 已提交
5305
                return "string";
5306
            case value_t::boolean:
N
cleanup  
Niels 已提交
5307
                return "boolean";
5308
            case value_t::discarded:
N
Niels 已提交
5309
                return "discarded";
N
Niels 已提交
5310
            default:
N
cleanup  
Niels 已提交
5311 5312 5313 5314
                return "number";
        }
    }

N
Niels 已提交
5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358
    /*!
    @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 已提交
5359
    /*!
N
Niels 已提交
5360
    @brief escape a string
N
Niels 已提交
5361

N
Niels 已提交
5362 5363 5364 5365 5366
    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 已提交
5367
    @param[in] s  the string to escape
N
Niels 已提交
5368 5369 5370
    @return  the escaped string

    @complexity Linear in the length of string @a s.
N
Niels 已提交
5371
    */
N
Niels 已提交
5372
    static string_t escape_string(const string_t& s) noexcept
N
Niels 已提交
5373
    {
N
Niels 已提交
5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384
        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 已提交
5385 5386 5387
        {
            switch (c)
            {
N
Niels 已提交
5388
                // quotation mark (0x22)
N
Niels 已提交
5389 5390
                case '"':
                {
N
Niels 已提交
5391 5392
                    result[pos + 1] = '"';
                    pos += 2;
N
Niels 已提交
5393 5394
                    break;
                }
N
Niels 已提交
5395

N
Niels 已提交
5396
                // reverse solidus (0x5c)
N
Niels 已提交
5397 5398
                case '\\':
                {
N
Niels 已提交
5399 5400
                    // nothing to change
                    pos += 2;
N
Niels 已提交
5401 5402
                    break;
                }
N
Niels 已提交
5403

N
Niels 已提交
5404
                // backspace (0x08)
N
Niels 已提交
5405 5406
                case '\b':
                {
N
Niels 已提交
5407 5408
                    result[pos + 1] = 'b';
                    pos += 2;
N
Niels 已提交
5409 5410
                    break;
                }
N
Niels 已提交
5411

N
Niels 已提交
5412
                // formfeed (0x0c)
N
Niels 已提交
5413 5414
                case '\f':
                {
N
Niels 已提交
5415 5416
                    result[pos + 1] = 'f';
                    pos += 2;
N
Niels 已提交
5417 5418
                    break;
                }
N
Niels 已提交
5419

N
Niels 已提交
5420
                // newline (0x0a)
N
Niels 已提交
5421 5422
                case '\n':
                {
N
Niels 已提交
5423 5424
                    result[pos + 1] = 'n';
                    pos += 2;
N
Niels 已提交
5425 5426
                    break;
                }
N
Niels 已提交
5427

N
Niels 已提交
5428
                // carriage return (0x0d)
N
Niels 已提交
5429 5430
                case '\r':
                {
N
Niels 已提交
5431 5432
                    result[pos + 1] = 'r';
                    pos += 2;
N
Niels 已提交
5433 5434
                    break;
                }
N
Niels 已提交
5435

N
Niels 已提交
5436
                // horizontal tab (0x09)
N
Niels 已提交
5437 5438
                case '\t':
                {
N
Niels 已提交
5439 5440
                    result[pos + 1] = 't';
                    pos += 2;
N
Niels 已提交
5441 5442
                    break;
                }
N
Niels 已提交
5443

N
Niels 已提交
5444 5445
                default:
                {
5446
                    if (c >= 0x00 and c <= 0x1f)
N
Niels 已提交
5447
                    {
5448 5449 5450 5451 5452 5453
                        // convert a number 0..15 to its hex representation (0..f)
                        auto hexify = [](const char v) -> char
                        {
                            return (v < 10) ? ('0' + v) : ('a' + v - 10);
                        };

N
Niels 已提交
5454
                        // print character c as \uxxxx
N
Niels 已提交
5455 5456 5457
                        for (const char m :
                    { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f)
                        })
5458 5459 5460 5461 5462
                        {
                            result[++pos] = m;
                        }

                        ++pos;
N
Niels 已提交
5463 5464 5465 5466
                    }
                    else
                    {
                        // all other characters are added as-is
N
Niels 已提交
5467
                        result[pos++] = c;
N
Niels 已提交
5468 5469
                    }
                    break;
N
Niels 已提交
5470 5471 5472
                }
            }
        }
N
Niels 已提交
5473 5474

        return result;
N
Niels 已提交
5475 5476
    }

N
cleanup  
Niels 已提交
5477
    /*!
N
Niels 已提交
5478
    @brief internal implementation of the serialization function
N
Niels 已提交
5479

N
Niels 已提交
5480
    This function is called by the public member function dump and organizes
N
Niels 已提交
5481
    the serialization internally. The indentation level is propagated as
N
Niels 已提交
5482 5483
    additional parameter. In case of arrays and objects, the function is called
    recursively. Note that
N
Niels 已提交
5484

N
Niels 已提交
5485
    - strings and object keys are escaped using escape_string()
N
Niels 已提交
5486
    - integer numbers are converted implicitly via operator<<
N
Niels 已提交
5487
    - floating-point numbers are converted to a string using "%g" format
N
cleanup  
Niels 已提交
5488

N
Niels 已提交
5489 5490 5491 5492
    @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 已提交
5493
    */
N
Niels 已提交
5494 5495 5496
    void dump(std::ostream& o,
              const bool pretty_print,
              const unsigned int indent_step,
N
Niels 已提交
5497
              const unsigned int current_indent = 0) const
N
cleanup  
Niels 已提交
5498
    {
N
Niels 已提交
5499
        // variable to hold indentation for recursive calls
N
Niels 已提交
5500
        unsigned int new_indent = current_indent;
N
Niels 已提交
5501

N
cleanup  
Niels 已提交
5502 5503
        switch (m_type)
        {
5504
            case value_t::object:
N
cleanup  
Niels 已提交
5505
            {
N
Niels 已提交
5506 5507
                assert(m_value.object != nullptr);

N
cleanup  
Niels 已提交
5508 5509
                if (m_value.object->empty())
                {
N
Niels 已提交
5510 5511
                    o << "{}";
                    return;
N
cleanup  
Niels 已提交
5512 5513
                }

N
Niels 已提交
5514
                o << "{";
N
cleanup  
Niels 已提交
5515 5516

                // increase indentation
N
Niels 已提交
5517
                if (pretty_print)
N
cleanup  
Niels 已提交
5518
                {
N
Niels 已提交
5519
                    new_indent += indent_step;
N
Niels 已提交
5520
                    o << "\n";
N
cleanup  
Niels 已提交
5521 5522
                }

N
Niels 已提交
5523
                for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
N
cleanup  
Niels 已提交
5524
                {
N
Niels 已提交
5525
                    if (i != m_value.object->cbegin())
N
cleanup  
Niels 已提交
5526
                    {
N
Niels 已提交
5527
                        o << (pretty_print ? ",\n" : ",");
N
cleanup  
Niels 已提交
5528
                    }
N
Niels 已提交
5529 5530 5531
                    o << string_t(new_indent, ' ') << "\""
                      << escape_string(i->first) << "\":"
                      << (pretty_print ? " " : "");
N
Niels 已提交
5532
                    i->second.dump(o, pretty_print, indent_step, new_indent);
N
cleanup  
Niels 已提交
5533 5534 5535
                }

                // decrease indentation
N
Niels 已提交
5536
                if (pretty_print)
N
cleanup  
Niels 已提交
5537
                {
N
Niels 已提交
5538
                    new_indent -= indent_step;
N
Niels 已提交
5539
                    o << "\n";
N
cleanup  
Niels 已提交
5540 5541
                }

N
Niels 已提交
5542 5543
                o << string_t(new_indent, ' ') + "}";
                return;
N
cleanup  
Niels 已提交
5544 5545
            }

5546
            case value_t::array:
N
cleanup  
Niels 已提交
5547
            {
N
Niels 已提交
5548 5549
                assert(m_value.array != nullptr);

N
cleanup  
Niels 已提交
5550 5551
                if (m_value.array->empty())
                {
N
Niels 已提交
5552 5553
                    o << "[]";
                    return;
N
cleanup  
Niels 已提交
5554 5555
                }

N
Niels 已提交
5556
                o << "[";
N
cleanup  
Niels 已提交
5557 5558

                // increase indentation
N
Niels 已提交
5559
                if (pretty_print)
N
cleanup  
Niels 已提交
5560
                {
N
Niels 已提交
5561
                    new_indent += indent_step;
N
Niels 已提交
5562
                    o << "\n";
N
cleanup  
Niels 已提交
5563 5564
                }

N
Niels 已提交
5565
                for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
N
cleanup  
Niels 已提交
5566
                {
N
Niels 已提交
5567
                    if (i != m_value.array->cbegin())
N
cleanup  
Niels 已提交
5568
                    {
N
Niels 已提交
5569
                        o << (pretty_print ? ",\n" : ",");
N
cleanup  
Niels 已提交
5570
                    }
N
Niels 已提交
5571
                    o << string_t(new_indent, ' ');
N
Niels 已提交
5572
                    i->dump(o, pretty_print, indent_step, new_indent);
N
cleanup  
Niels 已提交
5573 5574 5575
                }

                // decrease indentation
N
Niels 已提交
5576
                if (pretty_print)
N
cleanup  
Niels 已提交
5577
                {
N
Niels 已提交
5578
                    new_indent -= indent_step;
N
Niels 已提交
5579
                    o << "\n";
N
cleanup  
Niels 已提交
5580 5581
                }

N
Niels 已提交
5582 5583
                o << string_t(new_indent, ' ') << "]";
                return;
N
cleanup  
Niels 已提交
5584 5585
            }

5586
            case value_t::string:
N
cleanup  
Niels 已提交
5587
            {
N
Niels 已提交
5588
                assert(m_value.string != nullptr);
N
Niels 已提交
5589
                o << string_t("\"") << escape_string(*m_value.string) << "\"";
N
Niels 已提交
5590
                return;
N
cleanup  
Niels 已提交
5591 5592
            }

5593
            case value_t::boolean:
N
cleanup  
Niels 已提交
5594
            {
N
Niels 已提交
5595 5596
                o << (m_value.boolean ? "true" : "false");
                return;
N
cleanup  
Niels 已提交
5597 5598
            }

5599
            case value_t::number_integer:
N
cleanup  
Niels 已提交
5600
            {
N
Niels 已提交
5601 5602
                o << m_value.number_integer;
                return;
N
cleanup  
Niels 已提交
5603 5604
            }

5605
            case value_t::number_float:
N
cleanup  
Niels 已提交
5606
            {
N
Niels 已提交
5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620
                // If the number is an integer then output as a fixed with with
                // precision 1 to output "0.0", "1.0" etc as expected for some
                // round trip tests otherwise  15 digits of precision allows
                // round-trip IEEE 754 string->double->string; to be safe, we
                // read this value from
                // std::numeric_limits<number_float_t>::digits10
                if (std::fmod(m_value.number_float, 1) == 0)
                {
                    o << std::fixed << std::setprecision(1);
                }
                else
                {
                    // std::defaultfloat not supported in gcc version < 5
                    o.unsetf(std::ios_base::floatfield);
5621 5622
                    o << std::setprecision(std::numeric_limits<double>::digits10);
                }
5623
                o << m_value.number_float;
N
Niels 已提交
5624
                return;
N
cleanup  
Niels 已提交
5625
            }
N
Niels 已提交
5626

5627
            case value_t::discarded:
N
Niels 已提交
5628
            {
N
Niels 已提交
5629 5630
                o << "<discarded>";
                return;
N
Niels 已提交
5631
            }
N
Niels 已提交
5632

5633
            case value_t::null:
N
Niels 已提交
5634
            {
N
Niels 已提交
5635 5636
                o << "null";
                return;
N
Niels 已提交
5637
            }
N
cleanup  
Niels 已提交
5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651
        }
    }

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

N
Niels 已提交
5653
  private:
N
cleanup  
Niels 已提交
5654 5655 5656 5657
    ///////////////
    // iterators //
    ///////////////

5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700
    /*!
    @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 已提交
5701
        operator difference_type () const
5702 5703 5704 5705 5706 5707 5708 5709 5710
        {
            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
N
Niels 已提交
5711
        difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
5712 5713
    };

N
Niels 已提交
5714 5715 5716 5717 5718 5719 5720 5721
    /*!
    @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 已提交
5722 5723
    {
        /// iterator for JSON objects
N
Niels 已提交
5724
        typename object_t::iterator object_iterator;
N
Niels 已提交
5725
        /// iterator for JSON arrays
N
Niels 已提交
5726
        typename array_t::iterator array_iterator;
N
Niels 已提交
5727
        /// generic iterator for all other types
N
Niels 已提交
5728 5729 5730 5731 5732 5733
        primitive_iterator_t primitive_iterator;

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

N
cleanup  
Niels 已提交
5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770
    /// proxy class for the iterator_wrapper functions
    template<typename IteratorType>
    class iteration_proxy
    {
      private:
        /// helper class for iteration
        class iteration_proxy_internal
        {
          private:
            /// the iterator
            IteratorType anchor;
            /// an index for arrays (used to create key names)
            size_t array_index = 0;

          public:
            iteration_proxy_internal(IteratorType it)
                : anchor(it)
            {}

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

            /// increment operator (needed for range-based for)
            iteration_proxy_internal& operator++()
            {
                ++anchor;
                ++array_index;

                return *this;
            }

            /// inequality operator (needed for range-based for)
N
Niels 已提交
5771
            bool operator!= (const iteration_proxy_internal& o) const
N
cleanup  
Niels 已提交
5772 5773 5774 5775 5776 5777 5778
            {
                return anchor != o.anchor;
            }

            /// return key of the iterator
            typename basic_json::string_t key() const
            {
N
Niels 已提交
5779 5780
                assert(anchor.m_object != nullptr);

N
cleanup  
Niels 已提交
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 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831
                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 "";
                    }
                }
            }

            /// return value of the iterator
            typename IteratorType::reference value() const
            {
                return anchor.value();
            }
        };

        /// the container to iterate
        typename IteratorType::reference container;

      public:
        /// construct iteration proxy from a container
        iteration_proxy(typename IteratorType::reference cont)
            : container(cont)
        {}

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

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

N
Niels 已提交
5832
  public:
N
Niels 已提交
5833 5834 5835 5836 5837 5838 5839 5840 5841 5842
    /*!
    @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 已提交
5843

N
Niels 已提交
5844
    @since version 1.0.0
N
Niels 已提交
5845
    */
N
Niels 已提交
5846
    class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json>
N
cleanup  
Niels 已提交
5847
    {
N
Niels 已提交
5848
        /// allow basic_json to access private members
5849 5850
        friend class basic_json;

N
cleanup  
Niels 已提交
5851 5852
      public:
        /// the type of the values when the iterator is dereferenced
N
Niels 已提交
5853
        using value_type = typename basic_json::value_type;
N
cleanup  
Niels 已提交
5854
        /// a type to represent differences between iterators
N
Niels 已提交
5855
        using difference_type = typename basic_json::difference_type;
N
cleanup  
Niels 已提交
5856
        /// defines a pointer to the type iterated over (value_type)
N
Niels 已提交
5857
        using pointer = typename basic_json::const_pointer;
N
cleanup  
Niels 已提交
5858
        /// defines a reference to the type iterated over (value_type)
N
Niels 已提交
5859
        using reference = typename basic_json::const_reference;
N
cleanup  
Niels 已提交
5860
        /// the category of the iterator
N
Niels 已提交
5861
        using iterator_category = std::bidirectional_iterator_tag;
N
cleanup  
Niels 已提交
5862

5863
        /// default constructor
N
Niels 已提交
5864
        const_iterator() = default;
5865

N
cleanup  
Niels 已提交
5866
        /// constructor for a given JSON instance
N
Niels 已提交
5867
        const_iterator(pointer object) : m_object(object)
N
cleanup  
Niels 已提交
5868
        {
N
Niels 已提交
5869 5870
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
5871 5872
            switch (m_object->m_type)
            {
5873
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
5874 5875 5876 5877
                {
                    m_it.object_iterator = typename object_t::iterator();
                    break;
                }
5878 5879

                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
5880 5881 5882 5883
                {
                    m_it.array_iterator = typename array_t::iterator();
                    break;
                }
5884

N
cleanup  
Niels 已提交
5885 5886
                default:
                {
5887
                    m_it.primitive_iterator = primitive_iterator_t();
N
cleanup  
Niels 已提交
5888 5889 5890 5891 5892
                    break;
                }
            }
        }

N
Niels 已提交
5893 5894 5895
        /// copy constructor given a nonconst iterator
        const_iterator(const iterator& other) : m_object(other.m_object)
        {
N
Niels 已提交
5896 5897
            assert(m_object != nullptr);

N
Niels 已提交
5898 5899
            switch (m_object->m_type)
            {
5900
                case basic_json::value_t::object:
N
Niels 已提交
5901 5902 5903 5904 5905
                {
                    m_it.object_iterator = other.m_it.object_iterator;
                    break;
                }

5906
                case basic_json::value_t::array:
N
Niels 已提交
5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919
                {
                    m_it.array_iterator = other.m_it.array_iterator;
                    break;
                }

                default:
                {
                    m_it.primitive_iterator = other.m_it.primitive_iterator;
                    break;
                }
            }
        }

N
Niels 已提交
5920
        /// copy constructor
N
Niels 已提交
5921
        const_iterator(const const_iterator& other) noexcept
N
Niels 已提交
5922 5923 5924
            : m_object(other.m_object), m_it(other.m_it)
        {}

N
cleanup  
Niels 已提交
5925
        /// copy assignment
N
Niels 已提交
5926
        const_iterator& operator=(const_iterator other) noexcept(
N
Niels 已提交
5927 5928
            std::is_nothrow_move_constructible<pointer>::value and
            std::is_nothrow_move_assignable<pointer>::value and
N
Niels 已提交
5929 5930
            std::is_nothrow_move_constructible<internal_iterator>::value and
            std::is_nothrow_move_assignable<internal_iterator>::value
N
Niels 已提交
5931 5932 5933 5934
        )
        {
            std::swap(m_object, other.m_object);
            std::swap(m_it, other.m_it);
N
cleanup  
Niels 已提交
5935 5936 5937
            return *this;
        }

N
Niels 已提交
5938
      private:
N
cleanup  
Niels 已提交
5939
        /// set the iterator to the first value
N
Niels 已提交
5940
        void set_begin()
N
cleanup  
Niels 已提交
5941
        {
N
Niels 已提交
5942 5943
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
5944 5945
            switch (m_object->m_type)
            {
5946
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
5947
                {
N
Niels 已提交
5948
                    assert(m_object->m_value.object != nullptr);
N
cleanup  
Niels 已提交
5949 5950 5951 5952
                    m_it.object_iterator = m_object->m_value.object->begin();
                    break;
                }

5953
                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
5954
                {
N
Niels 已提交
5955
                    assert(m_object->m_value.array != nullptr);
N
cleanup  
Niels 已提交
5956 5957 5958 5959
                    m_it.array_iterator = m_object->m_value.array->begin();
                    break;
                }

5960
                case basic_json::value_t::null:
N
cleanup  
Niels 已提交
5961
                {
N
Niels 已提交
5962
                    // set to end so begin()==end() is true: null is empty
5963
                    m_it.primitive_iterator.set_end();
N
cleanup  
Niels 已提交
5964 5965 5966 5967 5968
                    break;
                }

                default:
                {
5969
                    m_it.primitive_iterator.set_begin();
N
cleanup  
Niels 已提交
5970 5971 5972 5973 5974 5975
                    break;
                }
            }
        }

        /// set the iterator past the last value
N
Niels 已提交
5976
        void set_end()
N
cleanup  
Niels 已提交
5977
        {
N
Niels 已提交
5978 5979
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
5980 5981
            switch (m_object->m_type)
            {
5982
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
5983
                {
N
Niels 已提交
5984
                    assert(m_object->m_value.object != nullptr);
N
cleanup  
Niels 已提交
5985 5986 5987 5988
                    m_it.object_iterator = m_object->m_value.object->end();
                    break;
                }

5989
                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
5990
                {
N
Niels 已提交
5991
                    assert(m_object->m_value.array != nullptr);
N
cleanup  
Niels 已提交
5992 5993 5994 5995 5996 5997
                    m_it.array_iterator = m_object->m_value.array->end();
                    break;
                }

                default:
                {
5998
                    m_it.primitive_iterator.set_end();
N
cleanup  
Niels 已提交
5999 6000 6001 6002 6003
                    break;
                }
            }
        }

N
Niels 已提交
6004
      public:
N
cleanup  
Niels 已提交
6005
        /// return a reference to the value pointed to by the iterator
N
Niels 已提交
6006
        reference operator*() const
N
cleanup  
Niels 已提交
6007
        {
N
Niels 已提交
6008 6009
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
6010 6011
            switch (m_object->m_type)
            {
6012
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
6013
                {
N
Niels 已提交
6014 6015
                    assert(m_object->m_value.object);
                    assert(m_it.object_iterator != m_object->m_value.object->end());
N
cleanup  
Niels 已提交
6016 6017 6018
                    return m_it.object_iterator->second;
                }

6019
                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
6020
                {
N
Niels 已提交
6021 6022
                    assert(m_object->m_value.array);
                    assert(m_it.array_iterator != m_object->m_value.array->end());
N
cleanup  
Niels 已提交
6023 6024 6025
                    return *m_it.array_iterator;
                }

6026
                case basic_json::value_t::null:
N
cleanup  
Niels 已提交
6027 6028 6029 6030 6031 6032
                {
                    throw std::out_of_range("cannot get value");
                }

                default:
                {
6033 6034 6035 6036 6037 6038 6039 6040
                    if (m_it.primitive_iterator.is_begin())
                    {
                        return *m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
N
cleanup  
Niels 已提交
6041 6042 6043 6044 6045
                }
            }
        }

        /// dereference the iterator
N
Niels 已提交
6046
        pointer operator->() const
N
cleanup  
Niels 已提交
6047
        {
N
Niels 已提交
6048 6049
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
6050 6051
            switch (m_object->m_type)
            {
6052
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
6053
                {
N
Niels 已提交
6054 6055
                    assert(m_object->m_value.object);
                    assert(m_it.object_iterator != m_object->m_value.object->end());
N
cleanup  
Niels 已提交
6056 6057 6058
                    return &(m_it.object_iterator->second);
                }

6059
                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
6060
                {
N
Niels 已提交
6061 6062
                    assert(m_object->m_value.array);
                    assert(m_it.array_iterator != m_object->m_value.array->end());
N
cleanup  
Niels 已提交
6063 6064 6065 6066 6067
                    return &*m_it.array_iterator;
                }

                default:
                {
6068 6069 6070 6071 6072 6073 6074 6075
                    if (m_it.primitive_iterator.is_begin())
                    {
                        return m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
N
cleanup  
Niels 已提交
6076 6077 6078 6079 6080
                }
            }
        }

        /// post-increment (it++)
N
Niels 已提交
6081
        const_iterator operator++(int)
N
cleanup  
Niels 已提交
6082
        {
N
Niels 已提交
6083
            auto result = *this;
N
Niels 已提交
6084
            ++(*this);
N
cleanup  
Niels 已提交
6085 6086 6087 6088
            return result;
        }

        /// pre-increment (++it)
N
Niels 已提交
6089
        const_iterator& operator++()
N
cleanup  
Niels 已提交
6090
        {
N
Niels 已提交
6091 6092
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
6093 6094
            switch (m_object->m_type)
            {
6095
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
6096 6097 6098 6099 6100
                {
                    ++m_it.object_iterator;
                    break;
                }

6101
                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
6102 6103 6104 6105 6106 6107 6108
                {
                    ++m_it.array_iterator;
                    break;
                }

                default:
                {
6109
                    ++m_it.primitive_iterator;
N
cleanup  
Niels 已提交
6110 6111 6112 6113 6114 6115 6116 6117
                    break;
                }
            }

            return *this;
        }

        /// post-decrement (it--)
N
Niels 已提交
6118
        const_iterator operator--(int)
N
cleanup  
Niels 已提交
6119
        {
N
Niels 已提交
6120
            auto result = *this;
N
Niels 已提交
6121
            --(*this);
N
cleanup  
Niels 已提交
6122 6123 6124 6125
            return result;
        }

        /// pre-decrement (--it)
N
Niels 已提交
6126
        const_iterator& operator--()
N
cleanup  
Niels 已提交
6127
        {
N
Niels 已提交
6128 6129
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
6130 6131
            switch (m_object->m_type)
            {
6132
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
6133 6134 6135 6136 6137
                {
                    --m_it.object_iterator;
                    break;
                }

6138
                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
6139 6140 6141 6142 6143 6144 6145
                {
                    --m_it.array_iterator;
                    break;
                }

                default:
                {
6146
                    --m_it.primitive_iterator;
N
cleanup  
Niels 已提交
6147 6148 6149 6150 6151 6152 6153 6154
                    break;
                }
            }

            return *this;
        }

        /// comparison: equal
N
Niels 已提交
6155
        bool operator==(const const_iterator& other) const
N
cleanup  
Niels 已提交
6156
        {
N
Niels 已提交
6157 6158
            // if objects are not the same, the comparison is undefined
            if (m_object != other.m_object)
N
cleanup  
Niels 已提交
6159
            {
N
Niels 已提交
6160
                throw std::domain_error("cannot compare iterators of different containers");
N
cleanup  
Niels 已提交
6161 6162
            }

N
Niels 已提交
6163 6164
            assert(m_object != nullptr);

N
cleanup  
Niels 已提交
6165 6166
            switch (m_object->m_type)
            {
6167
                case basic_json::value_t::object:
N
cleanup  
Niels 已提交
6168 6169 6170 6171
                {
                    return (m_it.object_iterator == other.m_it.object_iterator);
                }

6172
                case basic_json::value_t::array:
N
cleanup  
Niels 已提交
6173 6174 6175 6176 6177 6178
                {
                    return (m_it.array_iterator == other.m_it.array_iterator);
                }

                default:
                {
6179
                    return (m_it.primitive_iterator == other.m_it.primitive_iterator);
N
cleanup  
Niels 已提交
6180 6181 6182 6183 6184
                }
            }
        }

        /// comparison: not equal
N
Niels 已提交
6185
        bool operator!=(const const_iterator& other) const
N
cleanup  
Niels 已提交
6186 6187 6188 6189
        {
            return not operator==(other);
        }

N
Niels 已提交
6190
        /// comparison: smaller
N
Niels 已提交
6191
        bool operator<(const const_iterator& other) const
N
Niels 已提交
6192 6193 6194 6195 6196 6197 6198
        {
            // 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");
            }

N
Niels 已提交
6199 6200
            assert(m_object != nullptr);

N
Niels 已提交
6201 6202
            switch (m_object->m_type)
            {
6203
                case basic_json::value_t::object:
N
Niels 已提交
6204
                {
N
Niels 已提交
6205
                    throw std::domain_error("cannot compare order of object iterators");
N
Niels 已提交
6206 6207
                }

6208
                case basic_json::value_t::array:
N
Niels 已提交
6209 6210 6211 6212 6213 6214
                {
                    return (m_it.array_iterator < other.m_it.array_iterator);
                }

                default:
                {
6215
                    return (m_it.primitive_iterator < other.m_it.primitive_iterator);
N
Niels 已提交
6216 6217 6218 6219 6220
                }
            }
        }

        /// comparison: less than or equal
N
Niels 已提交
6221
        bool operator<=(const const_iterator& other) const
N
Niels 已提交
6222 6223 6224 6225 6226
        {
            return not other.operator < (*this);
        }

        /// comparison: greater than
N
Niels 已提交
6227
        bool operator>(const const_iterator& other) const
N
Niels 已提交
6228 6229 6230 6231 6232
        {
            return not operator<=(other);
        }

        /// comparison: greater than or equal
N
Niels 已提交
6233
        bool operator>=(const const_iterator& other) const
N
Niels 已提交
6234 6235 6236 6237 6238
        {
            return not operator<(other);
        }

        /// add to iterator
N
Niels 已提交
6239
        const_iterator& operator+=(difference_type i)
N
Niels 已提交
6240
        {
N
Niels 已提交
6241 6242
            assert(m_object != nullptr);

N
Niels 已提交
6243 6244
            switch (m_object->m_type)
            {
6245
                case basic_json::value_t::object:
N
Niels 已提交
6246
                {
N
Niels 已提交
6247
                    throw std::domain_error("cannot use offsets with object iterators");
N
Niels 已提交
6248 6249
                }

6250
                case basic_json::value_t::array:
N
Niels 已提交
6251 6252 6253 6254 6255 6256 6257
                {
                    m_it.array_iterator += i;
                    break;
                }

                default:
                {
6258
                    m_it.primitive_iterator += i;
N
Niels 已提交
6259 6260 6261 6262 6263 6264 6265 6266
                    break;
                }
            }

            return *this;
        }

        /// subtract from iterator
N
Niels 已提交
6267
        const_iterator& operator-=(difference_type i)
N
Niels 已提交
6268 6269 6270 6271 6272
        {
            return operator+=(-i);
        }

        /// add to iterator
N
Niels 已提交
6273
        const_iterator operator+(difference_type i)
N
Niels 已提交
6274 6275 6276 6277 6278 6279 6280
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
6281
        const_iterator operator-(difference_type i)
N
Niels 已提交
6282 6283 6284 6285 6286 6287 6288
        {
            auto result = *this;
            result -= i;
            return result;
        }

        /// return difference
N
Niels 已提交
6289
        difference_type operator-(const const_iterator& other) const
N
Niels 已提交
6290
        {
N
Niels 已提交
6291 6292
            assert(m_object != nullptr);

N
Niels 已提交
6293 6294
            switch (m_object->m_type)
            {
6295
                case basic_json::value_t::object:
N
Niels 已提交
6296
                {
N
Niels 已提交
6297
                    throw std::domain_error("cannot use offsets with object iterators");
N
Niels 已提交
6298 6299
                }

6300
                case basic_json::value_t::array:
N
Niels 已提交
6301 6302 6303 6304 6305 6306
                {
                    return m_it.array_iterator - other.m_it.array_iterator;
                }

                default:
                {
6307
                    return m_it.primitive_iterator - other.m_it.primitive_iterator;
N
Niels 已提交
6308 6309 6310 6311 6312
                }
            }
        }

        /// access to successor
N
Niels 已提交
6313
        reference operator[](difference_type n) const
N
Niels 已提交
6314
        {
N
Niels 已提交
6315 6316
            assert(m_object != nullptr);

N
Niels 已提交
6317 6318
            switch (m_object->m_type)
            {
6319
                case basic_json::value_t::object:
N
Niels 已提交
6320 6321 6322 6323
                {
                    throw std::domain_error("cannot use operator[] for object iterators");
                }

6324
                case basic_json::value_t::array:
N
Niels 已提交
6325 6326 6327 6328
                {
                    return *(m_it.array_iterator + n);
                }

6329
                case basic_json::value_t::null:
N
Niels 已提交
6330 6331 6332 6333 6334 6335
                {
                    throw std::out_of_range("cannot get value");
                }

                default:
                {
6336 6337 6338 6339 6340 6341 6342 6343
                    if (m_it.primitive_iterator == -n)
                    {
                        return *m_object;
                    }
                    else
                    {
                        throw std::out_of_range("cannot get value");
                    }
N
Niels 已提交
6344 6345 6346 6347
                }
            }
        }

6348
        /// return the key of an object iterator
6349
        typename object_t::key_type key() const
N
Niels 已提交
6350
        {
N
Niels 已提交
6351 6352
            assert(m_object != nullptr);

6353 6354 6355 6356 6357 6358 6359 6360
            if (m_object->is_object())
            {
                return m_it.object_iterator->first;
            }
            else
            {
                throw std::domain_error("cannot use key() for non-object iterators");
            }
N
Niels 已提交
6361 6362
        }

N
Niels 已提交
6363 6364
        /// return the value of an iterator
        reference value() const
N
Niels 已提交
6365 6366 6367 6368
        {
            return operator*();
        }

N
cleanup  
Niels 已提交
6369 6370 6371 6372
      private:
        /// associated JSON instance
        pointer m_object = nullptr;
        /// the actual iterator of the associated instance
N
Niels 已提交
6373
        internal_iterator m_it = internal_iterator();
N
cleanup  
Niels 已提交
6374 6375
    };

N
Niels 已提交
6376 6377 6378 6379 6380 6381 6382 6383 6384
    /*!
    @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 已提交
6385

N
Niels 已提交
6386
    @since version 1.0.0
N
Niels 已提交
6387
    */
N
Niels 已提交
6388
    class iterator : public const_iterator
N
cleanup  
Niels 已提交
6389 6390
    {
      public:
N
Niels 已提交
6391 6392 6393
        using base_iterator = const_iterator;
        using pointer = typename basic_json::pointer;
        using reference = typename basic_json::reference;
N
cleanup  
Niels 已提交
6394

6395
        /// default constructor
N
Niels 已提交
6396
        iterator() = default;
6397

N
cleanup  
Niels 已提交
6398
        /// constructor for a given JSON instance
N
cleanup  
Niels 已提交
6399 6400
        iterator(pointer object) noexcept
            : base_iterator(object)
N
Niels 已提交
6401
        {}
N
cleanup  
Niels 已提交
6402

N
Niels 已提交
6403
        /// copy constructor
N
Niels 已提交
6404 6405
        iterator(const iterator& other) noexcept
            : base_iterator(other)
N
Niels 已提交
6406 6407
        {}

N
cleanup  
Niels 已提交
6408
        /// copy assignment
N
Niels 已提交
6409
        iterator& operator=(iterator other) noexcept(
N
Niels 已提交
6410 6411
            std::is_nothrow_move_constructible<pointer>::value and
            std::is_nothrow_move_assignable<pointer>::value and
N
Niels 已提交
6412 6413
            std::is_nothrow_move_constructible<internal_iterator>::value and
            std::is_nothrow_move_assignable<internal_iterator>::value
N
Niels 已提交
6414 6415
        )
        {
N
Niels 已提交
6416
            base_iterator::operator=(other);
N
cleanup  
Niels 已提交
6417 6418 6419
            return *this;
        }

N
Niels 已提交
6420 6421
        /// return a reference to the value pointed to by the iterator
        reference operator*()
N
cleanup  
Niels 已提交
6422
        {
N
Niels 已提交
6423 6424
            return const_cast<reference>(base_iterator::operator*());
        }
N
cleanup  
Niels 已提交
6425

N
Niels 已提交
6426 6427 6428 6429 6430
        /// dereference the iterator
        pointer operator->()
        {
            return const_cast<pointer>(base_iterator::operator->());
        }
N
cleanup  
Niels 已提交
6431

N
Niels 已提交
6432 6433 6434 6435 6436 6437 6438
        /// post-increment (it++)
        iterator operator++(int)
        {
            iterator result = *this;
            base_iterator::operator++();
            return result;
        }
N
cleanup  
Niels 已提交
6439

N
Niels 已提交
6440 6441 6442 6443 6444
        /// pre-increment (++it)
        iterator& operator++()
        {
            base_iterator::operator++();
            return *this;
N
cleanup  
Niels 已提交
6445 6446
        }

N
Niels 已提交
6447 6448
        /// post-decrement (it--)
        iterator operator--(int)
N
cleanup  
Niels 已提交
6449
        {
N
Niels 已提交
6450 6451 6452 6453
            iterator result = *this;
            base_iterator::operator--();
            return result;
        }
N
cleanup  
Niels 已提交
6454

N
Niels 已提交
6455 6456 6457 6458 6459 6460
        /// pre-decrement (--it)
        iterator& operator--()
        {
            base_iterator::operator--();
            return *this;
        }
N
Niels 已提交
6461 6462

        /// add to iterator
N
Niels 已提交
6463
        iterator& operator+=(difference_type i)
N
Niels 已提交
6464
        {
N
Niels 已提交
6465
            base_iterator::operator+=(i);
N
Niels 已提交
6466 6467 6468 6469
            return *this;
        }

        /// subtract from iterator
N
Niels 已提交
6470
        iterator& operator-=(difference_type i)
N
Niels 已提交
6471
        {
N
Niels 已提交
6472 6473
            base_iterator::operator-=(i);
            return *this;
N
Niels 已提交
6474 6475 6476
        }

        /// add to iterator
N
Niels 已提交
6477
        iterator operator+(difference_type i)
N
Niels 已提交
6478 6479 6480 6481 6482 6483 6484
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
6485
        iterator operator-(difference_type i)
N
Niels 已提交
6486 6487 6488 6489 6490 6491
        {
            auto result = *this;
            result -= i;
            return result;
        }

N
Niels 已提交
6492
        difference_type operator-(const iterator& other) const
N
Niels 已提交
6493
        {
N
Niels 已提交
6494
            return base_iterator::operator-(other);
N
Niels 已提交
6495 6496 6497
        }

        /// access to successor
6498
        reference operator[](difference_type n) const
N
Niels 已提交
6499
        {
N
Niels 已提交
6500
            return const_cast<reference>(base_iterator::operator[](n));
N
Niels 已提交
6501 6502
        }

6503
        /// return the value of an iterator
6504
        reference value() const
N
Niels 已提交
6505
        {
N
Niels 已提交
6506
            return const_cast<reference>(base_iterator::value());
N
Niels 已提交
6507
        }
N
cleanup  
Niels 已提交
6508
    };
N
Niels 已提交
6509

N
Niels 已提交
6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523
    /*!
    @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 已提交
6524

N
Niels 已提交
6525
    @since version 1.0.0
N
Niels 已提交
6526
    */
N
Niels 已提交
6527 6528
    template<typename Base>
    class json_reverse_iterator : public std::reverse_iterator<Base>
6529 6530
    {
      public:
6531
        /// shortcut to the reverse iterator adaptor
N
Niels 已提交
6532
        using base_iterator = std::reverse_iterator<Base>;
N
Niels 已提交
6533
        /// the reference type for the pointed-to element
N
Niels 已提交
6534
        using reference = typename Base::reference;
6535

6536
        /// create reverse iterator from iterator
N
Niels 已提交
6537
        json_reverse_iterator(const typename base_iterator::iterator_type& it)
N
cleanup  
Niels 已提交
6538 6539
            : base_iterator(it)
        {}
6540 6541

        /// create reverse iterator from base class
N
cleanup  
Niels 已提交
6542 6543 6544
        json_reverse_iterator(const base_iterator& it)
            : base_iterator(it)
        {}
6545 6546

        /// post-increment (it++)
N
Niels 已提交
6547
        json_reverse_iterator operator++(int)
6548 6549 6550 6551 6552
        {
            return base_iterator::operator++(1);
        }

        /// pre-increment (++it)
N
Niels 已提交
6553
        json_reverse_iterator& operator++()
6554 6555 6556 6557 6558 6559
        {
            base_iterator::operator++();
            return *this;
        }

        /// post-decrement (it--)
N
Niels 已提交
6560
        json_reverse_iterator operator--(int)
6561 6562 6563 6564 6565
        {
            return base_iterator::operator--(1);
        }

        /// pre-decrement (--it)
N
Niels 已提交
6566
        json_reverse_iterator& operator--()
6567 6568 6569 6570 6571 6572
        {
            base_iterator::operator--();
            return *this;
        }

        /// add to iterator
N
Niels 已提交
6573
        json_reverse_iterator& operator+=(difference_type i)
6574 6575 6576 6577 6578 6579
        {
            base_iterator::operator+=(i);
            return *this;
        }

        /// add to iterator
N
Niels 已提交
6580
        json_reverse_iterator operator+(difference_type i) const
6581 6582 6583 6584 6585 6586 6587
        {
            auto result = *this;
            result += i;
            return result;
        }

        /// subtract from iterator
N
Niels 已提交
6588
        json_reverse_iterator operator-(difference_type i) const
6589 6590 6591 6592 6593 6594 6595
        {
            auto result = *this;
            result -= i;
            return result;
        }

        /// return difference
N
Niels 已提交
6596
        difference_type operator-(const json_reverse_iterator& other) const
6597 6598 6599 6600 6601 6602 6603 6604 6605
        {
            return this->base() - other.base();
        }

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

6607
        /// return the key of an object iterator
6608
        typename object_t::key_type key() const
6609
        {
N
Niels 已提交
6610 6611
            auto it = --this->base();
            return it.key();
6612 6613 6614
        }

        /// return the value of an iterator
6615
        reference value() const
6616
        {
N
Niels 已提交
6617 6618
            auto it = --this->base();
            return it.operator * ();
6619 6620 6621
        }
    };

N
Niels 已提交
6622

N
Niels 已提交
6623
  private:
N
Niels 已提交
6624 6625 6626
    //////////////////////
    // lexer and parser //
    //////////////////////
N
Niels 已提交
6627

N
Niels 已提交
6628 6629 6630 6631 6632
    /*!
    @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
6633
    a buffer and recognizes tokens according to RFC 7159.
N
Niels 已提交
6634
    */
N
Niels 已提交
6635
    class lexer
N
Niels 已提交
6636
    {
N
Niels 已提交
6637
      public:
N
Niels 已提交
6638 6639 6640
        /// token types for the parser
        enum class token_type
        {
N
Niels 已提交
6641 6642 6643 6644
            uninitialized,    ///< indicating the scanner is uninitialized
            literal_true,     ///< the "true" literal
            literal_false,    ///< the "false" literal
            literal_null,     ///< the "null" literal
N
Niels 已提交
6645 6646
            value_string,     ///< a string -- use get_string() for actual value
            value_number,     ///< a number -- use get_number() for actual value
N
Niels 已提交
6647 6648 6649 6650 6651 6652 6653 6654
            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 已提交
6655 6656
        };

N
Niels 已提交
6657
        /// the char type to use in the lexer
N
Niels 已提交
6658
        using lexer_char_t = unsigned char;
N
Niels 已提交
6659

N
Niels 已提交
6660
        /// constructor with a given buffer
N
Niels 已提交
6661
        explicit lexer(const string_t& s) noexcept
N
Niels 已提交
6662
            : m_stream(nullptr), m_buffer(s)
N
Niels 已提交
6663
        {
6664
            m_content = reinterpret_cast<const lexer_char_t*>(s.c_str());
N
Niels 已提交
6665
            assert(m_content != nullptr);
N
Niels 已提交
6666
            m_start = m_cursor = m_content;
N
Niels 已提交
6667
            m_limit = m_content + s.size();
N
Niels 已提交
6668
        }
N
Niels 已提交
6669 6670

        /// constructor with a given stream
N
Niels 已提交
6671
        explicit lexer(std::istream* s) noexcept
N
Niels 已提交
6672
            : m_stream(s), m_buffer()
6673
        {
N
Niels 已提交
6674
            assert(m_stream != nullptr);
6675 6676
            getline(*m_stream, m_buffer);
            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
N
Niels 已提交
6677
            assert(m_content != nullptr);
N
Niels 已提交
6678
            m_start = m_cursor = m_content;
6679
            m_limit = m_content + m_buffer.size();
N
Niels 已提交
6680 6681
        }

N
Niels 已提交
6682
        /// default constructor
6683
        lexer() = default;
N
Niels 已提交
6684

N
Niels 已提交
6685
        // switch off unwanted functions
N
Niels 已提交
6686 6687 6688
        lexer(const lexer&) = delete;
        lexer operator=(const lexer&) = delete;

N
Niels 已提交
6689 6690 6691
        /*!
        @brief create a string from a Unicode code point

N
Niels 已提交
6692 6693
        @param[in] codepoint1  the code point (can be high surrogate)
        @param[in] codepoint2  the code point (can be low surrogate or 0)
N
Niels 已提交
6694

N
Niels 已提交
6695
        @return string representation of the code point
N
Niels 已提交
6696

N
Niels 已提交
6697 6698
        @throw std::out_of_range if code point is >0x10ffff; example: `"code
        points above 0x10FFFF are invalid"`
N
Niels 已提交
6699 6700
        @throw std::invalid_argument if the low surrogate is invalid; example:
        `""missing or wrong low surrogate""`
N
Niels 已提交
6701 6702 6703

        @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
        */
6704
        static string_t to_unicode(const std::size_t codepoint1,
N
Niels 已提交
6705
                                   const std::size_t codepoint2 = 0)
N
Niels 已提交
6706
        {
N
Niels 已提交
6707
            string_t result;
N
Niels 已提交
6708

N
Niels 已提交
6709
            // calculate the codepoint from the given code points
N
Niels 已提交
6710
            std::size_t codepoint = codepoint1;
N
Niels 已提交
6711 6712

            // check if codepoint1 is a high surrogate
N
Niels 已提交
6713 6714
            if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
            {
N
Niels 已提交
6715
                // check if codepoint2 is a low surrogate
N
Niels 已提交
6716 6717 6718 6719 6720 6721 6722 6723
                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
N
Niels 已提交
6724
                        // in the result so we have to subtract with:
N
Niels 已提交
6725 6726 6727 6728 6729 6730 6731 6732 6733
                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
                        - 0x35FDC00;
                }
                else
                {
                    throw std::invalid_argument("missing or wrong low surrogate");
                }
            }

N
Niels 已提交
6734
            if (codepoint < 0x80)
N
Niels 已提交
6735
            {
N
Niels 已提交
6736
                // 1-byte characters: 0xxxxxxx (ASCII)
N
Niels 已提交
6737
                result.append(1, static_cast<typename string_t::value_type>(codepoint));
N
Niels 已提交
6738 6739 6740 6741
            }
            else if (codepoint <= 0x7ff)
            {
                // 2-byte characters: 110xxxxx 10xxxxxx
N
Niels 已提交
6742 6743
                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 已提交
6744 6745 6746 6747
            }
            else if (codepoint <= 0xffff)
            {
                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
N
Niels 已提交
6748 6749 6750
                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 已提交
6751 6752 6753 6754
            }
            else if (codepoint <= 0x10ffff)
            {
                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
N
Niels 已提交
6755 6756 6757 6758
                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 已提交
6759 6760 6761
            }
            else
            {
N
Niels 已提交
6762
                throw std::out_of_range("code points above 0x10FFFF are invalid");
N
Niels 已提交
6763 6764 6765 6766 6767
            }

            return result;
        }

N
Niels 已提交
6768
        /// return name of values of type token_type (only used for errors)
N
Niels 已提交
6769
        static std::string token_type_name(token_type t)
N
cleanup  
Niels 已提交
6770 6771 6772
        {
            switch (t)
            {
6773
                case token_type::uninitialized:
N
cleanup  
Niels 已提交
6774
                    return "<uninitialized>";
6775
                case token_type::literal_true:
N
cleanup  
Niels 已提交
6776
                    return "true literal";
6777
                case token_type::literal_false:
N
cleanup  
Niels 已提交
6778
                    return "false literal";
6779
                case token_type::literal_null:
N
cleanup  
Niels 已提交
6780
                    return "null literal";
6781
                case token_type::value_string:
N
cleanup  
Niels 已提交
6782
                    return "string literal";
6783
                case token_type::value_number:
N
cleanup  
Niels 已提交
6784
                    return "number literal";
6785
                case token_type::begin_array:
N
Niels 已提交
6786
                    return "'['";
6787
                case token_type::begin_object:
N
Niels 已提交
6788
                    return "'{'";
6789
                case token_type::end_array:
N
Niels 已提交
6790
                    return "']'";
6791
                case token_type::end_object:
N
Niels 已提交
6792
                    return "'}'";
6793
                case token_type::name_separator:
N
Niels 已提交
6794
                    return "':'";
6795
                case token_type::value_separator:
N
Niels 已提交
6796
                    return "','";
6797
                case token_type::parse_error:
N
Niels 已提交
6798
                    return "<parse error>";
6799
                case token_type::end_of_input:
N
Niels 已提交
6800
                    return "end of input";
N
Niels 已提交
6801 6802 6803 6804 6805
                default:
                {
                    // catch non-enum values
                    return "unknown token"; // LCOV_EXCL_LINE
                }
N
cleanup  
Niels 已提交
6806 6807 6808
            }
        }

N
fixes  
Niels 已提交
6809 6810
        /*!
        This function implements a scanner for JSON. It is specified using
6811 6812 6813 6814 6815
        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 已提交
6816 6817 6818

        @return the class of the next token read from the buffer
        */
6819
        token_type scan() noexcept
N
Niels 已提交
6820
        {
N
cleanup  
Niels 已提交
6821
            // pointer for backtracking information
6822
            m_marker = nullptr;
N
Niels 已提交
6823 6824 6825

            // remember the begin of the token
            m_start = m_cursor;
N
Niels 已提交
6826
            assert(m_start != nullptr);
N
Niels 已提交
6827 6828

            /*!re2c
N
Niels 已提交
6829 6830 6831 6832 6833
                re2c:define:YYCTYPE   = lexer_char_t;
                re2c:define:YYCURSOR  = m_cursor;
                re2c:define:YYLIMIT   = m_limit;
                re2c:define:YYMARKER  = m_marker;
                re2c:define:YYFILL    = "yyfill(); // LCOV_EXCL_LINE";
6834
                re2c:yyfill:parameter = 0;
N
Niels 已提交
6835 6836 6837
                re2c:indent:string    = "    ";
                re2c:indent:top       = 1;
                re2c:labelprefix      = "basic_json_parser_";
N
Niels 已提交
6838

N
Niels 已提交
6839
                // ignore whitespace
N
Niels 已提交
6840 6841 6842
                ws = [ \t\n\r]+;
                ws   { return scan(); }

N
Niels 已提交
6843 6844 6845 6846
                // ignore byte-order-mark
                bom = "\xEF\xBB\xBF";
                bom   { return scan(); }

N
Niels 已提交
6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876
                // 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 已提交
6877
                unescaped       = [^\"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F];
N
Niels 已提交
6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890
                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; }
             */
6891

N
Niels 已提交
6892 6893
        }

6894
        /// append data from the stream to the internal buffer
6895
        void yyfill() noexcept
6896
        {
N
Niels 已提交
6897
            if (m_stream == nullptr or not * m_stream)
N
Niels 已提交
6898 6899 6900
            {
                return;
            }
6901

N
Niels 已提交
6902 6903 6904
            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;
6905

N
Niels 已提交
6906
            m_buffer.erase(0, static_cast<size_t>(offset_start));
6907
            std::string line;
N
Niels 已提交
6908
            assert(m_stream != nullptr);
6909
            std::getline(*m_stream, line);
N
Niels 已提交
6910
            m_buffer += "\n" + line; // add line with newline symbol
6911

6912
            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
N
Niels 已提交
6913
            assert(m_content != nullptr);
6914 6915 6916 6917
            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 已提交
6918 6919
        }

N
Niels 已提交
6920
        /// return string representation of last read token
6921
        string_t get_token() const noexcept
N
Niels 已提交
6922
        {
N
Niels 已提交
6923
            assert(m_start != nullptr);
N
Niels 已提交
6924 6925
            return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
                            static_cast<size_t>(m_cursor - m_start));
N
Niels 已提交
6926 6927 6928
        }

        /*!
N
Niels 已提交
6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944
        @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 已提交
6945 6946

        @return string value of current token without opening and closing quotes
N
Niels 已提交
6947
        @throw std::out_of_range if to_unicode fails
N
Niels 已提交
6948
        */
6949
        string_t get_string() const
N
Niels 已提交
6950
        {
N
Niels 已提交
6951
            string_t result;
N
Niels 已提交
6952 6953 6954
            result.reserve(static_cast<size_t>(m_cursor - m_start - 2));

            // iterate the result between the quotes
N
Niels 已提交
6955
            for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
N
Niels 已提交
6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992
            {
                // 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 已提交
6993
                            result += "\\";
N
Niels 已提交
6994 6995 6996 6997
                            break;
                        }
                        case '/':
                        {
N
Niels 已提交
6998
                            result += "/";
N
Niels 已提交
6999 7000 7001 7002
                            break;
                        }
                        case '"':
                        {
N
Niels 已提交
7003
                            result += "\"";
N
Niels 已提交
7004 7005 7006 7007 7008 7009
                            break;
                        }

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

N
Niels 已提交
7014
                            // check if codepoint is a high surrogate
N
Niels 已提交
7015 7016
                            if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
                            {
N
Niels 已提交
7017
                                // make sure there is a subsequent unicode
N
Niels 已提交
7018
                                if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
N
Niels 已提交
7019 7020 7021 7022
                                {
                                    throw std::invalid_argument("missing low surrogate");
                                }

N
Niels 已提交
7023
                                // get code yyyy from uxxxx\uyyyy
N
Niels 已提交
7024 7025
                                auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
                                                               (i + 7), 4).c_str(), nullptr, 16);
N
Niels 已提交
7026
                                result += to_unicode(codepoint, codepoint2);
7027 7028
                                // skip the next 10 characters (xxxx\uyyyy)
                                i += 10;
N
Niels 已提交
7029 7030 7031 7032 7033 7034 7035 7036
                            }
                            else
                            {
                                // add unicode character(s)
                                result += to_unicode(codepoint);
                                // skip the next four characters (xxxx)
                                i += 4;
                            }
N
Niels 已提交
7037 7038 7039 7040 7041 7042 7043 7044
                            break;
                        }
                    }
                }
                else
                {
                    // all other characters are just copied to the end of the
                    // string
N
Niels 已提交
7045
                    result.append(1, static_cast<typename string_t::value_type>(*i));
N
Niels 已提交
7046 7047 7048 7049
                }
            }

            return result;
N
Niels 已提交
7050 7051
        }

7052 7053 7054 7055
        /*!
        @brief parse floating point number

        This function (and its overloads) serves to select the most approprate
N
Niels 已提交
7056 7057 7058
        standard floating point number parsing function (i.e., `std::strtof`,
        `std::strtod`, or `std::strtold`) based on the type supplied via the
        first parameter. Set this to @a static_cast<number_float_t>(nullptr).
7059

N
Niels 已提交
7060
        @param[in] type  the @ref number_float_t in use
7061

N
Niels 已提交
7062 7063
        @param[in,out] endptr recieves a pointer to the first character after
        the number
7064 7065

        @return the floating point number
N
Niels 已提交
7066 7067 7068 7069 7070

        @warning This function uses `std::strtof`, `std::strtod`, or
        `std::strtold` which use the current C locale to determine which
        character is used as decimal point character. This may yield to parse
        errors if the locale does not used `.`.
7071
        */
7072
        long double str_to_float_t(long double* /* type */, char** endptr) const
7073 7074 7075 7076
        {
            return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
        }

N
Niels 已提交
7077 7078
        /// @copydoc str_to_float_t
        double str_to_float_t(double*, char** endptr) const
7079 7080 7081 7082
        {
            return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
        }

N
Niels 已提交
7083 7084
        /// @copydoc str_to_float_t
        float str_to_float_t(float*, char** endptr) const
7085 7086 7087 7088
        {
            return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
        }

N
Niels 已提交
7089 7090 7091 7092
        /*!
        @brief return number value for number tokens

        This function translates the last token into a floating point number.
7093
        The pointer m_start points to the beginning of the parsed number. We
N
Niels 已提交
7094 7095 7096 7097 7098 7099 7100 7101 7102 7103
        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 已提交
7104
        @throw std::range_error if passed value is out of range
N
Niels 已提交
7105
        */
7106
        number_float_t get_number() const
N
Niels 已提交
7107
        {
N
Niels 已提交
7108 7109
            // conversion
            typename string_t::value_type* endptr;
N
Niels 已提交
7110
            assert(m_start != nullptr);
7111
            number_float_t float_val = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
N
Niels 已提交
7112 7113 7114 7115

            // 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 已提交
7116 7117 7118
        }

      private:
7119
        /// optional input stream
N
Niels 已提交
7120
        std::istream* m_stream = nullptr;
N
fixes  
Niels 已提交
7121
        /// the buffer
7122 7123
        string_t m_buffer;
        /// the buffer pointer
N
Niels 已提交
7124
        const lexer_char_t* m_content = nullptr;
7125
        /// pointer to the beginning of the current symbol
N
Niels 已提交
7126
        const lexer_char_t* m_start = nullptr;
7127 7128
        /// pointer for backtracking information
        const lexer_char_t* m_marker = nullptr;
N
fixes  
Niels 已提交
7129
        /// pointer to the current symbol
N
Niels 已提交
7130
        const lexer_char_t* m_cursor = nullptr;
N
fixes  
Niels 已提交
7131
        /// pointer to the end of the buffer
N
Niels 已提交
7132
        const lexer_char_t* m_limit = nullptr;
N
Niels 已提交
7133 7134
    };

N
Niels 已提交
7135 7136
    /*!
    @brief syntax analysis
N
Niels 已提交
7137 7138

    This class implements a recursive decent parser.
N
Niels 已提交
7139
    */
N
Niels 已提交
7140 7141
    class parser
    {
N
Niels 已提交
7142 7143
      public:
        /// constructor for strings
N
Niels 已提交
7144 7145
        parser(const string_t& s, parser_callback_t cb = nullptr)
            : callback(cb), m_lexer(s)
N
Niels 已提交
7146 7147 7148 7149 7150 7151
        {
            // read first token
            get_token();
        }

        /// a parser reading from an input stream
N
Niels 已提交
7152 7153
        parser(std::istream& _is, parser_callback_t cb = nullptr)
            : callback(cb), m_lexer(&_is)
N
Niels 已提交
7154 7155 7156 7157 7158
        {
            // read first token
            get_token();
        }

N
Niels 已提交
7159
        /// public parser interface
7160
        basic_json parse()
N
Niels 已提交
7161
        {
N
Niels 已提交
7162
            basic_json result = parse_internal(true);
N
Niels 已提交
7163 7164 7165

            expect(lexer::token_type::end_of_input);

N
Niels 已提交
7166 7167 7168
            // 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 已提交
7169 7170 7171 7172
        }

      private:
        /// the actual parser
7173
        basic_json parse_internal(bool keep)
N
Niels 已提交
7174
        {
N
Niels 已提交
7175 7176
            auto result = basic_json(value_t::discarded);

N
Niels 已提交
7177 7178
            switch (last_token)
            {
7179
                case lexer::token_type::begin_object:
N
Niels 已提交
7180
                {
7181
                    if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result))))
N
Niels 已提交
7182 7183
                    {
                        // explicitly set result to object to cope with {}
N
Niels 已提交
7184 7185
                        result.m_type = value_t::object;
                        result.m_value = json_value(value_t::object);
N
Niels 已提交
7186
                    }
N
Niels 已提交
7187 7188 7189 7190 7191

                    // read next token
                    get_token();

                    // closing } -> we are done
N
Niels 已提交
7192
                    if (last_token == lexer::token_type::end_object)
N
Niels 已提交
7193
                    {
N
Niels 已提交
7194
                        get_token();
7195
                        if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
N
Niels 已提交
7196 7197 7198
                        {
                            result = basic_json(value_t::discarded);
                        }
N
Niels 已提交
7199
                        return result;
N
Niels 已提交
7200 7201
                    }

N
Niels 已提交
7202 7203 7204
                    // no comma is expected here
                    unexpect(lexer::token_type::value_separator);

N
Niels 已提交
7205 7206 7207
                    // otherwise: parse key-value pairs
                    do
                    {
N
Niels 已提交
7208 7209 7210 7211 7212 7213
                        // ugly, but could be fixed with loop reorganization
                        if (last_token == lexer::token_type::value_separator)
                        {
                            get_token();
                        }

N
Niels 已提交
7214
                        // store key
N
Niels 已提交
7215 7216
                        expect(lexer::token_type::value_string);
                        const auto key = m_lexer.get_string();
N
Niels 已提交
7217

N
Niels 已提交
7218 7219 7220
                        bool keep_tag = false;
                        if (keep)
                        {
N
Niels 已提交
7221 7222 7223 7224 7225 7226 7227 7228 7229
                            if (callback)
                            {
                                basic_json k(key);
                                keep_tag = callback(depth, parse_event_t::key, k);
                            }
                            else
                            {
                                keep_tag = true;
                            }
N
Niels 已提交
7230 7231
                        }

N
Niels 已提交
7232 7233
                        // parse separator (:)
                        get_token();
N
Niels 已提交
7234
                        expect(lexer::token_type::name_separator);
N
Niels 已提交
7235

7236
                        // parse and add value
N
Niels 已提交
7237
                        get_token();
N
Niels 已提交
7238 7239 7240
                        auto value = parse_internal(keep);
                        if (keep and keep_tag and not value.is_discarded())
                        {
7241
                            result[key] = std::move(value);
N
Niels 已提交
7242
                        }
N
Niels 已提交
7243
                    }
N
Niels 已提交
7244
                    while (last_token == lexer::token_type::value_separator);
N
Niels 已提交
7245 7246

                    // closing }
N
Niels 已提交
7247
                    expect(lexer::token_type::end_object);
N
Niels 已提交
7248
                    get_token();
7249
                    if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
N
Niels 已提交
7250 7251 7252
                    {
                        result = basic_json(value_t::discarded);
                    }
N
Niels 已提交
7253 7254

                    return result;
N
Niels 已提交
7255 7256
                }

7257
                case lexer::token_type::begin_array:
N
Niels 已提交
7258
                {
7259
                    if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
N
Niels 已提交
7260 7261
                    {
                        // explicitly set result to object to cope with []
N
Niels 已提交
7262 7263
                        result.m_type = value_t::array;
                        result.m_value = json_value(value_t::array);
N
Niels 已提交
7264
                    }
N
Niels 已提交
7265 7266 7267 7268 7269

                    // read next token
                    get_token();

                    // closing ] -> we are done
N
Niels 已提交
7270
                    if (last_token == lexer::token_type::end_array)
N
Niels 已提交
7271
                    {
N
Niels 已提交
7272
                        get_token();
7273
                        if (callback and not callback(--depth, parse_event_t::array_end, result))
N
Niels 已提交
7274 7275 7276
                        {
                            result = basic_json(value_t::discarded);
                        }
N
Niels 已提交
7277
                        return result;
N
Niels 已提交
7278 7279
                    }

N
Niels 已提交
7280 7281 7282
                    // no comma is expected here
                    unexpect(lexer::token_type::value_separator);

N
Niels 已提交
7283 7284 7285
                    // otherwise: parse values
                    do
                    {
N
Niels 已提交
7286 7287 7288 7289 7290
                        // ugly, but could be fixed with loop reorganization
                        if (last_token == lexer::token_type::value_separator)
                        {
                            get_token();
                        }
N
Niels 已提交
7291

N
Niels 已提交
7292 7293 7294 7295
                        // parse value
                        auto value = parse_internal(keep);
                        if (keep and not value.is_discarded())
                        {
7296
                            result.push_back(std::move(value));
N
Niels 已提交
7297
                        }
N
Niels 已提交
7298
                    }
N
Niels 已提交
7299
                    while (last_token == lexer::token_type::value_separator);
N
Niels 已提交
7300 7301

                    // closing ]
N
Niels 已提交
7302
                    expect(lexer::token_type::end_array);
N
Niels 已提交
7303
                    get_token();
7304
                    if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
N
Niels 已提交
7305 7306 7307
                    {
                        result = basic_json(value_t::discarded);
                    }
N
Niels 已提交
7308 7309

                    return result;
N
Niels 已提交
7310 7311
                }

7312
                case lexer::token_type::literal_null:
N
Niels 已提交
7313
                {
N
Niels 已提交
7314
                    get_token();
N
Niels 已提交
7315
                    result.m_type = value_t::null;
N
Niels 已提交
7316
                    break;
N
Niels 已提交
7317 7318
                }

7319
                case lexer::token_type::value_string:
N
Niels 已提交
7320
                {
N
Niels 已提交
7321
                    const auto s = m_lexer.get_string();
N
Niels 已提交
7322
                    get_token();
N
Niels 已提交
7323 7324
                    result = basic_json(s);
                    break;
N
Niels 已提交
7325 7326
                }

7327
                case lexer::token_type::literal_true:
N
Niels 已提交
7328
                {
N
Niels 已提交
7329
                    get_token();
N
Niels 已提交
7330 7331
                    result.m_type = value_t::boolean;
                    result.m_value = true;
N
Niels 已提交
7332
                    break;
N
Niels 已提交
7333 7334
                }

7335
                case lexer::token_type::literal_false:
N
Niels 已提交
7336
                {
N
Niels 已提交
7337
                    get_token();
N
Niels 已提交
7338 7339
                    result.m_type = value_t::boolean;
                    result.m_value = false;
N
Niels 已提交
7340
                    break;
N
Niels 已提交
7341 7342
                }

7343
                case lexer::token_type::value_number:
N
Niels 已提交
7344
                {
7345
                    result.m_value = m_lexer.get_number();
N
Niels 已提交
7346

N
Niels 已提交
7347 7348
                    // NAN is returned if token could not be translated
                    // completely
7349
                    if (std::isnan(result.m_value.number_float))
N
Niels 已提交
7350 7351
                    {
                        throw std::invalid_argument(std::string("parse error - ") +
N
Niels 已提交
7352
                                                    m_lexer.get_token() + " is not a number");
N
Niels 已提交
7353 7354
                    }

N
Niels 已提交
7355 7356
                    get_token();

7357 7358
                    // check if conversion loses precision (special case -0.0 always loses precision)
                    const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
N
Niels 已提交
7359 7360
                    if (result.m_value.number_float == static_cast<number_float_t>(int_val) and
                            result.m_value.number_integer != json_value(-0.0f).number_integer)
N
Niels 已提交
7361
                    {
N
Niels 已提交
7362
                        // we would not lose precision -> return int
N
Niels 已提交
7363 7364
                        result.m_type = value_t::number_integer;
                        result.m_value = int_val;
N
Niels 已提交
7365 7366 7367
                    }
                    else
                    {
N
Niels 已提交
7368
                        // we would lose precision -> return float
N
Niels 已提交
7369
                        result.m_type = value_t::number_float;
N
Niels 已提交
7370
                    }
N
Niels 已提交
7371
                    break;
N
Niels 已提交
7372 7373 7374 7375
                }

                default:
                {
N
Niels 已提交
7376 7377
                    // the last token was unexpected
                    unexpect(last_token);
N
Niels 已提交
7378 7379
                }
            }
N
Niels 已提交
7380

7381
            if (keep and callback and not callback(depth, parse_event_t::value, result))
N
Niels 已提交
7382 7383 7384 7385
            {
                result = basic_json(value_t::discarded);
            }
            return result;
N
Niels 已提交
7386 7387
        }

N
Niels 已提交
7388
        /// get next token from lexer
7389
        typename lexer::token_type get_token()
N
Niels 已提交
7390
        {
N
Niels 已提交
7391 7392
            last_token = m_lexer.scan();
            return last_token;
N
Niels 已提交
7393 7394
        }

7395
        void expect(typename lexer::token_type t) const
N
Niels 已提交
7396 7397 7398
        {
            if (t != last_token)
            {
N
Niels 已提交
7399 7400 7401 7402
                std::string error_msg = "parse error - unexpected ";
                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token() + "'") :
                              lexer::token_type_name(last_token));
                error_msg += "; expected " + lexer::token_type_name(t);
N
Niels 已提交
7403 7404 7405 7406
                throw std::invalid_argument(error_msg);
            }
        }

7407
        void unexpect(typename lexer::token_type t) const
N
Niels 已提交
7408 7409 7410
        {
            if (t == last_token)
            {
N
Niels 已提交
7411 7412 7413
                std::string error_msg = "parse error - unexpected ";
                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token() + "'") :
                              lexer::token_type_name(last_token));
N
Niels 已提交
7414 7415 7416 7417
                throw std::invalid_argument(error_msg);
            }
        }

N
Niels 已提交
7418
      private:
N
Niels 已提交
7419
        /// current level of recursion
N
Niels 已提交
7420 7421 7422
        int depth = 0;
        /// callback function
        parser_callback_t callback;
N
Niels 已提交
7423
        /// the type of the last read token
N
Niels 已提交
7424
        typename lexer::token_type last_token = lexer::token_type::uninitialized;
N
Niels 已提交
7425
        /// the lexer
N
Niels 已提交
7426
        lexer m_lexer;
N
Niels 已提交
7427
    };
N
cleanup  
Niels 已提交
7428 7429 7430 7431 7432 7433 7434
};


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

N
Niels 已提交
7435 7436 7437 7438 7439
/*!
@brief default JSON class

This type is the default specialization of the @ref basic_json class which uses
the standard template types.
N
Niels 已提交
7440

N
Niels 已提交
7441
@since version 1.0.0
N
Niels 已提交
7442
*/
N
cleanup  
Niels 已提交
7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453
using json = basic_json<>;
}


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

// specialization of std::swap, and std::hash
namespace std
{
N
Niels 已提交
7454 7455
/*!
@brief exchanges the values of two JSON objects
N
Niels 已提交
7456

N
Niels 已提交
7457
@since version 1.0.0
N
Niels 已提交
7458
*/
N
cleanup  
Niels 已提交
7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472
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 已提交
7473 7474 7475
    /*!
    @brief return a hash value for a JSON object

N
Niels 已提交
7476
    @since version 1.0.0
N
Niels 已提交
7477
    */
7478
    std::size_t operator()(const nlohmann::json& j) const
N
cleanup  
Niels 已提交
7479 7480
    {
        // a naive hashing via the string representation
N
Niels 已提交
7481 7482
        const auto& h = hash<nlohmann::json::string_t>();
        return h(j.dump());
N
cleanup  
Niels 已提交
7483 7484 7485 7486
    }
};
}

N
Niels 已提交
7487
/*!
N
Niels 已提交
7488 7489
@brief user-defined string literal for JSON values

N
Niels 已提交
7490 7491 7492 7493
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 已提交
7494
@param[in] s  a string representation of a JSON object
N
Niels 已提交
7495
@return a JSON object
N
Niels 已提交
7496

N
Niels 已提交
7497
@since version 1.0.0
N
Niels 已提交
7498
*/
N
Niels 已提交
7499
inline nlohmann::json operator "" _json(const char* s, std::size_t)
N
Niels 已提交
7500
{
N
Niels 已提交
7501
    return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
N
Niels 已提交
7502 7503
}

7504 7505 7506 7507 7508
// restore GCC/clang diagnostic settings
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
    #pragma GCC diagnostic pop
#endif

N
cleanup  
Niels 已提交
7509
#endif