-
Notifications
You must be signed in to change notification settings - Fork 0
/
json.hpp
12201 lines (10207 loc) · 406 KB
/
json.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
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
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
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
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
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
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++
| | |__ | | | | | | version 2.0.9
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
*/
#ifndef NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_HPP
#include <algorithm> // all_of, for_each, transform
#include <array> // array
#include <cassert> // assert
#include <cctype> // isdigit
#include <ciso646> // and, not, or
#include <cmath> // isfinite, ldexp, signbit
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <cstdint> // int64_t, uint64_t
#include <cstdlib> // strtod, strtof, strtold, strtoul
#include <cstring> // strlen
#include <functional> // function, hash, less
#include <initializer_list> // initializer_list
#include <iomanip> // setw
#include <iostream> // istream, ostream
#include <iterator> // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
#include <limits> // numeric_limits
#include <locale> // locale
#include <map> // map
#include <memory> // addressof, allocator, allocator_traits, unique_ptr
#include <numeric> // accumulate
#include <sstream> // stringstream
#include <stdexcept> // domain_error, invalid_argument, out_of_range
#include <string> // getline, stoi, string, to_string
#include <type_traits> // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference
#include <utility> // declval, forward, make_pair, move, pair, swap
#include <vector> // vector
// exclude unsupported compilers
#if defined(__clang__)
#define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#if CLANG_VERSION < 30400
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
#endif
#elif defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if GCC_VERSION < 40900
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
#endif
#endif
// 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
// disable documentation warnings on clang
#if defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdocumentation"
#endif
// allow for portable deprecation warnings
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#define JSON_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define JSON_DEPRECATED __declspec(deprecated)
#else
#define JSON_DEPRECATED
#endif
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
@since version 1.0.0
*/
namespace nlohmann
{
/*!
@brief unnamed namespace with internal helper functions
@since version 1.0.0
*/
namespace
{
/*!
@brief Helper to determine whether there's a key_type for T.
Thus helper is used to tell associative containers apart from other containers
such as sequence containers. For instance, `std::map` passes the test as it
contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378
@since version 1.0.0, overworked in version 2.0.6
*/
template<typename T>
struct has_mapped_type
{
private:
template <typename U, typename = typename U::mapped_type>
static int detect(U&&);
static void detect(...);
public:
static constexpr bool value =
std::is_integral<decltype(detect(std::declval<T>()))>::value;
};
}
/*!
@brief a class to store JSON values
@tparam ObjectType type for JSON objects (`std::map` by default; will be used
in @ref object_t)
@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
in @ref array_t)
@tparam StringType type for JSON strings and object keys (`std::string` by
default; will be used in @ref string_t)
@tparam BooleanType type for JSON booleans (`bool` by default; will be used
in @ref boolean_t)
@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
default; will be used in @ref number_integer_t)
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
`uint64_t` by default; will be used in @ref number_unsigned_t)
@tparam NumberFloatType type for JSON floating-point numbers (`double` by
default; will be used in @ref number_float_t)
@tparam AllocatorType type of the allocator to use (`std::allocator` by
default)
@requirement The class satisfies the following concept requirements:
- Basic
- [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
JSON values can be default constructed. The result will be a JSON null value.
- [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
A JSON value can be constructed from an rvalue argument.
- [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
A JSON value can be copy-constructed from an lvalue expression.
- [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
A JSON value van be assigned from an rvalue argument.
- [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
A JSON value can be copy-assigned from an lvalue expression.
- [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
JSON values can be destructed.
- Layout
- [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.
- Library-wide
- [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.
- Container
- [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.
@invariant The member variables @a m_value and @a m_type have the following
relationship:
- If `m_type == value_t::object`, then `m_value.object != nullptr`.
- If `m_type == value_t::array`, then `m_value.array != nullptr`.
- If `m_type == value_t::string`, then `m_value.string != nullptr`.
The invariants are checked by member function assert_invariant().
@internal
@note ObjectType trick from http://stackoverflow.com/a/9860911
@endinternal
@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
Format](http://rfc7159.net/rfc7159)
@since version 1.0.0
@nosubgrouping
*/
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 = std::int64_t,
class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator
>
class basic_json
{
private:
/// workaround type for MSVC
using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType>;
public:
// forward declarations
template<typename U> class iter_impl;
template<typename Base> class json_reverse_iterator;
class json_pointer;
/////////////////////
// container types //
/////////////////////
/// @name container types
/// The canonic container types to use @ref basic_json like any other STL
/// container.
/// @{
/// the type of elements in a basic_json container
using value_type = basic_json;
/// the type of an element reference
using reference = value_type&;
/// the type of an element const reference
using const_reference = const value_type&;
/// a type to represent differences between iterators
using difference_type = std::ptrdiff_t;
/// a type to represent container sizes
using size_type = std::size_t;
/// the allocator type
using allocator_type = AllocatorType<basic_json>;
/// the type of an element pointer
using pointer = typename std::allocator_traits<allocator_type>::pointer;
/// the type of an element const pointer
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
/// an iterator for a basic_json container
using iterator = iter_impl<basic_json>;
/// a const iterator for a basic_json container
using const_iterator = iter_impl<const basic_json>;
/// a reverse iterator for a basic_json container
using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
/// a const reverse iterator for a basic_json container
using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
/// @}
/*!
@brief returns the allocator associated with the container
*/
static allocator_type get_allocator()
{
return allocator_type();
}
///////////////////////////
// JSON value data types //
///////////////////////////
/// @name JSON value data types
/// The data types to store a JSON value. These types are derived from
/// the template arguments passed to class @ref basic_json.
/// @{
/*!
@brief a type for an object
[RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
> An object is an unordered collection of zero or more name/value pairs,
> where a name is a string and a value is a string, number, boolean, null,
> object, or array.
To store objects in C++, a type is defined by the template parameters
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`)
#### Default type
With the default values for @a ObjectType (`std::map`), @a StringType
(`std::string`), and @a AllocatorType (`std::allocator`), the default
value for @a object_t is:
@code {.cpp}
std::map<
std::string, // key_type
basic_json, // value_type
std::less<std::string>, // key_compare
std::allocator<std::pair<const std::string, basic_json>> // allocator_type
>
@endcode
#### Behavior
The choice of @a object_t influences the behavior of the JSON class. With
the default type, objects have the following behavior:
- When all names are unique, objects will be interoperable in the sense
that all software implementations receiving that object will agree on
the name-value mappings.
- When the names within an object are not unique, later stored name/value
pairs overwrite previously stored name/value pairs, leaving the used
names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
be treated as equal and both stored as `{"key": 1}`.
- Internally, name/value pairs are stored in lexicographical order of the
names. Objects will also be serialized (see @ref dump) in this order.
For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
and serialized as `{"a": 2, "b": 1}`.
- When comparing objects, the order of the name/value pairs is irrelevant.
This makes objects interoperable in the sense that they will not be
affected by these differences. For instance, `{"b": 1, "a": 2}` and
`{"a": 2, "b": 1}` will be treated as equal.
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the maximum depth of nesting.
In this class, the object's limit of nesting is not constraint explicitly.
However, a maximum depth of nesting may be introduced by the compiler or
runtime environment. A theoretical limit can be queried by calling the
@ref max_size function of a JSON object.
#### Storage
Objects are stored as pointers in a @ref basic_json type. That is, for any
access to object values, a pointer of type `object_t*` must be
dereferenced.
@sa @ref array_t -- type for an array value
@since version 1.0.0
@note The order name/value pairs are added to the object is *not*
preserved by the library. Therefore, iterating an object may return
name/value pairs in a different order than they were originally stored. In
fact, keys will be traversed in alphabetical order as `std::map` with
`std::less` is used by default. Please note this behavior conforms to [RFC
7159](http://rfc7159.net/rfc7159), because any order implements the
specified "unordered" nature of JSON objects.
*/
using object_t = ObjectType<StringType,
basic_json,
std::less<StringType>,
AllocatorType<std::pair<const StringType,
basic_json>>>;
/*!
@brief a type for an array
[RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
> An array is an ordered sequence of zero or more values.
To store objects in C++, a type is defined by the template parameters
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`)
#### Default type
With the default values for @a ArrayType (`std::vector`) and @a
AllocatorType (`std::allocator`), the default value for @a array_t is:
@code {.cpp}
std::vector<
basic_json, // value_type
std::allocator<basic_json> // allocator_type
>
@endcode
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the maximum depth of nesting.
In this class, the array's limit of nesting is not constraint explicitly.
However, a maximum depth of nesting may be introduced by the compiler or
runtime environment. A theoretical limit can be queried by calling the
@ref max_size function of a JSON array.
#### Storage
Arrays are stored as pointers in a @ref basic_json type. That is, for any
access to array values, a pointer of type `array_t*` must be dereferenced.
@sa @ref object_t -- type for an object value
@since version 1.0.0
*/
using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
/*!
@brief a type for a string
[RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
> A string is a sequence of zero or more Unicode characters.
To store objects in C++, a type is defined by the template parameter
described below. Unicode values are split by the JSON class into
byte-sized characters during deserialization.
@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.
#### Default type
With the default values for @a StringType (`std::string`), the default
value for @a string_t is:
@code {.cpp}
std::string
@endcode
#### String comparison
[RFC 7159](http://rfc7159.net/rfc7159) states:
> Software implementations are typically required to test names of object
> members for equality. Implementations that transform the textual
> representation into sequences of Unicode code units and then perform the
> comparison numerically, code unit by code unit, are interoperable in the
> sense that implementations will agree in all cases on equality or
> inequality of two strings. For example, implementations that compare
> strings with escaped characters unconverted may incorrectly find that
> `"a\\b"` and `"a\u005Cb"` are not equal.
This implementation is interoperable as it does compare strings code unit
by code unit.
#### Storage
String values are stored as pointers in a @ref basic_json type. That is,
for any access to string values, a pointer of type `string_t*` must be
dereferenced.
@since version 1.0.0
*/
using string_t = StringType;
/*!
@brief a type for a boolean
[RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
type which differentiates the two literals `true` and `false`.
To store objects in C++, a type is defined by the template parameter @a
BooleanType which chooses the type to use.
#### Default type
With the default values for @a BooleanType (`bool`), the default value for
@a boolean_t is:
@code {.cpp}
bool
@endcode
#### Storage
Boolean values are stored directly inside a @ref basic_json type.
@since version 1.0.0
*/
using boolean_t = BooleanType;
/*!
@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 a signed integer, an unsigned integer or a floating-point number.
Therefore, three different types, @ref number_integer_t, @ref
number_unsigned_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_unsigned_t or @ref
number_float_t.
[RFC 7159](http://rfc7159.net/rfc7159) further states:
> Note that when such software is used, numbers that are integers and are
> in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
> that implementations will agree exactly on their numeric values.
As this range is a subrange of the exactly supported range [INT64_MIN,
INT64_MAX], this class's integer type is interoperable.
#### Storage
Integer number values are stored directly inside a @ref basic_json type.
@sa @ref number_float_t -- type for number values (floating-point)
@sa @ref number_unsigned_t -- type for number values (unsigned integer)
@since version 1.0.0
*/
using number_integer_t = NumberIntegerType;
/*!
@brief a type for a number (unsigned)
[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 a signed integer, an unsigned integer or a floating-point number.
Therefore, three different types, @ref number_integer_t, @ref
number_unsigned_t and @ref number_float_t are used.
To store unsigned integer numbers in C++, a type is defined by the
template parameter @a NumberUnsignedType which chooses the type to use.
#### Default type
With the default values for @a NumberUnsignedType (`uint64_t`), the
default value for @a number_unsigned_t is:
@code {.cpp}
uint64_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 `18446744073709551615` (UINT64_MAX) and the minimal integer
number that can be stored is `0`. 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_integer_t or @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 (when considered in conjunction with the
number_integer_t type) of the exactly supported range [0, UINT64_MAX],
this class's integer type is interoperable.
#### Storage
Integer number values are stored directly inside a @ref basic_json type.
@sa @ref number_float_t -- type for number values (floating-point)
@sa @ref number_integer_t -- type for number values (integer)
@since version 2.0.0
*/
using number_unsigned_t = NumberUnsignedType;
/*!
@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 a signed integer, an unsigned integer or a floating-point number.
Therefore, three different types, @ref number_integer_t, @ref
number_unsigned_t and @ref number_float_t are used.
To store floating-point numbers in C++, a type is defined by the template
parameter @a NumberFloatType which chooses the type to use.
#### Default type
With the default values for @a NumberFloatType (`double`), the default
value for @a number_float_t is:
@code {.cpp}
double
@endcode
#### Default behavior
- The restrictions about leading zeros is not enforced in C++. Instead,
leading zeros in floating-point literals will be ignored. Internally,
the value will be stored as decimal number. For instance, the C++
floating-point literal `01.2` will be serialized to `1.2`. During
deserialization, leading zeros yield an error.
- Not-a-number (NaN) values will be serialized to `null`.
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) states:
> This specification allows implementations to set limits on the range and
> precision of numbers accepted. Since software that implements IEEE
> 754-2008 binary64 (double precision) numbers is generally available and
> widely used, good interoperability can be achieved by implementations
> that expect no more precision or range than these provide, in the sense
> that implementations will approximate JSON numbers within the expected
> precision.
This implementation does exactly follow this approach, as it uses double
precision floating-point numbers. Note values smaller than
`-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
will be stored as NaN internally and be serialized to `null`.
#### Storage
Floating-point number values are stored directly inside a @ref basic_json
type.
@sa @ref number_integer_t -- type for number values (integer)
@sa @ref number_unsigned_t -- type for number values (unsigned integer)
@since version 1.0.0
*/
using number_float_t = NumberFloatType;
/// @}
///////////////////////////
// JSON type enumeration //
///////////////////////////
/*!
@brief the JSON type enumeration
This enumeration collects the different JSON types. It is internally used
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() (with @ref is_number_integer(), @ref is_number_unsigned(), and
@ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and
@ref is_structured() rely on it.
@note There are three enumeration entries (number_integer,
number_unsigned, and number_float), because the library distinguishes
these three types for numbers: @ref number_unsigned_t is used for unsigned
integers, @ref number_integer_t is used for signed integers, and @ref
number_float_t is used for floating-point numbers or to approximate
integers which do not fit in the limits of their respective type.
@sa @ref basic_json(const value_t value_type) -- create a JSON value with
the default value for a given type
@since version 1.0.0
*/
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 (signed integer)
number_unsigned, ///< number value (unsigned integer)
number_float, ///< number value (floating-point)
discarded ///< discarded by the the parser callback function
};
private:
/// helper for exception-safe object creation
template<typename T, typename... Args>
static T* create(Args&& ... args)
{
AllocatorType<T> alloc;
auto deleter = [&](T * object)
{
alloc.deallocate(object, 1);
};
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
alloc.construct(object.get(), std::forward<Args>(args)...);
assert(object.get() != nullptr);
return object.release();
}
////////////////////////
// JSON value storage //
////////////////////////
/*!
@brief a JSON value
The actual storage for a JSON value of the @ref basic_json class. This
union combines the different storage types for the JSON value types
defined in @ref value_t.
JSON type | value_t type | used type
--------- | --------------- | ------------------------
object | object | pointer to @ref object_t
array | array | pointer to @ref array_t
string | string | pointer to @ref string_t
boolean | boolean | @ref boolean_t
number | number_integer | @ref number_integer_t
number | number_unsigned | @ref number_unsigned_t
number | number_float | @ref number_float_t
null | null | *no value is stored*
@note Variable-length types (objects, arrays, and strings) are stored as
pointers. The size of the union should not exceed 64 bits if the default
value types are used.
@since version 1.0.0
*/
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;
/// boolean
boolean_t boolean;
/// number (integer)
number_integer_t number_integer;
/// number (unsigned integer)
number_unsigned_t number_unsigned;
/// number (floating-point)
number_float_t number_float;
/// default constructor (for null values)
json_value() = default;
/// constructor for booleans
json_value(boolean_t v) noexcept : boolean(v) {}
/// constructor for numbers (integer)
json_value(number_integer_t v) noexcept : number_integer(v) {}
/// constructor for numbers (unsigned)
json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
/// constructor for numbers (floating-point)
json_value(number_float_t v) noexcept : number_float(v) {}
/// constructor for empty values of a given type
json_value(value_t t)
{
switch (t)
{
case value_t::object:
{
object = create<object_t>();
break;
}
case value_t::array:
{
array = create<array_t>();
break;
}
case value_t::string:
{
string = create<string_t>("");
break;
}
case value_t::boolean:
{
boolean = boolean_t(false);
break;
}
case value_t::number_integer:
{
number_integer = number_integer_t(0);
break;
}
case value_t::number_unsigned:
{
number_unsigned = number_unsigned_t(0);
break;
}
case value_t::number_float:
{
number_float = number_float_t(0.0);
break;
}
default:
{
break;
}
}
}
/// constructor for strings
json_value(const string_t& value)
{
string = create<string_t>(value);
}
/// constructor for objects
json_value(const object_t& value)
{
object = create<object_t>(value);
}
/// constructor for arrays
json_value(const array_t& value)
{
array = create<array_t>(value);
}
};
/*!
@brief checks the class invariants
This function asserts the class invariants. It needs to be called at the
end of every constructor to make sure that created objects respect the
invariant. Furthermore, it has to be called each time the type of a JSON
value is changed, because the invariant expresses a relationship between
@a m_type and @a m_value.
*/
void assert_invariant() const
{
assert(m_type != value_t::object or m_value.object != nullptr);
assert(m_type != value_t::array or m_value.array != nullptr);
assert(m_type != value_t::string or m_value.string != nullptr);
}
public:
//////////////////////////
// JSON parser callback //
//////////////////////////
/*!
@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.
@image html callback_events.png "Example when certain parse events are triggered"
@since version 1.0.0
*/
enum class parse_event_t : uint8_t
{
/// 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
};
/*!
@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&, const
parser_callback_t) or @ref parse(const CharT, const 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
@image html callback_events.png "Example when certain parse events are triggered"
Discarding a value (i.e., returning `false`) has different effects
depending on the context in which function was called:
- Discarded values in structured types are skipped. That is, the parser
will behave as if the discarded value was never read.
- In case a value outside a structured type is skipped, it is replaced
with `null`. This case happens if the top-level element is skipped.
@param[in] depth the depth of the recursion during parsing
@param[in] event an event of type parse_event_t indicating the context in
the callback function has been called
@param[in,out] parsed the current intermediate parse result; note that
writing to this value has no effect for parse_event_t::key events
@return Whether the JSON value which called the function during parsing
should be kept (`true`) or not (`false`). In the latter case, it is either
skipped completely or replaced by an empty discarded object.
@sa @ref parse(std::istream&, parser_callback_t) or
@ref parse(const CharT, const parser_callback_t) for examples
@since version 1.0.0
*/