diff options
Diffstat (limited to 'vendor/json')
m--------- | vendor/json | 0 | ||||
-rw-r--r-- | vendor/json/json.hpp | 10794 |
2 files changed, 10794 insertions, 0 deletions
diff --git a/vendor/json b/vendor/json deleted file mode 160000 | |||
Subproject 2b137110095c2b2046cde5af4ac8892b8a3f380 | |||
diff --git a/vendor/json/json.hpp b/vendor/json/json.hpp new file mode 100644 index 0000000..4447412 --- /dev/null +++ b/vendor/json/json.hpp | |||
@@ -0,0 +1,10794 @@ | |||
1 | /* | ||
2 | __ _____ _____ _____ | ||
3 | __| | __| | | | JSON for Modern C++ | ||
4 | | | |__ | | | | | | version 2.0.7 | ||
5 | |_____|_____|_____|_|___| https://github.com/nlohmann/json | ||
6 | |||
7 | Licensed under the MIT License <http://opensource.org/licenses/MIT>. | ||
8 | Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>. | ||
9 | |||
10 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
11 | of this software and associated documentation files (the "Software"), to deal | ||
12 | in the Software without restriction, including without limitation the rights | ||
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
14 | copies of the Software, and to permit persons to whom the Software is | ||
15 | furnished to do so, subject to the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be included in all | ||
18 | copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
26 | SOFTWARE. | ||
27 | */ | ||
28 | |||
29 | #ifndef NLOHMANN_JSON_HPP | ||
30 | #define NLOHMANN_JSON_HPP | ||
31 | |||
32 | #include <algorithm> | ||
33 | #include <array> | ||
34 | #include <cassert> | ||
35 | #include <cctype> | ||
36 | #include <ciso646> | ||
37 | #include <cmath> | ||
38 | #include <cstddef> | ||
39 | #include <cstdint> | ||
40 | #include <cstdlib> | ||
41 | #include <cstring> | ||
42 | #include <functional> | ||
43 | #include <initializer_list> | ||
44 | #include <iomanip> | ||
45 | #include <iostream> | ||
46 | #include <iterator> | ||
47 | #include <limits> | ||
48 | #include <locale> | ||
49 | #include <map> | ||
50 | #include <memory> | ||
51 | #include <numeric> | ||
52 | #include <sstream> | ||
53 | #include <stdexcept> | ||
54 | #include <string> | ||
55 | #include <type_traits> | ||
56 | #include <utility> | ||
57 | #include <vector> | ||
58 | |||
59 | // exclude unsupported compilers | ||
60 | #if defined(__clang__) | ||
61 | #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) | ||
62 | #if CLANG_VERSION < 30400 | ||
63 | #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" | ||
64 | #endif | ||
65 | #elif defined(__GNUC__) | ||
66 | #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) | ||
67 | #if GCC_VERSION < 40900 | ||
68 | #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" | ||
69 | #endif | ||
70 | #endif | ||
71 | |||
72 | // disable float-equal warnings on GCC/clang | ||
73 | #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) | ||
74 | #pragma GCC diagnostic push | ||
75 | #pragma GCC diagnostic ignored "-Wfloat-equal" | ||
76 | #endif | ||
77 | |||
78 | // allow for portable deprecation warnings | ||
79 | #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) | ||
80 | #define JSON_DEPRECATED __attribute__((deprecated)) | ||
81 | #elif defined(_MSC_VER) | ||
82 | #define JSON_DEPRECATED __declspec(deprecated) | ||
83 | #else | ||
84 | #define JSON_DEPRECATED | ||
85 | #endif | ||
86 | |||
87 | /*! | ||
88 | @brief namespace for Niels Lohmann | ||
89 | @see https://github.com/nlohmann | ||
90 | @since version 1.0.0 | ||
91 | */ | ||
92 | namespace nlohmann | ||
93 | { | ||
94 | |||
95 | |||
96 | /*! | ||
97 | @brief unnamed namespace with internal helper functions | ||
98 | @since version 1.0.0 | ||
99 | */ | ||
100 | namespace | ||
101 | { | ||
102 | /*! | ||
103 | @brief Helper to determine whether there's a key_type for T. | ||
104 | |||
105 | Thus helper is used to tell associative containers apart from other containers | ||
106 | such as sequence containers. For instance, `std::map` passes the test as it | ||
107 | contains a `mapped_type`, whereas `std::vector` fails the test. | ||
108 | |||
109 | @sa http://stackoverflow.com/a/7728728/266378 | ||
110 | @since version 1.0.0, overworked in version 2.0.6 | ||
111 | */ | ||
112 | template<typename T> | ||
113 | struct has_mapped_type | ||
114 | { | ||
115 | private: | ||
116 | template <typename U, typename = typename U::mapped_type> | ||
117 | static int detect(U&&); | ||
118 | |||
119 | static void detect(...); | ||
120 | public: | ||
121 | static constexpr bool value = | ||
122 | std::is_integral<decltype(detect(std::declval<T>()))>::value; | ||
123 | }; | ||
124 | |||
125 | /*! | ||
126 | @brief helper class to create locales with decimal point | ||
127 | |||
128 | This struct is used a default locale during the JSON serialization. JSON | ||
129 | requires the decimal point to be `.`, so this function overloads the | ||
130 | `do_decimal_point()` function to return `.`. This function is called by | ||
131 | float-to-string conversions to retrieve the decimal separator between integer | ||
132 | and fractional parts. | ||
133 | |||
134 | @sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 | ||
135 | @since version 2.0.0 | ||
136 | */ | ||
137 | struct DecimalSeparator : std::numpunct<char> | ||
138 | { | ||
139 | char do_decimal_point() const | ||
140 | { | ||
141 | return '.'; | ||
142 | } | ||
143 | }; | ||
144 | |||
145 | } | ||
146 | |||
147 | /*! | ||
148 | @brief a class to store JSON values | ||
149 | |||
150 | @tparam ObjectType type for JSON objects (`std::map` by default; will be used | ||
151 | in @ref object_t) | ||
152 | @tparam ArrayType type for JSON arrays (`std::vector` by default; will be used | ||
153 | in @ref array_t) | ||
154 | @tparam StringType type for JSON strings and object keys (`std::string` by | ||
155 | default; will be used in @ref string_t) | ||
156 | @tparam BooleanType type for JSON booleans (`bool` by default; will be used | ||
157 | in @ref boolean_t) | ||
158 | @tparam NumberIntegerType type for JSON integer numbers (`int64_t` by | ||
159 | default; will be used in @ref number_integer_t) | ||
160 | @tparam NumberUnsignedType type for JSON unsigned integer numbers (@c | ||
161 | `uint64_t` by default; will be used in @ref number_unsigned_t) | ||
162 | @tparam NumberFloatType type for JSON floating-point numbers (`double` by | ||
163 | default; will be used in @ref number_float_t) | ||
164 | @tparam AllocatorType type of the allocator to use (`std::allocator` by | ||
165 | default) | ||
166 | |||
167 | @requirement The class satisfies the following concept requirements: | ||
168 | - Basic | ||
169 | - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): | ||
170 | JSON values can be default constructed. The result will be a JSON null value. | ||
171 | - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): | ||
172 | A JSON value can be constructed from an rvalue argument. | ||
173 | - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): | ||
174 | A JSON value can be copy-constructed from an lvalue expression. | ||
175 | - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): | ||
176 | A JSON value van be assigned from an rvalue argument. | ||
177 | - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): | ||
178 | A JSON value can be copy-assigned from an lvalue expression. | ||
179 | - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): | ||
180 | JSON values can be destructed. | ||
181 | - Layout | ||
182 | - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): | ||
183 | JSON values have | ||
184 | [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): | ||
185 | All non-static data members are private and standard layout types, the class | ||
186 | has no virtual functions or (virtual) base classes. | ||
187 | - Library-wide | ||
188 | - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): | ||
189 | JSON values can be compared with `==`, see @ref | ||
190 | operator==(const_reference,const_reference). | ||
191 | - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): | ||
192 | JSON values can be compared with `<`, see @ref | ||
193 | operator<(const_reference,const_reference). | ||
194 | - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): | ||
195 | Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of | ||
196 | other compatible types, using unqualified function call @ref swap(). | ||
197 | - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): | ||
198 | JSON values can be compared against `std::nullptr_t` objects which are used | ||
199 | to model the `null` value. | ||
200 | - Container | ||
201 | - [Container](http://en.cppreference.com/w/cpp/concept/Container): | ||
202 | JSON values can be used like STL containers and provide iterator access. | ||
203 | - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); | ||
204 | JSON values can be used like STL containers and provide reverse iterator | ||
205 | access. | ||
206 | |||
207 | @invariant The member variables @a m_value and @a m_type have the following | ||
208 | relationship: | ||
209 | - If `m_type == value_t::object`, then `m_value.object != nullptr`. | ||
210 | - If `m_type == value_t::array`, then `m_value.array != nullptr`. | ||
211 | - If `m_type == value_t::string`, then `m_value.string != nullptr`. | ||
212 | The invariants are checked by member function assert_invariant(). | ||
213 | |||
214 | @internal | ||
215 | @note ObjectType trick from http://stackoverflow.com/a/9860911 | ||
216 | @endinternal | ||
217 | |||
218 | @see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange | ||
219 | Format](http://rfc7159.net/rfc7159) | ||
220 | |||
221 | @since version 1.0.0 | ||
222 | |||
223 | @nosubgrouping | ||
224 | */ | ||
225 | template < | ||
226 | template<typename U, typename V, typename... Args> class ObjectType = std::map, | ||
227 | template<typename U, typename... Args> class ArrayType = std::vector, | ||
228 | class StringType = std::string, | ||
229 | class BooleanType = bool, | ||
230 | class NumberIntegerType = std::int64_t, | ||
231 | class NumberUnsignedType = std::uint64_t, | ||
232 | class NumberFloatType = double, | ||
233 | template<typename U> class AllocatorType = std::allocator | ||
234 | > | ||
235 | class basic_json | ||
236 | { | ||
237 | private: | ||
238 | /// workaround type for MSVC | ||
239 | using basic_json_t = basic_json<ObjectType, ArrayType, StringType, | ||
240 | BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, | ||
241 | AllocatorType>; | ||
242 | |||
243 | public: | ||
244 | // forward declarations | ||
245 | template<typename Base> class json_reverse_iterator; | ||
246 | class json_pointer; | ||
247 | |||
248 | ///////////////////// | ||
249 | // container types // | ||
250 | ///////////////////// | ||
251 | |||
252 | /// @name container types | ||
253 | /// The canonic container types to use @ref basic_json like any other STL | ||
254 | /// container. | ||
255 | /// @{ | ||
256 | |||
257 | /// the type of elements in a basic_json container | ||
258 | using value_type = basic_json; | ||
259 | |||
260 | /// the type of an element reference | ||
261 | using reference = value_type&; | ||
262 | /// the type of an element const reference | ||
263 | using const_reference = const value_type&; | ||
264 | |||
265 | /// a type to represent differences between iterators | ||
266 | using difference_type = std::ptrdiff_t; | ||
267 | /// a type to represent container sizes | ||
268 | using size_type = std::size_t; | ||
269 | |||
270 | /// the allocator type | ||
271 | using allocator_type = AllocatorType<basic_json>; | ||
272 | |||
273 | /// the type of an element pointer | ||
274 | using pointer = typename std::allocator_traits<allocator_type>::pointer; | ||
275 | /// the type of an element const pointer | ||
276 | using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; | ||
277 | |||
278 | /// an iterator for a basic_json container | ||
279 | class iterator; | ||
280 | /// a const iterator for a basic_json container | ||
281 | class const_iterator; | ||
282 | /// a reverse iterator for a basic_json container | ||
283 | using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>; | ||
284 | /// a const reverse iterator for a basic_json container | ||
285 | using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>; | ||
286 | |||
287 | /// @} | ||
288 | |||
289 | |||
290 | /*! | ||
291 | @brief returns the allocator associated with the container | ||
292 | */ | ||
293 | static allocator_type get_allocator() | ||
294 | { | ||
295 | return allocator_type(); | ||
296 | } | ||
297 | |||
298 | |||
299 | /////////////////////////// | ||
300 | // JSON value data types // | ||
301 | /////////////////////////// | ||
302 | |||
303 | /// @name JSON value data types | ||
304 | /// The data types to store a JSON value. These types are derived from | ||
305 | /// the template arguments passed to class @ref basic_json. | ||
306 | /// @{ | ||
307 | |||
308 | /*! | ||
309 | @brief a type for an object | ||
310 | |||
311 | [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: | ||
312 | > An object is an unordered collection of zero or more name/value pairs, | ||
313 | > where a name is a string and a value is a string, number, boolean, null, | ||
314 | > object, or array. | ||
315 | |||
316 | To store objects in C++, a type is defined by the template parameters | ||
317 | described below. | ||
318 | |||
319 | @tparam ObjectType the container to store objects (e.g., `std::map` or | ||
320 | `std::unordered_map`) | ||
321 | @tparam StringType the type of the keys or names (e.g., `std::string`). | ||
322 | The comparison function `std::less<StringType>` is used to order elements | ||
323 | inside the container. | ||
324 | @tparam AllocatorType the allocator to use for objects (e.g., | ||
325 | `std::allocator`) | ||
326 | |||
327 | #### Default type | ||
328 | |||
329 | With the default values for @a ObjectType (`std::map`), @a StringType | ||
330 | (`std::string`), and @a AllocatorType (`std::allocator`), the default | ||
331 | value for @a object_t is: | ||
332 | |||
333 | @code {.cpp} | ||
334 | std::map< | ||
335 | std::string, // key_type | ||
336 | basic_json, // value_type | ||
337 | std::less<std::string>, // key_compare | ||
338 | std::allocator<std::pair<const std::string, basic_json>> // allocator_type | ||
339 | > | ||
340 | @endcode | ||
341 | |||
342 | #### Behavior | ||
343 | |||
344 | The choice of @a object_t influences the behavior of the JSON class. With | ||
345 | the default type, objects have the following behavior: | ||
346 | |||
347 | - When all names are unique, objects will be interoperable in the sense | ||
348 | that all software implementations receiving that object will agree on | ||
349 | the name-value mappings. | ||
350 | - When the names within an object are not unique, later stored name/value | ||
351 | pairs overwrite previously stored name/value pairs, leaving the used | ||
352 | names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will | ||
353 | be treated as equal and both stored as `{"key": 1}`. | ||
354 | - Internally, name/value pairs are stored in lexicographical order of the | ||
355 | names. Objects will also be serialized (see @ref dump) in this order. | ||
356 | For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored | ||
357 | and serialized as `{"a": 2, "b": 1}`. | ||
358 | - When comparing objects, the order of the name/value pairs is irrelevant. | ||
359 | This makes objects interoperable in the sense that they will not be | ||
360 | affected by these differences. For instance, `{"b": 1, "a": 2}` and | ||
361 | `{"a": 2, "b": 1}` will be treated as equal. | ||
362 | |||
363 | #### Limits | ||
364 | |||
365 | [RFC 7159](http://rfc7159.net/rfc7159) specifies: | ||
366 | > An implementation may set limits on the maximum depth of nesting. | ||
367 | |||
368 | In this class, the object's limit of nesting is not constraint explicitly. | ||
369 | However, a maximum depth of nesting may be introduced by the compiler or | ||
370 | runtime environment. A theoretical limit can be queried by calling the | ||
371 | @ref max_size function of a JSON object. | ||
372 | |||
373 | #### Storage | ||
374 | |||
375 | Objects are stored as pointers in a @ref basic_json type. That is, for any | ||
376 | access to object values, a pointer of type `object_t*` must be | ||
377 | dereferenced. | ||
378 | |||
379 | @sa @ref array_t -- type for an array value | ||
380 | |||
381 | @since version 1.0.0 | ||
382 | |||
383 | @note The order name/value pairs are added to the object is *not* | ||
384 | preserved by the library. Therefore, iterating an object may return | ||
385 | name/value pairs in a different order than they were originally stored. In | ||
386 | fact, keys will be traversed in alphabetical order as `std::map` with | ||
387 | `std::less` is used by default. Please note this behavior conforms to [RFC | ||
388 | 7159](http://rfc7159.net/rfc7159), because any order implements the | ||
389 | specified "unordered" nature of JSON objects. | ||
390 | */ | ||
391 | using object_t = ObjectType<StringType, | ||
392 | basic_json, | ||
393 | std::less<StringType>, | ||
394 | AllocatorType<std::pair<const StringType, | ||
395 | basic_json>>>; | ||
396 | |||
397 | /*! | ||
398 | @brief a type for an array | ||
399 | |||
400 | [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: | ||
401 | > An array is an ordered sequence of zero or more values. | ||
402 | |||
403 | To store objects in C++, a type is defined by the template parameters | ||
404 | explained below. | ||
405 | |||
406 | @tparam ArrayType container type to store arrays (e.g., `std::vector` or | ||
407 | `std::list`) | ||
408 | @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) | ||
409 | |||
410 | #### Default type | ||
411 | |||
412 | With the default values for @a ArrayType (`std::vector`) and @a | ||
413 | AllocatorType (`std::allocator`), the default value for @a array_t is: | ||
414 | |||
415 | @code {.cpp} | ||
416 | std::vector< | ||
417 | basic_json, // value_type | ||
418 | std::allocator<basic_json> // allocator_type | ||
419 | > | ||
420 | @endcode | ||
421 | |||
422 | #### Limits | ||
423 | |||
424 | [RFC 7159](http://rfc7159.net/rfc7159) specifies: | ||
425 | > An implementation may set limits on the maximum depth of nesting. | ||
426 | |||
427 | In this class, the array's limit of nesting is not constraint explicitly. | ||
428 | However, a maximum depth of nesting may be introduced by the compiler or | ||
429 | runtime environment. A theoretical limit can be queried by calling the | ||
430 | @ref max_size function of a JSON array. | ||
431 | |||
432 | #### Storage | ||
433 | |||
434 | Arrays are stored as pointers in a @ref basic_json type. That is, for any | ||
435 | access to array values, a pointer of type `array_t*` must be dereferenced. | ||
436 | |||
437 | @sa @ref object_t -- type for an object value | ||
438 | |||
439 | @since version 1.0.0 | ||
440 | */ | ||
441 | using array_t = ArrayType<basic_json, AllocatorType<basic_json>>; | ||
442 | |||
443 | /*! | ||
444 | @brief a type for a string | ||
445 | |||
446 | [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: | ||
447 | > A string is a sequence of zero or more Unicode characters. | ||
448 | |||
449 | To store objects in C++, a type is defined by the template parameter | ||
450 | described below. Unicode values are split by the JSON class into | ||
451 | byte-sized characters during deserialization. | ||
452 | |||
453 | @tparam StringType the container to store strings (e.g., `std::string`). | ||
454 | Note this container is used for keys/names in objects, see @ref object_t. | ||
455 | |||
456 | #### Default type | ||
457 | |||
458 | With the default values for @a StringType (`std::string`), the default | ||
459 | value for @a string_t is: | ||
460 | |||
461 | @code {.cpp} | ||
462 | std::string | ||
463 | @endcode | ||
464 | |||
465 | #### String comparison | ||
466 | |||
467 | [RFC 7159](http://rfc7159.net/rfc7159) states: | ||
468 | > Software implementations are typically required to test names of object | ||
469 | > members for equality. Implementations that transform the textual | ||
470 | > representation into sequences of Unicode code units and then perform the | ||
471 | > comparison numerically, code unit by code unit, are interoperable in the | ||
472 | > sense that implementations will agree in all cases on equality or | ||
473 | > inequality of two strings. For example, implementations that compare | ||
474 | > strings with escaped characters unconverted may incorrectly find that | ||
475 | > `"a\\b"` and `"a\u005Cb"` are not equal. | ||
476 | |||
477 | This implementation is interoperable as it does compare strings code unit | ||
478 | by code unit. | ||
479 | |||
480 | #### Storage | ||
481 | |||
482 | String values are stored as pointers in a @ref basic_json type. That is, | ||
483 | for any access to string values, a pointer of type `string_t*` must be | ||
484 | dereferenced. | ||
485 | |||
486 | @since version 1.0.0 | ||
487 | */ | ||
488 | using string_t = StringType; | ||
489 | |||
490 | /*! | ||
491 | @brief a type for a boolean | ||
492 | |||
493 | [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a | ||
494 | type which differentiates the two literals `true` and `false`. | ||
495 | |||
496 | To store objects in C++, a type is defined by the template parameter @a | ||
497 | BooleanType which chooses the type to use. | ||
498 | |||
499 | #### Default type | ||
500 | |||
501 | With the default values for @a BooleanType (`bool`), the default value for | ||
502 | @a boolean_t is: | ||
503 | |||
504 | @code {.cpp} | ||
505 | bool | ||
506 | @endcode | ||
507 | |||
508 | #### Storage | ||
509 | |||
510 | Boolean values are stored directly inside a @ref basic_json type. | ||
511 | |||
512 | @since version 1.0.0 | ||
513 | */ | ||
514 | using boolean_t = BooleanType; | ||
515 | |||
516 | /*! | ||
517 | @brief a type for a number (integer) | ||
518 | |||
519 | [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: | ||
520 | > The representation of numbers is similar to that used in most | ||
521 | > programming languages. A number is represented in base 10 using decimal | ||
522 | > digits. It contains an integer component that may be prefixed with an | ||
523 | > optional minus sign, which may be followed by a fraction part and/or an | ||
524 | > exponent part. Leading zeros are not allowed. (...) Numeric values that | ||
525 | > cannot be represented in the grammar below (such as Infinity and NaN) | ||
526 | > are not permitted. | ||
527 | |||
528 | This description includes both integer and floating-point numbers. | ||
529 | However, C++ allows more precise storage if it is known whether the number | ||
530 | is a signed integer, an unsigned integer or a floating-point number. | ||
531 | Therefore, three different types, @ref number_integer_t, @ref | ||
532 | number_unsigned_t and @ref number_float_t are used. | ||
533 | |||
534 | To store integer numbers in C++, a type is defined by the template | ||
535 | parameter @a NumberIntegerType which chooses the type to use. | ||
536 | |||
537 | #### Default type | ||
538 | |||
539 | With the default values for @a NumberIntegerType (`int64_t`), the default | ||
540 | value for @a number_integer_t is: | ||
541 | |||
542 | @code {.cpp} | ||
543 | int64_t | ||
544 | @endcode | ||
545 | |||
546 | #### Default behavior | ||
547 | |||
548 | - The restrictions about leading zeros is not enforced in C++. Instead, | ||
549 | leading zeros in integer literals lead to an interpretation as octal | ||
550 | number. Internally, the value will be stored as decimal number. For | ||
551 | instance, the C++ integer literal `010` will be serialized to `8`. | ||
552 | During deserialization, leading zeros yield an error. | ||
553 | - Not-a-number (NaN) values will be serialized to `null`. | ||
554 | |||
555 | #### Limits | ||
556 | |||
557 | [RFC 7159](http://rfc7159.net/rfc7159) specifies: | ||
558 | > An implementation may set limits on the range and precision of numbers. | ||
559 | |||
560 | When the default type is used, the maximal integer number that can be | ||
561 | stored is `9223372036854775807` (INT64_MAX) and the minimal integer number | ||
562 | that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers | ||
563 | that are out of range will yield over/underflow when used in a | ||
564 | constructor. During deserialization, too large or small integer numbers | ||
565 | will be automatically be stored as @ref number_unsigned_t or @ref | ||
566 | number_float_t. | ||
567 | |||
568 | [RFC 7159](http://rfc7159.net/rfc7159) further states: | ||
569 | > Note that when such software is used, numbers that are integers and are | ||
570 | > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense | ||
571 | > that implementations will agree exactly on their numeric values. | ||
572 | |||
573 | As this range is a subrange of the exactly supported range [INT64_MIN, | ||
574 | INT64_MAX], this class's integer type is interoperable. | ||
575 | |||
576 | #### Storage | ||
577 | |||
578 | Integer number values are stored directly inside a @ref basic_json type. | ||
579 | |||
580 | @sa @ref number_float_t -- type for number values (floating-point) | ||
581 | |||
582 | @sa @ref number_unsigned_t -- type for number values (unsigned integer) | ||
583 | |||
584 | @since version 1.0.0 | ||
585 | */ | ||
586 | using number_integer_t = NumberIntegerType; | ||
587 | |||
588 | /*! | ||
589 | @brief a type for a number (unsigned) | ||
590 | |||
591 | [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: | ||
592 | > The representation of numbers is similar to that used in most | ||
593 | > programming languages. A number is represented in base 10 using decimal | ||
594 | > digits. It contains an integer component that may be prefixed with an | ||
595 | > optional minus sign, which may be followed by a fraction part and/or an | ||
596 | > exponent part. Leading zeros are not allowed. (...) Numeric values that | ||
597 | > cannot be represented in the grammar below (such as Infinity and NaN) | ||
598 | > are not permitted. | ||
599 | |||
600 | This description includes both integer and floating-point numbers. | ||
601 | However, C++ allows more precise storage if it is known whether the number | ||
602 | is a signed integer, an unsigned integer or a floating-point number. | ||
603 | Therefore, three different types, @ref number_integer_t, @ref | ||
604 | number_unsigned_t and @ref number_float_t are used. | ||
605 | |||
606 | To store unsigned integer numbers in C++, a type is defined by the | ||
607 | template parameter @a NumberUnsignedType which chooses the type to use. | ||
608 | |||
609 | #### Default type | ||
610 | |||
611 | With the default values for @a NumberUnsignedType (`uint64_t`), the | ||
612 | default value for @a number_unsigned_t is: | ||
613 | |||
614 | @code {.cpp} | ||
615 | uint64_t | ||
616 | @endcode | ||
617 | |||
618 | #### Default behavior | ||
619 | |||
620 | - The restrictions about leading zeros is not enforced in C++. Instead, | ||
621 | leading zeros in integer literals lead to an interpretation as octal | ||
622 | number. Internally, the value will be stored as decimal number. For | ||
623 | instance, the C++ integer literal `010` will be serialized to `8`. | ||
624 | During deserialization, leading zeros yield an error. | ||
625 | - Not-a-number (NaN) values will be serialized to `null`. | ||
626 | |||
627 | #### Limits | ||
628 | |||
629 | [RFC 7159](http://rfc7159.net/rfc7159) specifies: | ||
630 | > An implementation may set limits on the range and precision of numbers. | ||
631 | |||
632 | When the default type is used, the maximal integer number that can be | ||
633 | stored is `18446744073709551615` (UINT64_MAX) and the minimal integer | ||
634 | number that can be stored is `0`. Integer numbers that are out of range | ||
635 | will yield over/underflow when used in a constructor. During | ||
636 | deserialization, too large or small integer numbers will be automatically | ||
637 | be stored as @ref number_integer_t or @ref number_float_t. | ||
638 | |||
639 | [RFC 7159](http://rfc7159.net/rfc7159) further states: | ||
640 | > Note that when such software is used, numbers that are integers and are | ||
641 | > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense | ||
642 | > that implementations will agree exactly on their numeric values. | ||
643 | |||
644 | As this range is a subrange (when considered in conjunction with the | ||
645 | number_integer_t type) of the exactly supported range [0, UINT64_MAX], | ||
646 | this class's integer type is interoperable. | ||
647 | |||
648 | #### Storage | ||
649 | |||
650 | Integer number values are stored directly inside a @ref basic_json type. | ||
651 | |||
652 | @sa @ref number_float_t -- type for number values (floating-point) | ||
653 | @sa @ref number_integer_t -- type for number values (integer) | ||
654 | |||
655 | @since version 2.0.0 | ||
656 | */ | ||
657 | using number_unsigned_t = NumberUnsignedType; | ||
658 | |||
659 | /*! | ||
660 | @brief a type for a number (floating-point) | ||
661 | |||
662 | [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: | ||
663 | > The representation of numbers is similar to that used in most | ||
664 | > programming languages. A number is represented in base 10 using decimal | ||
665 | > digits. It contains an integer component that may be prefixed with an | ||
666 | > optional minus sign, which may be followed by a fraction part and/or an | ||
667 | > exponent part. Leading zeros are not allowed. (...) Numeric values that | ||
668 | > cannot be represented in the grammar below (such as Infinity and NaN) | ||
669 | > are not permitted. | ||
670 | |||
671 | This description includes both integer and floating-point numbers. | ||
672 | However, C++ allows more precise storage if it is known whether the number | ||
673 | is a signed integer, an unsigned integer or a floating-point number. | ||
674 | Therefore, three different types, @ref number_integer_t, @ref | ||
675 | number_unsigned_t and @ref number_float_t are used. | ||
676 | |||
677 | To store floating-point numbers in C++, a type is defined by the template | ||
678 | parameter @a NumberFloatType which chooses the type to use. | ||
679 | |||
680 | #### Default type | ||
681 | |||
682 | With the default values for @a NumberFloatType (`double`), the default | ||
683 | value for @a number_float_t is: | ||
684 | |||
685 | @code {.cpp} | ||
686 | double | ||
687 | @endcode | ||
688 | |||
689 | #### Default behavior | ||
690 | |||
691 | - The restrictions about leading zeros is not enforced in C++. Instead, | ||
692 | leading zeros in floating-point literals will be ignored. Internally, | ||
693 | the value will be stored as decimal number. For instance, the C++ | ||
694 | floating-point literal `01.2` will be serialized to `1.2`. During | ||
695 | deserialization, leading zeros yield an error. | ||
696 | - Not-a-number (NaN) values will be serialized to `null`. | ||
697 | |||
698 | #### Limits | ||
699 | |||
700 | [RFC 7159](http://rfc7159.net/rfc7159) states: | ||
701 | > This specification allows implementations to set limits on the range and | ||
702 | > precision of numbers accepted. Since software that implements IEEE | ||
703 | > 754-2008 binary64 (double precision) numbers is generally available and | ||
704 | > widely used, good interoperability can be achieved by implementations | ||
705 | > that expect no more precision or range than these provide, in the sense | ||
706 | > that implementations will approximate JSON numbers within the expected | ||
707 | > precision. | ||
708 | |||
709 | This implementation does exactly follow this approach, as it uses double | ||
710 | precision floating-point numbers. Note values smaller than | ||
711 | `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` | ||
712 | will be stored as NaN internally and be serialized to `null`. | ||
713 | |||
714 | #### Storage | ||
715 | |||
716 | Floating-point number values are stored directly inside a @ref basic_json | ||
717 | type. | ||
718 | |||
719 | @sa @ref number_integer_t -- type for number values (integer) | ||
720 | |||
721 | @sa @ref number_unsigned_t -- type for number values (unsigned integer) | ||
722 | |||
723 | @since version 1.0.0 | ||
724 | */ | ||
725 | using number_float_t = NumberFloatType; | ||
726 | |||
727 | /// @} | ||
728 | |||
729 | |||
730 | /////////////////////////// | ||
731 | // JSON type enumeration // | ||
732 | /////////////////////////// | ||
733 | |||
734 | /*! | ||
735 | @brief the JSON type enumeration | ||
736 | |||
737 | This enumeration collects the different JSON types. It is internally used | ||
738 | to distinguish the stored values, and the functions @ref is_null(), @ref | ||
739 | is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref | ||
740 | is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and | ||
741 | @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and | ||
742 | @ref is_structured() rely on it. | ||
743 | |||
744 | @note There are three enumeration entries (number_integer, | ||
745 | number_unsigned, and number_float), because the library distinguishes | ||
746 | these three types for numbers: @ref number_unsigned_t is used for unsigned | ||
747 | integers, @ref number_integer_t is used for signed integers, and @ref | ||
748 | number_float_t is used for floating-point numbers or to approximate | ||
749 | integers which do not fit in the limits of their respective type. | ||
750 | |||
751 | @sa @ref basic_json(const value_t value_type) -- create a JSON value with | ||
752 | the default value for a given type | ||
753 | |||
754 | @since version 1.0.0 | ||
755 | */ | ||
756 | enum class value_t : uint8_t | ||
757 | { | ||
758 | null, ///< null value | ||
759 | object, ///< object (unordered set of name/value pairs) | ||
760 | array, ///< array (ordered collection of values) | ||
761 | string, ///< string value | ||
762 | boolean, ///< boolean value | ||
763 | number_integer, ///< number value (signed integer) | ||
764 | number_unsigned, ///< number value (unsigned integer) | ||
765 | number_float, ///< number value (floating-point) | ||
766 | discarded ///< discarded by the the parser callback function | ||
767 | }; | ||
768 | |||
769 | |||
770 | private: | ||
771 | |||
772 | /// helper for exception-safe object creation | ||
773 | template<typename T, typename... Args> | ||
774 | static T* create(Args&& ... args) | ||
775 | { | ||
776 | AllocatorType<T> alloc; | ||
777 | auto deleter = [&](T * object) | ||
778 | { | ||
779 | alloc.deallocate(object, 1); | ||
780 | }; | ||
781 | std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter); | ||
782 | alloc.construct(object.get(), std::forward<Args>(args)...); | ||
783 | assert(object.get() != nullptr); | ||
784 | return object.release(); | ||
785 | } | ||
786 | |||
787 | //////////////////////// | ||
788 | // JSON value storage // | ||
789 | //////////////////////// | ||
790 | |||
791 | /*! | ||
792 | @brief a JSON value | ||
793 | |||
794 | The actual storage for a JSON value of the @ref basic_json class. This | ||
795 | union combines the different storage types for the JSON value types | ||
796 | defined in @ref value_t. | ||
797 | |||
798 | JSON type | value_t type | used type | ||
799 | --------- | --------------- | ------------------------ | ||
800 | object | object | pointer to @ref object_t | ||
801 | array | array | pointer to @ref array_t | ||
802 | string | string | pointer to @ref string_t | ||
803 | boolean | boolean | @ref boolean_t | ||
804 | number | number_integer | @ref number_integer_t | ||
805 | number | number_unsigned | @ref number_unsigned_t | ||
806 | number | number_float | @ref number_float_t | ||
807 | null | null | *no value is stored* | ||
808 | |||
809 | @note Variable-length types (objects, arrays, and strings) are stored as | ||
810 | pointers. The size of the union should not exceed 64 bits if the default | ||
811 | value types are used. | ||
812 | |||
813 | @since version 1.0.0 | ||
814 | */ | ||
815 | union json_value | ||
816 | { | ||
817 | /// object (stored with pointer to save storage) | ||
818 | object_t* object; | ||
819 | /// array (stored with pointer to save storage) | ||
820 | array_t* array; | ||
821 | /// string (stored with pointer to save storage) | ||
822 | string_t* string; | ||
823 | /// boolean | ||
824 | boolean_t boolean; | ||
825 | /// number (integer) | ||
826 | number_integer_t number_integer; | ||
827 | /// number (unsigned integer) | ||
828 | number_unsigned_t number_unsigned; | ||
829 | /// number (floating-point) | ||
830 | number_float_t number_float; | ||
831 | |||
832 | /// default constructor (for null values) | ||
833 | json_value() = default; | ||
834 | /// constructor for booleans | ||
835 | json_value(boolean_t v) noexcept : boolean(v) {} | ||
836 | /// constructor for numbers (integer) | ||
837 | json_value(number_integer_t v) noexcept : number_integer(v) {} | ||
838 | /// constructor for numbers (unsigned) | ||
839 | json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} | ||
840 | /// constructor for numbers (floating-point) | ||
841 | json_value(number_float_t v) noexcept : number_float(v) {} | ||
842 | /// constructor for empty values of a given type | ||
843 | json_value(value_t t) | ||
844 | { | ||
845 | switch (t) | ||
846 | { | ||
847 | case value_t::object: | ||
848 | { | ||
849 | object = create<object_t>(); | ||
850 | break; | ||
851 | } | ||
852 | |||
853 | case value_t::array: | ||
854 | { | ||
855 | array = create<array_t>(); | ||
856 | break; | ||
857 | } | ||
858 | |||
859 | case value_t::string: | ||
860 | { | ||
861 | string = create<string_t>(""); | ||
862 | break; | ||
863 | } | ||
864 | |||
865 | case value_t::boolean: | ||
866 | { | ||
867 | boolean = boolean_t(false); | ||
868 | break; | ||
869 | } | ||
870 | |||
871 | case value_t::number_integer: | ||
872 | { | ||
873 | number_integer = number_integer_t(0); | ||
874 | break; | ||
875 | } | ||
876 | |||
877 | case value_t::number_unsigned: | ||
878 | { | ||
879 | number_unsigned = number_unsigned_t(0); | ||
880 | break; | ||
881 | } | ||
882 | |||
883 | case value_t::number_float: | ||
884 | { | ||
885 | number_float = number_float_t(0.0); | ||
886 | break; | ||
887 | } | ||
888 | |||
889 | default: | ||
890 | { | ||
891 | break; | ||
892 | } | ||
893 | } | ||
894 | } | ||
895 | |||
896 | /// constructor for strings | ||
897 | json_value(const string_t& value) | ||
898 | { | ||
899 | string = create<string_t>(value); | ||
900 | } | ||
901 | |||
902 | /// constructor for objects | ||
903 | json_value(const object_t& value) | ||
904 | { | ||
905 | object = create<object_t>(value); | ||
906 | } | ||
907 | |||
908 | /// constructor for arrays | ||
909 | json_value(const array_t& value) | ||
910 | { | ||
911 | array = create<array_t>(value); | ||
912 | } | ||
913 | }; | ||
914 | |||
915 | /*! | ||
916 | @brief checks the class invariants | ||
917 | |||
918 | This function asserts the class invariants. It needs to be called at the | ||
919 | end of every constructor to make sure that created objects respect the | ||
920 | invariant. Furthermore, it has to be called each time the type of a JSON | ||
921 | value is changed, because the invariant expresses a relationship between | ||
922 | @a m_type and @a m_value. | ||
923 | */ | ||
924 | void assert_invariant() const | ||
925 | { | ||
926 | assert(m_type != value_t::object or m_value.object != nullptr); | ||
927 | assert(m_type != value_t::array or m_value.array != nullptr); | ||
928 | assert(m_type != value_t::string or m_value.string != nullptr); | ||
929 | } | ||
930 | |||
931 | public: | ||
932 | ////////////////////////// | ||
933 | // JSON parser callback // | ||
934 | ////////////////////////// | ||
935 | |||
936 | /*! | ||
937 | @brief JSON callback events | ||
938 | |||
939 | This enumeration lists the parser events that can trigger calling a | ||
940 | callback function of type @ref parser_callback_t during parsing. | ||
941 | |||
942 | @image html callback_events.png "Example when certain parse events are triggered" | ||
943 | |||
944 | @since version 1.0.0 | ||
945 | */ | ||
946 | enum class parse_event_t : uint8_t | ||
947 | { | ||
948 | /// the parser read `{` and started to process a JSON object | ||
949 | object_start, | ||
950 | /// the parser read `}` and finished processing a JSON object | ||
951 | object_end, | ||
952 | /// the parser read `[` and started to process a JSON array | ||
953 | array_start, | ||
954 | /// the parser read `]` and finished processing a JSON array | ||
955 | array_end, | ||
956 | /// the parser read a key of a value in an object | ||
957 | key, | ||
958 | /// the parser finished reading a JSON value | ||
959 | value | ||
960 | }; | ||
961 | |||
962 | /*! | ||
963 | @brief per-element parser callback type | ||
964 | |||
965 | With a parser callback function, the result of parsing a JSON text can be | ||
966 | influenced. When passed to @ref parse(std::istream&, const | ||
967 | parser_callback_t) or @ref parse(const char*, const parser_callback_t), | ||
968 | it is called on certain events (passed as @ref parse_event_t via parameter | ||
969 | @a event) with a set recursion depth @a depth and context JSON value | ||
970 | @a parsed. The return value of the callback function is a boolean | ||
971 | indicating whether the element that emitted the callback shall be kept or | ||
972 | not. | ||
973 | |||
974 | We distinguish six scenarios (determined by the event type) in which the | ||
975 | callback function can be called. The following table describes the values | ||
976 | of the parameters @a depth, @a event, and @a parsed. | ||
977 | |||
978 | parameter @a event | description | parameter @a depth | parameter @a parsed | ||
979 | ------------------ | ----------- | ------------------ | ------------------- | ||
980 | 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 | ||
981 | 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 | ||
982 | 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 | ||
983 | 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 | ||
984 | 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 | ||
985 | parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value | ||
986 | |||
987 | @image html callback_events.png "Example when certain parse events are triggered" | ||
988 | |||
989 | Discarding a value (i.e., returning `false`) has different effects | ||
990 | depending on the context in which function was called: | ||
991 | |||
992 | - Discarded values in structured types are skipped. That is, the parser | ||
993 | will behave as if the discarded value was never read. | ||
994 | - In case a value outside a structured type is skipped, it is replaced | ||
995 | with `null`. This case happens if the top-level element is skipped. | ||
996 | |||
997 | @param[in] depth the depth of the recursion during parsing | ||
998 | |||
999 | @param[in] event an event of type parse_event_t indicating the context in | ||
1000 | the callback function has been called | ||
1001 | |||
1002 | @param[in,out] parsed the current intermediate parse result; note that | ||
1003 | writing to this value has no effect for parse_event_t::key events | ||
1004 | |||
1005 | @return Whether the JSON value which called the function during parsing | ||
1006 | should be kept (`true`) or not (`false`). In the latter case, it is either | ||
1007 | skipped completely or replaced by an empty discarded object. | ||
1008 | |||
1009 | @sa @ref parse(std::istream&, parser_callback_t) or | ||
1010 | @ref parse(const char*, parser_callback_t) for examples | ||
1011 | |||
1012 | @since version 1.0.0 | ||
1013 | */ | ||
1014 | using parser_callback_t = std::function<bool(int depth, | ||
1015 | parse_event_t event, | ||
1016 | basic_json& parsed)>; | ||
1017 | |||
1018 | |||
1019 | ////////////////// | ||
1020 | // constructors // | ||
1021 | ////////////////// | ||
1022 | |||
1023 | /// @name constructors and destructors | ||
1024 | /// Constructors of class @ref basic_json, copy/move constructor, copy | ||
1025 | /// assignment, static functions creating objects, and the destructor. | ||
1026 | /// @{ | ||
1027 | |||
1028 | /*! | ||
1029 | @brief create an empty value with a given type | ||
1030 | |||
1031 | Create an empty JSON value with a given type. The value will be default | ||
1032 | initialized with an empty value which depends on the type: | ||
1033 | |||
1034 | Value type | initial value | ||
1035 | ----------- | ------------- | ||
1036 | null | `null` | ||
1037 | boolean | `false` | ||
1038 | string | `""` | ||
1039 | number | `0` | ||
1040 | object | `{}` | ||
1041 | array | `[]` | ||
1042 | |||
1043 | @param[in] value_type the type of the value to create | ||
1044 | |||
1045 | @complexity Constant. | ||
1046 | |||
1047 | @throw std::bad_alloc if allocation for object, array, or string value | ||
1048 | fails | ||
1049 | |||
1050 | @liveexample{The following code shows the constructor for different @ref | ||
1051 | value_t values,basic_json__value_t} | ||
1052 | |||
1053 | @sa @ref basic_json(std::nullptr_t) -- create a `null` value | ||
1054 | @sa @ref basic_json(boolean_t value) -- create a boolean value | ||
1055 | @sa @ref basic_json(const string_t&) -- create a string value | ||
1056 | @sa @ref basic_json(const object_t&) -- create a object value | ||
1057 | @sa @ref basic_json(const array_t&) -- create a array value | ||
1058 | @sa @ref basic_json(const number_float_t) -- create a number | ||
1059 | (floating-point) value | ||
1060 | @sa @ref basic_json(const number_integer_t) -- create a number (integer) | ||
1061 | value | ||
1062 | @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) | ||
1063 | value | ||
1064 | |||
1065 | @since version 1.0.0 | ||
1066 | */ | ||
1067 | basic_json(const value_t value_type) | ||
1068 | : m_type(value_type), m_value(value_type) | ||
1069 | { | ||
1070 | assert_invariant(); | ||
1071 | } | ||
1072 | |||
1073 | /*! | ||
1074 | @brief create a null object | ||
1075 | |||
1076 | Create a `null` JSON value. It either takes a null pointer as parameter | ||
1077 | (explicitly creating `null`) or no parameter (implicitly creating `null`). | ||
1078 | The passed null pointer itself is not read -- it is only used to choose | ||
1079 | the right constructor. | ||
1080 | |||
1081 | @complexity Constant. | ||
1082 | |||
1083 | @exceptionsafety No-throw guarantee: this constructor never throws | ||
1084 | exceptions. | ||
1085 | |||
1086 | @liveexample{The following code shows the constructor with and without a | ||
1087 | null pointer parameter.,basic_json__nullptr_t} | ||
1088 | |||
1089 | @since version 1.0.0 | ||
1090 | */ | ||
1091 | basic_json(std::nullptr_t = nullptr) noexcept | ||
1092 | : basic_json(value_t::null) | ||
1093 | { | ||
1094 | assert_invariant(); | ||
1095 | } | ||
1096 | |||
1097 | /*! | ||
1098 | @brief create an object (explicit) | ||
1099 | |||
1100 | Create an object JSON value with a given content. | ||
1101 | |||
1102 | @param[in] val a value for the object | ||
1103 | |||
1104 | @complexity Linear in the size of the passed @a val. | ||
1105 | |||
1106 | @throw std::bad_alloc if allocation for object value fails | ||
1107 | |||
1108 | @liveexample{The following code shows the constructor with an @ref | ||
1109 | object_t parameter.,basic_json__object_t} | ||
1110 | |||
1111 | @sa @ref basic_json(const CompatibleObjectType&) -- create an object value | ||
1112 | from a compatible STL container | ||
1113 | |||
1114 | @since version 1.0.0 | ||
1115 | */ | ||
1116 | basic_json(const object_t& val) | ||
1117 | : m_type(value_t::object), m_value(val) | ||
1118 | { | ||
1119 | assert_invariant(); | ||
1120 | } | ||
1121 | |||
1122 | /*! | ||
1123 | @brief create an object (implicit) | ||
1124 | |||
1125 | Create an object JSON value with a given content. This constructor allows | ||
1126 | any type @a CompatibleObjectType that can be used to construct values of | ||
1127 | type @ref object_t. | ||
1128 | |||
1129 | @tparam CompatibleObjectType An object type whose `key_type` and | ||
1130 | `value_type` is compatible to @ref object_t. Examples include `std::map`, | ||
1131 | `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with | ||
1132 | a `key_type` of `std::string`, and a `value_type` from which a @ref | ||
1133 | basic_json value can be constructed. | ||
1134 | |||
1135 | @param[in] val a value for the object | ||
1136 | |||
1137 | @complexity Linear in the size of the passed @a val. | ||
1138 | |||
1139 | @throw std::bad_alloc if allocation for object value fails | ||
1140 | |||
1141 | @liveexample{The following code shows the constructor with several | ||
1142 | compatible object type parameters.,basic_json__CompatibleObjectType} | ||
1143 | |||
1144 | @sa @ref basic_json(const object_t&) -- create an object value | ||
1145 | |||
1146 | @since version 1.0.0 | ||
1147 | */ | ||
1148 | template<class CompatibleObjectType, typename std::enable_if< | ||
1149 | std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and | ||
1150 | std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0> | ||
1151 | basic_json(const CompatibleObjectType& val) | ||
1152 | : m_type(value_t::object) | ||
1153 | { | ||
1154 | using std::begin; | ||
1155 | using std::end; | ||
1156 | m_value.object = create<object_t>(begin(val), end(val)); | ||
1157 | assert_invariant(); | ||
1158 | } | ||
1159 | |||
1160 | /*! | ||
1161 | @brief create an array (explicit) | ||
1162 | |||
1163 | Create an array JSON value with a given content. | ||
1164 | |||
1165 | @param[in] val a value for the array | ||
1166 | |||
1167 | @complexity Linear in the size of the passed @a val. | ||
1168 | |||
1169 | @throw std::bad_alloc if allocation for array value fails | ||
1170 | |||
1171 | @liveexample{The following code shows the constructor with an @ref array_t | ||
1172 | parameter.,basic_json__array_t} | ||
1173 | |||
1174 | @sa @ref basic_json(const CompatibleArrayType&) -- create an array value | ||
1175 | from a compatible STL containers | ||
1176 | |||
1177 | @since version 1.0.0 | ||
1178 | */ | ||
1179 | basic_json(const array_t& val) | ||
1180 | : m_type(value_t::array), m_value(val) | ||
1181 | { | ||
1182 | assert_invariant(); | ||
1183 | } | ||
1184 | |||
1185 | /*! | ||
1186 | @brief create an array (implicit) | ||
1187 | |||
1188 | Create an array JSON value with a given content. This constructor allows | ||
1189 | any type @a CompatibleArrayType that can be used to construct values of | ||
1190 | type @ref array_t. | ||
1191 | |||
1192 | @tparam CompatibleArrayType An object type whose `value_type` is | ||
1193 | compatible to @ref array_t. Examples include `std::vector`, `std::deque`, | ||
1194 | `std::list`, `std::forward_list`, `std::array`, `std::set`, | ||
1195 | `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a | ||
1196 | `value_type` from which a @ref basic_json value can be constructed. | ||
1197 | |||
1198 | @param[in] val a value for the array | ||
1199 | |||
1200 | @complexity Linear in the size of the passed @a val. | ||
1201 | |||
1202 | @throw std::bad_alloc if allocation for array value fails | ||
1203 | |||
1204 | @liveexample{The following code shows the constructor with several | ||
1205 | compatible array type parameters.,basic_json__CompatibleArrayType} | ||
1206 | |||
1207 | @sa @ref basic_json(const array_t&) -- create an array value | ||
1208 | |||
1209 | @since version 1.0.0 | ||
1210 | */ | ||
1211 | template<class CompatibleArrayType, typename std::enable_if< | ||
1212 | not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and | ||
1213 | not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and | ||
1214 | not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and | ||
1215 | not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and | ||
1216 | not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and | ||
1217 | not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and | ||
1218 | std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0> | ||
1219 | basic_json(const CompatibleArrayType& val) | ||
1220 | : m_type(value_t::array) | ||
1221 | { | ||
1222 | using std::begin; | ||
1223 | using std::end; | ||
1224 | m_value.array = create<array_t>(begin(val), end(val)); | ||
1225 | assert_invariant(); | ||
1226 | } | ||
1227 | |||
1228 | /*! | ||
1229 | @brief create a string (explicit) | ||
1230 | |||
1231 | Create an string JSON value with a given content. | ||
1232 | |||
1233 | @param[in] val a value for the string | ||
1234 | |||
1235 | @complexity Linear in the size of the passed @a val. | ||
1236 | |||
1237 | @throw std::bad_alloc if allocation for string value fails | ||
1238 | |||
1239 | @liveexample{The following code shows the constructor with an @ref | ||
1240 | string_t parameter.,basic_json__string_t} | ||
1241 | |||
1242 | @sa @ref basic_json(const typename string_t::value_type*) -- create a | ||
1243 | string value from a character pointer | ||
1244 | @sa @ref basic_json(const CompatibleStringType&) -- create a string value | ||
1245 | from a compatible string container | ||
1246 | |||
1247 | @since version 1.0.0 | ||
1248 | */ | ||
1249 | basic_json(const string_t& val) | ||
1250 | : m_type(value_t::string), m_value(val) | ||
1251 | { | ||
1252 | assert_invariant(); | ||
1253 | } | ||
1254 | |||
1255 | /*! | ||
1256 | @brief create a string (explicit) | ||
1257 | |||
1258 | Create a string JSON value with a given content. | ||
1259 | |||
1260 | @param[in] val a literal value for the string | ||
1261 | |||
1262 | @complexity Linear in the size of the passed @a val. | ||
1263 | |||
1264 | @throw std::bad_alloc if allocation for string value fails | ||
1265 | |||
1266 | @liveexample{The following code shows the constructor with string literal | ||
1267 | parameter.,basic_json__string_t_value_type} | ||
1268 | |||
1269 | @sa @ref basic_json(const string_t&) -- create a string value | ||
1270 | @sa @ref basic_json(const CompatibleStringType&) -- create a string value | ||
1271 | from a compatible string container | ||
1272 | |||
1273 | @since version 1.0.0 | ||
1274 | */ | ||
1275 | basic_json(const typename string_t::value_type* val) | ||
1276 | : basic_json(string_t(val)) | ||
1277 | { | ||
1278 | assert_invariant(); | ||
1279 | } | ||
1280 | |||
1281 | /*! | ||
1282 | @brief create a string (implicit) | ||
1283 | |||
1284 | Create a string JSON value with a given content. | ||
1285 | |||
1286 | @param[in] val a value for the string | ||
1287 | |||
1288 | @tparam CompatibleStringType an string type which is compatible to @ref | ||
1289 | string_t, for instance `std::string`. | ||
1290 | |||
1291 | @complexity Linear in the size of the passed @a val. | ||
1292 | |||
1293 | @throw std::bad_alloc if allocation for string value fails | ||
1294 | |||
1295 | @liveexample{The following code shows the construction of a string value | ||
1296 | from a compatible type.,basic_json__CompatibleStringType} | ||
1297 | |||
1298 | @sa @ref basic_json(const string_t&) -- create a string value | ||
1299 | @sa @ref basic_json(const typename string_t::value_type*) -- create a | ||
1300 | string value from a character pointer | ||
1301 | |||
1302 | @since version 1.0.0 | ||
1303 | */ | ||
1304 | template<class CompatibleStringType, typename std::enable_if< | ||
1305 | std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0> | ||
1306 | basic_json(const CompatibleStringType& val) | ||
1307 | : basic_json(string_t(val)) | ||
1308 | { | ||
1309 | assert_invariant(); | ||
1310 | } | ||
1311 | |||
1312 | /*! | ||
1313 | @brief create a boolean (explicit) | ||
1314 | |||
1315 | Creates a JSON boolean type from a given value. | ||
1316 | |||
1317 | @param[in] val a boolean value to store | ||
1318 | |||
1319 | @complexity Constant. | ||
1320 | |||
1321 | @liveexample{The example below demonstrates boolean | ||
1322 | values.,basic_json__boolean_t} | ||
1323 | |||
1324 | @since version 1.0.0 | ||
1325 | */ | ||
1326 | basic_json(boolean_t val) noexcept | ||
1327 | : m_type(value_t::boolean), m_value(val) | ||
1328 | { | ||
1329 | assert_invariant(); | ||
1330 | } | ||
1331 | |||
1332 | /*! | ||
1333 | @brief create an integer number (explicit) | ||
1334 | |||
1335 | Create an integer number JSON value with a given content. | ||
1336 | |||
1337 | @tparam T A helper type to remove this function via SFINAE in case @ref | ||
1338 | number_integer_t is the same as `int`. In this case, this constructor | ||
1339 | would have the same signature as @ref basic_json(const int value). Note | ||
1340 | the helper type @a T is not visible in this constructor's interface. | ||
1341 | |||
1342 | @param[in] val an integer to create a JSON number from | ||
1343 | |||
1344 | @complexity Constant. | ||
1345 | |||
1346 | @liveexample{The example below shows the construction of an integer | ||
1347 | number value.,basic_json__number_integer_t} | ||
1348 | |||
1349 | @sa @ref basic_json(const int) -- create a number value (integer) | ||
1350 | @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number | ||
1351 | value (integer) from a compatible number type | ||
1352 | |||
1353 | @since version 1.0.0 | ||
1354 | */ | ||
1355 | template<typename T, typename std::enable_if< | ||
1356 | not (std::is_same<T, int>::value) and | ||
1357 | std::is_same<T, number_integer_t>::value, int>::type = 0> | ||
1358 | basic_json(const number_integer_t val) noexcept | ||
1359 | : m_type(value_t::number_integer), m_value(val) | ||
1360 | { | ||
1361 | assert_invariant(); | ||
1362 | } | ||
1363 | |||
1364 | /*! | ||
1365 | @brief create an integer number from an enum type (explicit) | ||
1366 | |||
1367 | Create an integer number JSON value with a given content. | ||
1368 | |||
1369 | @param[in] val an integer to create a JSON number from | ||
1370 | |||
1371 | @note This constructor allows to pass enums directly to a constructor. As | ||
1372 | C++ has no way of specifying the type of an anonymous enum explicitly, we | ||
1373 | can only rely on the fact that such values implicitly convert to int. As | ||
1374 | int may already be the same type of number_integer_t, we may need to | ||
1375 | switch off the constructor @ref basic_json(const number_integer_t). | ||
1376 | |||
1377 | @complexity Constant. | ||
1378 | |||
1379 | @liveexample{The example below shows the construction of an integer | ||
1380 | number value from an anonymous enum.,basic_json__const_int} | ||
1381 | |||
1382 | @sa @ref basic_json(const number_integer_t) -- create a number value | ||
1383 | (integer) | ||
1384 | @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number | ||
1385 | value (integer) from a compatible number type | ||
1386 | |||
1387 | @since version 1.0.0 | ||
1388 | */ | ||
1389 | basic_json(const int val) noexcept | ||
1390 | : m_type(value_t::number_integer), | ||
1391 | m_value(static_cast<number_integer_t>(val)) | ||
1392 | { | ||
1393 | assert_invariant(); | ||
1394 | } | ||
1395 | |||
1396 | /*! | ||
1397 | @brief create an integer number (implicit) | ||
1398 | |||
1399 | Create an integer number JSON value with a given content. This constructor | ||
1400 | allows any type @a CompatibleNumberIntegerType that can be used to | ||
1401 | construct values of type @ref number_integer_t. | ||
1402 | |||
1403 | @tparam CompatibleNumberIntegerType An integer type which is compatible to | ||
1404 | @ref number_integer_t. Examples include the types `int`, `int32_t`, | ||
1405 | `long`, and `short`. | ||
1406 | |||
1407 | @param[in] val an integer to create a JSON number from | ||
1408 | |||
1409 | @complexity Constant. | ||
1410 | |||
1411 | @liveexample{The example below shows the construction of several integer | ||
1412 | number values from compatible | ||
1413 | types.,basic_json__CompatibleIntegerNumberType} | ||
1414 | |||
1415 | @sa @ref basic_json(const number_integer_t) -- create a number value | ||
1416 | (integer) | ||
1417 | @sa @ref basic_json(const int) -- create a number value (integer) | ||
1418 | |||
1419 | @since version 1.0.0 | ||
1420 | */ | ||
1421 | template<typename CompatibleNumberIntegerType, typename std::enable_if< | ||
1422 | std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and | ||
1423 | std::numeric_limits<CompatibleNumberIntegerType>::is_integer and | ||
1424 | std::numeric_limits<CompatibleNumberIntegerType>::is_signed, | ||
1425 | CompatibleNumberIntegerType>::type = 0> | ||
1426 | basic_json(const CompatibleNumberIntegerType val) noexcept | ||
1427 | : m_type(value_t::number_integer), | ||
1428 | m_value(static_cast<number_integer_t>(val)) | ||
1429 | { | ||
1430 | assert_invariant(); | ||
1431 | } | ||
1432 | |||
1433 | /*! | ||
1434 | @brief create an unsigned integer number (explicit) | ||
1435 | |||
1436 | Create an unsigned integer number JSON value with a given content. | ||
1437 | |||
1438 | @tparam T helper type to compare number_unsigned_t and unsigned int (not | ||
1439 | visible in) the interface. | ||
1440 | |||
1441 | @param[in] val an integer to create a JSON number from | ||
1442 | |||
1443 | @complexity Constant. | ||
1444 | |||
1445 | @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number | ||
1446 | value (unsigned integer) from a compatible number type | ||
1447 | |||
1448 | @since version 2.0.0 | ||
1449 | */ | ||
1450 | template<typename T, typename std::enable_if< | ||
1451 | not (std::is_same<T, int>::value) and | ||
1452 | std::is_same<T, number_unsigned_t>::value, int>::type = 0> | ||
1453 | basic_json(const number_unsigned_t val) noexcept | ||
1454 | : m_type(value_t::number_unsigned), m_value(val) | ||
1455 | { | ||
1456 | assert_invariant(); | ||
1457 | } | ||
1458 | |||
1459 | /*! | ||
1460 | @brief create an unsigned number (implicit) | ||
1461 | |||
1462 | Create an unsigned number JSON value with a given content. This | ||
1463 | constructor allows any type @a CompatibleNumberUnsignedType that can be | ||
1464 | used to construct values of type @ref number_unsigned_t. | ||
1465 | |||
1466 | @tparam CompatibleNumberUnsignedType An integer type which is compatible | ||
1467 | to @ref number_unsigned_t. Examples may include the types `unsigned int`, | ||
1468 | `uint32_t`, or `unsigned short`. | ||
1469 | |||
1470 | @param[in] val an unsigned integer to create a JSON number from | ||
1471 | |||
1472 | @complexity Constant. | ||
1473 | |||
1474 | @sa @ref basic_json(const number_unsigned_t) -- create a number value | ||
1475 | (unsigned) | ||
1476 | |||
1477 | @since version 2.0.0 | ||
1478 | */ | ||
1479 | template<typename CompatibleNumberUnsignedType, typename std::enable_if < | ||
1480 | std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and | ||
1481 | std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and | ||
1482 | not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed, | ||
1483 | CompatibleNumberUnsignedType>::type = 0> | ||
1484 | basic_json(const CompatibleNumberUnsignedType val) noexcept | ||
1485 | : m_type(value_t::number_unsigned), | ||
1486 | m_value(static_cast<number_unsigned_t>(val)) | ||
1487 | { | ||
1488 | assert_invariant(); | ||
1489 | } | ||
1490 | |||
1491 | /*! | ||
1492 | @brief create a floating-point number (explicit) | ||
1493 | |||
1494 | Create a floating-point number JSON value with a given content. | ||
1495 | |||
1496 | @param[in] val a floating-point value to create a JSON number from | ||
1497 | |||
1498 | @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 | ||
1499 | disallows NaN values: | ||
1500 | > Numeric values that cannot be represented in the grammar below (such as | ||
1501 | > Infinity and NaN) are not permitted. | ||
1502 | In case the parameter @a val is not a number, a JSON null value is created | ||
1503 | instead. | ||
1504 | |||
1505 | @complexity Constant. | ||
1506 | |||
1507 | @liveexample{The following example creates several floating-point | ||
1508 | values.,basic_json__number_float_t} | ||
1509 | |||
1510 | @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number | ||
1511 | value (floating-point) from a compatible number type | ||
1512 | |||
1513 | @since version 1.0.0 | ||
1514 | */ | ||
1515 | basic_json(const number_float_t val) noexcept | ||
1516 | : m_type(value_t::number_float), m_value(val) | ||
1517 | { | ||
1518 | // replace infinity and NAN by null | ||
1519 | if (not std::isfinite(val)) | ||
1520 | { | ||
1521 | m_type = value_t::null; | ||
1522 | m_value = json_value(); | ||
1523 | } | ||
1524 | |||
1525 | assert_invariant(); | ||
1526 | } | ||
1527 | |||
1528 | /*! | ||
1529 | @brief create an floating-point number (implicit) | ||
1530 | |||
1531 | Create an floating-point number JSON value with a given content. This | ||
1532 | constructor allows any type @a CompatibleNumberFloatType that can be used | ||
1533 | to construct values of type @ref number_float_t. | ||
1534 | |||
1535 | @tparam CompatibleNumberFloatType A floating-point type which is | ||
1536 | compatible to @ref number_float_t. Examples may include the types `float` | ||
1537 | or `double`. | ||
1538 | |||
1539 | @param[in] val a floating-point to create a JSON number from | ||
1540 | |||
1541 | @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 | ||
1542 | disallows NaN values: | ||
1543 | > Numeric values that cannot be represented in the grammar below (such as | ||
1544 | > Infinity and NaN) are not permitted. | ||
1545 | In case the parameter @a val is not a number, a JSON null value is | ||
1546 | created instead. | ||
1547 | |||
1548 | @complexity Constant. | ||
1549 | |||
1550 | @liveexample{The example below shows the construction of several | ||
1551 | floating-point number values from compatible | ||
1552 | types.,basic_json__CompatibleNumberFloatType} | ||
1553 | |||
1554 | @sa @ref basic_json(const number_float_t) -- create a number value | ||
1555 | (floating-point) | ||
1556 | |||
1557 | @since version 1.0.0 | ||
1558 | */ | ||
1559 | template<typename CompatibleNumberFloatType, typename = typename std::enable_if< | ||
1560 | std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and | ||
1561 | std::is_floating_point<CompatibleNumberFloatType>::value>::type> | ||
1562 | basic_json(const CompatibleNumberFloatType val) noexcept | ||
1563 | : basic_json(number_float_t(val)) | ||
1564 | { | ||
1565 | assert_invariant(); | ||
1566 | } | ||
1567 | |||
1568 | /*! | ||
1569 | @brief create a container (array or object) from an initializer list | ||
1570 | |||
1571 | Creates a JSON value of type array or object from the passed initializer | ||
1572 | list @a init. In case @a type_deduction is `true` (default), the type of | ||
1573 | the JSON value to be created is deducted from the initializer list @a init | ||
1574 | according to the following rules: | ||
1575 | |||
1576 | 1. If the list is empty, an empty JSON object value `{}` is created. | ||
1577 | 2. If the list consists of pairs whose first element is a string, a JSON | ||
1578 | object value is created where the first elements of the pairs are | ||
1579 | treated as keys and the second elements are as values. | ||
1580 | 3. In all other cases, an array is created. | ||
1581 | |||
1582 | The rules aim to create the best fit between a C++ initializer list and | ||
1583 | JSON values. The rationale is as follows: | ||
1584 | |||
1585 | 1. The empty initializer list is written as `{}` which is exactly an empty | ||
1586 | JSON object. | ||
1587 | 2. C++ has now way of describing mapped types other than to list a list of | ||
1588 | pairs. As JSON requires that keys must be of type string, rule 2 is the | ||
1589 | weakest constraint one can pose on initializer lists to interpret them | ||
1590 | as an object. | ||
1591 | 3. In all other cases, the initializer list could not be interpreted as | ||
1592 | JSON object type, so interpreting it as JSON array type is safe. | ||
1593 | |||
1594 | With the rules described above, the following JSON values cannot be | ||
1595 | expressed by an initializer list: | ||
1596 | |||
1597 | - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>) | ||
1598 | with an empty initializer list in this case | ||
1599 | - arrays whose elements satisfy rule 2: use @ref | ||
1600 | array(std::initializer_list<basic_json>) with the same initializer list | ||
1601 | in this case | ||
1602 | |||
1603 | @note When used without parentheses around an empty initializer list, @ref | ||
1604 | basic_json() is called instead of this function, yielding the JSON null | ||
1605 | value. | ||
1606 | |||
1607 | @param[in] init initializer list with JSON values | ||
1608 | |||
1609 | @param[in] type_deduction internal parameter; when set to `true`, the type | ||
1610 | of the JSON value is deducted from the initializer list @a init; when set | ||
1611 | to `false`, the type provided via @a manual_type is forced. This mode is | ||
1612 | used by the functions @ref array(std::initializer_list<basic_json>) and | ||
1613 | @ref object(std::initializer_list<basic_json>). | ||
1614 | |||
1615 | @param[in] manual_type internal parameter; when @a type_deduction is set | ||
1616 | to `false`, the created JSON value will use the provided type (only @ref | ||
1617 | value_t::array and @ref value_t::object are valid); when @a type_deduction | ||
1618 | is set to `true`, this parameter has no effect | ||
1619 | |||
1620 | @throw std::domain_error if @a type_deduction is `false`, @a manual_type | ||
1621 | is `value_t::object`, but @a init contains an element which is not a pair | ||
1622 | whose first element is a string; example: `"cannot create object from | ||
1623 | initializer list"` | ||
1624 | |||
1625 | @complexity Linear in the size of the initializer list @a init. | ||
1626 | |||
1627 | @liveexample{The example below shows how JSON values are created from | ||
1628 | initializer lists.,basic_json__list_init_t} | ||
1629 | |||
1630 | @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array | ||
1631 | value from an initializer list | ||
1632 | @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object | ||
1633 | value from an initializer list | ||
1634 | |||
1635 | @since version 1.0.0 | ||
1636 | */ | ||
1637 | basic_json(std::initializer_list<basic_json> init, | ||
1638 | bool type_deduction = true, | ||
1639 | value_t manual_type = value_t::array) | ||
1640 | { | ||
1641 | // check if each element is an array with two elements whose first | ||
1642 | // element is a string | ||
1643 | bool is_an_object = std::all_of(init.begin(), init.end(), | ||
1644 | [](const basic_json & element) | ||
1645 | { | ||
1646 | return element.is_array() and element.size() == 2 and element[0].is_string(); | ||
1647 | }); | ||
1648 | |||
1649 | // adjust type if type deduction is not wanted | ||
1650 | if (not type_deduction) | ||
1651 | { | ||
1652 | // if array is wanted, do not create an object though possible | ||
1653 | if (manual_type == value_t::array) | ||
1654 | { | ||
1655 | is_an_object = false; | ||
1656 | } | ||
1657 | |||
1658 | // if object is wanted but impossible, throw an exception | ||
1659 | if (manual_type == value_t::object and not is_an_object) | ||
1660 | { | ||
1661 | throw std::domain_error("cannot create object from initializer list"); | ||
1662 | } | ||
1663 | } | ||
1664 | |||
1665 | if (is_an_object) | ||
1666 | { | ||
1667 | // the initializer list is a list of pairs -> create object | ||
1668 | m_type = value_t::object; | ||
1669 | m_value = value_t::object; | ||
1670 | |||
1671 | std::for_each(init.begin(), init.end(), [this](const basic_json & element) | ||
1672 | { | ||
1673 | m_value.object->emplace(*(element[0].m_value.string), element[1]); | ||
1674 | }); | ||
1675 | } | ||
1676 | else | ||
1677 | { | ||
1678 | // the initializer list describes an array -> create array | ||
1679 | m_type = value_t::array; | ||
1680 | m_value.array = create<array_t>(init); | ||
1681 | } | ||
1682 | |||
1683 | assert_invariant(); | ||
1684 | } | ||
1685 | |||
1686 | /*! | ||
1687 | @brief explicitly create an array from an initializer list | ||
1688 | |||
1689 | Creates a JSON array value from a given initializer list. That is, given a | ||
1690 | list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the | ||
1691 | initializer list is empty, the empty array `[]` is created. | ||
1692 | |||
1693 | @note This function is only needed to express two edge cases that cannot | ||
1694 | be realized with the initializer list constructor (@ref | ||
1695 | basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases | ||
1696 | are: | ||
1697 | 1. creating an array whose elements are all pairs whose first element is a | ||
1698 | string -- in this case, the initializer list constructor would create an | ||
1699 | object, taking the first elements as keys | ||
1700 | 2. creating an empty array -- passing the empty initializer list to the | ||
1701 | initializer list constructor yields an empty object | ||
1702 | |||
1703 | @param[in] init initializer list with JSON values to create an array from | ||
1704 | (optional) | ||
1705 | |||
1706 | @return JSON array value | ||
1707 | |||
1708 | @complexity Linear in the size of @a init. | ||
1709 | |||
1710 | @liveexample{The following code shows an example for the `array` | ||
1711 | function.,array} | ||
1712 | |||
1713 | @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) -- | ||
1714 | create a JSON value from an initializer list | ||
1715 | @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object | ||
1716 | value from an initializer list | ||
1717 | |||
1718 | @since version 1.0.0 | ||
1719 | */ | ||
1720 | static basic_json array(std::initializer_list<basic_json> init = | ||
1721 | std::initializer_list<basic_json>()) | ||
1722 | { | ||
1723 | return basic_json(init, false, value_t::array); | ||
1724 | } | ||
1725 | |||
1726 | /*! | ||
1727 | @brief explicitly create an object from an initializer list | ||
1728 | |||
1729 | Creates a JSON object value from a given initializer list. The initializer | ||
1730 | lists elements must be pairs, and their first elements must be strings. If | ||
1731 | the initializer list is empty, the empty object `{}` is created. | ||
1732 | |||
1733 | @note This function is only added for symmetry reasons. In contrast to the | ||
1734 | related function @ref array(std::initializer_list<basic_json>), there are | ||
1735 | no cases which can only be expressed by this function. That is, any | ||
1736 | initializer list @a init can also be passed to the initializer list | ||
1737 | constructor @ref basic_json(std::initializer_list<basic_json>, bool, | ||
1738 | value_t). | ||
1739 | |||
1740 | @param[in] init initializer list to create an object from (optional) | ||
1741 | |||
1742 | @return JSON object value | ||
1743 | |||
1744 | @throw std::domain_error if @a init is not a pair whose first elements are | ||
1745 | strings; thrown by | ||
1746 | @ref basic_json(std::initializer_list<basic_json>, bool, value_t) | ||
1747 | |||
1748 | @complexity Linear in the size of @a init. | ||
1749 | |||
1750 | @liveexample{The following code shows an example for the `object` | ||
1751 | function.,object} | ||
1752 | |||
1753 | @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) -- | ||
1754 | create a JSON value from an initializer list | ||
1755 | @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array | ||
1756 | value from an initializer list | ||
1757 | |||
1758 | @since version 1.0.0 | ||
1759 | */ | ||
1760 | static basic_json object(std::initializer_list<basic_json> init = | ||
1761 | std::initializer_list<basic_json>()) | ||
1762 | { | ||
1763 | return basic_json(init, false, value_t::object); | ||
1764 | } | ||
1765 | |||
1766 | /*! | ||
1767 | @brief construct an array with count copies of given value | ||
1768 | |||
1769 | Constructs a JSON array value by creating @a cnt copies of a passed value. | ||
1770 | In case @a cnt is `0`, an empty array is created. As postcondition, | ||
1771 | `std::distance(begin(),end()) == cnt` holds. | ||
1772 | |||
1773 | @param[in] cnt the number of JSON copies of @a val to create | ||
1774 | @param[in] val the JSON value to copy | ||
1775 | |||
1776 | @complexity Linear in @a cnt. | ||
1777 | |||
1778 | @liveexample{The following code shows examples for the @ref | ||
1779 | basic_json(size_type\, const basic_json&) | ||
1780 | constructor.,basic_json__size_type_basic_json} | ||
1781 | |||
1782 | @since version 1.0.0 | ||
1783 | */ | ||
1784 | basic_json(size_type cnt, const basic_json& val) | ||
1785 | : m_type(value_t::array) | ||
1786 | { | ||
1787 | m_value.array = create<array_t>(cnt, val); | ||
1788 | assert_invariant(); | ||
1789 | } | ||
1790 | |||
1791 | /*! | ||
1792 | @brief construct a JSON container given an iterator range | ||
1793 | |||
1794 | Constructs the JSON value with the contents of the range `[first, last)`. | ||
1795 | The semantics depends on the different types a JSON value can have: | ||
1796 | - In case of primitive types (number, boolean, or string), @a first must | ||
1797 | be `begin()` and @a last must be `end()`. In this case, the value is | ||
1798 | copied. Otherwise, std::out_of_range is thrown. | ||
1799 | - In case of structured types (array, object), the constructor behaves as | ||
1800 | similar versions for `std::vector`. | ||
1801 | - In case of a null type, std::domain_error is thrown. | ||
1802 | |||
1803 | @tparam InputIT an input iterator type (@ref iterator or @ref | ||
1804 | const_iterator) | ||
1805 | |||
1806 | @param[in] first begin of the range to copy from (included) | ||
1807 | @param[in] last end of the range to copy from (excluded) | ||
1808 | |||
1809 | @pre Iterators @a first and @a last must be initialized. **This | ||
1810 | precondition is enforced with an assertion.** | ||
1811 | |||
1812 | @throw std::domain_error if iterators are not compatible; that is, do not | ||
1813 | belong to the same JSON value; example: `"iterators are not compatible"` | ||
1814 | @throw std::out_of_range if iterators are for a primitive type (number, | ||
1815 | boolean, or string) where an out of range error can be detected easily; | ||
1816 | example: `"iterators out of range"` | ||
1817 | @throw std::bad_alloc if allocation for object, array, or string fails | ||
1818 | @throw std::domain_error if called with a null value; example: `"cannot | ||
1819 | use construct with iterators from null"` | ||
1820 | |||
1821 | @complexity Linear in distance between @a first and @a last. | ||
1822 | |||
1823 | @liveexample{The example below shows several ways to create JSON values by | ||
1824 | specifying a subrange with iterators.,basic_json__InputIt_InputIt} | ||
1825 | |||
1826 | @since version 1.0.0 | ||
1827 | */ | ||
1828 | template<class InputIT, typename std::enable_if< | ||
1829 | std::is_same<InputIT, typename basic_json_t::iterator>::value or | ||
1830 | std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0> | ||
1831 | basic_json(InputIT first, InputIT last) | ||
1832 | { | ||
1833 | assert(first.m_object != nullptr); | ||
1834 | assert(last.m_object != nullptr); | ||
1835 | |||
1836 | // make sure iterator fits the current value | ||
1837 | if (first.m_object != last.m_object) | ||
1838 | { | ||
1839 | throw std::domain_error("iterators are not compatible"); | ||
1840 | } | ||
1841 | |||
1842 | // copy type from first iterator | ||
1843 | m_type = first.m_object->m_type; | ||
1844 | |||
1845 | // check if iterator range is complete for primitive values | ||
1846 | switch (m_type) | ||
1847 | { | ||
1848 | case value_t::boolean: | ||
1849 | case value_t::number_float: | ||
1850 | case value_t::number_integer: | ||
1851 | case value_t::number_unsigned: | ||
1852 | case value_t::string: | ||
1853 | { | ||
1854 | if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) | ||
1855 | { | ||
1856 | throw std::out_of_range("iterators out of range"); | ||
1857 | } | ||
1858 | break; | ||
1859 | } | ||
1860 | |||
1861 | default: | ||
1862 | { | ||
1863 | break; | ||
1864 | } | ||
1865 | } | ||
1866 | |||
1867 | switch (m_type) | ||
1868 | { | ||
1869 | case value_t::number_integer: | ||
1870 | { | ||
1871 | m_value.number_integer = first.m_object->m_value.number_integer; | ||
1872 | break; | ||
1873 | } | ||
1874 | |||
1875 | case value_t::number_unsigned: | ||
1876 | { | ||
1877 | m_value.number_unsigned = first.m_object->m_value.number_unsigned; | ||
1878 | break; | ||
1879 | } | ||
1880 | |||
1881 | case value_t::number_float: | ||
1882 | { | ||
1883 | m_value.number_float = first.m_object->m_value.number_float; | ||
1884 | break; | ||
1885 | } | ||
1886 | |||
1887 | case value_t::boolean: | ||
1888 | { | ||
1889 | m_value.boolean = first.m_object->m_value.boolean; | ||
1890 | break; | ||
1891 | } | ||
1892 | |||
1893 | case value_t::string: | ||
1894 | { | ||
1895 | m_value = *first.m_object->m_value.string; | ||
1896 | break; | ||
1897 | } | ||
1898 | |||
1899 | case value_t::object: | ||
1900 | { | ||
1901 | m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator); | ||
1902 | break; | ||
1903 | } | ||
1904 | |||
1905 | case value_t::array: | ||
1906 | { | ||
1907 | m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator); | ||
1908 | break; | ||
1909 | } | ||
1910 | |||
1911 | default: | ||
1912 | { | ||
1913 | throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); | ||
1914 | } | ||
1915 | } | ||
1916 | |||
1917 | assert_invariant(); | ||
1918 | } | ||
1919 | |||
1920 | /*! | ||
1921 | @brief construct a JSON value given an input stream | ||
1922 | |||
1923 | @param[in,out] i stream to read a serialized JSON value from | ||
1924 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
1925 | which is used to control the deserialization by filtering unwanted values | ||
1926 | (optional) | ||
1927 | |||
1928 | @complexity Linear in the length of the input. The parser is a predictive | ||
1929 | LL(1) parser. The complexity can be higher if the parser callback function | ||
1930 | @a cb has a super-linear complexity. | ||
1931 | |||
1932 | @note A UTF-8 byte order mark is silently ignored. | ||
1933 | |||
1934 | @deprecated This constructor is deprecated and will be removed in version | ||
1935 | 3.0.0 to unify the interface of the library. Deserialization will be | ||
1936 | done by stream operators or by calling one of the `parse` functions, | ||
1937 | e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls | ||
1938 | like `json j(i);` for an input stream @a i need to be replaced by | ||
1939 | `json j = json::parse(i);`. See the example below. | ||
1940 | |||
1941 | @liveexample{The example below demonstrates constructing a JSON value from | ||
1942 | a `std::stringstream` with and without callback | ||
1943 | function.,basic_json__istream} | ||
1944 | |||
1945 | @since version 2.0.0, deprecated in version 2.0.3, to be removed in | ||
1946 | version 3.0.0 | ||
1947 | */ | ||
1948 | JSON_DEPRECATED | ||
1949 | explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) | ||
1950 | { | ||
1951 | *this = parser(i, cb).parse(); | ||
1952 | assert_invariant(); | ||
1953 | } | ||
1954 | |||
1955 | /////////////////////////////////////// | ||
1956 | // other constructors and destructor // | ||
1957 | /////////////////////////////////////// | ||
1958 | |||
1959 | /*! | ||
1960 | @brief copy constructor | ||
1961 | |||
1962 | Creates a copy of a given JSON value. | ||
1963 | |||
1964 | @param[in] other the JSON value to copy | ||
1965 | |||
1966 | @complexity Linear in the size of @a other. | ||
1967 | |||
1968 | @requirement This function helps `basic_json` satisfying the | ||
1969 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
1970 | requirements: | ||
1971 | - The complexity is linear. | ||
1972 | - As postcondition, it holds: `other == basic_json(other)`. | ||
1973 | |||
1974 | @throw std::bad_alloc if allocation for object, array, or string fails. | ||
1975 | |||
1976 | @liveexample{The following code shows an example for the copy | ||
1977 | constructor.,basic_json__basic_json} | ||
1978 | |||
1979 | @since version 1.0.0 | ||
1980 | */ | ||
1981 | basic_json(const basic_json& other) | ||
1982 | : m_type(other.m_type) | ||
1983 | { | ||
1984 | // check of passed value is valid | ||
1985 | other.assert_invariant(); | ||
1986 | |||
1987 | switch (m_type) | ||
1988 | { | ||
1989 | case value_t::object: | ||
1990 | { | ||
1991 | m_value = *other.m_value.object; | ||
1992 | break; | ||
1993 | } | ||
1994 | |||
1995 | case value_t::array: | ||
1996 | { | ||
1997 | m_value = *other.m_value.array; | ||
1998 | break; | ||
1999 | } | ||
2000 | |||
2001 | case value_t::string: | ||
2002 | { | ||
2003 | m_value = *other.m_value.string; | ||
2004 | break; | ||
2005 | } | ||
2006 | |||
2007 | case value_t::boolean: | ||
2008 | { | ||
2009 | m_value = other.m_value.boolean; | ||
2010 | break; | ||
2011 | } | ||
2012 | |||
2013 | case value_t::number_integer: | ||
2014 | { | ||
2015 | m_value = other.m_value.number_integer; | ||
2016 | break; | ||
2017 | } | ||
2018 | |||
2019 | case value_t::number_unsigned: | ||
2020 | { | ||
2021 | m_value = other.m_value.number_unsigned; | ||
2022 | break; | ||
2023 | } | ||
2024 | |||
2025 | case value_t::number_float: | ||
2026 | { | ||
2027 | m_value = other.m_value.number_float; | ||
2028 | break; | ||
2029 | } | ||
2030 | |||
2031 | default: | ||
2032 | { | ||
2033 | break; | ||
2034 | } | ||
2035 | } | ||
2036 | |||
2037 | assert_invariant(); | ||
2038 | } | ||
2039 | |||
2040 | /*! | ||
2041 | @brief move constructor | ||
2042 | |||
2043 | Move constructor. Constructs a JSON value with the contents of the given | ||
2044 | value @a other using move semantics. It "steals" the resources from @a | ||
2045 | other and leaves it as JSON null value. | ||
2046 | |||
2047 | @param[in,out] other value to move to this object | ||
2048 | |||
2049 | @post @a other is a JSON null value | ||
2050 | |||
2051 | @complexity Constant. | ||
2052 | |||
2053 | @liveexample{The code below shows the move constructor explicitly called | ||
2054 | via std::move.,basic_json__moveconstructor} | ||
2055 | |||
2056 | @since version 1.0.0 | ||
2057 | */ | ||
2058 | basic_json(basic_json&& other) noexcept | ||
2059 | : m_type(std::move(other.m_type)), | ||
2060 | m_value(std::move(other.m_value)) | ||
2061 | { | ||
2062 | // check that passed value is valid | ||
2063 | other.assert_invariant(); | ||
2064 | |||
2065 | // invalidate payload | ||
2066 | other.m_type = value_t::null; | ||
2067 | other.m_value = {}; | ||
2068 | |||
2069 | assert_invariant(); | ||
2070 | } | ||
2071 | |||
2072 | /*! | ||
2073 | @brief copy assignment | ||
2074 | |||
2075 | Copy assignment operator. Copies a JSON value via the "copy and swap" | ||
2076 | strategy: It is expressed in terms of the copy constructor, destructor, | ||
2077 | and the swap() member function. | ||
2078 | |||
2079 | @param[in] other value to copy from | ||
2080 | |||
2081 | @complexity Linear. | ||
2082 | |||
2083 | @requirement This function helps `basic_json` satisfying the | ||
2084 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
2085 | requirements: | ||
2086 | - The complexity is linear. | ||
2087 | |||
2088 | @liveexample{The code below shows and example for the copy assignment. It | ||
2089 | creates a copy of value `a` which is then swapped with `b`. Finally\, the | ||
2090 | copy of `a` (which is the null value after the swap) is | ||
2091 | destroyed.,basic_json__copyassignment} | ||
2092 | |||
2093 | @since version 1.0.0 | ||
2094 | */ | ||
2095 | reference& operator=(basic_json other) noexcept ( | ||
2096 | std::is_nothrow_move_constructible<value_t>::value and | ||
2097 | std::is_nothrow_move_assignable<value_t>::value and | ||
2098 | std::is_nothrow_move_constructible<json_value>::value and | ||
2099 | std::is_nothrow_move_assignable<json_value>::value | ||
2100 | ) | ||
2101 | { | ||
2102 | // check that passed value is valid | ||
2103 | other.assert_invariant(); | ||
2104 | |||
2105 | using std::swap; | ||
2106 | swap(m_type, other.m_type); | ||
2107 | swap(m_value, other.m_value); | ||
2108 | |||
2109 | assert_invariant(); | ||
2110 | return *this; | ||
2111 | } | ||
2112 | |||
2113 | /*! | ||
2114 | @brief destructor | ||
2115 | |||
2116 | Destroys the JSON value and frees all allocated memory. | ||
2117 | |||
2118 | @complexity Linear. | ||
2119 | |||
2120 | @requirement This function helps `basic_json` satisfying the | ||
2121 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
2122 | requirements: | ||
2123 | - The complexity is linear. | ||
2124 | - All stored elements are destroyed and all memory is freed. | ||
2125 | |||
2126 | @since version 1.0.0 | ||
2127 | */ | ||
2128 | ~basic_json() | ||
2129 | { | ||
2130 | assert_invariant(); | ||
2131 | |||
2132 | switch (m_type) | ||
2133 | { | ||
2134 | case value_t::object: | ||
2135 | { | ||
2136 | AllocatorType<object_t> alloc; | ||
2137 | alloc.destroy(m_value.object); | ||
2138 | alloc.deallocate(m_value.object, 1); | ||
2139 | break; | ||
2140 | } | ||
2141 | |||
2142 | case value_t::array: | ||
2143 | { | ||
2144 | AllocatorType<array_t> alloc; | ||
2145 | alloc.destroy(m_value.array); | ||
2146 | alloc.deallocate(m_value.array, 1); | ||
2147 | break; | ||
2148 | } | ||
2149 | |||
2150 | case value_t::string: | ||
2151 | { | ||
2152 | AllocatorType<string_t> alloc; | ||
2153 | alloc.destroy(m_value.string); | ||
2154 | alloc.deallocate(m_value.string, 1); | ||
2155 | break; | ||
2156 | } | ||
2157 | |||
2158 | default: | ||
2159 | { | ||
2160 | // all other types need no specific destructor | ||
2161 | break; | ||
2162 | } | ||
2163 | } | ||
2164 | } | ||
2165 | |||
2166 | /// @} | ||
2167 | |||
2168 | public: | ||
2169 | /////////////////////// | ||
2170 | // object inspection // | ||
2171 | /////////////////////// | ||
2172 | |||
2173 | /// @name object inspection | ||
2174 | /// Functions to inspect the type of a JSON value. | ||
2175 | /// @{ | ||
2176 | |||
2177 | /*! | ||
2178 | @brief serialization | ||
2179 | |||
2180 | Serialization function for JSON values. The function tries to mimic | ||
2181 | Python's `json.dumps()` function, and currently supports its @a indent | ||
2182 | parameter. | ||
2183 | |||
2184 | @param[in] indent If indent is nonnegative, then array elements and object | ||
2185 | members will be pretty-printed with that indent level. An indent level of | ||
2186 | `0` will only insert newlines. `-1` (the default) selects the most compact | ||
2187 | representation. | ||
2188 | |||
2189 | @return string containing the serialization of the JSON value | ||
2190 | |||
2191 | @complexity Linear. | ||
2192 | |||
2193 | @liveexample{The following example shows the effect of different @a indent | ||
2194 | parameters to the result of the serialization.,dump} | ||
2195 | |||
2196 | @see https://docs.python.org/2/library/json.html#json.dump | ||
2197 | |||
2198 | @since version 1.0.0 | ||
2199 | */ | ||
2200 | string_t dump(const int indent = -1) const | ||
2201 | { | ||
2202 | std::stringstream ss; | ||
2203 | // fix locale problems | ||
2204 | const static std::locale loc(std::locale(), new DecimalSeparator); | ||
2205 | ss.imbue(loc); | ||
2206 | |||
2207 | // 6, 15 or 16 digits of precision allows round-trip IEEE 754 | ||
2208 | // string->float->string, string->double->string or string->long | ||
2209 | // double->string; to be safe, we read this value from | ||
2210 | // std::numeric_limits<number_float_t>::digits10 | ||
2211 | ss.precision(std::numeric_limits<double>::digits10); | ||
2212 | |||
2213 | if (indent >= 0) | ||
2214 | { | ||
2215 | dump(ss, true, static_cast<unsigned int>(indent)); | ||
2216 | } | ||
2217 | else | ||
2218 | { | ||
2219 | dump(ss, false, 0); | ||
2220 | } | ||
2221 | |||
2222 | return ss.str(); | ||
2223 | } | ||
2224 | |||
2225 | /*! | ||
2226 | @brief return the type of the JSON value (explicit) | ||
2227 | |||
2228 | Return the type of the JSON value as a value from the @ref value_t | ||
2229 | enumeration. | ||
2230 | |||
2231 | @return the type of the JSON value | ||
2232 | |||
2233 | @complexity Constant. | ||
2234 | |||
2235 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2236 | exceptions. | ||
2237 | |||
2238 | @liveexample{The following code exemplifies `type()` for all JSON | ||
2239 | types.,type} | ||
2240 | |||
2241 | @since version 1.0.0 | ||
2242 | */ | ||
2243 | constexpr value_t type() const noexcept | ||
2244 | { | ||
2245 | return m_type; | ||
2246 | } | ||
2247 | |||
2248 | /*! | ||
2249 | @brief return whether type is primitive | ||
2250 | |||
2251 | This function returns true iff the JSON type is primitive (string, number, | ||
2252 | boolean, or null). | ||
2253 | |||
2254 | @return `true` if type is primitive (string, number, boolean, or null), | ||
2255 | `false` otherwise. | ||
2256 | |||
2257 | @complexity Constant. | ||
2258 | |||
2259 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2260 | exceptions. | ||
2261 | |||
2262 | @liveexample{The following code exemplifies `is_primitive()` for all JSON | ||
2263 | types.,is_primitive} | ||
2264 | |||
2265 | @sa @ref is_structured() -- returns whether JSON value is structured | ||
2266 | @sa @ref is_null() -- returns whether JSON value is `null` | ||
2267 | @sa @ref is_string() -- returns whether JSON value is a string | ||
2268 | @sa @ref is_boolean() -- returns whether JSON value is a boolean | ||
2269 | @sa @ref is_number() -- returns whether JSON value is a number | ||
2270 | |||
2271 | @since version 1.0.0 | ||
2272 | */ | ||
2273 | constexpr bool is_primitive() const noexcept | ||
2274 | { | ||
2275 | return is_null() or is_string() or is_boolean() or is_number(); | ||
2276 | } | ||
2277 | |||
2278 | /*! | ||
2279 | @brief return whether type is structured | ||
2280 | |||
2281 | This function returns true iff the JSON type is structured (array or | ||
2282 | object). | ||
2283 | |||
2284 | @return `true` if type is structured (array or object), `false` otherwise. | ||
2285 | |||
2286 | @complexity Constant. | ||
2287 | |||
2288 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2289 | exceptions. | ||
2290 | |||
2291 | @liveexample{The following code exemplifies `is_structured()` for all JSON | ||
2292 | types.,is_structured} | ||
2293 | |||
2294 | @sa @ref is_primitive() -- returns whether value is primitive | ||
2295 | @sa @ref is_array() -- returns whether value is an array | ||
2296 | @sa @ref is_object() -- returns whether value is an object | ||
2297 | |||
2298 | @since version 1.0.0 | ||
2299 | */ | ||
2300 | constexpr bool is_structured() const noexcept | ||
2301 | { | ||
2302 | return is_array() or is_object(); | ||
2303 | } | ||
2304 | |||
2305 | /*! | ||
2306 | @brief return whether value is null | ||
2307 | |||
2308 | This function returns true iff the JSON value is null. | ||
2309 | |||
2310 | @return `true` if type is null, `false` otherwise. | ||
2311 | |||
2312 | @complexity Constant. | ||
2313 | |||
2314 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2315 | exceptions. | ||
2316 | |||
2317 | @liveexample{The following code exemplifies `is_null()` for all JSON | ||
2318 | types.,is_null} | ||
2319 | |||
2320 | @since version 1.0.0 | ||
2321 | */ | ||
2322 | constexpr bool is_null() const noexcept | ||
2323 | { | ||
2324 | return m_type == value_t::null; | ||
2325 | } | ||
2326 | |||
2327 | /*! | ||
2328 | @brief return whether value is a boolean | ||
2329 | |||
2330 | This function returns true iff the JSON value is a boolean. | ||
2331 | |||
2332 | @return `true` if type is boolean, `false` otherwise. | ||
2333 | |||
2334 | @complexity Constant. | ||
2335 | |||
2336 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2337 | exceptions. | ||
2338 | |||
2339 | @liveexample{The following code exemplifies `is_boolean()` for all JSON | ||
2340 | types.,is_boolean} | ||
2341 | |||
2342 | @since version 1.0.0 | ||
2343 | */ | ||
2344 | constexpr bool is_boolean() const noexcept | ||
2345 | { | ||
2346 | return m_type == value_t::boolean; | ||
2347 | } | ||
2348 | |||
2349 | /*! | ||
2350 | @brief return whether value is a number | ||
2351 | |||
2352 | This function returns true iff the JSON value is a number. This includes | ||
2353 | both integer and floating-point values. | ||
2354 | |||
2355 | @return `true` if type is number (regardless whether integer, unsigned | ||
2356 | integer or floating-type), `false` otherwise. | ||
2357 | |||
2358 | @complexity Constant. | ||
2359 | |||
2360 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2361 | exceptions. | ||
2362 | |||
2363 | @liveexample{The following code exemplifies `is_number()` for all JSON | ||
2364 | types.,is_number} | ||
2365 | |||
2366 | @sa @ref is_number_integer() -- check if value is an integer or unsigned | ||
2367 | integer number | ||
2368 | @sa @ref is_number_unsigned() -- check if value is an unsigned integer | ||
2369 | number | ||
2370 | @sa @ref is_number_float() -- check if value is a floating-point number | ||
2371 | |||
2372 | @since version 1.0.0 | ||
2373 | */ | ||
2374 | constexpr bool is_number() const noexcept | ||
2375 | { | ||
2376 | return is_number_integer() or is_number_float(); | ||
2377 | } | ||
2378 | |||
2379 | /*! | ||
2380 | @brief return whether value is an integer number | ||
2381 | |||
2382 | This function returns true iff the JSON value is an integer or unsigned | ||
2383 | integer number. This excludes floating-point values. | ||
2384 | |||
2385 | @return `true` if type is an integer or unsigned integer number, `false` | ||
2386 | otherwise. | ||
2387 | |||
2388 | @complexity Constant. | ||
2389 | |||
2390 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2391 | exceptions. | ||
2392 | |||
2393 | @liveexample{The following code exemplifies `is_number_integer()` for all | ||
2394 | JSON types.,is_number_integer} | ||
2395 | |||
2396 | @sa @ref is_number() -- check if value is a number | ||
2397 | @sa @ref is_number_unsigned() -- check if value is an unsigned integer | ||
2398 | number | ||
2399 | @sa @ref is_number_float() -- check if value is a floating-point number | ||
2400 | |||
2401 | @since version 1.0.0 | ||
2402 | */ | ||
2403 | constexpr bool is_number_integer() const noexcept | ||
2404 | { | ||
2405 | return m_type == value_t::number_integer or m_type == value_t::number_unsigned; | ||
2406 | } | ||
2407 | |||
2408 | /*! | ||
2409 | @brief return whether value is an unsigned integer number | ||
2410 | |||
2411 | This function returns true iff the JSON value is an unsigned integer | ||
2412 | number. This excludes floating-point and (signed) integer values. | ||
2413 | |||
2414 | @return `true` if type is an unsigned integer number, `false` otherwise. | ||
2415 | |||
2416 | @complexity Constant. | ||
2417 | |||
2418 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2419 | exceptions. | ||
2420 | |||
2421 | @liveexample{The following code exemplifies `is_number_unsigned()` for all | ||
2422 | JSON types.,is_number_unsigned} | ||
2423 | |||
2424 | @sa @ref is_number() -- check if value is a number | ||
2425 | @sa @ref is_number_integer() -- check if value is an integer or unsigned | ||
2426 | integer number | ||
2427 | @sa @ref is_number_float() -- check if value is a floating-point number | ||
2428 | |||
2429 | @since version 2.0.0 | ||
2430 | */ | ||
2431 | constexpr bool is_number_unsigned() const noexcept | ||
2432 | { | ||
2433 | return m_type == value_t::number_unsigned; | ||
2434 | } | ||
2435 | |||
2436 | /*! | ||
2437 | @brief return whether value is a floating-point number | ||
2438 | |||
2439 | This function returns true iff the JSON value is a floating-point number. | ||
2440 | This excludes integer and unsigned integer values. | ||
2441 | |||
2442 | @return `true` if type is a floating-point number, `false` otherwise. | ||
2443 | |||
2444 | @complexity Constant. | ||
2445 | |||
2446 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2447 | exceptions. | ||
2448 | |||
2449 | @liveexample{The following code exemplifies `is_number_float()` for all | ||
2450 | JSON types.,is_number_float} | ||
2451 | |||
2452 | @sa @ref is_number() -- check if value is number | ||
2453 | @sa @ref is_number_integer() -- check if value is an integer number | ||
2454 | @sa @ref is_number_unsigned() -- check if value is an unsigned integer | ||
2455 | number | ||
2456 | |||
2457 | @since version 1.0.0 | ||
2458 | */ | ||
2459 | constexpr bool is_number_float() const noexcept | ||
2460 | { | ||
2461 | return m_type == value_t::number_float; | ||
2462 | } | ||
2463 | |||
2464 | /*! | ||
2465 | @brief return whether value is an object | ||
2466 | |||
2467 | This function returns true iff the JSON value is an object. | ||
2468 | |||
2469 | @return `true` if type is object, `false` otherwise. | ||
2470 | |||
2471 | @complexity Constant. | ||
2472 | |||
2473 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2474 | exceptions. | ||
2475 | |||
2476 | @liveexample{The following code exemplifies `is_object()` for all JSON | ||
2477 | types.,is_object} | ||
2478 | |||
2479 | @since version 1.0.0 | ||
2480 | */ | ||
2481 | constexpr bool is_object() const noexcept | ||
2482 | { | ||
2483 | return m_type == value_t::object; | ||
2484 | } | ||
2485 | |||
2486 | /*! | ||
2487 | @brief return whether value is an array | ||
2488 | |||
2489 | This function returns true iff the JSON value is an array. | ||
2490 | |||
2491 | @return `true` if type is array, `false` otherwise. | ||
2492 | |||
2493 | @complexity Constant. | ||
2494 | |||
2495 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2496 | exceptions. | ||
2497 | |||
2498 | @liveexample{The following code exemplifies `is_array()` for all JSON | ||
2499 | types.,is_array} | ||
2500 | |||
2501 | @since version 1.0.0 | ||
2502 | */ | ||
2503 | constexpr bool is_array() const noexcept | ||
2504 | { | ||
2505 | return m_type == value_t::array; | ||
2506 | } | ||
2507 | |||
2508 | /*! | ||
2509 | @brief return whether value is a string | ||
2510 | |||
2511 | This function returns true iff the JSON value is a string. | ||
2512 | |||
2513 | @return `true` if type is string, `false` otherwise. | ||
2514 | |||
2515 | @complexity Constant. | ||
2516 | |||
2517 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2518 | exceptions. | ||
2519 | |||
2520 | @liveexample{The following code exemplifies `is_string()` for all JSON | ||
2521 | types.,is_string} | ||
2522 | |||
2523 | @since version 1.0.0 | ||
2524 | */ | ||
2525 | constexpr bool is_string() const noexcept | ||
2526 | { | ||
2527 | return m_type == value_t::string; | ||
2528 | } | ||
2529 | |||
2530 | /*! | ||
2531 | @brief return whether value is discarded | ||
2532 | |||
2533 | This function returns true iff the JSON value was discarded during parsing | ||
2534 | with a callback function (see @ref parser_callback_t). | ||
2535 | |||
2536 | @note This function will always be `false` for JSON values after parsing. | ||
2537 | That is, discarded values can only occur during parsing, but will be | ||
2538 | removed when inside a structured value or replaced by null in other cases. | ||
2539 | |||
2540 | @return `true` if type is discarded, `false` otherwise. | ||
2541 | |||
2542 | @complexity Constant. | ||
2543 | |||
2544 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2545 | exceptions. | ||
2546 | |||
2547 | @liveexample{The following code exemplifies `is_discarded()` for all JSON | ||
2548 | types.,is_discarded} | ||
2549 | |||
2550 | @since version 1.0.0 | ||
2551 | */ | ||
2552 | constexpr bool is_discarded() const noexcept | ||
2553 | { | ||
2554 | return m_type == value_t::discarded; | ||
2555 | } | ||
2556 | |||
2557 | /*! | ||
2558 | @brief return the type of the JSON value (implicit) | ||
2559 | |||
2560 | Implicitly return the type of the JSON value as a value from the @ref | ||
2561 | value_t enumeration. | ||
2562 | |||
2563 | @return the type of the JSON value | ||
2564 | |||
2565 | @complexity Constant. | ||
2566 | |||
2567 | @exceptionsafety No-throw guarantee: this member function never throws | ||
2568 | exceptions. | ||
2569 | |||
2570 | @liveexample{The following code exemplifies the @ref value_t operator for | ||
2571 | all JSON types.,operator__value_t} | ||
2572 | |||
2573 | @since version 1.0.0 | ||
2574 | */ | ||
2575 | constexpr operator value_t() const noexcept | ||
2576 | { | ||
2577 | return m_type; | ||
2578 | } | ||
2579 | |||
2580 | /// @} | ||
2581 | |||
2582 | private: | ||
2583 | ////////////////// | ||
2584 | // value access // | ||
2585 | ////////////////// | ||
2586 | |||
2587 | /// get an object (explicit) | ||
2588 | template<class T, typename std::enable_if< | ||
2589 | std::is_convertible<typename object_t::key_type, typename T::key_type>::value and | ||
2590 | std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0> | ||
2591 | T get_impl(T*) const | ||
2592 | { | ||
2593 | if (is_object()) | ||
2594 | { | ||
2595 | return T(m_value.object->begin(), m_value.object->end()); | ||
2596 | } | ||
2597 | else | ||
2598 | { | ||
2599 | throw std::domain_error("type must be object, but is " + type_name()); | ||
2600 | } | ||
2601 | } | ||
2602 | |||
2603 | /// get an object (explicit) | ||
2604 | object_t get_impl(object_t*) const | ||
2605 | { | ||
2606 | if (is_object()) | ||
2607 | { | ||
2608 | return *(m_value.object); | ||
2609 | } | ||
2610 | else | ||
2611 | { | ||
2612 | throw std::domain_error("type must be object, but is " + type_name()); | ||
2613 | } | ||
2614 | } | ||
2615 | |||
2616 | /// get an array (explicit) | ||
2617 | template<class T, typename std::enable_if< | ||
2618 | std::is_convertible<basic_json_t, typename T::value_type>::value and | ||
2619 | not std::is_same<basic_json_t, typename T::value_type>::value and | ||
2620 | not std::is_arithmetic<T>::value and | ||
2621 | not std::is_convertible<std::string, T>::value and | ||
2622 | not has_mapped_type<T>::value, int>::type = 0> | ||
2623 | T get_impl(T*) const | ||
2624 | { | ||
2625 | if (is_array()) | ||
2626 | { | ||
2627 | T to_vector; | ||
2628 | std::transform(m_value.array->begin(), m_value.array->end(), | ||
2629 | std::inserter(to_vector, to_vector.end()), [](basic_json i) | ||
2630 | { | ||
2631 | return i.get<typename T::value_type>(); | ||
2632 | }); | ||
2633 | return to_vector; | ||
2634 | } | ||
2635 | else | ||
2636 | { | ||
2637 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2638 | } | ||
2639 | } | ||
2640 | |||
2641 | /// get an array (explicit) | ||
2642 | template<class T, typename std::enable_if< | ||
2643 | std::is_convertible<basic_json_t, T>::value and | ||
2644 | not std::is_same<basic_json_t, T>::value, int>::type = 0> | ||
2645 | std::vector<T> get_impl(std::vector<T>*) const | ||
2646 | { | ||
2647 | if (is_array()) | ||
2648 | { | ||
2649 | std::vector<T> to_vector; | ||
2650 | to_vector.reserve(m_value.array->size()); | ||
2651 | std::transform(m_value.array->begin(), m_value.array->end(), | ||
2652 | std::inserter(to_vector, to_vector.end()), [](basic_json i) | ||
2653 | { | ||
2654 | return i.get<T>(); | ||
2655 | }); | ||
2656 | return to_vector; | ||
2657 | } | ||
2658 | else | ||
2659 | { | ||
2660 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2661 | } | ||
2662 | } | ||
2663 | |||
2664 | /// get an array (explicit) | ||
2665 | template<class T, typename std::enable_if< | ||
2666 | std::is_same<basic_json, typename T::value_type>::value and | ||
2667 | not has_mapped_type<T>::value, int>::type = 0> | ||
2668 | T get_impl(T*) const | ||
2669 | { | ||
2670 | if (is_array()) | ||
2671 | { | ||
2672 | return T(m_value.array->begin(), m_value.array->end()); | ||
2673 | } | ||
2674 | else | ||
2675 | { | ||
2676 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2677 | } | ||
2678 | } | ||
2679 | |||
2680 | /// get an array (explicit) | ||
2681 | array_t get_impl(array_t*) const | ||
2682 | { | ||
2683 | if (is_array()) | ||
2684 | { | ||
2685 | return *(m_value.array); | ||
2686 | } | ||
2687 | else | ||
2688 | { | ||
2689 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2690 | } | ||
2691 | } | ||
2692 | |||
2693 | /// get a string (explicit) | ||
2694 | template<typename T, typename std::enable_if< | ||
2695 | std::is_convertible<string_t, T>::value, int>::type = 0> | ||
2696 | T get_impl(T*) const | ||
2697 | { | ||
2698 | if (is_string()) | ||
2699 | { | ||
2700 | return *m_value.string; | ||
2701 | } | ||
2702 | else | ||
2703 | { | ||
2704 | throw std::domain_error("type must be string, but is " + type_name()); | ||
2705 | } | ||
2706 | } | ||
2707 | |||
2708 | /// get a number (explicit) | ||
2709 | template<typename T, typename std::enable_if< | ||
2710 | std::is_arithmetic<T>::value, int>::type = 0> | ||
2711 | T get_impl(T*) const | ||
2712 | { | ||
2713 | switch (m_type) | ||
2714 | { | ||
2715 | case value_t::number_integer: | ||
2716 | { | ||
2717 | return static_cast<T>(m_value.number_integer); | ||
2718 | } | ||
2719 | |||
2720 | case value_t::number_unsigned: | ||
2721 | { | ||
2722 | return static_cast<T>(m_value.number_unsigned); | ||
2723 | } | ||
2724 | |||
2725 | case value_t::number_float: | ||
2726 | { | ||
2727 | return static_cast<T>(m_value.number_float); | ||
2728 | } | ||
2729 | |||
2730 | default: | ||
2731 | { | ||
2732 | throw std::domain_error("type must be number, but is " + type_name()); | ||
2733 | } | ||
2734 | } | ||
2735 | } | ||
2736 | |||
2737 | /// get a boolean (explicit) | ||
2738 | constexpr boolean_t get_impl(boolean_t*) const | ||
2739 | { | ||
2740 | return is_boolean() | ||
2741 | ? m_value.boolean | ||
2742 | : throw std::domain_error("type must be boolean, but is " + type_name()); | ||
2743 | } | ||
2744 | |||
2745 | /// get a pointer to the value (object) | ||
2746 | object_t* get_impl_ptr(object_t*) noexcept | ||
2747 | { | ||
2748 | return is_object() ? m_value.object : nullptr; | ||
2749 | } | ||
2750 | |||
2751 | /// get a pointer to the value (object) | ||
2752 | constexpr const object_t* get_impl_ptr(const object_t*) const noexcept | ||
2753 | { | ||
2754 | return is_object() ? m_value.object : nullptr; | ||
2755 | } | ||
2756 | |||
2757 | /// get a pointer to the value (array) | ||
2758 | array_t* get_impl_ptr(array_t*) noexcept | ||
2759 | { | ||
2760 | return is_array() ? m_value.array : nullptr; | ||
2761 | } | ||
2762 | |||
2763 | /// get a pointer to the value (array) | ||
2764 | constexpr const array_t* get_impl_ptr(const array_t*) const noexcept | ||
2765 | { | ||
2766 | return is_array() ? m_value.array : nullptr; | ||
2767 | } | ||
2768 | |||
2769 | /// get a pointer to the value (string) | ||
2770 | string_t* get_impl_ptr(string_t*) noexcept | ||
2771 | { | ||
2772 | return is_string() ? m_value.string : nullptr; | ||
2773 | } | ||
2774 | |||
2775 | /// get a pointer to the value (string) | ||
2776 | constexpr const string_t* get_impl_ptr(const string_t*) const noexcept | ||
2777 | { | ||
2778 | return is_string() ? m_value.string : nullptr; | ||
2779 | } | ||
2780 | |||
2781 | /// get a pointer to the value (boolean) | ||
2782 | boolean_t* get_impl_ptr(boolean_t*) noexcept | ||
2783 | { | ||
2784 | return is_boolean() ? &m_value.boolean : nullptr; | ||
2785 | } | ||
2786 | |||
2787 | /// get a pointer to the value (boolean) | ||
2788 | constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept | ||
2789 | { | ||
2790 | return is_boolean() ? &m_value.boolean : nullptr; | ||
2791 | } | ||
2792 | |||
2793 | /// get a pointer to the value (integer number) | ||
2794 | number_integer_t* get_impl_ptr(number_integer_t*) noexcept | ||
2795 | { | ||
2796 | return is_number_integer() ? &m_value.number_integer : nullptr; | ||
2797 | } | ||
2798 | |||
2799 | /// get a pointer to the value (integer number) | ||
2800 | constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept | ||
2801 | { | ||
2802 | return is_number_integer() ? &m_value.number_integer : nullptr; | ||
2803 | } | ||
2804 | |||
2805 | /// get a pointer to the value (unsigned number) | ||
2806 | number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept | ||
2807 | { | ||
2808 | return is_number_unsigned() ? &m_value.number_unsigned : nullptr; | ||
2809 | } | ||
2810 | |||
2811 | /// get a pointer to the value (unsigned number) | ||
2812 | constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept | ||
2813 | { | ||
2814 | return is_number_unsigned() ? &m_value.number_unsigned : nullptr; | ||
2815 | } | ||
2816 | |||
2817 | /// get a pointer to the value (floating-point number) | ||
2818 | number_float_t* get_impl_ptr(number_float_t*) noexcept | ||
2819 | { | ||
2820 | return is_number_float() ? &m_value.number_float : nullptr; | ||
2821 | } | ||
2822 | |||
2823 | /// get a pointer to the value (floating-point number) | ||
2824 | constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept | ||
2825 | { | ||
2826 | return is_number_float() ? &m_value.number_float : nullptr; | ||
2827 | } | ||
2828 | |||
2829 | /*! | ||
2830 | @brief helper function to implement get_ref() | ||
2831 | |||
2832 | This funcion helps to implement get_ref() without code duplication for | ||
2833 | const and non-const overloads | ||
2834 | |||
2835 | @tparam ThisType will be deduced as `basic_json` or `const basic_json` | ||
2836 | |||
2837 | @throw std::domain_error if ReferenceType does not match underlying value | ||
2838 | type of the current JSON | ||
2839 | */ | ||
2840 | template<typename ReferenceType, typename ThisType> | ||
2841 | static ReferenceType get_ref_impl(ThisType& obj) | ||
2842 | { | ||
2843 | // helper type | ||
2844 | using PointerType = typename std::add_pointer<ReferenceType>::type; | ||
2845 | |||
2846 | // delegate the call to get_ptr<>() | ||
2847 | auto ptr = obj.template get_ptr<PointerType>(); | ||
2848 | |||
2849 | if (ptr != nullptr) | ||
2850 | { | ||
2851 | return *ptr; | ||
2852 | } | ||
2853 | else | ||
2854 | { | ||
2855 | throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + | ||
2856 | obj.type_name()); | ||
2857 | } | ||
2858 | } | ||
2859 | |||
2860 | public: | ||
2861 | |||
2862 | /// @name value access | ||
2863 | /// Direct access to the stored value of a JSON value. | ||
2864 | /// @{ | ||
2865 | |||
2866 | /*! | ||
2867 | @brief get a value (explicit) | ||
2868 | |||
2869 | Explicit type conversion between the JSON value and a compatible value. | ||
2870 | |||
2871 | @tparam ValueType non-pointer type compatible to the JSON value, for | ||
2872 | instance `int` for JSON integer numbers, `bool` for JSON booleans, or | ||
2873 | `std::vector` types for JSON arrays | ||
2874 | |||
2875 | @return copy of the JSON value, converted to type @a ValueType | ||
2876 | |||
2877 | @throw std::domain_error in case passed type @a ValueType is incompatible | ||
2878 | to JSON; example: `"type must be object, but is null"` | ||
2879 | |||
2880 | @complexity Linear in the size of the JSON value. | ||
2881 | |||
2882 | @liveexample{The example below shows several conversions from JSON values | ||
2883 | to other types. There a few things to note: (1) Floating-point numbers can | ||
2884 | be converted to integers\, (2) A JSON array can be converted to a standard | ||
2885 | `std::vector<short>`\, (3) A JSON object can be converted to C++ | ||
2886 | associative containers such as `std::unordered_map<std::string\, | ||
2887 | json>`.,get__ValueType_const} | ||
2888 | |||
2889 | @internal | ||
2890 | The idea of using a casted null pointer to choose the correct | ||
2891 | implementation is from <http://stackoverflow.com/a/8315197/266378>. | ||
2892 | @endinternal | ||
2893 | |||
2894 | @sa @ref operator ValueType() const for implicit conversion | ||
2895 | @sa @ref get() for pointer-member access | ||
2896 | |||
2897 | @since version 1.0.0 | ||
2898 | */ | ||
2899 | template<typename ValueType, typename std::enable_if< | ||
2900 | not std::is_pointer<ValueType>::value, int>::type = 0> | ||
2901 | ValueType get() const | ||
2902 | { | ||
2903 | return get_impl(static_cast<ValueType*>(nullptr)); | ||
2904 | } | ||
2905 | |||
2906 | /*! | ||
2907 | @brief get a pointer value (explicit) | ||
2908 | |||
2909 | Explicit pointer access to the internally stored JSON value. No copies are | ||
2910 | made. | ||
2911 | |||
2912 | @warning The pointer becomes invalid if the underlying JSON object | ||
2913 | changes. | ||
2914 | |||
2915 | @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref | ||
2916 | object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, | ||
2917 | @ref number_unsigned_t, or @ref number_float_t. | ||
2918 | |||
2919 | @return pointer to the internally stored JSON value if the requested | ||
2920 | pointer type @a PointerType fits to the JSON value; `nullptr` otherwise | ||
2921 | |||
2922 | @complexity Constant. | ||
2923 | |||
2924 | @liveexample{The example below shows how pointers to internal values of a | ||
2925 | JSON value can be requested. Note that no type conversions are made and a | ||
2926 | `nullptr` is returned if the value and the requested pointer type does not | ||
2927 | match.,get__PointerType} | ||
2928 | |||
2929 | @sa @ref get_ptr() for explicit pointer-member access | ||
2930 | |||
2931 | @since version 1.0.0 | ||
2932 | */ | ||
2933 | template<typename PointerType, typename std::enable_if< | ||
2934 | std::is_pointer<PointerType>::value, int>::type = 0> | ||
2935 | PointerType get() noexcept | ||
2936 | { | ||
2937 | // delegate the call to get_ptr | ||
2938 | return get_ptr<PointerType>(); | ||
2939 | } | ||
2940 | |||
2941 | /*! | ||
2942 | @brief get a pointer value (explicit) | ||
2943 | @copydoc get() | ||
2944 | */ | ||
2945 | template<typename PointerType, typename std::enable_if< | ||
2946 | std::is_pointer<PointerType>::value, int>::type = 0> | ||
2947 | constexpr const PointerType get() const noexcept | ||
2948 | { | ||
2949 | // delegate the call to get_ptr | ||
2950 | return get_ptr<PointerType>(); | ||
2951 | } | ||
2952 | |||
2953 | /*! | ||
2954 | @brief get a pointer value (implicit) | ||
2955 | |||
2956 | Implicit pointer access to the internally stored JSON value. No copies are | ||
2957 | made. | ||
2958 | |||
2959 | @warning Writing data to the pointee of the result yields an undefined | ||
2960 | state. | ||
2961 | |||
2962 | @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref | ||
2963 | object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, | ||
2964 | @ref number_unsigned_t, or @ref number_float_t. Enforced by a static | ||
2965 | assertion. | ||
2966 | |||
2967 | @return pointer to the internally stored JSON value if the requested | ||
2968 | pointer type @a PointerType fits to the JSON value; `nullptr` otherwise | ||
2969 | |||
2970 | @complexity Constant. | ||
2971 | |||
2972 | @liveexample{The example below shows how pointers to internal values of a | ||
2973 | JSON value can be requested. Note that no type conversions are made and a | ||
2974 | `nullptr` is returned if the value and the requested pointer type does not | ||
2975 | match.,get_ptr} | ||
2976 | |||
2977 | @since version 1.0.0 | ||
2978 | */ | ||
2979 | template<typename PointerType, typename std::enable_if< | ||
2980 | std::is_pointer<PointerType>::value, int>::type = 0> | ||
2981 | PointerType get_ptr() noexcept | ||
2982 | { | ||
2983 | // get the type of the PointerType (remove pointer and const) | ||
2984 | using pointee_t = typename std::remove_const<typename | ||
2985 | std::remove_pointer<typename | ||
2986 | std::remove_const<PointerType>::type>::type>::type; | ||
2987 | // make sure the type matches the allowed types | ||
2988 | static_assert( | ||
2989 | std::is_same<object_t, pointee_t>::value | ||
2990 | or std::is_same<array_t, pointee_t>::value | ||
2991 | or std::is_same<string_t, pointee_t>::value | ||
2992 | or std::is_same<boolean_t, pointee_t>::value | ||
2993 | or std::is_same<number_integer_t, pointee_t>::value | ||
2994 | or std::is_same<number_unsigned_t, pointee_t>::value | ||
2995 | or std::is_same<number_float_t, pointee_t>::value | ||
2996 | , "incompatible pointer type"); | ||
2997 | |||
2998 | // delegate the call to get_impl_ptr<>() | ||
2999 | return get_impl_ptr(static_cast<PointerType>(nullptr)); | ||
3000 | } | ||
3001 | |||
3002 | /*! | ||
3003 | @brief get a pointer value (implicit) | ||
3004 | @copydoc get_ptr() | ||
3005 | */ | ||
3006 | template<typename PointerType, typename std::enable_if< | ||
3007 | std::is_pointer<PointerType>::value and | ||
3008 | std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0> | ||
3009 | constexpr const PointerType get_ptr() const noexcept | ||
3010 | { | ||
3011 | // get the type of the PointerType (remove pointer and const) | ||
3012 | using pointee_t = typename std::remove_const<typename | ||
3013 | std::remove_pointer<typename | ||
3014 | std::remove_const<PointerType>::type>::type>::type; | ||
3015 | // make sure the type matches the allowed types | ||
3016 | static_assert( | ||
3017 | std::is_same<object_t, pointee_t>::value | ||
3018 | or std::is_same<array_t, pointee_t>::value | ||
3019 | or std::is_same<string_t, pointee_t>::value | ||
3020 | or std::is_same<boolean_t, pointee_t>::value | ||
3021 | or std::is_same<number_integer_t, pointee_t>::value | ||
3022 | or std::is_same<number_unsigned_t, pointee_t>::value | ||
3023 | or std::is_same<number_float_t, pointee_t>::value | ||
3024 | , "incompatible pointer type"); | ||
3025 | |||
3026 | // delegate the call to get_impl_ptr<>() const | ||
3027 | return get_impl_ptr(static_cast<const PointerType>(nullptr)); | ||
3028 | } | ||
3029 | |||
3030 | /*! | ||
3031 | @brief get a reference value (implicit) | ||
3032 | |||
3033 | Implict reference access to the internally stored JSON value. No copies | ||
3034 | are made. | ||
3035 | |||
3036 | @warning Writing data to the referee of the result yields an undefined | ||
3037 | state. | ||
3038 | |||
3039 | @tparam ReferenceType reference type; must be a reference to @ref array_t, | ||
3040 | @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or | ||
3041 | @ref number_float_t. Enforced by static assertion. | ||
3042 | |||
3043 | @return reference to the internally stored JSON value if the requested | ||
3044 | reference type @a ReferenceType fits to the JSON value; throws | ||
3045 | std::domain_error otherwise | ||
3046 | |||
3047 | @throw std::domain_error in case passed type @a ReferenceType is | ||
3048 | incompatible with the stored JSON value | ||
3049 | |||
3050 | @complexity Constant. | ||
3051 | |||
3052 | @liveexample{The example shows several calls to `get_ref()`.,get_ref} | ||
3053 | |||
3054 | @since version 1.1.0 | ||
3055 | */ | ||
3056 | template<typename ReferenceType, typename std::enable_if< | ||
3057 | std::is_reference<ReferenceType>::value, int>::type = 0> | ||
3058 | ReferenceType get_ref() | ||
3059 | { | ||
3060 | // delegate call to get_ref_impl | ||
3061 | return get_ref_impl<ReferenceType>(*this); | ||
3062 | } | ||
3063 | |||
3064 | /*! | ||
3065 | @brief get a reference value (implicit) | ||
3066 | @copydoc get_ref() | ||
3067 | */ | ||
3068 | template<typename ReferenceType, typename std::enable_if< | ||
3069 | std::is_reference<ReferenceType>::value and | ||
3070 | std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0> | ||
3071 | ReferenceType get_ref() const | ||
3072 | { | ||
3073 | // delegate call to get_ref_impl | ||
3074 | return get_ref_impl<ReferenceType>(*this); | ||
3075 | } | ||
3076 | |||
3077 | /*! | ||
3078 | @brief get a value (implicit) | ||
3079 | |||
3080 | Implicit type conversion between the JSON value and a compatible value. | ||
3081 | The call is realized by calling @ref get() const. | ||
3082 | |||
3083 | @tparam ValueType non-pointer type compatible to the JSON value, for | ||
3084 | instance `int` for JSON integer numbers, `bool` for JSON booleans, or | ||
3085 | `std::vector` types for JSON arrays. The character type of @ref string_t | ||
3086 | as well as an initializer list of this type is excluded to avoid | ||
3087 | ambiguities as these types implicitly convert to `std::string`. | ||
3088 | |||
3089 | @return copy of the JSON value, converted to type @a ValueType | ||
3090 | |||
3091 | @throw std::domain_error in case passed type @a ValueType is incompatible | ||
3092 | to JSON, thrown by @ref get() const | ||
3093 | |||
3094 | @complexity Linear in the size of the JSON value. | ||
3095 | |||
3096 | @liveexample{The example below shows several conversions from JSON values | ||
3097 | to other types. There a few things to note: (1) Floating-point numbers can | ||
3098 | be converted to integers\, (2) A JSON array can be converted to a standard | ||
3099 | `std::vector<short>`\, (3) A JSON object can be converted to C++ | ||
3100 | associative containers such as `std::unordered_map<std::string\, | ||
3101 | json>`.,operator__ValueType} | ||
3102 | |||
3103 | @since version 1.0.0 | ||
3104 | */ | ||
3105 | template < typename ValueType, typename std::enable_if < | ||
3106 | not std::is_pointer<ValueType>::value and | ||
3107 | not std::is_same<ValueType, typename string_t::value_type>::value | ||
3108 | #ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 | ||
3109 | and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value | ||
3110 | #endif | ||
3111 | , int >::type = 0 > | ||
3112 | operator ValueType() const | ||
3113 | { | ||
3114 | // delegate the call to get<>() const | ||
3115 | return get<ValueType>(); | ||
3116 | } | ||
3117 | |||
3118 | /// @} | ||
3119 | |||
3120 | |||
3121 | //////////////////// | ||
3122 | // element access // | ||
3123 | //////////////////// | ||
3124 | |||
3125 | /// @name element access | ||
3126 | /// Access to the JSON value. | ||
3127 | /// @{ | ||
3128 | |||
3129 | /*! | ||
3130 | @brief access specified array element with bounds checking | ||
3131 | |||
3132 | Returns a reference to the element at specified location @a idx, with | ||
3133 | bounds checking. | ||
3134 | |||
3135 | @param[in] idx index of the element to access | ||
3136 | |||
3137 | @return reference to the element at index @a idx | ||
3138 | |||
3139 | @throw std::domain_error if the JSON value is not an array; example: | ||
3140 | `"cannot use at() with string"` | ||
3141 | @throw std::out_of_range if the index @a idx is out of range of the array; | ||
3142 | that is, `idx >= size()`; example: `"array index 7 is out of range"` | ||
3143 | |||
3144 | @complexity Constant. | ||
3145 | |||
3146 | @liveexample{The example below shows how array elements can be read and | ||
3147 | written using `at()`.,at__size_type} | ||
3148 | |||
3149 | @since version 1.0.0 | ||
3150 | */ | ||
3151 | reference at(size_type idx) | ||
3152 | { | ||
3153 | // at only works for arrays | ||
3154 | if (is_array()) | ||
3155 | { | ||
3156 | try | ||
3157 | { | ||
3158 | return m_value.array->at(idx); | ||
3159 | } | ||
3160 | catch (std::out_of_range&) | ||
3161 | { | ||
3162 | // create better exception explanation | ||
3163 | throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); | ||
3164 | } | ||
3165 | } | ||
3166 | else | ||
3167 | { | ||
3168 | throw std::domain_error("cannot use at() with " + type_name()); | ||
3169 | } | ||
3170 | } | ||
3171 | |||
3172 | /*! | ||
3173 | @brief access specified array element with bounds checking | ||
3174 | |||
3175 | Returns a const reference to the element at specified location @a idx, | ||
3176 | with bounds checking. | ||
3177 | |||
3178 | @param[in] idx index of the element to access | ||
3179 | |||
3180 | @return const reference to the element at index @a idx | ||
3181 | |||
3182 | @throw std::domain_error if the JSON value is not an array; example: | ||
3183 | `"cannot use at() with string"` | ||
3184 | @throw std::out_of_range if the index @a idx is out of range of the array; | ||
3185 | that is, `idx >= size()`; example: `"array index 7 is out of range"` | ||
3186 | |||
3187 | @complexity Constant. | ||
3188 | |||
3189 | @liveexample{The example below shows how array elements can be read using | ||
3190 | `at()`.,at__size_type_const} | ||
3191 | |||
3192 | @since version 1.0.0 | ||
3193 | */ | ||
3194 | const_reference at(size_type idx) const | ||
3195 | { | ||
3196 | // at only works for arrays | ||
3197 | if (is_array()) | ||
3198 | { | ||
3199 | try | ||
3200 | { | ||
3201 | return m_value.array->at(idx); | ||
3202 | } | ||
3203 | catch (std::out_of_range&) | ||
3204 | { | ||
3205 | // create better exception explanation | ||
3206 | throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); | ||
3207 | } | ||
3208 | } | ||
3209 | else | ||
3210 | { | ||
3211 | throw std::domain_error("cannot use at() with " + type_name()); | ||
3212 | } | ||
3213 | } | ||
3214 | |||
3215 | /*! | ||
3216 | @brief access specified object element with bounds checking | ||
3217 | |||
3218 | Returns a reference to the element at with specified key @a key, with | ||
3219 | bounds checking. | ||
3220 | |||
3221 | @param[in] key key of the element to access | ||
3222 | |||
3223 | @return reference to the element at key @a key | ||
3224 | |||
3225 | @throw std::domain_error if the JSON value is not an object; example: | ||
3226 | `"cannot use at() with boolean"` | ||
3227 | @throw std::out_of_range if the key @a key is is not stored in the object; | ||
3228 | that is, `find(key) == end()`; example: `"key "the fast" not found"` | ||
3229 | |||
3230 | @complexity Logarithmic in the size of the container. | ||
3231 | |||
3232 | @liveexample{The example below shows how object elements can be read and | ||
3233 | written using `at()`.,at__object_t_key_type} | ||
3234 | |||
3235 | @sa @ref operator[](const typename object_t::key_type&) for unchecked | ||
3236 | access by reference | ||
3237 | @sa @ref value() for access by value with a default value | ||
3238 | |||
3239 | @since version 1.0.0 | ||
3240 | */ | ||
3241 | reference at(const typename object_t::key_type& key) | ||
3242 | { | ||
3243 | // at only works for objects | ||
3244 | if (is_object()) | ||
3245 | { | ||
3246 | try | ||
3247 | { | ||
3248 | return m_value.object->at(key); | ||
3249 | } | ||
3250 | catch (std::out_of_range&) | ||
3251 | { | ||
3252 | // create better exception explanation | ||
3253 | throw std::out_of_range("key '" + key + "' not found"); | ||
3254 | } | ||
3255 | } | ||
3256 | else | ||
3257 | { | ||
3258 | throw std::domain_error("cannot use at() with " + type_name()); | ||
3259 | } | ||
3260 | } | ||
3261 | |||
3262 | /*! | ||
3263 | @brief access specified object element with bounds checking | ||
3264 | |||
3265 | Returns a const reference to the element at with specified key @a key, | ||
3266 | with bounds checking. | ||
3267 | |||
3268 | @param[in] key key of the element to access | ||
3269 | |||
3270 | @return const reference to the element at key @a key | ||
3271 | |||
3272 | @throw std::domain_error if the JSON value is not an object; example: | ||
3273 | `"cannot use at() with boolean"` | ||
3274 | @throw std::out_of_range if the key @a key is is not stored in the object; | ||
3275 | that is, `find(key) == end()`; example: `"key "the fast" not found"` | ||
3276 | |||
3277 | @complexity Logarithmic in the size of the container. | ||
3278 | |||
3279 | @liveexample{The example below shows how object elements can be read using | ||
3280 | `at()`.,at__object_t_key_type_const} | ||
3281 | |||
3282 | @sa @ref operator[](const typename object_t::key_type&) for unchecked | ||
3283 | access by reference | ||
3284 | @sa @ref value() for access by value with a default value | ||
3285 | |||
3286 | @since version 1.0.0 | ||
3287 | */ | ||
3288 | const_reference at(const typename object_t::key_type& key) const | ||
3289 | { | ||
3290 | // at only works for objects | ||
3291 | if (is_object()) | ||
3292 | { | ||
3293 | try | ||
3294 | { | ||
3295 | return m_value.object->at(key); | ||
3296 | } | ||
3297 | catch (std::out_of_range&) | ||
3298 | { | ||
3299 | // create better exception explanation | ||
3300 | throw std::out_of_range("key '" + key + "' not found"); | ||
3301 | } | ||
3302 | } | ||
3303 | else | ||
3304 | { | ||
3305 | throw std::domain_error("cannot use at() with " + type_name()); | ||
3306 | } | ||
3307 | } | ||
3308 | |||
3309 | /*! | ||
3310 | @brief access specified array element | ||
3311 | |||
3312 | Returns a reference to the element at specified location @a idx. | ||
3313 | |||
3314 | @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), | ||
3315 | then the array is silently filled up with `null` values to make `idx` a | ||
3316 | valid reference to the last stored element. | ||
3317 | |||
3318 | @param[in] idx index of the element to access | ||
3319 | |||
3320 | @return reference to the element at index @a idx | ||
3321 | |||
3322 | @throw std::domain_error if JSON is not an array or null; example: | ||
3323 | `"cannot use operator[] with string"` | ||
3324 | |||
3325 | @complexity Constant if @a idx is in the range of the array. Otherwise | ||
3326 | linear in `idx - size()`. | ||
3327 | |||
3328 | @liveexample{The example below shows how array elements can be read and | ||
3329 | written using `[]` operator. Note the addition of `null` | ||
3330 | values.,operatorarray__size_type} | ||
3331 | |||
3332 | @since version 1.0.0 | ||
3333 | */ | ||
3334 | reference operator[](size_type idx) | ||
3335 | { | ||
3336 | // implicitly convert null value to an empty array | ||
3337 | if (is_null()) | ||
3338 | { | ||
3339 | m_type = value_t::array; | ||
3340 | m_value.array = create<array_t>(); | ||
3341 | assert_invariant(); | ||
3342 | } | ||
3343 | |||
3344 | // operator[] only works for arrays | ||
3345 | if (is_array()) | ||
3346 | { | ||
3347 | // fill up array with null values if given idx is outside range | ||
3348 | if (idx >= m_value.array->size()) | ||
3349 | { | ||
3350 | m_value.array->insert(m_value.array->end(), | ||
3351 | idx - m_value.array->size() + 1, | ||
3352 | basic_json()); | ||
3353 | } | ||
3354 | |||
3355 | return m_value.array->operator[](idx); | ||
3356 | } | ||
3357 | else | ||
3358 | { | ||
3359 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
3360 | } | ||
3361 | } | ||
3362 | |||
3363 | /*! | ||
3364 | @brief access specified array element | ||
3365 | |||
3366 | Returns a const reference to the element at specified location @a idx. | ||
3367 | |||
3368 | @param[in] idx index of the element to access | ||
3369 | |||
3370 | @return const reference to the element at index @a idx | ||
3371 | |||
3372 | @throw std::domain_error if JSON is not an array; example: `"cannot use | ||
3373 | operator[] with null"` | ||
3374 | |||
3375 | @complexity Constant. | ||
3376 | |||
3377 | @liveexample{The example below shows how array elements can be read using | ||
3378 | the `[]` operator.,operatorarray__size_type_const} | ||
3379 | |||
3380 | @since version 1.0.0 | ||
3381 | */ | ||
3382 | const_reference operator[](size_type idx) const | ||
3383 | { | ||
3384 | // const operator[] only works for arrays | ||
3385 | if (is_array()) | ||
3386 | { | ||
3387 | return m_value.array->operator[](idx); | ||
3388 | } | ||
3389 | else | ||
3390 | { | ||
3391 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
3392 | } | ||
3393 | } | ||
3394 | |||
3395 | /*! | ||
3396 | @brief access specified object element | ||
3397 | |||
3398 | Returns a reference to the element at with specified key @a key. | ||
3399 | |||
3400 | @note If @a key is not found in the object, then it is silently added to | ||
3401 | the object and filled with a `null` value to make `key` a valid reference. | ||
3402 | In case the value was `null` before, it is converted to an object. | ||
3403 | |||
3404 | @param[in] key key of the element to access | ||
3405 | |||
3406 | @return reference to the element at key @a key | ||
3407 | |||
3408 | @throw std::domain_error if JSON is not an object or null; example: | ||
3409 | `"cannot use operator[] with string"` | ||
3410 | |||
3411 | @complexity Logarithmic in the size of the container. | ||
3412 | |||
3413 | @liveexample{The example below shows how object elements can be read and | ||
3414 | written using the `[]` operator.,operatorarray__key_type} | ||
3415 | |||
3416 | @sa @ref at(const typename object_t::key_type&) for access by reference | ||
3417 | with range checking | ||
3418 | @sa @ref value() for access by value with a default value | ||
3419 | |||
3420 | @since version 1.0.0 | ||
3421 | */ | ||
3422 | reference operator[](const typename object_t::key_type& key) | ||
3423 | { | ||
3424 | // implicitly convert null value to an empty object | ||
3425 | if (is_null()) | ||
3426 | { | ||
3427 | m_type = value_t::object; | ||
3428 | m_value.object = create<object_t>(); | ||
3429 | assert_invariant(); | ||
3430 | } | ||
3431 | |||
3432 | // operator[] only works for objects | ||
3433 | if (is_object()) | ||
3434 | { | ||
3435 | return m_value.object->operator[](key); | ||
3436 | } | ||
3437 | else | ||
3438 | { | ||
3439 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
3440 | } | ||
3441 | } | ||
3442 | |||
3443 | /*! | ||
3444 | @brief read-only access specified object element | ||
3445 | |||
3446 | Returns a const reference to the element at with specified key @a key. No | ||
3447 | bounds checking is performed. | ||
3448 | |||
3449 | @warning If the element with key @a key does not exist, the behavior is | ||
3450 | undefined. | ||
3451 | |||
3452 | @param[in] key key of the element to access | ||
3453 | |||
3454 | @return const reference to the element at key @a key | ||
3455 | |||
3456 | @pre The element with key @a key must exist. **This precondition is | ||
3457 | enforced with an assertion.** | ||
3458 | |||
3459 | @throw std::domain_error if JSON is not an object; example: `"cannot use | ||
3460 | operator[] with null"` | ||
3461 | |||
3462 | @complexity Logarithmic in the size of the container. | ||
3463 | |||
3464 | @liveexample{The example below shows how object elements can be read using | ||
3465 | the `[]` operator.,operatorarray__key_type_const} | ||
3466 | |||
3467 | @sa @ref at(const typename object_t::key_type&) for access by reference | ||
3468 | with range checking | ||
3469 | @sa @ref value() for access by value with a default value | ||
3470 | |||
3471 | @since version 1.0.0 | ||
3472 | */ | ||
3473 | const_reference operator[](const typename object_t::key_type& key) const | ||
3474 | { | ||
3475 | // const operator[] only works for objects | ||
3476 | if (is_object()) | ||
3477 | { | ||
3478 | assert(m_value.object->find(key) != m_value.object->end()); | ||
3479 | return m_value.object->find(key)->second; | ||
3480 | } | ||
3481 | else | ||
3482 | { | ||
3483 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
3484 | } | ||
3485 | } | ||
3486 | |||
3487 | /*! | ||
3488 | @brief access specified object element | ||
3489 | |||
3490 | Returns a reference to the element at with specified key @a key. | ||
3491 | |||
3492 | @note If @a key is not found in the object, then it is silently added to | ||
3493 | the object and filled with a `null` value to make `key` a valid reference. | ||
3494 | In case the value was `null` before, it is converted to an object. | ||
3495 | |||
3496 | @param[in] key key of the element to access | ||
3497 | |||
3498 | @return reference to the element at key @a key | ||
3499 | |||
3500 | @throw std::domain_error if JSON is not an object or null; example: | ||
3501 | `"cannot use operator[] with string"` | ||
3502 | |||
3503 | @complexity Logarithmic in the size of the container. | ||
3504 | |||
3505 | @liveexample{The example below shows how object elements can be read and | ||
3506 | written using the `[]` operator.,operatorarray__key_type} | ||
3507 | |||
3508 | @sa @ref at(const typename object_t::key_type&) for access by reference | ||
3509 | with range checking | ||
3510 | @sa @ref value() for access by value with a default value | ||
3511 | |||
3512 | @since version 1.0.0 | ||
3513 | */ | ||
3514 | template<typename T, std::size_t n> | ||
3515 | reference operator[](T * (&key)[n]) | ||
3516 | { | ||
3517 | return operator[](static_cast<const T>(key)); | ||
3518 | } | ||
3519 | |||
3520 | /*! | ||
3521 | @brief read-only access specified object element | ||
3522 | |||
3523 | Returns a const reference to the element at with specified key @a key. No | ||
3524 | bounds checking is performed. | ||
3525 | |||
3526 | @warning If the element with key @a key does not exist, the behavior is | ||
3527 | undefined. | ||
3528 | |||
3529 | @note This function is required for compatibility reasons with Clang. | ||
3530 | |||
3531 | @param[in] key key of the element to access | ||
3532 | |||
3533 | @return const reference to the element at key @a key | ||
3534 | |||
3535 | @throw std::domain_error if JSON is not an object; example: `"cannot use | ||
3536 | operator[] with null"` | ||
3537 | |||
3538 | @complexity Logarithmic in the size of the container. | ||
3539 | |||
3540 | @liveexample{The example below shows how object elements can be read using | ||
3541 | the `[]` operator.,operatorarray__key_type_const} | ||
3542 | |||
3543 | @sa @ref at(const typename object_t::key_type&) for access by reference | ||
3544 | with range checking | ||
3545 | @sa @ref value() for access by value with a default value | ||
3546 | |||
3547 | @since version 1.0.0 | ||
3548 | */ | ||
3549 | template<typename T, std::size_t n> | ||
3550 | const_reference operator[](T * (&key)[n]) const | ||
3551 | { | ||
3552 | return operator[](static_cast<const T>(key)); | ||
3553 | } | ||
3554 | |||
3555 | /*! | ||
3556 | @brief access specified object element | ||
3557 | |||
3558 | Returns a reference to the element at with specified key @a key. | ||
3559 | |||
3560 | @note If @a key is not found in the object, then it is silently added to | ||
3561 | the object and filled with a `null` value to make `key` a valid reference. | ||
3562 | In case the value was `null` before, it is converted to an object. | ||
3563 | |||
3564 | @param[in] key key of the element to access | ||
3565 | |||
3566 | @return reference to the element at key @a key | ||
3567 | |||
3568 | @throw std::domain_error if JSON is not an object or null; example: | ||
3569 | `"cannot use operator[] with string"` | ||
3570 | |||
3571 | @complexity Logarithmic in the size of the container. | ||
3572 | |||
3573 | @liveexample{The example below shows how object elements can be read and | ||
3574 | written using the `[]` operator.,operatorarray__key_type} | ||
3575 | |||
3576 | @sa @ref at(const typename object_t::key_type&) for access by reference | ||
3577 | with range checking | ||
3578 | @sa @ref value() for access by value with a default value | ||
3579 | |||
3580 | @since version 1.1.0 | ||
3581 | */ | ||
3582 | template<typename T> | ||
3583 | reference operator[](T* key) | ||
3584 | { | ||
3585 | // implicitly convert null to object | ||
3586 | if (is_null()) | ||
3587 | { | ||
3588 | m_type = value_t::object; | ||
3589 | m_value = value_t::object; | ||
3590 | assert_invariant(); | ||
3591 | } | ||
3592 | |||
3593 | // at only works for objects | ||
3594 | if (is_object()) | ||
3595 | { | ||
3596 | return m_value.object->operator[](key); | ||
3597 | } | ||
3598 | else | ||
3599 | { | ||
3600 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
3601 | } | ||
3602 | } | ||
3603 | |||
3604 | /*! | ||
3605 | @brief read-only access specified object element | ||
3606 | |||
3607 | Returns a const reference to the element at with specified key @a key. No | ||
3608 | bounds checking is performed. | ||
3609 | |||
3610 | @warning If the element with key @a key does not exist, the behavior is | ||
3611 | undefined. | ||
3612 | |||
3613 | @param[in] key key of the element to access | ||
3614 | |||
3615 | @return const reference to the element at key @a key | ||
3616 | |||
3617 | @pre The element with key @a key must exist. **This precondition is | ||
3618 | enforced with an assertion.** | ||
3619 | |||
3620 | @throw std::domain_error if JSON is not an object; example: `"cannot use | ||
3621 | operator[] with null"` | ||
3622 | |||
3623 | @complexity Logarithmic in the size of the container. | ||
3624 | |||
3625 | @liveexample{The example below shows how object elements can be read using | ||
3626 | the `[]` operator.,operatorarray__key_type_const} | ||
3627 | |||
3628 | @sa @ref at(const typename object_t::key_type&) for access by reference | ||
3629 | with range checking | ||
3630 | @sa @ref value() for access by value with a default value | ||
3631 | |||
3632 | @since version 1.1.0 | ||
3633 | */ | ||
3634 | template<typename T> | ||
3635 | const_reference operator[](T* key) const | ||
3636 | { | ||
3637 | // at only works for objects | ||
3638 | if (is_object()) | ||
3639 | { | ||
3640 | assert(m_value.object->find(key) != m_value.object->end()); | ||
3641 | return m_value.object->find(key)->second; | ||
3642 | } | ||
3643 | else | ||
3644 | { | ||
3645 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
3646 | } | ||
3647 | } | ||
3648 | |||
3649 | /*! | ||
3650 | @brief access specified object element with default value | ||
3651 | |||
3652 | Returns either a copy of an object's element at the specified key @a key | ||
3653 | or a given default value if no element with key @a key exists. | ||
3654 | |||
3655 | The function is basically equivalent to executing | ||
3656 | @code {.cpp} | ||
3657 | try { | ||
3658 | return at(key); | ||
3659 | } catch(std::out_of_range) { | ||
3660 | return default_value; | ||
3661 | } | ||
3662 | @endcode | ||
3663 | |||
3664 | @note Unlike @ref at(const typename object_t::key_type&), this function | ||
3665 | does not throw if the given key @a key was not found. | ||
3666 | |||
3667 | @note Unlike @ref operator[](const typename object_t::key_type& key), this | ||
3668 | function does not implicitly add an element to the position defined by @a | ||
3669 | key. This function is furthermore also applicable to const objects. | ||
3670 | |||
3671 | @param[in] key key of the element to access | ||
3672 | @param[in] default_value the value to return if @a key is not found | ||
3673 | |||
3674 | @tparam ValueType type compatible to JSON values, for instance `int` for | ||
3675 | JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for | ||
3676 | JSON arrays. Note the type of the expected value at @a key and the default | ||
3677 | value @a default_value must be compatible. | ||
3678 | |||
3679 | @return copy of the element at key @a key or @a default_value if @a key | ||
3680 | is not found | ||
3681 | |||
3682 | @throw std::domain_error if JSON is not an object; example: `"cannot use | ||
3683 | value() with null"` | ||
3684 | |||
3685 | @complexity Logarithmic in the size of the container. | ||
3686 | |||
3687 | @liveexample{The example below shows how object elements can be queried | ||
3688 | with a default value.,basic_json__value} | ||
3689 | |||
3690 | @sa @ref at(const typename object_t::key_type&) for access by reference | ||
3691 | with range checking | ||
3692 | @sa @ref operator[](const typename object_t::key_type&) for unchecked | ||
3693 | access by reference | ||
3694 | |||
3695 | @since version 1.0.0 | ||
3696 | */ | ||
3697 | template<class ValueType, typename std::enable_if< | ||
3698 | std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0> | ||
3699 | ValueType value(const typename object_t::key_type& key, ValueType default_value) const | ||
3700 | { | ||
3701 | // at only works for objects | ||
3702 | if (is_object()) | ||
3703 | { | ||
3704 | // if key is found, return value and given default value otherwise | ||
3705 | const auto it = find(key); | ||
3706 | if (it != end()) | ||
3707 | { | ||
3708 | return *it; | ||
3709 | } | ||
3710 | else | ||
3711 | { | ||
3712 | return default_value; | ||
3713 | } | ||
3714 | } | ||
3715 | else | ||
3716 | { | ||
3717 | throw std::domain_error("cannot use value() with " + type_name()); | ||
3718 | } | ||
3719 | } | ||
3720 | |||
3721 | /*! | ||
3722 | @brief overload for a default value of type const char* | ||
3723 | @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const | ||
3724 | */ | ||
3725 | string_t value(const typename object_t::key_type& key, const char* default_value) const | ||
3726 | { | ||
3727 | return value(key, string_t(default_value)); | ||
3728 | } | ||
3729 | |||
3730 | /*! | ||
3731 | @brief access specified object element via JSON Pointer with default value | ||
3732 | |||
3733 | Returns either a copy of an object's element at the specified key @a key | ||
3734 | or a given default value if no element with key @a key exists. | ||
3735 | |||
3736 | The function is basically equivalent to executing | ||
3737 | @code {.cpp} | ||
3738 | try { | ||
3739 | return at(ptr); | ||
3740 | } catch(std::out_of_range) { | ||
3741 | return default_value; | ||
3742 | } | ||
3743 | @endcode | ||
3744 | |||
3745 | @note Unlike @ref at(const json_pointer&), this function does not throw | ||
3746 | if the given key @a key was not found. | ||
3747 | |||
3748 | @param[in] ptr a JSON pointer to the element to access | ||
3749 | @param[in] default_value the value to return if @a ptr found no value | ||
3750 | |||
3751 | @tparam ValueType type compatible to JSON values, for instance `int` for | ||
3752 | JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for | ||
3753 | JSON arrays. Note the type of the expected value at @a key and the default | ||
3754 | value @a default_value must be compatible. | ||
3755 | |||
3756 | @return copy of the element at key @a key or @a default_value if @a key | ||
3757 | is not found | ||
3758 | |||
3759 | @throw std::domain_error if JSON is not an object; example: `"cannot use | ||
3760 | value() with null"` | ||
3761 | |||
3762 | @complexity Logarithmic in the size of the container. | ||
3763 | |||
3764 | @liveexample{The example below shows how object elements can be queried | ||
3765 | with a default value.,basic_json__value_ptr} | ||
3766 | |||
3767 | @sa @ref operator[](const json_pointer&) for unchecked access by reference | ||
3768 | |||
3769 | @since version 2.0.2 | ||
3770 | */ | ||
3771 | template<class ValueType, typename std::enable_if< | ||
3772 | std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0> | ||
3773 | ValueType value(const json_pointer& ptr, ValueType default_value) const | ||
3774 | { | ||
3775 | // at only works for objects | ||
3776 | if (is_object()) | ||
3777 | { | ||
3778 | // if pointer resolves a value, return it or use default value | ||
3779 | try | ||
3780 | { | ||
3781 | return ptr.get_checked(this); | ||
3782 | } | ||
3783 | catch (std::out_of_range&) | ||
3784 | { | ||
3785 | return default_value; | ||
3786 | } | ||
3787 | } | ||
3788 | else | ||
3789 | { | ||
3790 | throw std::domain_error("cannot use value() with " + type_name()); | ||
3791 | } | ||
3792 | } | ||
3793 | |||
3794 | /*! | ||
3795 | @brief overload for a default value of type const char* | ||
3796 | @copydoc basic_json::value(const json_pointer&, ValueType) const | ||
3797 | */ | ||
3798 | string_t value(const json_pointer& ptr, const char* default_value) const | ||
3799 | { | ||
3800 | return value(ptr, string_t(default_value)); | ||
3801 | } | ||
3802 | |||
3803 | /*! | ||
3804 | @brief access the first element | ||
3805 | |||
3806 | Returns a reference to the first element in the container. For a JSON | ||
3807 | container `c`, the expression `c.front()` is equivalent to `*c.begin()`. | ||
3808 | |||
3809 | @return In case of a structured type (array or object), a reference to the | ||
3810 | first element is returned. In cast of number, string, or boolean values, a | ||
3811 | reference to the value is returned. | ||
3812 | |||
3813 | @complexity Constant. | ||
3814 | |||
3815 | @pre The JSON value must not be `null` (would throw `std::out_of_range`) | ||
3816 | or an empty array or object (undefined behavior, **guarded by | ||
3817 | assertions**). | ||
3818 | @post The JSON value remains unchanged. | ||
3819 | |||
3820 | @throw std::out_of_range when called on `null` value | ||
3821 | |||
3822 | @liveexample{The following code shows an example for `front()`.,front} | ||
3823 | |||
3824 | @sa @ref back() -- access the last element | ||
3825 | |||
3826 | @since version 1.0.0 | ||
3827 | */ | ||
3828 | reference front() | ||
3829 | { | ||
3830 | return *begin(); | ||
3831 | } | ||
3832 | |||
3833 | /*! | ||
3834 | @copydoc basic_json::front() | ||
3835 | */ | ||
3836 | const_reference front() const | ||
3837 | { | ||
3838 | return *cbegin(); | ||
3839 | } | ||
3840 | |||
3841 | /*! | ||
3842 | @brief access the last element | ||
3843 | |||
3844 | Returns a reference to the last element in the container. For a JSON | ||
3845 | container `c`, the expression `c.back()` is equivalent to | ||
3846 | @code {.cpp} | ||
3847 | auto tmp = c.end(); | ||
3848 | --tmp; | ||
3849 | return *tmp; | ||
3850 | @endcode | ||
3851 | |||
3852 | @return In case of a structured type (array or object), a reference to the | ||
3853 | last element is returned. In cast of number, string, or boolean values, a | ||
3854 | reference to the value is returned. | ||
3855 | |||
3856 | @complexity Constant. | ||
3857 | |||
3858 | @pre The JSON value must not be `null` (would throw `std::out_of_range`) | ||
3859 | or an empty array or object (undefined behavior, **guarded by | ||
3860 | assertions**). | ||
3861 | @post The JSON value remains unchanged. | ||
3862 | |||
3863 | @throw std::out_of_range when called on `null` value. | ||
3864 | |||
3865 | @liveexample{The following code shows an example for `back()`.,back} | ||
3866 | |||
3867 | @sa @ref front() -- access the first element | ||
3868 | |||
3869 | @since version 1.0.0 | ||
3870 | */ | ||
3871 | reference back() | ||
3872 | { | ||
3873 | auto tmp = end(); | ||
3874 | --tmp; | ||
3875 | return *tmp; | ||
3876 | } | ||
3877 | |||
3878 | /*! | ||
3879 | @copydoc basic_json::back() | ||
3880 | */ | ||
3881 | const_reference back() const | ||
3882 | { | ||
3883 | auto tmp = cend(); | ||
3884 | --tmp; | ||
3885 | return *tmp; | ||
3886 | } | ||
3887 | |||
3888 | /*! | ||
3889 | @brief remove element given an iterator | ||
3890 | |||
3891 | Removes the element specified by iterator @a pos. The iterator @a pos must | ||
3892 | be valid and dereferenceable. Thus the `end()` iterator (which is valid, | ||
3893 | but is not dereferenceable) cannot be used as a value for @a pos. | ||
3894 | |||
3895 | If called on a primitive type other than `null`, the resulting JSON value | ||
3896 | will be `null`. | ||
3897 | |||
3898 | @param[in] pos iterator to the element to remove | ||
3899 | @return Iterator following the last removed element. If the iterator @a | ||
3900 | pos refers to the last element, the `end()` iterator is returned. | ||
3901 | |||
3902 | @tparam IteratorType an @ref iterator or @ref const_iterator | ||
3903 | |||
3904 | @post Invalidates iterators and references at or after the point of the | ||
3905 | erase, including the `end()` iterator. | ||
3906 | |||
3907 | @throw std::domain_error if called on a `null` value; example: `"cannot | ||
3908 | use erase() with null"` | ||
3909 | @throw std::domain_error if called on an iterator which does not belong to | ||
3910 | the current JSON value; example: `"iterator does not fit current value"` | ||
3911 | @throw std::out_of_range if called on a primitive type with invalid | ||
3912 | iterator (i.e., any iterator which is not `begin()`); example: `"iterator | ||
3913 | out of range"` | ||
3914 | |||
3915 | @complexity The complexity depends on the type: | ||
3916 | - objects: amortized constant | ||
3917 | - arrays: linear in distance between pos and the end of the container | ||
3918 | - strings: linear in the length of the string | ||
3919 | - other types: constant | ||
3920 | |||
3921 | @liveexample{The example shows the result of `erase()` for different JSON | ||
3922 | types.,erase__IteratorType} | ||
3923 | |||
3924 | @sa @ref erase(IteratorType, IteratorType) -- removes the elements in | ||
3925 | the given range | ||
3926 | @sa @ref erase(const typename object_t::key_type&) -- removes the element | ||
3927 | from an object at the given key | ||
3928 | @sa @ref erase(const size_type) -- removes the element from an array at | ||
3929 | the given index | ||
3930 | |||
3931 | @since version 1.0.0 | ||
3932 | */ | ||
3933 | template<class IteratorType, typename std::enable_if< | ||
3934 | std::is_same<IteratorType, typename basic_json_t::iterator>::value or | ||
3935 | std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type | ||
3936 | = 0> | ||
3937 | IteratorType erase(IteratorType pos) | ||
3938 | { | ||
3939 | // make sure iterator fits the current value | ||
3940 | if (this != pos.m_object) | ||
3941 | { | ||
3942 | throw std::domain_error("iterator does not fit current value"); | ||
3943 | } | ||
3944 | |||
3945 | IteratorType result = end(); | ||
3946 | |||
3947 | switch (m_type) | ||
3948 | { | ||
3949 | case value_t::boolean: | ||
3950 | case value_t::number_float: | ||
3951 | case value_t::number_integer: | ||
3952 | case value_t::number_unsigned: | ||
3953 | case value_t::string: | ||
3954 | { | ||
3955 | if (not pos.m_it.primitive_iterator.is_begin()) | ||
3956 | { | ||
3957 | throw std::out_of_range("iterator out of range"); | ||
3958 | } | ||
3959 | |||
3960 | if (is_string()) | ||
3961 | { | ||
3962 | AllocatorType<string_t> alloc; | ||
3963 | alloc.destroy(m_value.string); | ||
3964 | alloc.deallocate(m_value.string, 1); | ||
3965 | m_value.string = nullptr; | ||
3966 | } | ||
3967 | |||
3968 | m_type = value_t::null; | ||
3969 | assert_invariant(); | ||
3970 | break; | ||
3971 | } | ||
3972 | |||
3973 | case value_t::object: | ||
3974 | { | ||
3975 | result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); | ||
3976 | break; | ||
3977 | } | ||
3978 | |||
3979 | case value_t::array: | ||
3980 | { | ||
3981 | result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); | ||
3982 | break; | ||
3983 | } | ||
3984 | |||
3985 | default: | ||
3986 | { | ||
3987 | throw std::domain_error("cannot use erase() with " + type_name()); | ||
3988 | } | ||
3989 | } | ||
3990 | |||
3991 | return result; | ||
3992 | } | ||
3993 | |||
3994 | /*! | ||
3995 | @brief remove elements given an iterator range | ||
3996 | |||
3997 | Removes the element specified by the range `[first; last)`. The iterator | ||
3998 | @a first does not need to be dereferenceable if `first == last`: erasing | ||
3999 | an empty range is a no-op. | ||
4000 | |||
4001 | If called on a primitive type other than `null`, the resulting JSON value | ||
4002 | will be `null`. | ||
4003 | |||
4004 | @param[in] first iterator to the beginning of the range to remove | ||
4005 | @param[in] last iterator past the end of the range to remove | ||
4006 | @return Iterator following the last removed element. If the iterator @a | ||
4007 | second refers to the last element, the `end()` iterator is returned. | ||
4008 | |||
4009 | @tparam IteratorType an @ref iterator or @ref const_iterator | ||
4010 | |||
4011 | @post Invalidates iterators and references at or after the point of the | ||
4012 | erase, including the `end()` iterator. | ||
4013 | |||
4014 | @throw std::domain_error if called on a `null` value; example: `"cannot | ||
4015 | use erase() with null"` | ||
4016 | @throw std::domain_error if called on iterators which does not belong to | ||
4017 | the current JSON value; example: `"iterators do not fit current value"` | ||
4018 | @throw std::out_of_range if called on a primitive type with invalid | ||
4019 | iterators (i.e., if `first != begin()` and `last != end()`); example: | ||
4020 | `"iterators out of range"` | ||
4021 | |||
4022 | @complexity The complexity depends on the type: | ||
4023 | - objects: `log(size()) + std::distance(first, last)` | ||
4024 | - arrays: linear in the distance between @a first and @a last, plus linear | ||
4025 | in the distance between @a last and end of the container | ||
4026 | - strings: linear in the length of the string | ||
4027 | - other types: constant | ||
4028 | |||
4029 | @liveexample{The example shows the result of `erase()` for different JSON | ||
4030 | types.,erase__IteratorType_IteratorType} | ||
4031 | |||
4032 | @sa @ref erase(IteratorType) -- removes the element at a given position | ||
4033 | @sa @ref erase(const typename object_t::key_type&) -- removes the element | ||
4034 | from an object at the given key | ||
4035 | @sa @ref erase(const size_type) -- removes the element from an array at | ||
4036 | the given index | ||
4037 | |||
4038 | @since version 1.0.0 | ||
4039 | */ | ||
4040 | template<class IteratorType, typename std::enable_if< | ||
4041 | std::is_same<IteratorType, typename basic_json_t::iterator>::value or | ||
4042 | std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type | ||
4043 | = 0> | ||
4044 | IteratorType erase(IteratorType first, IteratorType last) | ||
4045 | { | ||
4046 | // make sure iterator fits the current value | ||
4047 | if (this != first.m_object or this != last.m_object) | ||
4048 | { | ||
4049 | throw std::domain_error("iterators do not fit current value"); | ||
4050 | } | ||
4051 | |||
4052 | IteratorType result = end(); | ||
4053 | |||
4054 | switch (m_type) | ||
4055 | { | ||
4056 | case value_t::boolean: | ||
4057 | case value_t::number_float: | ||
4058 | case value_t::number_integer: | ||
4059 | case value_t::number_unsigned: | ||
4060 | case value_t::string: | ||
4061 | { | ||
4062 | if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) | ||
4063 | { | ||
4064 | throw std::out_of_range("iterators out of range"); | ||
4065 | } | ||
4066 | |||
4067 | if (is_string()) | ||
4068 | { | ||
4069 | AllocatorType<string_t> alloc; | ||
4070 | alloc.destroy(m_value.string); | ||
4071 | alloc.deallocate(m_value.string, 1); | ||
4072 | m_value.string = nullptr; | ||
4073 | } | ||
4074 | |||
4075 | m_type = value_t::null; | ||
4076 | assert_invariant(); | ||
4077 | break; | ||
4078 | } | ||
4079 | |||
4080 | case value_t::object: | ||
4081 | { | ||
4082 | result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, | ||
4083 | last.m_it.object_iterator); | ||
4084 | break; | ||
4085 | } | ||
4086 | |||
4087 | case value_t::array: | ||
4088 | { | ||
4089 | result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, | ||
4090 | last.m_it.array_iterator); | ||
4091 | break; | ||
4092 | } | ||
4093 | |||
4094 | default: | ||
4095 | { | ||
4096 | throw std::domain_error("cannot use erase() with " + type_name()); | ||
4097 | } | ||
4098 | } | ||
4099 | |||
4100 | return result; | ||
4101 | } | ||
4102 | |||
4103 | /*! | ||
4104 | @brief remove element from a JSON object given a key | ||
4105 | |||
4106 | Removes elements from a JSON object with the key value @a key. | ||
4107 | |||
4108 | @param[in] key value of the elements to remove | ||
4109 | |||
4110 | @return Number of elements removed. If @a ObjectType is the default | ||
4111 | `std::map` type, the return value will always be `0` (@a key was not | ||
4112 | found) or `1` (@a key was found). | ||
4113 | |||
4114 | @post References and iterators to the erased elements are invalidated. | ||
4115 | Other references and iterators are not affected. | ||
4116 | |||
4117 | @throw std::domain_error when called on a type other than JSON object; | ||
4118 | example: `"cannot use erase() with null"` | ||
4119 | |||
4120 | @complexity `log(size()) + count(key)` | ||
4121 | |||
4122 | @liveexample{The example shows the effect of `erase()`.,erase__key_type} | ||
4123 | |||
4124 | @sa @ref erase(IteratorType) -- removes the element at a given position | ||
4125 | @sa @ref erase(IteratorType, IteratorType) -- removes the elements in | ||
4126 | the given range | ||
4127 | @sa @ref erase(const size_type) -- removes the element from an array at | ||
4128 | the given index | ||
4129 | |||
4130 | @since version 1.0.0 | ||
4131 | */ | ||
4132 | size_type erase(const typename object_t::key_type& key) | ||
4133 | { | ||
4134 | // this erase only works for objects | ||
4135 | if (is_object()) | ||
4136 | { | ||
4137 | return m_value.object->erase(key); | ||
4138 | } | ||
4139 | else | ||
4140 | { | ||
4141 | throw std::domain_error("cannot use erase() with " + type_name()); | ||
4142 | } | ||
4143 | } | ||
4144 | |||
4145 | /*! | ||
4146 | @brief remove element from a JSON array given an index | ||
4147 | |||
4148 | Removes element from a JSON array at the index @a idx. | ||
4149 | |||
4150 | @param[in] idx index of the element to remove | ||
4151 | |||
4152 | @throw std::domain_error when called on a type other than JSON array; | ||
4153 | example: `"cannot use erase() with null"` | ||
4154 | @throw std::out_of_range when `idx >= size()`; example: `"array index 17 | ||
4155 | is out of range"` | ||
4156 | |||
4157 | @complexity Linear in distance between @a idx and the end of the container. | ||
4158 | |||
4159 | @liveexample{The example shows the effect of `erase()`.,erase__size_type} | ||
4160 | |||
4161 | @sa @ref erase(IteratorType) -- removes the element at a given position | ||
4162 | @sa @ref erase(IteratorType, IteratorType) -- removes the elements in | ||
4163 | the given range | ||
4164 | @sa @ref erase(const typename object_t::key_type&) -- removes the element | ||
4165 | from an object at the given key | ||
4166 | |||
4167 | @since version 1.0.0 | ||
4168 | */ | ||
4169 | void erase(const size_type idx) | ||
4170 | { | ||
4171 | // this erase only works for arrays | ||
4172 | if (is_array()) | ||
4173 | { | ||
4174 | if (idx >= size()) | ||
4175 | { | ||
4176 | throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); | ||
4177 | } | ||
4178 | |||
4179 | m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx)); | ||
4180 | } | ||
4181 | else | ||
4182 | { | ||
4183 | throw std::domain_error("cannot use erase() with " + type_name()); | ||
4184 | } | ||
4185 | } | ||
4186 | |||
4187 | /// @} | ||
4188 | |||
4189 | |||
4190 | //////////// | ||
4191 | // lookup // | ||
4192 | //////////// | ||
4193 | |||
4194 | /// @name lookup | ||
4195 | /// @{ | ||
4196 | |||
4197 | /*! | ||
4198 | @brief find an element in a JSON object | ||
4199 | |||
4200 | Finds an element in a JSON object with key equivalent to @a key. If the | ||
4201 | element is not found or the JSON value is not an object, end() is | ||
4202 | returned. | ||
4203 | |||
4204 | @param[in] key key value of the element to search for | ||
4205 | |||
4206 | @return Iterator to an element with key equivalent to @a key. If no such | ||
4207 | element is found, past-the-end (see end()) iterator is returned. | ||
4208 | |||
4209 | @complexity Logarithmic in the size of the JSON object. | ||
4210 | |||
4211 | @liveexample{The example shows how `find()` is used.,find__key_type} | ||
4212 | |||
4213 | @since version 1.0.0 | ||
4214 | */ | ||
4215 | iterator find(typename object_t::key_type key) | ||
4216 | { | ||
4217 | auto result = end(); | ||
4218 | |||
4219 | if (is_object()) | ||
4220 | { | ||
4221 | result.m_it.object_iterator = m_value.object->find(key); | ||
4222 | } | ||
4223 | |||
4224 | return result; | ||
4225 | } | ||
4226 | |||
4227 | /*! | ||
4228 | @brief find an element in a JSON object | ||
4229 | @copydoc find(typename object_t::key_type) | ||
4230 | */ | ||
4231 | const_iterator find(typename object_t::key_type key) const | ||
4232 | { | ||
4233 | auto result = cend(); | ||
4234 | |||
4235 | if (is_object()) | ||
4236 | { | ||
4237 | result.m_it.object_iterator = m_value.object->find(key); | ||
4238 | } | ||
4239 | |||
4240 | return result; | ||
4241 | } | ||
4242 | |||
4243 | /*! | ||
4244 | @brief returns the number of occurrences of a key in a JSON object | ||
4245 | |||
4246 | Returns the number of elements with key @a key. If ObjectType is the | ||
4247 | default `std::map` type, the return value will always be `0` (@a key was | ||
4248 | not found) or `1` (@a key was found). | ||
4249 | |||
4250 | @param[in] key key value of the element to count | ||
4251 | |||
4252 | @return Number of elements with key @a key. If the JSON value is not an | ||
4253 | object, the return value will be `0`. | ||
4254 | |||
4255 | @complexity Logarithmic in the size of the JSON object. | ||
4256 | |||
4257 | @liveexample{The example shows how `count()` is used.,count} | ||
4258 | |||
4259 | @since version 1.0.0 | ||
4260 | */ | ||
4261 | size_type count(typename object_t::key_type key) const | ||
4262 | { | ||
4263 | // return 0 for all nonobject types | ||
4264 | return is_object() ? m_value.object->count(key) : 0; | ||
4265 | } | ||
4266 | |||
4267 | /// @} | ||
4268 | |||
4269 | |||
4270 | /////////////// | ||
4271 | // iterators // | ||
4272 | /////////////// | ||
4273 | |||
4274 | /// @name iterators | ||
4275 | /// @{ | ||
4276 | |||
4277 | /*! | ||
4278 | @brief returns an iterator to the first element | ||
4279 | |||
4280 | Returns an iterator to the first element. | ||
4281 | |||
4282 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
4283 | |||
4284 | @return iterator to the first element | ||
4285 | |||
4286 | @complexity Constant. | ||
4287 | |||
4288 | @requirement This function helps `basic_json` satisfying the | ||
4289 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
4290 | requirements: | ||
4291 | - The complexity is constant. | ||
4292 | |||
4293 | @liveexample{The following code shows an example for `begin()`.,begin} | ||
4294 | |||
4295 | @sa @ref cbegin() -- returns a const iterator to the beginning | ||
4296 | @sa @ref end() -- returns an iterator to the end | ||
4297 | @sa @ref cend() -- returns a const iterator to the end | ||
4298 | |||
4299 | @since version 1.0.0 | ||
4300 | */ | ||
4301 | iterator begin() noexcept | ||
4302 | { | ||
4303 | iterator result(this); | ||
4304 | result.set_begin(); | ||
4305 | return result; | ||
4306 | } | ||
4307 | |||
4308 | /*! | ||
4309 | @copydoc basic_json::cbegin() | ||
4310 | */ | ||
4311 | const_iterator begin() const noexcept | ||
4312 | { | ||
4313 | return cbegin(); | ||
4314 | } | ||
4315 | |||
4316 | /*! | ||
4317 | @brief returns a const iterator to the first element | ||
4318 | |||
4319 | Returns a const iterator to the first element. | ||
4320 | |||
4321 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
4322 | |||
4323 | @return const iterator to the first element | ||
4324 | |||
4325 | @complexity Constant. | ||
4326 | |||
4327 | @requirement This function helps `basic_json` satisfying the | ||
4328 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
4329 | requirements: | ||
4330 | - The complexity is constant. | ||
4331 | - Has the semantics of `const_cast<const basic_json&>(*this).begin()`. | ||
4332 | |||
4333 | @liveexample{The following code shows an example for `cbegin()`.,cbegin} | ||
4334 | |||
4335 | @sa @ref begin() -- returns an iterator to the beginning | ||
4336 | @sa @ref end() -- returns an iterator to the end | ||
4337 | @sa @ref cend() -- returns a const iterator to the end | ||
4338 | |||
4339 | @since version 1.0.0 | ||
4340 | */ | ||
4341 | const_iterator cbegin() const noexcept | ||
4342 | { | ||
4343 | const_iterator result(this); | ||
4344 | result.set_begin(); | ||
4345 | return result; | ||
4346 | } | ||
4347 | |||
4348 | /*! | ||
4349 | @brief returns an iterator to one past the last element | ||
4350 | |||
4351 | Returns an iterator to one past the last element. | ||
4352 | |||
4353 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
4354 | |||
4355 | @return iterator one past the last element | ||
4356 | |||
4357 | @complexity Constant. | ||
4358 | |||
4359 | @requirement This function helps `basic_json` satisfying the | ||
4360 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
4361 | requirements: | ||
4362 | - The complexity is constant. | ||
4363 | |||
4364 | @liveexample{The following code shows an example for `end()`.,end} | ||
4365 | |||
4366 | @sa @ref cend() -- returns a const iterator to the end | ||
4367 | @sa @ref begin() -- returns an iterator to the beginning | ||
4368 | @sa @ref cbegin() -- returns a const iterator to the beginning | ||
4369 | |||
4370 | @since version 1.0.0 | ||
4371 | */ | ||
4372 | iterator end() noexcept | ||
4373 | { | ||
4374 | iterator result(this); | ||
4375 | result.set_end(); | ||
4376 | return result; | ||
4377 | } | ||
4378 | |||
4379 | /*! | ||
4380 | @copydoc basic_json::cend() | ||
4381 | */ | ||
4382 | const_iterator end() const noexcept | ||
4383 | { | ||
4384 | return cend(); | ||
4385 | } | ||
4386 | |||
4387 | /*! | ||
4388 | @brief returns a const iterator to one past the last element | ||
4389 | |||
4390 | Returns a const iterator to one past the last element. | ||
4391 | |||
4392 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
4393 | |||
4394 | @return const iterator one past the last element | ||
4395 | |||
4396 | @complexity Constant. | ||
4397 | |||
4398 | @requirement This function helps `basic_json` satisfying the | ||
4399 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
4400 | requirements: | ||
4401 | - The complexity is constant. | ||
4402 | - Has the semantics of `const_cast<const basic_json&>(*this).end()`. | ||
4403 | |||
4404 | @liveexample{The following code shows an example for `cend()`.,cend} | ||
4405 | |||
4406 | @sa @ref end() -- returns an iterator to the end | ||
4407 | @sa @ref begin() -- returns an iterator to the beginning | ||
4408 | @sa @ref cbegin() -- returns a const iterator to the beginning | ||
4409 | |||
4410 | @since version 1.0.0 | ||
4411 | */ | ||
4412 | const_iterator cend() const noexcept | ||
4413 | { | ||
4414 | const_iterator result(this); | ||
4415 | result.set_end(); | ||
4416 | return result; | ||
4417 | } | ||
4418 | |||
4419 | /*! | ||
4420 | @brief returns an iterator to the reverse-beginning | ||
4421 | |||
4422 | Returns an iterator to the reverse-beginning; that is, the last element. | ||
4423 | |||
4424 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
4425 | |||
4426 | @complexity Constant. | ||
4427 | |||
4428 | @requirement This function helps `basic_json` satisfying the | ||
4429 | [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) | ||
4430 | requirements: | ||
4431 | - The complexity is constant. | ||
4432 | - Has the semantics of `reverse_iterator(end())`. | ||
4433 | |||
4434 | @liveexample{The following code shows an example for `rbegin()`.,rbegin} | ||
4435 | |||
4436 | @sa @ref crbegin() -- returns a const reverse iterator to the beginning | ||
4437 | @sa @ref rend() -- returns a reverse iterator to the end | ||
4438 | @sa @ref crend() -- returns a const reverse iterator to the end | ||
4439 | |||
4440 | @since version 1.0.0 | ||
4441 | */ | ||
4442 | reverse_iterator rbegin() noexcept | ||
4443 | { | ||
4444 | return reverse_iterator(end()); | ||
4445 | } | ||
4446 | |||
4447 | /*! | ||
4448 | @copydoc basic_json::crbegin() | ||
4449 | */ | ||
4450 | const_reverse_iterator rbegin() const noexcept | ||
4451 | { | ||
4452 | return crbegin(); | ||
4453 | } | ||
4454 | |||
4455 | /*! | ||
4456 | @brief returns an iterator to the reverse-end | ||
4457 | |||
4458 | Returns an iterator to the reverse-end; that is, one before the first | ||
4459 | element. | ||
4460 | |||
4461 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
4462 | |||
4463 | @complexity Constant. | ||
4464 | |||
4465 | @requirement This function helps `basic_json` satisfying the | ||
4466 | [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) | ||
4467 | requirements: | ||
4468 | - The complexity is constant. | ||
4469 | - Has the semantics of `reverse_iterator(begin())`. | ||
4470 | |||
4471 | @liveexample{The following code shows an example for `rend()`.,rend} | ||
4472 | |||
4473 | @sa @ref crend() -- returns a const reverse iterator to the end | ||
4474 | @sa @ref rbegin() -- returns a reverse iterator to the beginning | ||
4475 | @sa @ref crbegin() -- returns a const reverse iterator to the beginning | ||
4476 | |||
4477 | @since version 1.0.0 | ||
4478 | */ | ||
4479 | reverse_iterator rend() noexcept | ||
4480 | { | ||
4481 | return reverse_iterator(begin()); | ||
4482 | } | ||
4483 | |||
4484 | /*! | ||
4485 | @copydoc basic_json::crend() | ||
4486 | */ | ||
4487 | const_reverse_iterator rend() const noexcept | ||
4488 | { | ||
4489 | return crend(); | ||
4490 | } | ||
4491 | |||
4492 | /*! | ||
4493 | @brief returns a const reverse iterator to the last element | ||
4494 | |||
4495 | Returns a const iterator to the reverse-beginning; that is, the last | ||
4496 | element. | ||
4497 | |||
4498 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
4499 | |||
4500 | @complexity Constant. | ||
4501 | |||
4502 | @requirement This function helps `basic_json` satisfying the | ||
4503 | [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) | ||
4504 | requirements: | ||
4505 | - The complexity is constant. | ||
4506 | - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`. | ||
4507 | |||
4508 | @liveexample{The following code shows an example for `crbegin()`.,crbegin} | ||
4509 | |||
4510 | @sa @ref rbegin() -- returns a reverse iterator to the beginning | ||
4511 | @sa @ref rend() -- returns a reverse iterator to the end | ||
4512 | @sa @ref crend() -- returns a const reverse iterator to the end | ||
4513 | |||
4514 | @since version 1.0.0 | ||
4515 | */ | ||
4516 | const_reverse_iterator crbegin() const noexcept | ||
4517 | { | ||
4518 | return const_reverse_iterator(cend()); | ||
4519 | } | ||
4520 | |||
4521 | /*! | ||
4522 | @brief returns a const reverse iterator to one before the first | ||
4523 | |||
4524 | Returns a const reverse iterator to the reverse-end; that is, one before | ||
4525 | the first element. | ||
4526 | |||
4527 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
4528 | |||
4529 | @complexity Constant. | ||
4530 | |||
4531 | @requirement This function helps `basic_json` satisfying the | ||
4532 | [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) | ||
4533 | requirements: | ||
4534 | - The complexity is constant. | ||
4535 | - Has the semantics of `const_cast<const basic_json&>(*this).rend()`. | ||
4536 | |||
4537 | @liveexample{The following code shows an example for `crend()`.,crend} | ||
4538 | |||
4539 | @sa @ref rend() -- returns a reverse iterator to the end | ||
4540 | @sa @ref rbegin() -- returns a reverse iterator to the beginning | ||
4541 | @sa @ref crbegin() -- returns a const reverse iterator to the beginning | ||
4542 | |||
4543 | @since version 1.0.0 | ||
4544 | */ | ||
4545 | const_reverse_iterator crend() const noexcept | ||
4546 | { | ||
4547 | return const_reverse_iterator(cbegin()); | ||
4548 | } | ||
4549 | |||
4550 | private: | ||
4551 | // forward declaration | ||
4552 | template<typename IteratorType> class iteration_proxy; | ||
4553 | |||
4554 | public: | ||
4555 | /*! | ||
4556 | @brief wrapper to access iterator member functions in range-based for | ||
4557 | |||
4558 | This function allows to access @ref iterator::key() and @ref | ||
4559 | iterator::value() during range-based for loops. In these loops, a | ||
4560 | reference to the JSON values is returned, so there is no access to the | ||
4561 | underlying iterator. | ||
4562 | |||
4563 | @note The name of this function is not yet final and may change in the | ||
4564 | future. | ||
4565 | */ | ||
4566 | static iteration_proxy<iterator> iterator_wrapper(reference cont) | ||
4567 | { | ||
4568 | return iteration_proxy<iterator>(cont); | ||
4569 | } | ||
4570 | |||
4571 | /*! | ||
4572 | @copydoc iterator_wrapper(reference) | ||
4573 | */ | ||
4574 | static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont) | ||
4575 | { | ||
4576 | return iteration_proxy<const_iterator>(cont); | ||
4577 | } | ||
4578 | |||
4579 | /// @} | ||
4580 | |||
4581 | |||
4582 | ////////////// | ||
4583 | // capacity // | ||
4584 | ////////////// | ||
4585 | |||
4586 | /// @name capacity | ||
4587 | /// @{ | ||
4588 | |||
4589 | /*! | ||
4590 | @brief checks whether the container is empty | ||
4591 | |||
4592 | Checks if a JSON value has no elements. | ||
4593 | |||
4594 | @return The return value depends on the different types and is | ||
4595 | defined as follows: | ||
4596 | Value type | return value | ||
4597 | ----------- | ------------- | ||
4598 | null | `true` | ||
4599 | boolean | `false` | ||
4600 | string | `false` | ||
4601 | number | `false` | ||
4602 | object | result of function `object_t::empty()` | ||
4603 | array | result of function `array_t::empty()` | ||
4604 | |||
4605 | @note This function does not return whether a string stored as JSON value | ||
4606 | is empty - it returns whether the JSON container itself is empty which is | ||
4607 | false in the case of a string. | ||
4608 | |||
4609 | @complexity Constant, as long as @ref array_t and @ref object_t satisfy | ||
4610 | the Container concept; that is, their `empty()` functions have constant | ||
4611 | complexity. | ||
4612 | |||
4613 | @requirement This function helps `basic_json` satisfying the | ||
4614 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
4615 | requirements: | ||
4616 | - The complexity is constant. | ||
4617 | - Has the semantics of `begin() == end()`. | ||
4618 | |||
4619 | @liveexample{The following code uses `empty()` to check if a JSON | ||
4620 | object contains any elements.,empty} | ||
4621 | |||
4622 | @sa @ref size() -- returns the number of elements | ||
4623 | |||
4624 | @since version 1.0.0 | ||
4625 | */ | ||
4626 | bool empty() const noexcept | ||
4627 | { | ||
4628 | switch (m_type) | ||
4629 | { | ||
4630 | case value_t::null: | ||
4631 | { | ||
4632 | // null values are empty | ||
4633 | return true; | ||
4634 | } | ||
4635 | |||
4636 | case value_t::array: | ||
4637 | { | ||
4638 | // delegate call to array_t::empty() | ||
4639 | return m_value.array->empty(); | ||
4640 | } | ||
4641 | |||
4642 | case value_t::object: | ||
4643 | { | ||
4644 | // delegate call to object_t::empty() | ||
4645 | return m_value.object->empty(); | ||
4646 | } | ||
4647 | |||
4648 | default: | ||
4649 | { | ||
4650 | // all other types are nonempty | ||
4651 | return false; | ||
4652 | } | ||
4653 | } | ||
4654 | } | ||
4655 | |||
4656 | /*! | ||
4657 | @brief returns the number of elements | ||
4658 | |||
4659 | Returns the number of elements in a JSON value. | ||
4660 | |||
4661 | @return The return value depends on the different types and is | ||
4662 | defined as follows: | ||
4663 | Value type | return value | ||
4664 | ----------- | ------------- | ||
4665 | null | `0` | ||
4666 | boolean | `1` | ||
4667 | string | `1` | ||
4668 | number | `1` | ||
4669 | object | result of function object_t::size() | ||
4670 | array | result of function array_t::size() | ||
4671 | |||
4672 | @note This function does not return the length of a string stored as JSON | ||
4673 | value - it returns the number of elements in the JSON value which is 1 in | ||
4674 | the case of a string. | ||
4675 | |||
4676 | @complexity Constant, as long as @ref array_t and @ref object_t satisfy | ||
4677 | the Container concept; that is, their size() functions have constant | ||
4678 | complexity. | ||
4679 | |||
4680 | @requirement This function helps `basic_json` satisfying the | ||
4681 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
4682 | requirements: | ||
4683 | - The complexity is constant. | ||
4684 | - Has the semantics of `std::distance(begin(), end())`. | ||
4685 | |||
4686 | @liveexample{The following code calls `size()` on the different value | ||
4687 | types.,size} | ||
4688 | |||
4689 | @sa @ref empty() -- checks whether the container is empty | ||
4690 | @sa @ref max_size() -- returns the maximal number of elements | ||
4691 | |||
4692 | @since version 1.0.0 | ||
4693 | */ | ||
4694 | size_type size() const noexcept | ||
4695 | { | ||
4696 | switch (m_type) | ||
4697 | { | ||
4698 | case value_t::null: | ||
4699 | { | ||
4700 | // null values are empty | ||
4701 | return 0; | ||
4702 | } | ||
4703 | |||
4704 | case value_t::array: | ||
4705 | { | ||
4706 | // delegate call to array_t::size() | ||
4707 | return m_value.array->size(); | ||
4708 | } | ||
4709 | |||
4710 | case value_t::object: | ||
4711 | { | ||
4712 | // delegate call to object_t::size() | ||
4713 | return m_value.object->size(); | ||
4714 | } | ||
4715 | |||
4716 | default: | ||
4717 | { | ||
4718 | // all other types have size 1 | ||
4719 | return 1; | ||
4720 | } | ||
4721 | } | ||
4722 | } | ||
4723 | |||
4724 | /*! | ||
4725 | @brief returns the maximum possible number of elements | ||
4726 | |||
4727 | Returns the maximum number of elements a JSON value is able to hold due to | ||
4728 | system or library implementation limitations, i.e. `std::distance(begin(), | ||
4729 | end())` for the JSON value. | ||
4730 | |||
4731 | @return The return value depends on the different types and is | ||
4732 | defined as follows: | ||
4733 | Value type | return value | ||
4734 | ----------- | ------------- | ||
4735 | null | `0` (same as `size()`) | ||
4736 | boolean | `1` (same as `size()`) | ||
4737 | string | `1` (same as `size()`) | ||
4738 | number | `1` (same as `size()`) | ||
4739 | object | result of function `object_t::max_size()` | ||
4740 | array | result of function `array_t::max_size()` | ||
4741 | |||
4742 | @complexity Constant, as long as @ref array_t and @ref object_t satisfy | ||
4743 | the Container concept; that is, their `max_size()` functions have constant | ||
4744 | complexity. | ||
4745 | |||
4746 | @requirement This function helps `basic_json` satisfying the | ||
4747 | [Container](http://en.cppreference.com/w/cpp/concept/Container) | ||
4748 | requirements: | ||
4749 | - The complexity is constant. | ||
4750 | - Has the semantics of returning `b.size()` where `b` is the largest | ||
4751 | possible JSON value. | ||
4752 | |||
4753 | @liveexample{The following code calls `max_size()` on the different value | ||
4754 | types. Note the output is implementation specific.,max_size} | ||
4755 | |||
4756 | @sa @ref size() -- returns the number of elements | ||
4757 | |||
4758 | @since version 1.0.0 | ||
4759 | */ | ||
4760 | size_type max_size() const noexcept | ||
4761 | { | ||
4762 | switch (m_type) | ||
4763 | { | ||
4764 | case value_t::array: | ||
4765 | { | ||
4766 | // delegate call to array_t::max_size() | ||
4767 | return m_value.array->max_size(); | ||
4768 | } | ||
4769 | |||
4770 | case value_t::object: | ||
4771 | { | ||
4772 | // delegate call to object_t::max_size() | ||
4773 | return m_value.object->max_size(); | ||
4774 | } | ||
4775 | |||
4776 | default: | ||
4777 | { | ||
4778 | // all other types have max_size() == size() | ||
4779 | return size(); | ||
4780 | } | ||
4781 | } | ||
4782 | } | ||
4783 | |||
4784 | /// @} | ||
4785 | |||
4786 | |||
4787 | /////////////// | ||
4788 | // modifiers // | ||
4789 | /////////////// | ||
4790 | |||
4791 | /// @name modifiers | ||
4792 | /// @{ | ||
4793 | |||
4794 | /*! | ||
4795 | @brief clears the contents | ||
4796 | |||
4797 | Clears the content of a JSON value and resets it to the default value as | ||
4798 | if @ref basic_json(value_t) would have been called: | ||
4799 | |||
4800 | Value type | initial value | ||
4801 | ----------- | ------------- | ||
4802 | null | `null` | ||
4803 | boolean | `false` | ||
4804 | string | `""` | ||
4805 | number | `0` | ||
4806 | object | `{}` | ||
4807 | array | `[]` | ||
4808 | |||
4809 | @note Floating-point numbers are set to `0.0` which will be serialized to | ||
4810 | `0`. The vale type remains @ref number_float_t. | ||
4811 | |||
4812 | @complexity Linear in the size of the JSON value. | ||
4813 | |||
4814 | @liveexample{The example below shows the effect of `clear()` to different | ||
4815 | JSON types.,clear} | ||
4816 | |||
4817 | @since version 1.0.0 | ||
4818 | */ | ||
4819 | void clear() noexcept | ||
4820 | { | ||
4821 | switch (m_type) | ||
4822 | { | ||
4823 | case value_t::number_integer: | ||
4824 | { | ||
4825 | m_value.number_integer = 0; | ||
4826 | break; | ||
4827 | } | ||
4828 | |||
4829 | case value_t::number_unsigned: | ||
4830 | { | ||
4831 | m_value.number_unsigned = 0; | ||
4832 | break; | ||
4833 | } | ||
4834 | |||
4835 | case value_t::number_float: | ||
4836 | { | ||
4837 | m_value.number_float = 0.0; | ||
4838 | break; | ||
4839 | } | ||
4840 | |||
4841 | case value_t::boolean: | ||
4842 | { | ||
4843 | m_value.boolean = false; | ||
4844 | break; | ||
4845 | } | ||
4846 | |||
4847 | case value_t::string: | ||
4848 | { | ||
4849 | m_value.string->clear(); | ||
4850 | break; | ||
4851 | } | ||
4852 | |||
4853 | case value_t::array: | ||
4854 | { | ||
4855 | m_value.array->clear(); | ||
4856 | break; | ||
4857 | } | ||
4858 | |||
4859 | case value_t::object: | ||
4860 | { | ||
4861 | m_value.object->clear(); | ||
4862 | break; | ||
4863 | } | ||
4864 | |||
4865 | default: | ||
4866 | { | ||
4867 | break; | ||
4868 | } | ||
4869 | } | ||
4870 | } | ||
4871 | |||
4872 | /*! | ||
4873 | @brief add an object to an array | ||
4874 | |||
4875 | Appends the given element @a val to the end of the JSON value. If the | ||
4876 | function is called on a JSON null value, an empty array is created before | ||
4877 | appending @a val. | ||
4878 | |||
4879 | @param[in] val the value to add to the JSON array | ||
4880 | |||
4881 | @throw std::domain_error when called on a type other than JSON array or | ||
4882 | null; example: `"cannot use push_back() with number"` | ||
4883 | |||
4884 | @complexity Amortized constant. | ||
4885 | |||
4886 | @liveexample{The example shows how `push_back()` and `+=` can be used to | ||
4887 | add elements to a JSON array. Note how the `null` value was silently | ||
4888 | converted to a JSON array.,push_back} | ||
4889 | |||
4890 | @since version 1.0.0 | ||
4891 | */ | ||
4892 | void push_back(basic_json&& val) | ||
4893 | { | ||
4894 | // push_back only works for null objects or arrays | ||
4895 | if (not(is_null() or is_array())) | ||
4896 | { | ||
4897 | throw std::domain_error("cannot use push_back() with " + type_name()); | ||
4898 | } | ||
4899 | |||
4900 | // transform null object into an array | ||
4901 | if (is_null()) | ||
4902 | { | ||
4903 | m_type = value_t::array; | ||
4904 | m_value = value_t::array; | ||
4905 | assert_invariant(); | ||
4906 | } | ||
4907 | |||
4908 | // add element to array (move semantics) | ||
4909 | m_value.array->push_back(std::move(val)); | ||
4910 | // invalidate object | ||
4911 | val.m_type = value_t::null; | ||
4912 | } | ||
4913 | |||
4914 | /*! | ||
4915 | @brief add an object to an array | ||
4916 | @copydoc push_back(basic_json&&) | ||
4917 | */ | ||
4918 | reference operator+=(basic_json&& val) | ||
4919 | { | ||
4920 | push_back(std::move(val)); | ||
4921 | return *this; | ||
4922 | } | ||
4923 | |||
4924 | /*! | ||
4925 | @brief add an object to an array | ||
4926 | @copydoc push_back(basic_json&&) | ||
4927 | */ | ||
4928 | void push_back(const basic_json& val) | ||
4929 | { | ||
4930 | // push_back only works for null objects or arrays | ||
4931 | if (not(is_null() or is_array())) | ||
4932 | { | ||
4933 | throw std::domain_error("cannot use push_back() with " + type_name()); | ||
4934 | } | ||
4935 | |||
4936 | // transform null object into an array | ||
4937 | if (is_null()) | ||
4938 | { | ||
4939 | m_type = value_t::array; | ||
4940 | m_value = value_t::array; | ||
4941 | assert_invariant(); | ||
4942 | } | ||
4943 | |||
4944 | // add element to array | ||
4945 | m_value.array->push_back(val); | ||
4946 | } | ||
4947 | |||
4948 | /*! | ||
4949 | @brief add an object to an array | ||
4950 | @copydoc push_back(basic_json&&) | ||
4951 | */ | ||
4952 | reference operator+=(const basic_json& val) | ||
4953 | { | ||
4954 | push_back(val); | ||
4955 | return *this; | ||
4956 | } | ||
4957 | |||
4958 | /*! | ||
4959 | @brief add an object to an object | ||
4960 | |||
4961 | Inserts the given element @a val to the JSON object. If the function is | ||
4962 | called on a JSON null value, an empty object is created before inserting | ||
4963 | @a val. | ||
4964 | |||
4965 | @param[in] val the value to add to the JSON object | ||
4966 | |||
4967 | @throw std::domain_error when called on a type other than JSON object or | ||
4968 | null; example: `"cannot use push_back() with number"` | ||
4969 | |||
4970 | @complexity Logarithmic in the size of the container, O(log(`size()`)). | ||
4971 | |||
4972 | @liveexample{The example shows how `push_back()` and `+=` can be used to | ||
4973 | add elements to a JSON object. Note how the `null` value was silently | ||
4974 | converted to a JSON object.,push_back__object_t__value} | ||
4975 | |||
4976 | @since version 1.0.0 | ||
4977 | */ | ||
4978 | void push_back(const typename object_t::value_type& val) | ||
4979 | { | ||
4980 | // push_back only works for null objects or objects | ||
4981 | if (not(is_null() or is_object())) | ||
4982 | { | ||
4983 | throw std::domain_error("cannot use push_back() with " + type_name()); | ||
4984 | } | ||
4985 | |||
4986 | // transform null object into an object | ||
4987 | if (is_null()) | ||
4988 | { | ||
4989 | m_type = value_t::object; | ||
4990 | m_value = value_t::object; | ||
4991 | assert_invariant(); | ||
4992 | } | ||
4993 | |||
4994 | // add element to array | ||
4995 | m_value.object->insert(val); | ||
4996 | } | ||
4997 | |||
4998 | /*! | ||
4999 | @brief add an object to an object | ||
5000 | @copydoc push_back(const typename object_t::value_type&) | ||
5001 | */ | ||
5002 | reference operator+=(const typename object_t::value_type& val) | ||
5003 | { | ||
5004 | push_back(val); | ||
5005 | return *this; | ||
5006 | } | ||
5007 | |||
5008 | /*! | ||
5009 | @brief add an object to an object | ||
5010 | |||
5011 | This function allows to use `push_back` with an initializer list. In case | ||
5012 | |||
5013 | 1. the current value is an object, | ||
5014 | 2. the initializer list @a init contains only two elements, and | ||
5015 | 3. the first element of @a init is a string, | ||
5016 | |||
5017 | @a init is converted into an object element and added using | ||
5018 | @ref push_back(const typename object_t::value_type&). Otherwise, @a init | ||
5019 | is converted to a JSON value and added using @ref push_back(basic_json&&). | ||
5020 | |||
5021 | @param init an initializer list | ||
5022 | |||
5023 | @complexity Linear in the size of the initializer list @a init. | ||
5024 | |||
5025 | @note This function is required to resolve an ambiguous overload error, | ||
5026 | because pairs like `{"key", "value"}` can be both interpreted as | ||
5027 | `object_t::value_type` or `std::initializer_list<basic_json>`, see | ||
5028 | https://github.com/nlohmann/json/issues/235 for more information. | ||
5029 | |||
5030 | @liveexample{The example shows how initializer lists are treated as | ||
5031 | objects when possible.,push_back__initializer_list} | ||
5032 | */ | ||
5033 | void push_back(std::initializer_list<basic_json> init) | ||
5034 | { | ||
5035 | if (is_object() and init.size() == 2 and init.begin()->is_string()) | ||
5036 | { | ||
5037 | const string_t key = *init.begin(); | ||
5038 | push_back(typename object_t::value_type(key, *(init.begin() + 1))); | ||
5039 | } | ||
5040 | else | ||
5041 | { | ||
5042 | push_back(basic_json(init)); | ||
5043 | } | ||
5044 | } | ||
5045 | |||
5046 | /*! | ||
5047 | @brief add an object to an object | ||
5048 | @copydoc push_back(std::initializer_list<basic_json>) | ||
5049 | */ | ||
5050 | reference operator+=(std::initializer_list<basic_json> init) | ||
5051 | { | ||
5052 | push_back(init); | ||
5053 | return *this; | ||
5054 | } | ||
5055 | |||
5056 | /*! | ||
5057 | @brief inserts element | ||
5058 | |||
5059 | Inserts element @a val before iterator @a pos. | ||
5060 | |||
5061 | @param[in] pos iterator before which the content will be inserted; may be | ||
5062 | the end() iterator | ||
5063 | @param[in] val element to insert | ||
5064 | @return iterator pointing to the inserted @a val. | ||
5065 | |||
5066 | @throw std::domain_error if called on JSON values other than arrays; | ||
5067 | example: `"cannot use insert() with string"` | ||
5068 | @throw std::domain_error if @a pos is not an iterator of *this; example: | ||
5069 | `"iterator does not fit current value"` | ||
5070 | |||
5071 | @complexity Constant plus linear in the distance between pos and end of the | ||
5072 | container. | ||
5073 | |||
5074 | @liveexample{The example shows how `insert()` is used.,insert} | ||
5075 | |||
5076 | @since version 1.0.0 | ||
5077 | */ | ||
5078 | iterator insert(const_iterator pos, const basic_json& val) | ||
5079 | { | ||
5080 | // insert only works for arrays | ||
5081 | if (is_array()) | ||
5082 | { | ||
5083 | // check if iterator pos fits to this JSON value | ||
5084 | if (pos.m_object != this) | ||
5085 | { | ||
5086 | throw std::domain_error("iterator does not fit current value"); | ||
5087 | } | ||
5088 | |||
5089 | // insert to array and return iterator | ||
5090 | iterator result(this); | ||
5091 | result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); | ||
5092 | return result; | ||
5093 | } | ||
5094 | else | ||
5095 | { | ||
5096 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
5097 | } | ||
5098 | } | ||
5099 | |||
5100 | /*! | ||
5101 | @brief inserts element | ||
5102 | @copydoc insert(const_iterator, const basic_json&) | ||
5103 | */ | ||
5104 | iterator insert(const_iterator pos, basic_json&& val) | ||
5105 | { | ||
5106 | return insert(pos, val); | ||
5107 | } | ||
5108 | |||
5109 | /*! | ||
5110 | @brief inserts elements | ||
5111 | |||
5112 | Inserts @a cnt copies of @a val before iterator @a pos. | ||
5113 | |||
5114 | @param[in] pos iterator before which the content will be inserted; may be | ||
5115 | the end() iterator | ||
5116 | @param[in] cnt number of copies of @a val to insert | ||
5117 | @param[in] val element to insert | ||
5118 | @return iterator pointing to the first element inserted, or @a pos if | ||
5119 | `cnt==0` | ||
5120 | |||
5121 | @throw std::domain_error if called on JSON values other than arrays; | ||
5122 | example: `"cannot use insert() with string"` | ||
5123 | @throw std::domain_error if @a pos is not an iterator of *this; example: | ||
5124 | `"iterator does not fit current value"` | ||
5125 | |||
5126 | @complexity Linear in @a cnt plus linear in the distance between @a pos | ||
5127 | and end of the container. | ||
5128 | |||
5129 | @liveexample{The example shows how `insert()` is used.,insert__count} | ||
5130 | |||
5131 | @since version 1.0.0 | ||
5132 | */ | ||
5133 | iterator insert(const_iterator pos, size_type cnt, const basic_json& val) | ||
5134 | { | ||
5135 | // insert only works for arrays | ||
5136 | if (is_array()) | ||
5137 | { | ||
5138 | // check if iterator pos fits to this JSON value | ||
5139 | if (pos.m_object != this) | ||
5140 | { | ||
5141 | throw std::domain_error("iterator does not fit current value"); | ||
5142 | } | ||
5143 | |||
5144 | // insert to array and return iterator | ||
5145 | iterator result(this); | ||
5146 | result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); | ||
5147 | return result; | ||
5148 | } | ||
5149 | else | ||
5150 | { | ||
5151 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
5152 | } | ||
5153 | } | ||
5154 | |||
5155 | /*! | ||
5156 | @brief inserts elements | ||
5157 | |||
5158 | Inserts elements from range `[first, last)` before iterator @a pos. | ||
5159 | |||
5160 | @param[in] pos iterator before which the content will be inserted; may be | ||
5161 | the end() iterator | ||
5162 | @param[in] first begin of the range of elements to insert | ||
5163 | @param[in] last end of the range of elements to insert | ||
5164 | |||
5165 | @throw std::domain_error if called on JSON values other than arrays; | ||
5166 | example: `"cannot use insert() with string"` | ||
5167 | @throw std::domain_error if @a pos is not an iterator of *this; example: | ||
5168 | `"iterator does not fit current value"` | ||
5169 | @throw std::domain_error if @a first and @a last do not belong to the same | ||
5170 | JSON value; example: `"iterators do not fit"` | ||
5171 | @throw std::domain_error if @a first or @a last are iterators into | ||
5172 | container for which insert is called; example: `"passed iterators may not | ||
5173 | belong to container"` | ||
5174 | |||
5175 | @return iterator pointing to the first element inserted, or @a pos if | ||
5176 | `first==last` | ||
5177 | |||
5178 | @complexity Linear in `std::distance(first, last)` plus linear in the | ||
5179 | distance between @a pos and end of the container. | ||
5180 | |||
5181 | @liveexample{The example shows how `insert()` is used.,insert__range} | ||
5182 | |||
5183 | @since version 1.0.0 | ||
5184 | */ | ||
5185 | iterator insert(const_iterator pos, const_iterator first, const_iterator last) | ||
5186 | { | ||
5187 | // insert only works for arrays | ||
5188 | if (not is_array()) | ||
5189 | { | ||
5190 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
5191 | } | ||
5192 | |||
5193 | // check if iterator pos fits to this JSON value | ||
5194 | if (pos.m_object != this) | ||
5195 | { | ||
5196 | throw std::domain_error("iterator does not fit current value"); | ||
5197 | } | ||
5198 | |||
5199 | // check if range iterators belong to the same JSON object | ||
5200 | if (first.m_object != last.m_object) | ||
5201 | { | ||
5202 | throw std::domain_error("iterators do not fit"); | ||
5203 | } | ||
5204 | |||
5205 | if (first.m_object == this or last.m_object == this) | ||
5206 | { | ||
5207 | throw std::domain_error("passed iterators may not belong to container"); | ||
5208 | } | ||
5209 | |||
5210 | // insert to array and return iterator | ||
5211 | iterator result(this); | ||
5212 | result.m_it.array_iterator = m_value.array->insert( | ||
5213 | pos.m_it.array_iterator, | ||
5214 | first.m_it.array_iterator, | ||
5215 | last.m_it.array_iterator); | ||
5216 | return result; | ||
5217 | } | ||
5218 | |||
5219 | /*! | ||
5220 | @brief inserts elements | ||
5221 | |||
5222 | Inserts elements from initializer list @a ilist before iterator @a pos. | ||
5223 | |||
5224 | @param[in] pos iterator before which the content will be inserted; may be | ||
5225 | the end() iterator | ||
5226 | @param[in] ilist initializer list to insert the values from | ||
5227 | |||
5228 | @throw std::domain_error if called on JSON values other than arrays; | ||
5229 | example: `"cannot use insert() with string"` | ||
5230 | @throw std::domain_error if @a pos is not an iterator of *this; example: | ||
5231 | `"iterator does not fit current value"` | ||
5232 | |||
5233 | @return iterator pointing to the first element inserted, or @a pos if | ||
5234 | `ilist` is empty | ||
5235 | |||
5236 | @complexity Linear in `ilist.size()` plus linear in the distance between | ||
5237 | @a pos and end of the container. | ||
5238 | |||
5239 | @liveexample{The example shows how `insert()` is used.,insert__ilist} | ||
5240 | |||
5241 | @since version 1.0.0 | ||
5242 | */ | ||
5243 | iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist) | ||
5244 | { | ||
5245 | // insert only works for arrays | ||
5246 | if (not is_array()) | ||
5247 | { | ||
5248 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
5249 | } | ||
5250 | |||
5251 | // check if iterator pos fits to this JSON value | ||
5252 | if (pos.m_object != this) | ||
5253 | { | ||
5254 | throw std::domain_error("iterator does not fit current value"); | ||
5255 | } | ||
5256 | |||
5257 | // insert to array and return iterator | ||
5258 | iterator result(this); | ||
5259 | result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); | ||
5260 | return result; | ||
5261 | } | ||
5262 | |||
5263 | /*! | ||
5264 | @brief exchanges the values | ||
5265 | |||
5266 | Exchanges the contents of the JSON value with those of @a other. Does not | ||
5267 | invoke any move, copy, or swap operations on individual elements. All | ||
5268 | iterators and references remain valid. The past-the-end iterator is | ||
5269 | invalidated. | ||
5270 | |||
5271 | @param[in,out] other JSON value to exchange the contents with | ||
5272 | |||
5273 | @complexity Constant. | ||
5274 | |||
5275 | @liveexample{The example below shows how JSON values can be swapped with | ||
5276 | `swap()`.,swap__reference} | ||
5277 | |||
5278 | @since version 1.0.0 | ||
5279 | */ | ||
5280 | void swap(reference other) noexcept ( | ||
5281 | std::is_nothrow_move_constructible<value_t>::value and | ||
5282 | std::is_nothrow_move_assignable<value_t>::value and | ||
5283 | std::is_nothrow_move_constructible<json_value>::value and | ||
5284 | std::is_nothrow_move_assignable<json_value>::value | ||
5285 | ) | ||
5286 | { | ||
5287 | std::swap(m_type, other.m_type); | ||
5288 | std::swap(m_value, other.m_value); | ||
5289 | assert_invariant(); | ||
5290 | } | ||
5291 | |||
5292 | /*! | ||
5293 | @brief exchanges the values | ||
5294 | |||
5295 | Exchanges the contents of a JSON array with those of @a other. Does not | ||
5296 | invoke any move, copy, or swap operations on individual elements. All | ||
5297 | iterators and references remain valid. The past-the-end iterator is | ||
5298 | invalidated. | ||
5299 | |||
5300 | @param[in,out] other array to exchange the contents with | ||
5301 | |||
5302 | @throw std::domain_error when JSON value is not an array; example: `"cannot | ||
5303 | use swap() with string"` | ||
5304 | |||
5305 | @complexity Constant. | ||
5306 | |||
5307 | @liveexample{The example below shows how arrays can be swapped with | ||
5308 | `swap()`.,swap__array_t} | ||
5309 | |||
5310 | @since version 1.0.0 | ||
5311 | */ | ||
5312 | void swap(array_t& other) | ||
5313 | { | ||
5314 | // swap only works for arrays | ||
5315 | if (is_array()) | ||
5316 | { | ||
5317 | std::swap(*(m_value.array), other); | ||
5318 | } | ||
5319 | else | ||
5320 | { | ||
5321 | throw std::domain_error("cannot use swap() with " + type_name()); | ||
5322 | } | ||
5323 | } | ||
5324 | |||
5325 | /*! | ||
5326 | @brief exchanges the values | ||
5327 | |||
5328 | Exchanges the contents of a JSON object with those of @a other. Does not | ||
5329 | invoke any move, copy, or swap operations on individual elements. All | ||
5330 | iterators and references remain valid. The past-the-end iterator is | ||
5331 | invalidated. | ||
5332 | |||
5333 | @param[in,out] other object to exchange the contents with | ||
5334 | |||
5335 | @throw std::domain_error when JSON value is not an object; example: | ||
5336 | `"cannot use swap() with string"` | ||
5337 | |||
5338 | @complexity Constant. | ||
5339 | |||
5340 | @liveexample{The example below shows how objects can be swapped with | ||
5341 | `swap()`.,swap__object_t} | ||
5342 | |||
5343 | @since version 1.0.0 | ||
5344 | */ | ||
5345 | void swap(object_t& other) | ||
5346 | { | ||
5347 | // swap only works for objects | ||
5348 | if (is_object()) | ||
5349 | { | ||
5350 | std::swap(*(m_value.object), other); | ||
5351 | } | ||
5352 | else | ||
5353 | { | ||
5354 | throw std::domain_error("cannot use swap() with " + type_name()); | ||
5355 | } | ||
5356 | } | ||
5357 | |||
5358 | /*! | ||
5359 | @brief exchanges the values | ||
5360 | |||
5361 | Exchanges the contents of a JSON string with those of @a other. Does not | ||
5362 | invoke any move, copy, or swap operations on individual elements. All | ||
5363 | iterators and references remain valid. The past-the-end iterator is | ||
5364 | invalidated. | ||
5365 | |||
5366 | @param[in,out] other string to exchange the contents with | ||
5367 | |||
5368 | @throw std::domain_error when JSON value is not a string; example: `"cannot | ||
5369 | use swap() with boolean"` | ||
5370 | |||
5371 | @complexity Constant. | ||
5372 | |||
5373 | @liveexample{The example below shows how strings can be swapped with | ||
5374 | `swap()`.,swap__string_t} | ||
5375 | |||
5376 | @since version 1.0.0 | ||
5377 | */ | ||
5378 | void swap(string_t& other) | ||
5379 | { | ||
5380 | // swap only works for strings | ||
5381 | if (is_string()) | ||
5382 | { | ||
5383 | std::swap(*(m_value.string), other); | ||
5384 | } | ||
5385 | else | ||
5386 | { | ||
5387 | throw std::domain_error("cannot use swap() with " + type_name()); | ||
5388 | } | ||
5389 | } | ||
5390 | |||
5391 | /// @} | ||
5392 | |||
5393 | |||
5394 | ////////////////////////////////////////// | ||
5395 | // lexicographical comparison operators // | ||
5396 | ////////////////////////////////////////// | ||
5397 | |||
5398 | /// @name lexicographical comparison operators | ||
5399 | /// @{ | ||
5400 | |||
5401 | private: | ||
5402 | /*! | ||
5403 | @brief comparison operator for JSON types | ||
5404 | |||
5405 | Returns an ordering that is similar to Python: | ||
5406 | - order: null < boolean < number < object < array < string | ||
5407 | - furthermore, each type is not smaller than itself | ||
5408 | |||
5409 | @since version 1.0.0 | ||
5410 | */ | ||
5411 | friend bool operator<(const value_t lhs, const value_t rhs) noexcept | ||
5412 | { | ||
5413 | static constexpr std::array<uint8_t, 8> order = {{ | ||
5414 | 0, // null | ||
5415 | 3, // object | ||
5416 | 4, // array | ||
5417 | 5, // string | ||
5418 | 1, // boolean | ||
5419 | 2, // integer | ||
5420 | 2, // unsigned | ||
5421 | 2, // float | ||
5422 | } | ||
5423 | }; | ||
5424 | |||
5425 | // discarded values are not comparable | ||
5426 | if (lhs == value_t::discarded or rhs == value_t::discarded) | ||
5427 | { | ||
5428 | return false; | ||
5429 | } | ||
5430 | |||
5431 | return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)]; | ||
5432 | } | ||
5433 | |||
5434 | public: | ||
5435 | /*! | ||
5436 | @brief comparison: equal | ||
5437 | |||
5438 | Compares two JSON values for equality according to the following rules: | ||
5439 | - Two JSON values are equal if (1) they are from the same type and (2) | ||
5440 | their stored values are the same. | ||
5441 | - Integer and floating-point numbers are automatically converted before | ||
5442 | comparison. Floating-point numbers are compared indirectly: two | ||
5443 | floating-point numbers `f1` and `f2` are considered equal if neither | ||
5444 | `f1 > f2` nor `f2 > f1` holds. | ||
5445 | - Two JSON null values are equal. | ||
5446 | |||
5447 | @param[in] lhs first JSON value to consider | ||
5448 | @param[in] rhs second JSON value to consider | ||
5449 | @return whether the values @a lhs and @a rhs are equal | ||
5450 | |||
5451 | @complexity Linear. | ||
5452 | |||
5453 | @liveexample{The example demonstrates comparing several JSON | ||
5454 | types.,operator__equal} | ||
5455 | |||
5456 | @since version 1.0.0 | ||
5457 | */ | ||
5458 | friend bool operator==(const_reference lhs, const_reference rhs) noexcept | ||
5459 | { | ||
5460 | const auto lhs_type = lhs.type(); | ||
5461 | const auto rhs_type = rhs.type(); | ||
5462 | |||
5463 | if (lhs_type == rhs_type) | ||
5464 | { | ||
5465 | switch (lhs_type) | ||
5466 | { | ||
5467 | case value_t::array: | ||
5468 | { | ||
5469 | return *lhs.m_value.array == *rhs.m_value.array; | ||
5470 | } | ||
5471 | case value_t::object: | ||
5472 | { | ||
5473 | return *lhs.m_value.object == *rhs.m_value.object; | ||
5474 | } | ||
5475 | case value_t::null: | ||
5476 | { | ||
5477 | return true; | ||
5478 | } | ||
5479 | case value_t::string: | ||
5480 | { | ||
5481 | return *lhs.m_value.string == *rhs.m_value.string; | ||
5482 | } | ||
5483 | case value_t::boolean: | ||
5484 | { | ||
5485 | return lhs.m_value.boolean == rhs.m_value.boolean; | ||
5486 | } | ||
5487 | case value_t::number_integer: | ||
5488 | { | ||
5489 | return lhs.m_value.number_integer == rhs.m_value.number_integer; | ||
5490 | } | ||
5491 | case value_t::number_unsigned: | ||
5492 | { | ||
5493 | return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; | ||
5494 | } | ||
5495 | case value_t::number_float: | ||
5496 | { | ||
5497 | return lhs.m_value.number_float == rhs.m_value.number_float; | ||
5498 | } | ||
5499 | default: | ||
5500 | { | ||
5501 | return false; | ||
5502 | } | ||
5503 | } | ||
5504 | } | ||
5505 | else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) | ||
5506 | { | ||
5507 | return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float; | ||
5508 | } | ||
5509 | else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) | ||
5510 | { | ||
5511 | return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer); | ||
5512 | } | ||
5513 | else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) | ||
5514 | { | ||
5515 | return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float; | ||
5516 | } | ||
5517 | else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) | ||
5518 | { | ||
5519 | return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned); | ||
5520 | } | ||
5521 | else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) | ||
5522 | { | ||
5523 | return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; | ||
5524 | } | ||
5525 | else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) | ||
5526 | { | ||
5527 | return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned); | ||
5528 | } | ||
5529 | |||
5530 | return false; | ||
5531 | } | ||
5532 | |||
5533 | /*! | ||
5534 | @brief comparison: equal | ||
5535 | |||
5536 | The functions compares the given JSON value against a null pointer. As the | ||
5537 | null pointer can be used to initialize a JSON value to null, a comparison | ||
5538 | of JSON value @a v with a null pointer should be equivalent to call | ||
5539 | `v.is_null()`. | ||
5540 | |||
5541 | @param[in] v JSON value to consider | ||
5542 | @return whether @a v is null | ||
5543 | |||
5544 | @complexity Constant. | ||
5545 | |||
5546 | @liveexample{The example compares several JSON types to the null pointer. | ||
5547 | ,operator__equal__nullptr_t} | ||
5548 | |||
5549 | @since version 1.0.0 | ||
5550 | */ | ||
5551 | friend bool operator==(const_reference v, std::nullptr_t) noexcept | ||
5552 | { | ||
5553 | return v.is_null(); | ||
5554 | } | ||
5555 | |||
5556 | /*! | ||
5557 | @brief comparison: equal | ||
5558 | @copydoc operator==(const_reference, std::nullptr_t) | ||
5559 | */ | ||
5560 | friend bool operator==(std::nullptr_t, const_reference v) noexcept | ||
5561 | { | ||
5562 | return v.is_null(); | ||
5563 | } | ||
5564 | |||
5565 | /*! | ||
5566 | @brief comparison: not equal | ||
5567 | |||
5568 | Compares two JSON values for inequality by calculating `not (lhs == rhs)`. | ||
5569 | |||
5570 | @param[in] lhs first JSON value to consider | ||
5571 | @param[in] rhs second JSON value to consider | ||
5572 | @return whether the values @a lhs and @a rhs are not equal | ||
5573 | |||
5574 | @complexity Linear. | ||
5575 | |||
5576 | @liveexample{The example demonstrates comparing several JSON | ||
5577 | types.,operator__notequal} | ||
5578 | |||
5579 | @since version 1.0.0 | ||
5580 | */ | ||
5581 | friend bool operator!=(const_reference lhs, const_reference rhs) noexcept | ||
5582 | { | ||
5583 | return not (lhs == rhs); | ||
5584 | } | ||
5585 | |||
5586 | /*! | ||
5587 | @brief comparison: not equal | ||
5588 | |||
5589 | The functions compares the given JSON value against a null pointer. As the | ||
5590 | null pointer can be used to initialize a JSON value to null, a comparison | ||
5591 | of JSON value @a v with a null pointer should be equivalent to call | ||
5592 | `not v.is_null()`. | ||
5593 | |||
5594 | @param[in] v JSON value to consider | ||
5595 | @return whether @a v is not null | ||
5596 | |||
5597 | @complexity Constant. | ||
5598 | |||
5599 | @liveexample{The example compares several JSON types to the null pointer. | ||
5600 | ,operator__notequal__nullptr_t} | ||
5601 | |||
5602 | @since version 1.0.0 | ||
5603 | */ | ||
5604 | friend bool operator!=(const_reference v, std::nullptr_t) noexcept | ||
5605 | { | ||
5606 | return not v.is_null(); | ||
5607 | } | ||
5608 | |||
5609 | /*! | ||
5610 | @brief comparison: not equal | ||
5611 | @copydoc operator!=(const_reference, std::nullptr_t) | ||
5612 | */ | ||
5613 | friend bool operator!=(std::nullptr_t, const_reference v) noexcept | ||
5614 | { | ||
5615 | return not v.is_null(); | ||
5616 | } | ||
5617 | |||
5618 | /*! | ||
5619 | @brief comparison: less than | ||
5620 | |||
5621 | Compares whether one JSON value @a lhs is less than another JSON value @a | ||
5622 | rhs according to the following rules: | ||
5623 | - If @a lhs and @a rhs have the same type, the values are compared using | ||
5624 | the default `<` operator. | ||
5625 | - Integer and floating-point numbers are automatically converted before | ||
5626 | comparison | ||
5627 | - In case @a lhs and @a rhs have different types, the values are ignored | ||
5628 | and the order of the types is considered, see | ||
5629 | @ref operator<(const value_t, const value_t). | ||
5630 | |||
5631 | @param[in] lhs first JSON value to consider | ||
5632 | @param[in] rhs second JSON value to consider | ||
5633 | @return whether @a lhs is less than @a rhs | ||
5634 | |||
5635 | @complexity Linear. | ||
5636 | |||
5637 | @liveexample{The example demonstrates comparing several JSON | ||
5638 | types.,operator__less} | ||
5639 | |||
5640 | @since version 1.0.0 | ||
5641 | */ | ||
5642 | friend bool operator<(const_reference lhs, const_reference rhs) noexcept | ||
5643 | { | ||
5644 | const auto lhs_type = lhs.type(); | ||
5645 | const auto rhs_type = rhs.type(); | ||
5646 | |||
5647 | if (lhs_type == rhs_type) | ||
5648 | { | ||
5649 | switch (lhs_type) | ||
5650 | { | ||
5651 | case value_t::array: | ||
5652 | { | ||
5653 | return *lhs.m_value.array < *rhs.m_value.array; | ||
5654 | } | ||
5655 | case value_t::object: | ||
5656 | { | ||
5657 | return *lhs.m_value.object < *rhs.m_value.object; | ||
5658 | } | ||
5659 | case value_t::null: | ||
5660 | { | ||
5661 | return false; | ||
5662 | } | ||
5663 | case value_t::string: | ||
5664 | { | ||
5665 | return *lhs.m_value.string < *rhs.m_value.string; | ||
5666 | } | ||
5667 | case value_t::boolean: | ||
5668 | { | ||
5669 | return lhs.m_value.boolean < rhs.m_value.boolean; | ||
5670 | } | ||
5671 | case value_t::number_integer: | ||
5672 | { | ||
5673 | return lhs.m_value.number_integer < rhs.m_value.number_integer; | ||
5674 | } | ||
5675 | case value_t::number_unsigned: | ||
5676 | { | ||
5677 | return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; | ||
5678 | } | ||
5679 | case value_t::number_float: | ||
5680 | { | ||
5681 | return lhs.m_value.number_float < rhs.m_value.number_float; | ||
5682 | } | ||
5683 | default: | ||
5684 | { | ||
5685 | return false; | ||
5686 | } | ||
5687 | } | ||
5688 | } | ||
5689 | else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) | ||
5690 | { | ||
5691 | return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float; | ||
5692 | } | ||
5693 | else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) | ||
5694 | { | ||
5695 | return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer); | ||
5696 | } | ||
5697 | else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) | ||
5698 | { | ||
5699 | return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float; | ||
5700 | } | ||
5701 | else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) | ||
5702 | { | ||
5703 | return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned); | ||
5704 | } | ||
5705 | else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) | ||
5706 | { | ||
5707 | return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned); | ||
5708 | } | ||
5709 | else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) | ||
5710 | { | ||
5711 | return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; | ||
5712 | } | ||
5713 | |||
5714 | // We only reach this line if we cannot compare values. In that case, | ||
5715 | // we compare types. Note we have to call the operator explicitly, | ||
5716 | // because MSVC has problems otherwise. | ||
5717 | return operator<(lhs_type, rhs_type); | ||
5718 | } | ||
5719 | |||
5720 | /*! | ||
5721 | @brief comparison: less than or equal | ||
5722 | |||
5723 | Compares whether one JSON value @a lhs is less than or equal to another | ||
5724 | JSON value by calculating `not (rhs < lhs)`. | ||
5725 | |||
5726 | @param[in] lhs first JSON value to consider | ||
5727 | @param[in] rhs second JSON value to consider | ||
5728 | @return whether @a lhs is less than or equal to @a rhs | ||
5729 | |||
5730 | @complexity Linear. | ||
5731 | |||
5732 | @liveexample{The example demonstrates comparing several JSON | ||
5733 | types.,operator__greater} | ||
5734 | |||
5735 | @since version 1.0.0 | ||
5736 | */ | ||
5737 | friend bool operator<=(const_reference lhs, const_reference rhs) noexcept | ||
5738 | { | ||
5739 | return not (rhs < lhs); | ||
5740 | } | ||
5741 | |||
5742 | /*! | ||
5743 | @brief comparison: greater than | ||
5744 | |||
5745 | Compares whether one JSON value @a lhs is greater than another | ||
5746 | JSON value by calculating `not (lhs <= rhs)`. | ||
5747 | |||
5748 | @param[in] lhs first JSON value to consider | ||
5749 | @param[in] rhs second JSON value to consider | ||
5750 | @return whether @a lhs is greater than to @a rhs | ||
5751 | |||
5752 | @complexity Linear. | ||
5753 | |||
5754 | @liveexample{The example demonstrates comparing several JSON | ||
5755 | types.,operator__lessequal} | ||
5756 | |||
5757 | @since version 1.0.0 | ||
5758 | */ | ||
5759 | friend bool operator>(const_reference lhs, const_reference rhs) noexcept | ||
5760 | { | ||
5761 | return not (lhs <= rhs); | ||
5762 | } | ||
5763 | |||
5764 | /*! | ||
5765 | @brief comparison: greater than or equal | ||
5766 | |||
5767 | Compares whether one JSON value @a lhs is greater than or equal to another | ||
5768 | JSON value by calculating `not (lhs < rhs)`. | ||
5769 | |||
5770 | @param[in] lhs first JSON value to consider | ||
5771 | @param[in] rhs second JSON value to consider | ||
5772 | @return whether @a lhs is greater than or equal to @a rhs | ||
5773 | |||
5774 | @complexity Linear. | ||
5775 | |||
5776 | @liveexample{The example demonstrates comparing several JSON | ||
5777 | types.,operator__greaterequal} | ||
5778 | |||
5779 | @since version 1.0.0 | ||
5780 | */ | ||
5781 | friend bool operator>=(const_reference lhs, const_reference rhs) noexcept | ||
5782 | { | ||
5783 | return not (lhs < rhs); | ||
5784 | } | ||
5785 | |||
5786 | /// @} | ||
5787 | |||
5788 | |||
5789 | /////////////////// | ||
5790 | // serialization // | ||
5791 | /////////////////// | ||
5792 | |||
5793 | /// @name serialization | ||
5794 | /// @{ | ||
5795 | |||
5796 | /*! | ||
5797 | @brief serialize to stream | ||
5798 | |||
5799 | Serialize the given JSON value @a j to the output stream @a o. The JSON | ||
5800 | value will be serialized using the @ref dump member function. The | ||
5801 | indentation of the output can be controlled with the member variable | ||
5802 | `width` of the output stream @a o. For instance, using the manipulator | ||
5803 | `std::setw(4)` on @a o sets the indentation level to `4` and the | ||
5804 | serialization result is the same as calling `dump(4)`. | ||
5805 | |||
5806 | @note During serializaion, the locale and the precision of the output | ||
5807 | stream @a o are changed. The original values are restored when the | ||
5808 | function returns. | ||
5809 | |||
5810 | @param[in,out] o stream to serialize to | ||
5811 | @param[in] j JSON value to serialize | ||
5812 | |||
5813 | @return the stream @a o | ||
5814 | |||
5815 | @complexity Linear. | ||
5816 | |||
5817 | @liveexample{The example below shows the serialization with different | ||
5818 | parameters to `width` to adjust the indentation level.,operator_serialize} | ||
5819 | |||
5820 | @since version 1.0.0 | ||
5821 | */ | ||
5822 | friend std::ostream& operator<<(std::ostream& o, const basic_json& j) | ||
5823 | { | ||
5824 | // read width member and use it as indentation parameter if nonzero | ||
5825 | const bool pretty_print = (o.width() > 0); | ||
5826 | const auto indentation = (pretty_print ? o.width() : 0); | ||
5827 | |||
5828 | // reset width to 0 for subsequent calls to this stream | ||
5829 | o.width(0); | ||
5830 | |||
5831 | // fix locale problems | ||
5832 | const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); | ||
5833 | // set precision | ||
5834 | |||
5835 | // 6, 15 or 16 digits of precision allows round-trip IEEE 754 | ||
5836 | // string->float->string, string->double->string or string->long | ||
5837 | // double->string; to be safe, we read this value from | ||
5838 | // std::numeric_limits<number_float_t>::digits10 | ||
5839 | const auto old_precision = o.precision(std::numeric_limits<double>::digits10); | ||
5840 | |||
5841 | // do the actual serialization | ||
5842 | j.dump(o, pretty_print, static_cast<unsigned int>(indentation)); | ||
5843 | |||
5844 | // reset locale and precision | ||
5845 | o.imbue(old_locale); | ||
5846 | o.precision(old_precision); | ||
5847 | return o; | ||
5848 | } | ||
5849 | |||
5850 | /*! | ||
5851 | @brief serialize to stream | ||
5852 | @copydoc operator<<(std::ostream&, const basic_json&) | ||
5853 | */ | ||
5854 | friend std::ostream& operator>>(const basic_json& j, std::ostream& o) | ||
5855 | { | ||
5856 | return o << j; | ||
5857 | } | ||
5858 | |||
5859 | /// @} | ||
5860 | |||
5861 | |||
5862 | ///////////////////// | ||
5863 | // deserialization // | ||
5864 | ///////////////////// | ||
5865 | |||
5866 | /// @name deserialization | ||
5867 | /// @{ | ||
5868 | |||
5869 | /*! | ||
5870 | @brief deserialize from an array | ||
5871 | |||
5872 | This function reads from an array of 1-byte values. | ||
5873 | |||
5874 | @pre Each element of the container has a size of 1 byte. Violating this | ||
5875 | precondition yields undefined behavior. **This precondition is enforced | ||
5876 | with a static assertion.** | ||
5877 | |||
5878 | @param[in] array array to read from | ||
5879 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
5880 | which is used to control the deserialization by filtering unwanted values | ||
5881 | (optional) | ||
5882 | |||
5883 | @return result of the deserialization | ||
5884 | |||
5885 | @complexity Linear in the length of the input. The parser is a predictive | ||
5886 | LL(1) parser. The complexity can be higher if the parser callback function | ||
5887 | @a cb has a super-linear complexity. | ||
5888 | |||
5889 | @note A UTF-8 byte order mark is silently ignored. | ||
5890 | |||
5891 | @liveexample{The example below demonstrates the `parse()` function reading | ||
5892 | from an array.,parse__array__parser_callback_t} | ||
5893 | |||
5894 | @since version 2.0.3 | ||
5895 | */ | ||
5896 | template<class T, std::size_t N> | ||
5897 | static basic_json parse(T (&array)[N], | ||
5898 | const parser_callback_t cb = nullptr) | ||
5899 | { | ||
5900 | // delegate the call to the iterator-range parse overload | ||
5901 | return parse(std::begin(array), std::end(array), cb); | ||
5902 | } | ||
5903 | |||
5904 | /*! | ||
5905 | @brief deserialize from string literal | ||
5906 | |||
5907 | @tparam CharT character/literal type with size of 1 byte | ||
5908 | @param[in] s string literal to read a serialized JSON value from | ||
5909 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
5910 | which is used to control the deserialization by filtering unwanted values | ||
5911 | (optional) | ||
5912 | |||
5913 | @return result of the deserialization | ||
5914 | |||
5915 | @complexity Linear in the length of the input. The parser is a predictive | ||
5916 | LL(1) parser. The complexity can be higher if the parser callback function | ||
5917 | @a cb has a super-linear complexity. | ||
5918 | |||
5919 | @note A UTF-8 byte order mark is silently ignored. | ||
5920 | @note String containers like `std::string` or @ref string_t can be parsed | ||
5921 | with @ref parse(const ContiguousContainer&, const parser_callback_t) | ||
5922 | |||
5923 | @liveexample{The example below demonstrates the `parse()` function with | ||
5924 | and without callback function.,parse__string__parser_callback_t} | ||
5925 | |||
5926 | @sa @ref parse(std::istream&, const parser_callback_t) for a version that | ||
5927 | reads from an input stream | ||
5928 | |||
5929 | @since version 1.0.0 (originally for @ref string_t) | ||
5930 | */ | ||
5931 | template<typename CharPT, typename std::enable_if< | ||
5932 | std::is_pointer<CharPT>::value and | ||
5933 | std::is_integral<typename std::remove_pointer<CharPT>::type>::value and | ||
5934 | sizeof(typename std::remove_pointer<CharPT>::type) == 1, int>::type = 0> | ||
5935 | static basic_json parse(const CharPT s, | ||
5936 | const parser_callback_t cb = nullptr) | ||
5937 | { | ||
5938 | return parser(reinterpret_cast<const char*>(s), cb).parse(); | ||
5939 | } | ||
5940 | |||
5941 | /*! | ||
5942 | @brief deserialize from stream | ||
5943 | |||
5944 | @param[in,out] i stream to read a serialized JSON value from | ||
5945 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
5946 | which is used to control the deserialization by filtering unwanted values | ||
5947 | (optional) | ||
5948 | |||
5949 | @return result of the deserialization | ||
5950 | |||
5951 | @complexity Linear in the length of the input. The parser is a predictive | ||
5952 | LL(1) parser. The complexity can be higher if the parser callback function | ||
5953 | @a cb has a super-linear complexity. | ||
5954 | |||
5955 | @note A UTF-8 byte order mark is silently ignored. | ||
5956 | |||
5957 | @liveexample{The example below demonstrates the `parse()` function with | ||
5958 | and without callback function.,parse__istream__parser_callback_t} | ||
5959 | |||
5960 | @sa @ref parse(const char*, const parser_callback_t) for a version | ||
5961 | that reads from a string | ||
5962 | |||
5963 | @since version 1.0.0 | ||
5964 | */ | ||
5965 | static basic_json parse(std::istream& i, | ||
5966 | const parser_callback_t cb = nullptr) | ||
5967 | { | ||
5968 | return parser(i, cb).parse(); | ||
5969 | } | ||
5970 | |||
5971 | /*! | ||
5972 | @copydoc parse(std::istream&, const parser_callback_t) | ||
5973 | */ | ||
5974 | static basic_json parse(std::istream&& i, | ||
5975 | const parser_callback_t cb = nullptr) | ||
5976 | { | ||
5977 | return parser(i, cb).parse(); | ||
5978 | } | ||
5979 | |||
5980 | /*! | ||
5981 | @brief deserialize from an iterator range with contiguous storage | ||
5982 | |||
5983 | This function reads from an iterator range of a container with contiguous | ||
5984 | storage of 1-byte values. Compatible container types include | ||
5985 | `std::vector`, `std::string`, `std::array`, `std::valarray`, and | ||
5986 | `std::initializer_list`. Furthermore, C-style arrays can be used with | ||
5987 | `std::begin()`/`std::end()`. User-defined containers can be used as long | ||
5988 | as they implement random-access iterators and a contiguous storage. | ||
5989 | |||
5990 | @pre The iterator range is contiguous. Violating this precondition yields | ||
5991 | undefined behavior. **This precondition is enforced with an assertion.** | ||
5992 | @pre Each element in the range has a size of 1 byte. Violating this | ||
5993 | precondition yields undefined behavior. **This precondition is enforced | ||
5994 | with a static assertion.** | ||
5995 | |||
5996 | @warning There is no way to enforce all preconditions at compile-time. If | ||
5997 | the function is called with noncompliant iterators and with | ||
5998 | assertions switched off, the behavior is undefined and will most | ||
5999 | likely yield segmentation violation. | ||
6000 | |||
6001 | @tparam IteratorType iterator of container with contiguous storage | ||
6002 | @param[in] first begin of the range to parse (included) | ||
6003 | @param[in] last end of the range to parse (excluded) | ||
6004 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
6005 | which is used to control the deserialization by filtering unwanted values | ||
6006 | (optional) | ||
6007 | |||
6008 | @return result of the deserialization | ||
6009 | |||
6010 | @complexity Linear in the length of the input. The parser is a predictive | ||
6011 | LL(1) parser. The complexity can be higher if the parser callback function | ||
6012 | @a cb has a super-linear complexity. | ||
6013 | |||
6014 | @note A UTF-8 byte order mark is silently ignored. | ||
6015 | |||
6016 | @liveexample{The example below demonstrates the `parse()` function reading | ||
6017 | from an iterator range.,parse__iteratortype__parser_callback_t} | ||
6018 | |||
6019 | @since version 2.0.3 | ||
6020 | */ | ||
6021 | template<class IteratorType, typename std::enable_if< | ||
6022 | std::is_base_of< | ||
6023 | std::random_access_iterator_tag, | ||
6024 | typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0> | ||
6025 | static basic_json parse(IteratorType first, IteratorType last, | ||
6026 | const parser_callback_t cb = nullptr) | ||
6027 | { | ||
6028 | // assertion to check that the iterator range is indeed contiguous, | ||
6029 | // see http://stackoverflow.com/a/35008842/266378 for more discussion | ||
6030 | assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0), | ||
6031 | [&first](std::pair<bool, int> res, decltype(*first) val) | ||
6032 | { | ||
6033 | res.first &= (val == *(std::next(std::addressof(*first), res.second++))); | ||
6034 | return res; | ||
6035 | }).first); | ||
6036 | |||
6037 | // assertion to check that each element is 1 byte long | ||
6038 | static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1, | ||
6039 | "each element in the iterator range must have the size of 1 byte"); | ||
6040 | |||
6041 | // if iterator range is empty, create a parser with an empty string | ||
6042 | // to generate "unexpected EOF" error message | ||
6043 | if (std::distance(first, last) <= 0) | ||
6044 | { | ||
6045 | return parser("").parse(); | ||
6046 | } | ||
6047 | |||
6048 | return parser(first, last, cb).parse(); | ||
6049 | } | ||
6050 | |||
6051 | /*! | ||
6052 | @brief deserialize from a container with contiguous storage | ||
6053 | |||
6054 | This function reads from a container with contiguous storage of 1-byte | ||
6055 | values. Compatible container types include `std::vector`, `std::string`, | ||
6056 | `std::array`, and `std::initializer_list`. User-defined containers can be | ||
6057 | used as long as they implement random-access iterators and a contiguous | ||
6058 | storage. | ||
6059 | |||
6060 | @pre The container storage is contiguous. Violating this precondition | ||
6061 | yields undefined behavior. **This precondition is enforced with an | ||
6062 | assertion.** | ||
6063 | @pre Each element of the container has a size of 1 byte. Violating this | ||
6064 | precondition yields undefined behavior. **This precondition is enforced | ||
6065 | with a static assertion.** | ||
6066 | |||
6067 | @warning There is no way to enforce all preconditions at compile-time. If | ||
6068 | the function is called with a noncompliant container and with | ||
6069 | assertions switched off, the behavior is undefined and will most | ||
6070 | likely yield segmentation violation. | ||
6071 | |||
6072 | @tparam ContiguousContainer container type with contiguous storage | ||
6073 | @param[in] c container to read from | ||
6074 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
6075 | which is used to control the deserialization by filtering unwanted values | ||
6076 | (optional) | ||
6077 | |||
6078 | @return result of the deserialization | ||
6079 | |||
6080 | @complexity Linear in the length of the input. The parser is a predictive | ||
6081 | LL(1) parser. The complexity can be higher if the parser callback function | ||
6082 | @a cb has a super-linear complexity. | ||
6083 | |||
6084 | @note A UTF-8 byte order mark is silently ignored. | ||
6085 | |||
6086 | @liveexample{The example below demonstrates the `parse()` function reading | ||
6087 | from a contiguous container.,parse__contiguouscontainer__parser_callback_t} | ||
6088 | |||
6089 | @since version 2.0.3 | ||
6090 | */ | ||
6091 | template<class ContiguousContainer, typename std::enable_if< | ||
6092 | not std::is_pointer<ContiguousContainer>::value and | ||
6093 | std::is_base_of< | ||
6094 | std::random_access_iterator_tag, | ||
6095 | typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value | ||
6096 | , int>::type = 0> | ||
6097 | static basic_json parse(const ContiguousContainer& c, | ||
6098 | const parser_callback_t cb = nullptr) | ||
6099 | { | ||
6100 | // delegate the call to the iterator-range parse overload | ||
6101 | return parse(std::begin(c), std::end(c), cb); | ||
6102 | } | ||
6103 | |||
6104 | /*! | ||
6105 | @brief deserialize from stream | ||
6106 | |||
6107 | Deserializes an input stream to a JSON value. | ||
6108 | |||
6109 | @param[in,out] i input stream to read a serialized JSON value from | ||
6110 | @param[in,out] j JSON value to write the deserialized input to | ||
6111 | |||
6112 | @throw std::invalid_argument in case of parse errors | ||
6113 | |||
6114 | @complexity Linear in the length of the input. The parser is a predictive | ||
6115 | LL(1) parser. | ||
6116 | |||
6117 | @note A UTF-8 byte order mark is silently ignored. | ||
6118 | |||
6119 | @liveexample{The example below shows how a JSON value is constructed by | ||
6120 | reading a serialization from a stream.,operator_deserialize} | ||
6121 | |||
6122 | @sa parse(std::istream&, const parser_callback_t) for a variant with a | ||
6123 | parser callback function to filter values while parsing | ||
6124 | |||
6125 | @since version 1.0.0 | ||
6126 | */ | ||
6127 | friend std::istream& operator<<(basic_json& j, std::istream& i) | ||
6128 | { | ||
6129 | j = parser(i).parse(); | ||
6130 | return i; | ||
6131 | } | ||
6132 | |||
6133 | /*! | ||
6134 | @brief deserialize from stream | ||
6135 | @copydoc operator<<(basic_json&, std::istream&) | ||
6136 | */ | ||
6137 | friend std::istream& operator>>(std::istream& i, basic_json& j) | ||
6138 | { | ||
6139 | j = parser(i).parse(); | ||
6140 | return i; | ||
6141 | } | ||
6142 | |||
6143 | /// @} | ||
6144 | |||
6145 | |||
6146 | private: | ||
6147 | /////////////////////////// | ||
6148 | // convenience functions // | ||
6149 | /////////////////////////// | ||
6150 | |||
6151 | /*! | ||
6152 | @brief return the type as string | ||
6153 | |||
6154 | Returns the type name as string to be used in error messages - usually to | ||
6155 | indicate that a function was called on a wrong JSON type. | ||
6156 | |||
6157 | @return basically a string representation of a the @a m_type member | ||
6158 | |||
6159 | @complexity Constant. | ||
6160 | |||
6161 | @since version 1.0.0 | ||
6162 | */ | ||
6163 | std::string type_name() const | ||
6164 | { | ||
6165 | switch (m_type) | ||
6166 | { | ||
6167 | case value_t::null: | ||
6168 | return "null"; | ||
6169 | case value_t::object: | ||
6170 | return "object"; | ||
6171 | case value_t::array: | ||
6172 | return "array"; | ||
6173 | case value_t::string: | ||
6174 | return "string"; | ||
6175 | case value_t::boolean: | ||
6176 | return "boolean"; | ||
6177 | case value_t::discarded: | ||
6178 | return "discarded"; | ||
6179 | default: | ||
6180 | return "number"; | ||
6181 | } | ||
6182 | } | ||
6183 | |||
6184 | /*! | ||
6185 | @brief calculates the extra space to escape a JSON string | ||
6186 | |||
6187 | @param[in] s the string to escape | ||
6188 | @return the number of characters required to escape string @a s | ||
6189 | |||
6190 | @complexity Linear in the length of string @a s. | ||
6191 | */ | ||
6192 | static std::size_t extra_space(const string_t& s) noexcept | ||
6193 | { | ||
6194 | return std::accumulate(s.begin(), s.end(), size_t{}, | ||
6195 | [](size_t res, typename string_t::value_type c) | ||
6196 | { | ||
6197 | switch (c) | ||
6198 | { | ||
6199 | case '"': | ||
6200 | case '\\': | ||
6201 | case '\b': | ||
6202 | case '\f': | ||
6203 | case '\n': | ||
6204 | case '\r': | ||
6205 | case '\t': | ||
6206 | { | ||
6207 | // from c (1 byte) to \x (2 bytes) | ||
6208 | return res + 1; | ||
6209 | } | ||
6210 | |||
6211 | default: | ||
6212 | { | ||
6213 | if (c >= 0x00 and c <= 0x1f) | ||
6214 | { | ||
6215 | // from c (1 byte) to \uxxxx (6 bytes) | ||
6216 | return res + 5; | ||
6217 | } | ||
6218 | else | ||
6219 | { | ||
6220 | return res; | ||
6221 | } | ||
6222 | } | ||
6223 | } | ||
6224 | }); | ||
6225 | } | ||
6226 | |||
6227 | /*! | ||
6228 | @brief escape a string | ||
6229 | |||
6230 | Escape a string by replacing certain special characters by a sequence of | ||
6231 | an escape character (backslash) and another character and other control | ||
6232 | characters by a sequence of "\u" followed by a four-digit hex | ||
6233 | representation. | ||
6234 | |||
6235 | @param[in] s the string to escape | ||
6236 | @return the escaped string | ||
6237 | |||
6238 | @complexity Linear in the length of string @a s. | ||
6239 | */ | ||
6240 | static string_t escape_string(const string_t& s) | ||
6241 | { | ||
6242 | const auto space = extra_space(s); | ||
6243 | if (space == 0) | ||
6244 | { | ||
6245 | return s; | ||
6246 | } | ||
6247 | |||
6248 | // create a result string of necessary size | ||
6249 | string_t result(s.size() + space, '\\'); | ||
6250 | std::size_t pos = 0; | ||
6251 | |||
6252 | for (const auto& c : s) | ||
6253 | { | ||
6254 | switch (c) | ||
6255 | { | ||
6256 | // quotation mark (0x22) | ||
6257 | case '"': | ||
6258 | { | ||
6259 | result[pos + 1] = '"'; | ||
6260 | pos += 2; | ||
6261 | break; | ||
6262 | } | ||
6263 | |||
6264 | // reverse solidus (0x5c) | ||
6265 | case '\\': | ||
6266 | { | ||
6267 | // nothing to change | ||
6268 | pos += 2; | ||
6269 | break; | ||
6270 | } | ||
6271 | |||
6272 | // backspace (0x08) | ||
6273 | case '\b': | ||
6274 | { | ||
6275 | result[pos + 1] = 'b'; | ||
6276 | pos += 2; | ||
6277 | break; | ||
6278 | } | ||
6279 | |||
6280 | // formfeed (0x0c) | ||
6281 | case '\f': | ||
6282 | { | ||
6283 | result[pos + 1] = 'f'; | ||
6284 | pos += 2; | ||
6285 | break; | ||
6286 | } | ||
6287 | |||
6288 | // newline (0x0a) | ||
6289 | case '\n': | ||
6290 | { | ||
6291 | result[pos + 1] = 'n'; | ||
6292 | pos += 2; | ||
6293 | break; | ||
6294 | } | ||
6295 | |||
6296 | // carriage return (0x0d) | ||
6297 | case '\r': | ||
6298 | { | ||
6299 | result[pos + 1] = 'r'; | ||
6300 | pos += 2; | ||
6301 | break; | ||
6302 | } | ||
6303 | |||
6304 | // horizontal tab (0x09) | ||
6305 | case '\t': | ||
6306 | { | ||
6307 | result[pos + 1] = 't'; | ||
6308 | pos += 2; | ||
6309 | break; | ||
6310 | } | ||
6311 | |||
6312 | default: | ||
6313 | { | ||
6314 | if (c >= 0x00 and c <= 0x1f) | ||
6315 | { | ||
6316 | // convert a number 0..15 to its hex representation | ||
6317 | // (0..f) | ||
6318 | static const char hexify[16] = | ||
6319 | { | ||
6320 | '0', '1', '2', '3', '4', '5', '6', '7', | ||
6321 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' | ||
6322 | }; | ||
6323 | |||
6324 | // print character c as \uxxxx | ||
6325 | for (const char m : | ||
6326 | { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] | ||
6327 | }) | ||
6328 | { | ||
6329 | result[++pos] = m; | ||
6330 | } | ||
6331 | |||
6332 | ++pos; | ||
6333 | } | ||
6334 | else | ||
6335 | { | ||
6336 | // all other characters are added as-is | ||
6337 | result[pos++] = c; | ||
6338 | } | ||
6339 | break; | ||
6340 | } | ||
6341 | } | ||
6342 | } | ||
6343 | |||
6344 | return result; | ||
6345 | } | ||
6346 | |||
6347 | /*! | ||
6348 | @brief internal implementation of the serialization function | ||
6349 | |||
6350 | This function is called by the public member function dump and organizes | ||
6351 | the serialization internally. The indentation level is propagated as | ||
6352 | additional parameter. In case of arrays and objects, the function is | ||
6353 | called recursively. Note that | ||
6354 | |||
6355 | - strings and object keys are escaped using `escape_string()` | ||
6356 | - integer numbers are converted implicitly via `operator<<` | ||
6357 | - floating-point numbers are converted to a string using `"%g"` format | ||
6358 | |||
6359 | @param[out] o stream to write to | ||
6360 | @param[in] pretty_print whether the output shall be pretty-printed | ||
6361 | @param[in] indent_step the indent level | ||
6362 | @param[in] current_indent the current indent level (only used internally) | ||
6363 | */ | ||
6364 | void dump(std::ostream& o, | ||
6365 | const bool pretty_print, | ||
6366 | const unsigned int indent_step, | ||
6367 | const unsigned int current_indent = 0) const | ||
6368 | { | ||
6369 | // variable to hold indentation for recursive calls | ||
6370 | unsigned int new_indent = current_indent; | ||
6371 | |||
6372 | switch (m_type) | ||
6373 | { | ||
6374 | case value_t::object: | ||
6375 | { | ||
6376 | if (m_value.object->empty()) | ||
6377 | { | ||
6378 | o << "{}"; | ||
6379 | return; | ||
6380 | } | ||
6381 | |||
6382 | o << "{"; | ||
6383 | |||
6384 | // increase indentation | ||
6385 | if (pretty_print) | ||
6386 | { | ||
6387 | new_indent += indent_step; | ||
6388 | o << "\n"; | ||
6389 | } | ||
6390 | |||
6391 | for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) | ||
6392 | { | ||
6393 | if (i != m_value.object->cbegin()) | ||
6394 | { | ||
6395 | o << (pretty_print ? ",\n" : ","); | ||
6396 | } | ||
6397 | o << string_t(new_indent, ' ') << "\"" | ||
6398 | << escape_string(i->first) << "\":" | ||
6399 | << (pretty_print ? " " : ""); | ||
6400 | i->second.dump(o, pretty_print, indent_step, new_indent); | ||
6401 | } | ||
6402 | |||
6403 | // decrease indentation | ||
6404 | if (pretty_print) | ||
6405 | { | ||
6406 | new_indent -= indent_step; | ||
6407 | o << "\n"; | ||
6408 | } | ||
6409 | |||
6410 | o << string_t(new_indent, ' ') + "}"; | ||
6411 | return; | ||
6412 | } | ||
6413 | |||
6414 | case value_t::array: | ||
6415 | { | ||
6416 | if (m_value.array->empty()) | ||
6417 | { | ||
6418 | o << "[]"; | ||
6419 | return; | ||
6420 | } | ||
6421 | |||
6422 | o << "["; | ||
6423 | |||
6424 | // increase indentation | ||
6425 | if (pretty_print) | ||
6426 | { | ||
6427 | new_indent += indent_step; | ||
6428 | o << "\n"; | ||
6429 | } | ||
6430 | |||
6431 | for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) | ||
6432 | { | ||
6433 | if (i != m_value.array->cbegin()) | ||
6434 | { | ||
6435 | o << (pretty_print ? ",\n" : ","); | ||
6436 | } | ||
6437 | o << string_t(new_indent, ' '); | ||
6438 | i->dump(o, pretty_print, indent_step, new_indent); | ||
6439 | } | ||
6440 | |||
6441 | // decrease indentation | ||
6442 | if (pretty_print) | ||
6443 | { | ||
6444 | new_indent -= indent_step; | ||
6445 | o << "\n"; | ||
6446 | } | ||
6447 | |||
6448 | o << string_t(new_indent, ' ') << "]"; | ||
6449 | return; | ||
6450 | } | ||
6451 | |||
6452 | case value_t::string: | ||
6453 | { | ||
6454 | o << string_t("\"") << escape_string(*m_value.string) << "\""; | ||
6455 | return; | ||
6456 | } | ||
6457 | |||
6458 | case value_t::boolean: | ||
6459 | { | ||
6460 | o << (m_value.boolean ? "true" : "false"); | ||
6461 | return; | ||
6462 | } | ||
6463 | |||
6464 | case value_t::number_integer: | ||
6465 | { | ||
6466 | o << m_value.number_integer; | ||
6467 | return; | ||
6468 | } | ||
6469 | |||
6470 | case value_t::number_unsigned: | ||
6471 | { | ||
6472 | o << m_value.number_unsigned; | ||
6473 | return; | ||
6474 | } | ||
6475 | |||
6476 | case value_t::number_float: | ||
6477 | { | ||
6478 | if (m_value.number_float == 0) | ||
6479 | { | ||
6480 | // special case for zero to get "0.0"/"-0.0" | ||
6481 | o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); | ||
6482 | } | ||
6483 | else | ||
6484 | { | ||
6485 | o << m_value.number_float; | ||
6486 | } | ||
6487 | return; | ||
6488 | } | ||
6489 | |||
6490 | case value_t::discarded: | ||
6491 | { | ||
6492 | o << "<discarded>"; | ||
6493 | return; | ||
6494 | } | ||
6495 | |||
6496 | case value_t::null: | ||
6497 | { | ||
6498 | o << "null"; | ||
6499 | return; | ||
6500 | } | ||
6501 | } | ||
6502 | } | ||
6503 | |||
6504 | private: | ||
6505 | ////////////////////// | ||
6506 | // member variables // | ||
6507 | ////////////////////// | ||
6508 | |||
6509 | /// the type of the current element | ||
6510 | value_t m_type = value_t::null; | ||
6511 | |||
6512 | /// the value of the current element | ||
6513 | json_value m_value = {}; | ||
6514 | |||
6515 | |||
6516 | private: | ||
6517 | /////////////// | ||
6518 | // iterators // | ||
6519 | /////////////// | ||
6520 | |||
6521 | /*! | ||
6522 | @brief an iterator for primitive JSON types | ||
6523 | |||
6524 | This class models an iterator for primitive JSON types (boolean, number, | ||
6525 | string). It's only purpose is to allow the iterator/const_iterator classes | ||
6526 | to "iterate" over primitive values. Internally, the iterator is modeled by | ||
6527 | a `difference_type` variable. Value begin_value (`0`) models the begin, | ||
6528 | end_value (`1`) models past the end. | ||
6529 | */ | ||
6530 | class primitive_iterator_t | ||
6531 | { | ||
6532 | public: | ||
6533 | /// set iterator to a defined beginning | ||
6534 | void set_begin() noexcept | ||
6535 | { | ||
6536 | m_it = begin_value; | ||
6537 | } | ||
6538 | |||
6539 | /// set iterator to a defined past the end | ||
6540 | void set_end() noexcept | ||
6541 | { | ||
6542 | m_it = end_value; | ||
6543 | } | ||
6544 | |||
6545 | /// return whether the iterator can be dereferenced | ||
6546 | constexpr bool is_begin() const noexcept | ||
6547 | { | ||
6548 | return (m_it == begin_value); | ||
6549 | } | ||
6550 | |||
6551 | /// return whether the iterator is at end | ||
6552 | constexpr bool is_end() const noexcept | ||
6553 | { | ||
6554 | return (m_it == end_value); | ||
6555 | } | ||
6556 | |||
6557 | /// return reference to the value to change and compare | ||
6558 | operator difference_type& () noexcept | ||
6559 | { | ||
6560 | return m_it; | ||
6561 | } | ||
6562 | |||
6563 | /// return value to compare | ||
6564 | constexpr operator difference_type () const noexcept | ||
6565 | { | ||
6566 | return m_it; | ||
6567 | } | ||
6568 | |||
6569 | private: | ||
6570 | static constexpr difference_type begin_value = 0; | ||
6571 | static constexpr difference_type end_value = begin_value + 1; | ||
6572 | |||
6573 | /// iterator as signed integer type | ||
6574 | difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min(); | ||
6575 | }; | ||
6576 | |||
6577 | /*! | ||
6578 | @brief an iterator value | ||
6579 | |||
6580 | @note This structure could easily be a union, but MSVC currently does not | ||
6581 | allow unions members with complex constructors, see | ||
6582 | https://github.com/nlohmann/json/pull/105. | ||
6583 | */ | ||
6584 | struct internal_iterator | ||
6585 | { | ||
6586 | /// iterator for JSON objects | ||
6587 | typename object_t::iterator object_iterator; | ||
6588 | /// iterator for JSON arrays | ||
6589 | typename array_t::iterator array_iterator; | ||
6590 | /// generic iterator for all other types | ||
6591 | primitive_iterator_t primitive_iterator; | ||
6592 | |||
6593 | /// create an uninitialized internal_iterator | ||
6594 | internal_iterator() noexcept | ||
6595 | : object_iterator(), array_iterator(), primitive_iterator() | ||
6596 | {} | ||
6597 | }; | ||
6598 | |||
6599 | /// proxy class for the iterator_wrapper functions | ||
6600 | template<typename IteratorType> | ||
6601 | class iteration_proxy | ||
6602 | { | ||
6603 | private: | ||
6604 | /// helper class for iteration | ||
6605 | class iteration_proxy_internal | ||
6606 | { | ||
6607 | private: | ||
6608 | /// the iterator | ||
6609 | IteratorType anchor; | ||
6610 | /// an index for arrays (used to create key names) | ||
6611 | size_t array_index = 0; | ||
6612 | |||
6613 | public: | ||
6614 | explicit iteration_proxy_internal(IteratorType it) noexcept | ||
6615 | : anchor(it) | ||
6616 | {} | ||
6617 | |||
6618 | /// dereference operator (needed for range-based for) | ||
6619 | iteration_proxy_internal& operator*() | ||
6620 | { | ||
6621 | return *this; | ||
6622 | } | ||
6623 | |||
6624 | /// increment operator (needed for range-based for) | ||
6625 | iteration_proxy_internal& operator++() | ||
6626 | { | ||
6627 | ++anchor; | ||
6628 | ++array_index; | ||
6629 | |||
6630 | return *this; | ||
6631 | } | ||
6632 | |||
6633 | /// inequality operator (needed for range-based for) | ||
6634 | bool operator!= (const iteration_proxy_internal& o) const | ||
6635 | { | ||
6636 | return anchor != o.anchor; | ||
6637 | } | ||
6638 | |||
6639 | /// return key of the iterator | ||
6640 | typename basic_json::string_t key() const | ||
6641 | { | ||
6642 | assert(anchor.m_object != nullptr); | ||
6643 | |||
6644 | switch (anchor.m_object->type()) | ||
6645 | { | ||
6646 | // use integer array index as key | ||
6647 | case value_t::array: | ||
6648 | { | ||
6649 | return std::to_string(array_index); | ||
6650 | } | ||
6651 | |||
6652 | // use key from the object | ||
6653 | case value_t::object: | ||
6654 | { | ||
6655 | return anchor.key(); | ||
6656 | } | ||
6657 | |||
6658 | // use an empty key for all primitive types | ||
6659 | default: | ||
6660 | { | ||
6661 | return ""; | ||
6662 | } | ||
6663 | } | ||
6664 | } | ||
6665 | |||
6666 | /// return value of the iterator | ||
6667 | typename IteratorType::reference value() const | ||
6668 | { | ||
6669 | return anchor.value(); | ||
6670 | } | ||
6671 | }; | ||
6672 | |||
6673 | /// the container to iterate | ||
6674 | typename IteratorType::reference container; | ||
6675 | |||
6676 | public: | ||
6677 | /// construct iteration proxy from a container | ||
6678 | explicit iteration_proxy(typename IteratorType::reference cont) | ||
6679 | : container(cont) | ||
6680 | {} | ||
6681 | |||
6682 | /// return iterator begin (needed for range-based for) | ||
6683 | iteration_proxy_internal begin() noexcept | ||
6684 | { | ||
6685 | return iteration_proxy_internal(container.begin()); | ||
6686 | } | ||
6687 | |||
6688 | /// return iterator end (needed for range-based for) | ||
6689 | iteration_proxy_internal end() noexcept | ||
6690 | { | ||
6691 | return iteration_proxy_internal(container.end()); | ||
6692 | } | ||
6693 | }; | ||
6694 | |||
6695 | public: | ||
6696 | /*! | ||
6697 | @brief a const random access iterator for the @ref basic_json class | ||
6698 | |||
6699 | This class implements a const iterator for the @ref basic_json class. From | ||
6700 | this class, the @ref iterator class is derived. | ||
6701 | |||
6702 | @note An iterator is called *initialized* when a pointer to a JSON value | ||
6703 | has been set (e.g., by a constructor or a copy assignment). If the | ||
6704 | iterator is default-constructed, it is *uninitialized* and most | ||
6705 | methods are undefined. **The library uses assertions to detect calls | ||
6706 | on uninitialized iterators.** | ||
6707 | |||
6708 | @requirement The class satisfies the following concept requirements: | ||
6709 | - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): | ||
6710 | The iterator that can be moved to point (forward and backward) to any | ||
6711 | element in constant time. | ||
6712 | |||
6713 | @since version 1.0.0 | ||
6714 | */ | ||
6715 | class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json> | ||
6716 | { | ||
6717 | /// allow basic_json to access private members | ||
6718 | friend class basic_json; | ||
6719 | |||
6720 | public: | ||
6721 | /// the type of the values when the iterator is dereferenced | ||
6722 | using value_type = typename basic_json::value_type; | ||
6723 | /// a type to represent differences between iterators | ||
6724 | using difference_type = typename basic_json::difference_type; | ||
6725 | /// defines a pointer to the type iterated over (value_type) | ||
6726 | using pointer = typename basic_json::const_pointer; | ||
6727 | /// defines a reference to the type iterated over (value_type) | ||
6728 | using reference = typename basic_json::const_reference; | ||
6729 | /// the category of the iterator | ||
6730 | using iterator_category = std::bidirectional_iterator_tag; | ||
6731 | |||
6732 | /// default constructor | ||
6733 | const_iterator() = default; | ||
6734 | |||
6735 | /*! | ||
6736 | @brief constructor for a given JSON instance | ||
6737 | @param[in] object pointer to a JSON object for this iterator | ||
6738 | @pre object != nullptr | ||
6739 | @post The iterator is initialized; i.e. `m_object != nullptr`. | ||
6740 | */ | ||
6741 | explicit const_iterator(pointer object) noexcept | ||
6742 | : m_object(object) | ||
6743 | { | ||
6744 | assert(m_object != nullptr); | ||
6745 | |||
6746 | switch (m_object->m_type) | ||
6747 | { | ||
6748 | case basic_json::value_t::object: | ||
6749 | { | ||
6750 | m_it.object_iterator = typename object_t::iterator(); | ||
6751 | break; | ||
6752 | } | ||
6753 | |||
6754 | case basic_json::value_t::array: | ||
6755 | { | ||
6756 | m_it.array_iterator = typename array_t::iterator(); | ||
6757 | break; | ||
6758 | } | ||
6759 | |||
6760 | default: | ||
6761 | { | ||
6762 | m_it.primitive_iterator = primitive_iterator_t(); | ||
6763 | break; | ||
6764 | } | ||
6765 | } | ||
6766 | } | ||
6767 | |||
6768 | /*! | ||
6769 | @brief copy constructor given a non-const iterator | ||
6770 | @param[in] other iterator to copy from | ||
6771 | @note It is not checked whether @a other is initialized. | ||
6772 | */ | ||
6773 | explicit const_iterator(const iterator& other) noexcept | ||
6774 | : m_object(other.m_object) | ||
6775 | { | ||
6776 | if (m_object != nullptr) | ||
6777 | { | ||
6778 | switch (m_object->m_type) | ||
6779 | { | ||
6780 | case basic_json::value_t::object: | ||
6781 | { | ||
6782 | m_it.object_iterator = other.m_it.object_iterator; | ||
6783 | break; | ||
6784 | } | ||
6785 | |||
6786 | case basic_json::value_t::array: | ||
6787 | { | ||
6788 | m_it.array_iterator = other.m_it.array_iterator; | ||
6789 | break; | ||
6790 | } | ||
6791 | |||
6792 | default: | ||
6793 | { | ||
6794 | m_it.primitive_iterator = other.m_it.primitive_iterator; | ||
6795 | break; | ||
6796 | } | ||
6797 | } | ||
6798 | } | ||
6799 | } | ||
6800 | |||
6801 | /*! | ||
6802 | @brief copy constructor | ||
6803 | @param[in] other iterator to copy from | ||
6804 | @note It is not checked whether @a other is initialized. | ||
6805 | */ | ||
6806 | const_iterator(const const_iterator& other) noexcept | ||
6807 | : m_object(other.m_object), m_it(other.m_it) | ||
6808 | {} | ||
6809 | |||
6810 | /*! | ||
6811 | @brief copy assignment | ||
6812 | @param[in,out] other iterator to copy from | ||
6813 | @note It is not checked whether @a other is initialized. | ||
6814 | */ | ||
6815 | const_iterator& operator=(const_iterator other) noexcept( | ||
6816 | std::is_nothrow_move_constructible<pointer>::value and | ||
6817 | std::is_nothrow_move_assignable<pointer>::value and | ||
6818 | std::is_nothrow_move_constructible<internal_iterator>::value and | ||
6819 | std::is_nothrow_move_assignable<internal_iterator>::value | ||
6820 | ) | ||
6821 | { | ||
6822 | std::swap(m_object, other.m_object); | ||
6823 | std::swap(m_it, other.m_it); | ||
6824 | return *this; | ||
6825 | } | ||
6826 | |||
6827 | private: | ||
6828 | /*! | ||
6829 | @brief set the iterator to the first value | ||
6830 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
6831 | */ | ||
6832 | void set_begin() noexcept | ||
6833 | { | ||
6834 | assert(m_object != nullptr); | ||
6835 | |||
6836 | switch (m_object->m_type) | ||
6837 | { | ||
6838 | case basic_json::value_t::object: | ||
6839 | { | ||
6840 | m_it.object_iterator = m_object->m_value.object->begin(); | ||
6841 | break; | ||
6842 | } | ||
6843 | |||
6844 | case basic_json::value_t::array: | ||
6845 | { | ||
6846 | m_it.array_iterator = m_object->m_value.array->begin(); | ||
6847 | break; | ||
6848 | } | ||
6849 | |||
6850 | case basic_json::value_t::null: | ||
6851 | { | ||
6852 | // set to end so begin()==end() is true: null is empty | ||
6853 | m_it.primitive_iterator.set_end(); | ||
6854 | break; | ||
6855 | } | ||
6856 | |||
6857 | default: | ||
6858 | { | ||
6859 | m_it.primitive_iterator.set_begin(); | ||
6860 | break; | ||
6861 | } | ||
6862 | } | ||
6863 | } | ||
6864 | |||
6865 | /*! | ||
6866 | @brief set the iterator past the last value | ||
6867 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
6868 | */ | ||
6869 | void set_end() noexcept | ||
6870 | { | ||
6871 | assert(m_object != nullptr); | ||
6872 | |||
6873 | switch (m_object->m_type) | ||
6874 | { | ||
6875 | case basic_json::value_t::object: | ||
6876 | { | ||
6877 | m_it.object_iterator = m_object->m_value.object->end(); | ||
6878 | break; | ||
6879 | } | ||
6880 | |||
6881 | case basic_json::value_t::array: | ||
6882 | { | ||
6883 | m_it.array_iterator = m_object->m_value.array->end(); | ||
6884 | break; | ||
6885 | } | ||
6886 | |||
6887 | default: | ||
6888 | { | ||
6889 | m_it.primitive_iterator.set_end(); | ||
6890 | break; | ||
6891 | } | ||
6892 | } | ||
6893 | } | ||
6894 | |||
6895 | public: | ||
6896 | /*! | ||
6897 | @brief return a reference to the value pointed to by the iterator | ||
6898 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
6899 | */ | ||
6900 | reference operator*() const | ||
6901 | { | ||
6902 | assert(m_object != nullptr); | ||
6903 | |||
6904 | switch (m_object->m_type) | ||
6905 | { | ||
6906 | case basic_json::value_t::object: | ||
6907 | { | ||
6908 | assert(m_it.object_iterator != m_object->m_value.object->end()); | ||
6909 | return m_it.object_iterator->second; | ||
6910 | } | ||
6911 | |||
6912 | case basic_json::value_t::array: | ||
6913 | { | ||
6914 | assert(m_it.array_iterator != m_object->m_value.array->end()); | ||
6915 | return *m_it.array_iterator; | ||
6916 | } | ||
6917 | |||
6918 | case basic_json::value_t::null: | ||
6919 | { | ||
6920 | throw std::out_of_range("cannot get value"); | ||
6921 | } | ||
6922 | |||
6923 | default: | ||
6924 | { | ||
6925 | if (m_it.primitive_iterator.is_begin()) | ||
6926 | { | ||
6927 | return *m_object; | ||
6928 | } | ||
6929 | else | ||
6930 | { | ||
6931 | throw std::out_of_range("cannot get value"); | ||
6932 | } | ||
6933 | } | ||
6934 | } | ||
6935 | } | ||
6936 | |||
6937 | /*! | ||
6938 | @brief dereference the iterator | ||
6939 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
6940 | */ | ||
6941 | pointer operator->() const | ||
6942 | { | ||
6943 | assert(m_object != nullptr); | ||
6944 | |||
6945 | switch (m_object->m_type) | ||
6946 | { | ||
6947 | case basic_json::value_t::object: | ||
6948 | { | ||
6949 | assert(m_it.object_iterator != m_object->m_value.object->end()); | ||
6950 | return &(m_it.object_iterator->second); | ||
6951 | } | ||
6952 | |||
6953 | case basic_json::value_t::array: | ||
6954 | { | ||
6955 | assert(m_it.array_iterator != m_object->m_value.array->end()); | ||
6956 | return &*m_it.array_iterator; | ||
6957 | } | ||
6958 | |||
6959 | default: | ||
6960 | { | ||
6961 | if (m_it.primitive_iterator.is_begin()) | ||
6962 | { | ||
6963 | return m_object; | ||
6964 | } | ||
6965 | else | ||
6966 | { | ||
6967 | throw std::out_of_range("cannot get value"); | ||
6968 | } | ||
6969 | } | ||
6970 | } | ||
6971 | } | ||
6972 | |||
6973 | /*! | ||
6974 | @brief post-increment (it++) | ||
6975 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
6976 | */ | ||
6977 | const_iterator operator++(int) | ||
6978 | { | ||
6979 | auto result = *this; | ||
6980 | ++(*this); | ||
6981 | return result; | ||
6982 | } | ||
6983 | |||
6984 | /*! | ||
6985 | @brief pre-increment (++it) | ||
6986 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
6987 | */ | ||
6988 | const_iterator& operator++() | ||
6989 | { | ||
6990 | assert(m_object != nullptr); | ||
6991 | |||
6992 | switch (m_object->m_type) | ||
6993 | { | ||
6994 | case basic_json::value_t::object: | ||
6995 | { | ||
6996 | std::advance(m_it.object_iterator, 1); | ||
6997 | break; | ||
6998 | } | ||
6999 | |||
7000 | case basic_json::value_t::array: | ||
7001 | { | ||
7002 | std::advance(m_it.array_iterator, 1); | ||
7003 | break; | ||
7004 | } | ||
7005 | |||
7006 | default: | ||
7007 | { | ||
7008 | ++m_it.primitive_iterator; | ||
7009 | break; | ||
7010 | } | ||
7011 | } | ||
7012 | |||
7013 | return *this; | ||
7014 | } | ||
7015 | |||
7016 | /*! | ||
7017 | @brief post-decrement (it--) | ||
7018 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7019 | */ | ||
7020 | const_iterator operator--(int) | ||
7021 | { | ||
7022 | auto result = *this; | ||
7023 | --(*this); | ||
7024 | return result; | ||
7025 | } | ||
7026 | |||
7027 | /*! | ||
7028 | @brief pre-decrement (--it) | ||
7029 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7030 | */ | ||
7031 | const_iterator& operator--() | ||
7032 | { | ||
7033 | assert(m_object != nullptr); | ||
7034 | |||
7035 | switch (m_object->m_type) | ||
7036 | { | ||
7037 | case basic_json::value_t::object: | ||
7038 | { | ||
7039 | std::advance(m_it.object_iterator, -1); | ||
7040 | break; | ||
7041 | } | ||
7042 | |||
7043 | case basic_json::value_t::array: | ||
7044 | { | ||
7045 | std::advance(m_it.array_iterator, -1); | ||
7046 | break; | ||
7047 | } | ||
7048 | |||
7049 | default: | ||
7050 | { | ||
7051 | --m_it.primitive_iterator; | ||
7052 | break; | ||
7053 | } | ||
7054 | } | ||
7055 | |||
7056 | return *this; | ||
7057 | } | ||
7058 | |||
7059 | /*! | ||
7060 | @brief comparison: equal | ||
7061 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7062 | */ | ||
7063 | bool operator==(const const_iterator& other) const | ||
7064 | { | ||
7065 | // if objects are not the same, the comparison is undefined | ||
7066 | if (m_object != other.m_object) | ||
7067 | { | ||
7068 | throw std::domain_error("cannot compare iterators of different containers"); | ||
7069 | } | ||
7070 | |||
7071 | assert(m_object != nullptr); | ||
7072 | |||
7073 | switch (m_object->m_type) | ||
7074 | { | ||
7075 | case basic_json::value_t::object: | ||
7076 | { | ||
7077 | return (m_it.object_iterator == other.m_it.object_iterator); | ||
7078 | } | ||
7079 | |||
7080 | case basic_json::value_t::array: | ||
7081 | { | ||
7082 | return (m_it.array_iterator == other.m_it.array_iterator); | ||
7083 | } | ||
7084 | |||
7085 | default: | ||
7086 | { | ||
7087 | return (m_it.primitive_iterator == other.m_it.primitive_iterator); | ||
7088 | } | ||
7089 | } | ||
7090 | } | ||
7091 | |||
7092 | /*! | ||
7093 | @brief comparison: not equal | ||
7094 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7095 | */ | ||
7096 | bool operator!=(const const_iterator& other) const | ||
7097 | { | ||
7098 | return not operator==(other); | ||
7099 | } | ||
7100 | |||
7101 | /*! | ||
7102 | @brief comparison: smaller | ||
7103 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7104 | */ | ||
7105 | bool operator<(const const_iterator& other) const | ||
7106 | { | ||
7107 | // if objects are not the same, the comparison is undefined | ||
7108 | if (m_object != other.m_object) | ||
7109 | { | ||
7110 | throw std::domain_error("cannot compare iterators of different containers"); | ||
7111 | } | ||
7112 | |||
7113 | assert(m_object != nullptr); | ||
7114 | |||
7115 | switch (m_object->m_type) | ||
7116 | { | ||
7117 | case basic_json::value_t::object: | ||
7118 | { | ||
7119 | throw std::domain_error("cannot compare order of object iterators"); | ||
7120 | } | ||
7121 | |||
7122 | case basic_json::value_t::array: | ||
7123 | { | ||
7124 | return (m_it.array_iterator < other.m_it.array_iterator); | ||
7125 | } | ||
7126 | |||
7127 | default: | ||
7128 | { | ||
7129 | return (m_it.primitive_iterator < other.m_it.primitive_iterator); | ||
7130 | } | ||
7131 | } | ||
7132 | } | ||
7133 | |||
7134 | /*! | ||
7135 | @brief comparison: less than or equal | ||
7136 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7137 | */ | ||
7138 | bool operator<=(const const_iterator& other) const | ||
7139 | { | ||
7140 | return not other.operator < (*this); | ||
7141 | } | ||
7142 | |||
7143 | /*! | ||
7144 | @brief comparison: greater than | ||
7145 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7146 | */ | ||
7147 | bool operator>(const const_iterator& other) const | ||
7148 | { | ||
7149 | return not operator<=(other); | ||
7150 | } | ||
7151 | |||
7152 | /*! | ||
7153 | @brief comparison: greater than or equal | ||
7154 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7155 | */ | ||
7156 | bool operator>=(const const_iterator& other) const | ||
7157 | { | ||
7158 | return not operator<(other); | ||
7159 | } | ||
7160 | |||
7161 | /*! | ||
7162 | @brief add to iterator | ||
7163 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7164 | */ | ||
7165 | const_iterator& operator+=(difference_type i) | ||
7166 | { | ||
7167 | assert(m_object != nullptr); | ||
7168 | |||
7169 | switch (m_object->m_type) | ||
7170 | { | ||
7171 | case basic_json::value_t::object: | ||
7172 | { | ||
7173 | throw std::domain_error("cannot use offsets with object iterators"); | ||
7174 | } | ||
7175 | |||
7176 | case basic_json::value_t::array: | ||
7177 | { | ||
7178 | std::advance(m_it.array_iterator, i); | ||
7179 | break; | ||
7180 | } | ||
7181 | |||
7182 | default: | ||
7183 | { | ||
7184 | m_it.primitive_iterator += i; | ||
7185 | break; | ||
7186 | } | ||
7187 | } | ||
7188 | |||
7189 | return *this; | ||
7190 | } | ||
7191 | |||
7192 | /*! | ||
7193 | @brief subtract from iterator | ||
7194 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7195 | */ | ||
7196 | const_iterator& operator-=(difference_type i) | ||
7197 | { | ||
7198 | return operator+=(-i); | ||
7199 | } | ||
7200 | |||
7201 | /*! | ||
7202 | @brief add to iterator | ||
7203 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7204 | */ | ||
7205 | const_iterator operator+(difference_type i) | ||
7206 | { | ||
7207 | auto result = *this; | ||
7208 | result += i; | ||
7209 | return result; | ||
7210 | } | ||
7211 | |||
7212 | /*! | ||
7213 | @brief subtract from iterator | ||
7214 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7215 | */ | ||
7216 | const_iterator operator-(difference_type i) | ||
7217 | { | ||
7218 | auto result = *this; | ||
7219 | result -= i; | ||
7220 | return result; | ||
7221 | } | ||
7222 | |||
7223 | /*! | ||
7224 | @brief return difference | ||
7225 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7226 | */ | ||
7227 | difference_type operator-(const const_iterator& other) const | ||
7228 | { | ||
7229 | assert(m_object != nullptr); | ||
7230 | |||
7231 | switch (m_object->m_type) | ||
7232 | { | ||
7233 | case basic_json::value_t::object: | ||
7234 | { | ||
7235 | throw std::domain_error("cannot use offsets with object iterators"); | ||
7236 | } | ||
7237 | |||
7238 | case basic_json::value_t::array: | ||
7239 | { | ||
7240 | return m_it.array_iterator - other.m_it.array_iterator; | ||
7241 | } | ||
7242 | |||
7243 | default: | ||
7244 | { | ||
7245 | return m_it.primitive_iterator - other.m_it.primitive_iterator; | ||
7246 | } | ||
7247 | } | ||
7248 | } | ||
7249 | |||
7250 | /*! | ||
7251 | @brief access to successor | ||
7252 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7253 | */ | ||
7254 | reference operator[](difference_type n) const | ||
7255 | { | ||
7256 | assert(m_object != nullptr); | ||
7257 | |||
7258 | switch (m_object->m_type) | ||
7259 | { | ||
7260 | case basic_json::value_t::object: | ||
7261 | { | ||
7262 | throw std::domain_error("cannot use operator[] for object iterators"); | ||
7263 | } | ||
7264 | |||
7265 | case basic_json::value_t::array: | ||
7266 | { | ||
7267 | return *std::next(m_it.array_iterator, n); | ||
7268 | } | ||
7269 | |||
7270 | case basic_json::value_t::null: | ||
7271 | { | ||
7272 | throw std::out_of_range("cannot get value"); | ||
7273 | } | ||
7274 | |||
7275 | default: | ||
7276 | { | ||
7277 | if (m_it.primitive_iterator == -n) | ||
7278 | { | ||
7279 | return *m_object; | ||
7280 | } | ||
7281 | else | ||
7282 | { | ||
7283 | throw std::out_of_range("cannot get value"); | ||
7284 | } | ||
7285 | } | ||
7286 | } | ||
7287 | } | ||
7288 | |||
7289 | /*! | ||
7290 | @brief return the key of an object iterator | ||
7291 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7292 | */ | ||
7293 | typename object_t::key_type key() const | ||
7294 | { | ||
7295 | assert(m_object != nullptr); | ||
7296 | |||
7297 | if (m_object->is_object()) | ||
7298 | { | ||
7299 | return m_it.object_iterator->first; | ||
7300 | } | ||
7301 | else | ||
7302 | { | ||
7303 | throw std::domain_error("cannot use key() for non-object iterators"); | ||
7304 | } | ||
7305 | } | ||
7306 | |||
7307 | /*! | ||
7308 | @brief return the value of an iterator | ||
7309 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | ||
7310 | */ | ||
7311 | reference value() const | ||
7312 | { | ||
7313 | return operator*(); | ||
7314 | } | ||
7315 | |||
7316 | private: | ||
7317 | /// associated JSON instance | ||
7318 | pointer m_object = nullptr; | ||
7319 | /// the actual iterator of the associated instance | ||
7320 | internal_iterator m_it = internal_iterator(); | ||
7321 | }; | ||
7322 | |||
7323 | /*! | ||
7324 | @brief a mutable random access iterator for the @ref basic_json class | ||
7325 | |||
7326 | @requirement The class satisfies the following concept requirements: | ||
7327 | - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): | ||
7328 | The iterator that can be moved to point (forward and backward) to any | ||
7329 | element in constant time. | ||
7330 | - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): | ||
7331 | It is possible to write to the pointed-to element. | ||
7332 | |||
7333 | @since version 1.0.0 | ||
7334 | */ | ||
7335 | class iterator : public const_iterator | ||
7336 | { | ||
7337 | public: | ||
7338 | using base_iterator = const_iterator; | ||
7339 | using pointer = typename basic_json::pointer; | ||
7340 | using reference = typename basic_json::reference; | ||
7341 | |||
7342 | /// default constructor | ||
7343 | iterator() = default; | ||
7344 | |||
7345 | /// constructor for a given JSON instance | ||
7346 | explicit iterator(pointer object) noexcept | ||
7347 | : base_iterator(object) | ||
7348 | {} | ||
7349 | |||
7350 | /// copy constructor | ||
7351 | iterator(const iterator& other) noexcept | ||
7352 | : base_iterator(other) | ||
7353 | {} | ||
7354 | |||
7355 | /// copy assignment | ||
7356 | iterator& operator=(iterator other) noexcept( | ||
7357 | std::is_nothrow_move_constructible<pointer>::value and | ||
7358 | std::is_nothrow_move_assignable<pointer>::value and | ||
7359 | std::is_nothrow_move_constructible<internal_iterator>::value and | ||
7360 | std::is_nothrow_move_assignable<internal_iterator>::value | ||
7361 | ) | ||
7362 | { | ||
7363 | base_iterator::operator=(other); | ||
7364 | return *this; | ||
7365 | } | ||
7366 | |||
7367 | /// return a reference to the value pointed to by the iterator | ||
7368 | reference operator*() const | ||
7369 | { | ||
7370 | return const_cast<reference>(base_iterator::operator*()); | ||
7371 | } | ||
7372 | |||
7373 | /// dereference the iterator | ||
7374 | pointer operator->() const | ||
7375 | { | ||
7376 | return const_cast<pointer>(base_iterator::operator->()); | ||
7377 | } | ||
7378 | |||
7379 | /// post-increment (it++) | ||
7380 | iterator operator++(int) | ||
7381 | { | ||
7382 | iterator result = *this; | ||
7383 | base_iterator::operator++(); | ||
7384 | return result; | ||
7385 | } | ||
7386 | |||
7387 | /// pre-increment (++it) | ||
7388 | iterator& operator++() | ||
7389 | { | ||
7390 | base_iterator::operator++(); | ||
7391 | return *this; | ||
7392 | } | ||
7393 | |||
7394 | /// post-decrement (it--) | ||
7395 | iterator operator--(int) | ||
7396 | { | ||
7397 | iterator result = *this; | ||
7398 | base_iterator::operator--(); | ||
7399 | return result; | ||
7400 | } | ||
7401 | |||
7402 | /// pre-decrement (--it) | ||
7403 | iterator& operator--() | ||
7404 | { | ||
7405 | base_iterator::operator--(); | ||
7406 | return *this; | ||
7407 | } | ||
7408 | |||
7409 | /// add to iterator | ||
7410 | iterator& operator+=(difference_type i) | ||
7411 | { | ||
7412 | base_iterator::operator+=(i); | ||
7413 | return *this; | ||
7414 | } | ||
7415 | |||
7416 | /// subtract from iterator | ||
7417 | iterator& operator-=(difference_type i) | ||
7418 | { | ||
7419 | base_iterator::operator-=(i); | ||
7420 | return *this; | ||
7421 | } | ||
7422 | |||
7423 | /// add to iterator | ||
7424 | iterator operator+(difference_type i) | ||
7425 | { | ||
7426 | auto result = *this; | ||
7427 | result += i; | ||
7428 | return result; | ||
7429 | } | ||
7430 | |||
7431 | /// subtract from iterator | ||
7432 | iterator operator-(difference_type i) | ||
7433 | { | ||
7434 | auto result = *this; | ||
7435 | result -= i; | ||
7436 | return result; | ||
7437 | } | ||
7438 | |||
7439 | /// return difference | ||
7440 | difference_type operator-(const iterator& other) const | ||
7441 | { | ||
7442 | return base_iterator::operator-(other); | ||
7443 | } | ||
7444 | |||
7445 | /// access to successor | ||
7446 | reference operator[](difference_type n) const | ||
7447 | { | ||
7448 | return const_cast<reference>(base_iterator::operator[](n)); | ||
7449 | } | ||
7450 | |||
7451 | /// return the value of an iterator | ||
7452 | reference value() const | ||
7453 | { | ||
7454 | return const_cast<reference>(base_iterator::value()); | ||
7455 | } | ||
7456 | }; | ||
7457 | |||
7458 | /*! | ||
7459 | @brief a template for a reverse iterator class | ||
7460 | |||
7461 | @tparam Base the base iterator type to reverse. Valid types are @ref | ||
7462 | iterator (to create @ref reverse_iterator) and @ref const_iterator (to | ||
7463 | create @ref const_reverse_iterator). | ||
7464 | |||
7465 | @requirement The class satisfies the following concept requirements: | ||
7466 | - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): | ||
7467 | The iterator that can be moved to point (forward and backward) to any | ||
7468 | element in constant time. | ||
7469 | - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): | ||
7470 | It is possible to write to the pointed-to element (only if @a Base is | ||
7471 | @ref iterator). | ||
7472 | |||
7473 | @since version 1.0.0 | ||
7474 | */ | ||
7475 | template<typename Base> | ||
7476 | class json_reverse_iterator : public std::reverse_iterator<Base> | ||
7477 | { | ||
7478 | public: | ||
7479 | /// shortcut to the reverse iterator adaptor | ||
7480 | using base_iterator = std::reverse_iterator<Base>; | ||
7481 | /// the reference type for the pointed-to element | ||
7482 | using reference = typename Base::reference; | ||
7483 | |||
7484 | /// create reverse iterator from iterator | ||
7485 | json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept | ||
7486 | : base_iterator(it) | ||
7487 | {} | ||
7488 | |||
7489 | /// create reverse iterator from base class | ||
7490 | json_reverse_iterator(const base_iterator& it) noexcept | ||
7491 | : base_iterator(it) | ||
7492 | {} | ||
7493 | |||
7494 | /// post-increment (it++) | ||
7495 | json_reverse_iterator operator++(int) | ||
7496 | { | ||
7497 | return base_iterator::operator++(1); | ||
7498 | } | ||
7499 | |||
7500 | /// pre-increment (++it) | ||
7501 | json_reverse_iterator& operator++() | ||
7502 | { | ||
7503 | base_iterator::operator++(); | ||
7504 | return *this; | ||
7505 | } | ||
7506 | |||
7507 | /// post-decrement (it--) | ||
7508 | json_reverse_iterator operator--(int) | ||
7509 | { | ||
7510 | return base_iterator::operator--(1); | ||
7511 | } | ||
7512 | |||
7513 | /// pre-decrement (--it) | ||
7514 | json_reverse_iterator& operator--() | ||
7515 | { | ||
7516 | base_iterator::operator--(); | ||
7517 | return *this; | ||
7518 | } | ||
7519 | |||
7520 | /// add to iterator | ||
7521 | json_reverse_iterator& operator+=(difference_type i) | ||
7522 | { | ||
7523 | base_iterator::operator+=(i); | ||
7524 | return *this; | ||
7525 | } | ||
7526 | |||
7527 | /// add to iterator | ||
7528 | json_reverse_iterator operator+(difference_type i) const | ||
7529 | { | ||
7530 | auto result = *this; | ||
7531 | result += i; | ||
7532 | return result; | ||
7533 | } | ||
7534 | |||
7535 | /// subtract from iterator | ||
7536 | json_reverse_iterator operator-(difference_type i) const | ||
7537 | { | ||
7538 | auto result = *this; | ||
7539 | result -= i; | ||
7540 | return result; | ||
7541 | } | ||
7542 | |||
7543 | /// return difference | ||
7544 | difference_type operator-(const json_reverse_iterator& other) const | ||
7545 | { | ||
7546 | return this->base() - other.base(); | ||
7547 | } | ||
7548 | |||
7549 | /// access to successor | ||
7550 | reference operator[](difference_type n) const | ||
7551 | { | ||
7552 | return *(this->operator+(n)); | ||
7553 | } | ||
7554 | |||
7555 | /// return the key of an object iterator | ||
7556 | typename object_t::key_type key() const | ||
7557 | { | ||
7558 | auto it = --this->base(); | ||
7559 | return it.key(); | ||
7560 | } | ||
7561 | |||
7562 | /// return the value of an iterator | ||
7563 | reference value() const | ||
7564 | { | ||
7565 | auto it = --this->base(); | ||
7566 | return it.operator * (); | ||
7567 | } | ||
7568 | }; | ||
7569 | |||
7570 | |||
7571 | private: | ||
7572 | ////////////////////// | ||
7573 | // lexer and parser // | ||
7574 | ////////////////////// | ||
7575 | |||
7576 | /*! | ||
7577 | @brief lexical analysis | ||
7578 | |||
7579 | This class organizes the lexical analysis during JSON deserialization. The | ||
7580 | core of it is a scanner generated by [re2c](http://re2c.org) that | ||
7581 | processes a buffer and recognizes tokens according to RFC 7159. | ||
7582 | */ | ||
7583 | class lexer | ||
7584 | { | ||
7585 | public: | ||
7586 | /// token types for the parser | ||
7587 | enum class token_type | ||
7588 | { | ||
7589 | uninitialized, ///< indicating the scanner is uninitialized | ||
7590 | literal_true, ///< the `true` literal | ||
7591 | literal_false, ///< the `false` literal | ||
7592 | literal_null, ///< the `null` literal | ||
7593 | value_string, ///< a string -- use get_string() for actual value | ||
7594 | value_number, ///< a number -- use get_number() for actual value | ||
7595 | begin_array, ///< the character for array begin `[` | ||
7596 | begin_object, ///< the character for object begin `{` | ||
7597 | end_array, ///< the character for array end `]` | ||
7598 | end_object, ///< the character for object end `}` | ||
7599 | name_separator, ///< the name separator `:` | ||
7600 | value_separator, ///< the value separator `,` | ||
7601 | parse_error, ///< indicating a parse error | ||
7602 | end_of_input ///< indicating the end of the input buffer | ||
7603 | }; | ||
7604 | |||
7605 | /// the char type to use in the lexer | ||
7606 | using lexer_char_t = unsigned char; | ||
7607 | |||
7608 | /// a lexer from a buffer with given length | ||
7609 | lexer(const lexer_char_t* buff, const size_t len) noexcept | ||
7610 | : m_content(buff) | ||
7611 | { | ||
7612 | assert(m_content != nullptr); | ||
7613 | m_start = m_cursor = m_content; | ||
7614 | m_limit = m_content + len; | ||
7615 | } | ||
7616 | |||
7617 | /// a lexer from an input stream | ||
7618 | explicit lexer(std::istream& s) | ||
7619 | : m_stream(&s), m_line_buffer() | ||
7620 | { | ||
7621 | // fill buffer | ||
7622 | fill_line_buffer(); | ||
7623 | |||
7624 | // skip UTF-8 byte-order mark | ||
7625 | if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF") | ||
7626 | { | ||
7627 | m_line_buffer[0] = ' '; | ||
7628 | m_line_buffer[1] = ' '; | ||
7629 | m_line_buffer[2] = ' '; | ||
7630 | } | ||
7631 | } | ||
7632 | |||
7633 | // switch off unwanted functions (due to pointer members) | ||
7634 | lexer() = delete; | ||
7635 | lexer(const lexer&) = delete; | ||
7636 | lexer operator=(const lexer&) = delete; | ||
7637 | |||
7638 | /*! | ||
7639 | @brief create a string from one or two Unicode code points | ||
7640 | |||
7641 | There are two cases: (1) @a codepoint1 is in the Basic Multilingual | ||
7642 | Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2) | ||
7643 | @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to | ||
7644 | represent a code point above U+FFFF. | ||
7645 | |||
7646 | @param[in] codepoint1 the code point (can be high surrogate) | ||
7647 | @param[in] codepoint2 the code point (can be low surrogate or 0) | ||
7648 | |||
7649 | @return string representation of the code point; the length of the | ||
7650 | result string is between 1 and 4 characters. | ||
7651 | |||
7652 | @throw std::out_of_range if code point is > 0x10ffff; example: `"code | ||
7653 | points above 0x10FFFF are invalid"` | ||
7654 | @throw std::invalid_argument if the low surrogate is invalid; example: | ||
7655 | `""missing or wrong low surrogate""` | ||
7656 | |||
7657 | @complexity Constant. | ||
7658 | |||
7659 | @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code> | ||
7660 | */ | ||
7661 | static string_t to_unicode(const std::size_t codepoint1, | ||
7662 | const std::size_t codepoint2 = 0) | ||
7663 | { | ||
7664 | // calculate the code point from the given code points | ||
7665 | std::size_t codepoint = codepoint1; | ||
7666 | |||
7667 | // check if codepoint1 is a high surrogate | ||
7668 | if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) | ||
7669 | { | ||
7670 | // check if codepoint2 is a low surrogate | ||
7671 | if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) | ||
7672 | { | ||
7673 | codepoint = | ||
7674 | // high surrogate occupies the most significant 22 bits | ||
7675 | (codepoint1 << 10) | ||
7676 | // low surrogate occupies the least significant 15 bits | ||
7677 | + codepoint2 | ||
7678 | // there is still the 0xD800, 0xDC00 and 0x10000 noise | ||
7679 | // in the result so we have to subtract with: | ||
7680 | // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 | ||
7681 | - 0x35FDC00; | ||
7682 | } | ||
7683 | else | ||
7684 | { | ||
7685 | throw std::invalid_argument("missing or wrong low surrogate"); | ||
7686 | } | ||
7687 | } | ||
7688 | |||
7689 | string_t result; | ||
7690 | |||
7691 | if (codepoint < 0x80) | ||
7692 | { | ||
7693 | // 1-byte characters: 0xxxxxxx (ASCII) | ||
7694 | result.append(1, static_cast<typename string_t::value_type>(codepoint)); | ||
7695 | } | ||
7696 | else if (codepoint <= 0x7ff) | ||
7697 | { | ||
7698 | // 2-byte characters: 110xxxxx 10xxxxxx | ||
7699 | result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F))); | ||
7700 | result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); | ||
7701 | } | ||
7702 | else if (codepoint <= 0xffff) | ||
7703 | { | ||
7704 | // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx | ||
7705 | result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F))); | ||
7706 | result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F))); | ||
7707 | result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); | ||
7708 | } | ||
7709 | else if (codepoint <= 0x10ffff) | ||
7710 | { | ||
7711 | // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | ||
7712 | result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07))); | ||
7713 | result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F))); | ||
7714 | result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F))); | ||
7715 | result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); | ||
7716 | } | ||
7717 | else | ||
7718 | { | ||
7719 | throw std::out_of_range("code points above 0x10FFFF are invalid"); | ||
7720 | } | ||
7721 | |||
7722 | return result; | ||
7723 | } | ||
7724 | |||
7725 | /// return name of values of type token_type (only used for errors) | ||
7726 | static std::string token_type_name(const token_type t) | ||
7727 | { | ||
7728 | switch (t) | ||
7729 | { | ||
7730 | case token_type::uninitialized: | ||
7731 | return "<uninitialized>"; | ||
7732 | case token_type::literal_true: | ||
7733 | return "true literal"; | ||
7734 | case token_type::literal_false: | ||
7735 | return "false literal"; | ||
7736 | case token_type::literal_null: | ||
7737 | return "null literal"; | ||
7738 | case token_type::value_string: | ||
7739 | return "string literal"; | ||
7740 | case token_type::value_number: | ||
7741 | return "number literal"; | ||
7742 | case token_type::begin_array: | ||
7743 | return "'['"; | ||
7744 | case token_type::begin_object: | ||
7745 | return "'{'"; | ||
7746 | case token_type::end_array: | ||
7747 | return "']'"; | ||
7748 | case token_type::end_object: | ||
7749 | return "'}'"; | ||
7750 | case token_type::name_separator: | ||
7751 | return "':'"; | ||
7752 | case token_type::value_separator: | ||
7753 | return "','"; | ||
7754 | case token_type::parse_error: | ||
7755 | return "<parse error>"; | ||
7756 | case token_type::end_of_input: | ||
7757 | return "end of input"; | ||
7758 | default: | ||
7759 | { | ||
7760 | // catch non-enum values | ||
7761 | return "unknown token"; // LCOV_EXCL_LINE | ||
7762 | } | ||
7763 | } | ||
7764 | } | ||
7765 | |||
7766 | /*! | ||
7767 | This function implements a scanner for JSON. It is specified using | ||
7768 | regular expressions that try to follow RFC 7159 as close as possible. | ||
7769 | These regular expressions are then translated into a minimized | ||
7770 | deterministic finite automaton (DFA) by the tool | ||
7771 | [re2c](http://re2c.org). As a result, the translated code for this | ||
7772 | function consists of a large block of code with `goto` jumps. | ||
7773 | |||
7774 | @return the class of the next token read from the buffer | ||
7775 | |||
7776 | @complexity Linear in the length of the input.\n | ||
7777 | |||
7778 | Proposition: The loop below will always terminate for finite input.\n | ||
7779 | |||
7780 | Proof (by contradiction): Assume a finite input. To loop forever, the | ||
7781 | loop must never hit code with a `break` statement. The only code | ||
7782 | snippets without a `break` statement are the continue statements for | ||
7783 | whitespace and byte-order-marks. To loop forever, the input must be an | ||
7784 | infinite sequence of whitespace or byte-order-marks. This contradicts | ||
7785 | the assumption of finite input, q.e.d. | ||
7786 | */ | ||
7787 | token_type scan() | ||
7788 | { | ||
7789 | while (true) | ||
7790 | { | ||
7791 | // pointer for backtracking information | ||
7792 | m_marker = nullptr; | ||
7793 | |||
7794 | // remember the begin of the token | ||
7795 | m_start = m_cursor; | ||
7796 | assert(m_start != nullptr); | ||
7797 | |||
7798 | |||
7799 | { | ||
7800 | lexer_char_t yych; | ||
7801 | unsigned int yyaccept = 0; | ||
7802 | static const unsigned char yybm[] = | ||
7803 | { | ||
7804 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7805 | 0, 32, 32, 0, 0, 32, 0, 0, | ||
7806 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7807 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7808 | 160, 128, 0, 128, 128, 128, 128, 128, | ||
7809 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7810 | 192, 192, 192, 192, 192, 192, 192, 192, | ||
7811 | 192, 192, 128, 128, 128, 128, 128, 128, | ||
7812 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7813 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7814 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7815 | 128, 128, 128, 128, 0, 128, 128, 128, | ||
7816 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7817 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7818 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7819 | 128, 128, 128, 128, 128, 128, 128, 128, | ||
7820 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7821 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7822 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7823 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7824 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7825 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7826 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7827 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7828 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7829 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7830 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7831 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7832 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7833 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7834 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7835 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
7836 | }; | ||
7837 | if ((m_limit - m_cursor) < 5) | ||
7838 | { | ||
7839 | fill_line_buffer(5); // LCOV_EXCL_LINE | ||
7840 | } | ||
7841 | yych = *m_cursor; | ||
7842 | if (yybm[0 + yych] & 32) | ||
7843 | { | ||
7844 | goto basic_json_parser_6; | ||
7845 | } | ||
7846 | if (yych <= '[') | ||
7847 | { | ||
7848 | if (yych <= '-') | ||
7849 | { | ||
7850 | if (yych <= '"') | ||
7851 | { | ||
7852 | if (yych <= 0x00) | ||
7853 | { | ||
7854 | goto basic_json_parser_2; | ||
7855 | } | ||
7856 | if (yych <= '!') | ||
7857 | { | ||
7858 | goto basic_json_parser_4; | ||
7859 | } | ||
7860 | goto basic_json_parser_9; | ||
7861 | } | ||
7862 | else | ||
7863 | { | ||
7864 | if (yych <= '+') | ||
7865 | { | ||
7866 | goto basic_json_parser_4; | ||
7867 | } | ||
7868 | if (yych <= ',') | ||
7869 | { | ||
7870 | goto basic_json_parser_10; | ||
7871 | } | ||
7872 | goto basic_json_parser_12; | ||
7873 | } | ||
7874 | } | ||
7875 | else | ||
7876 | { | ||
7877 | if (yych <= '9') | ||
7878 | { | ||
7879 | if (yych <= '/') | ||
7880 | { | ||
7881 | goto basic_json_parser_4; | ||
7882 | } | ||
7883 | if (yych <= '0') | ||
7884 | { | ||
7885 | goto basic_json_parser_13; | ||
7886 | } | ||
7887 | goto basic_json_parser_15; | ||
7888 | } | ||
7889 | else | ||
7890 | { | ||
7891 | if (yych <= ':') | ||
7892 | { | ||
7893 | goto basic_json_parser_17; | ||
7894 | } | ||
7895 | if (yych <= 'Z') | ||
7896 | { | ||
7897 | goto basic_json_parser_4; | ||
7898 | } | ||
7899 | goto basic_json_parser_19; | ||
7900 | } | ||
7901 | } | ||
7902 | } | ||
7903 | else | ||
7904 | { | ||
7905 | if (yych <= 'n') | ||
7906 | { | ||
7907 | if (yych <= 'e') | ||
7908 | { | ||
7909 | if (yych == ']') | ||
7910 | { | ||
7911 | goto basic_json_parser_21; | ||
7912 | } | ||
7913 | goto basic_json_parser_4; | ||
7914 | } | ||
7915 | else | ||
7916 | { | ||
7917 | if (yych <= 'f') | ||
7918 | { | ||
7919 | goto basic_json_parser_23; | ||
7920 | } | ||
7921 | if (yych <= 'm') | ||
7922 | { | ||
7923 | goto basic_json_parser_4; | ||
7924 | } | ||
7925 | goto basic_json_parser_24; | ||
7926 | } | ||
7927 | } | ||
7928 | else | ||
7929 | { | ||
7930 | if (yych <= 'z') | ||
7931 | { | ||
7932 | if (yych == 't') | ||
7933 | { | ||
7934 | goto basic_json_parser_25; | ||
7935 | } | ||
7936 | goto basic_json_parser_4; | ||
7937 | } | ||
7938 | else | ||
7939 | { | ||
7940 | if (yych <= '{') | ||
7941 | { | ||
7942 | goto basic_json_parser_26; | ||
7943 | } | ||
7944 | if (yych == '}') | ||
7945 | { | ||
7946 | goto basic_json_parser_28; | ||
7947 | } | ||
7948 | goto basic_json_parser_4; | ||
7949 | } | ||
7950 | } | ||
7951 | } | ||
7952 | basic_json_parser_2: | ||
7953 | ++m_cursor; | ||
7954 | { | ||
7955 | last_token_type = token_type::end_of_input; | ||
7956 | break; | ||
7957 | } | ||
7958 | basic_json_parser_4: | ||
7959 | ++m_cursor; | ||
7960 | basic_json_parser_5: | ||
7961 | { | ||
7962 | last_token_type = token_type::parse_error; | ||
7963 | break; | ||
7964 | } | ||
7965 | basic_json_parser_6: | ||
7966 | ++m_cursor; | ||
7967 | if (m_limit <= m_cursor) | ||
7968 | { | ||
7969 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
7970 | } | ||
7971 | yych = *m_cursor; | ||
7972 | if (yybm[0 + yych] & 32) | ||
7973 | { | ||
7974 | goto basic_json_parser_6; | ||
7975 | } | ||
7976 | { | ||
7977 | continue; | ||
7978 | } | ||
7979 | basic_json_parser_9: | ||
7980 | yyaccept = 0; | ||
7981 | yych = *(m_marker = ++m_cursor); | ||
7982 | if (yych <= 0x1F) | ||
7983 | { | ||
7984 | goto basic_json_parser_5; | ||
7985 | } | ||
7986 | if (yych <= 0x7F) | ||
7987 | { | ||
7988 | goto basic_json_parser_31; | ||
7989 | } | ||
7990 | if (yych <= 0xC1) | ||
7991 | { | ||
7992 | goto basic_json_parser_5; | ||
7993 | } | ||
7994 | if (yych <= 0xF4) | ||
7995 | { | ||
7996 | goto basic_json_parser_31; | ||
7997 | } | ||
7998 | goto basic_json_parser_5; | ||
7999 | basic_json_parser_10: | ||
8000 | ++m_cursor; | ||
8001 | { | ||
8002 | last_token_type = token_type::value_separator; | ||
8003 | break; | ||
8004 | } | ||
8005 | basic_json_parser_12: | ||
8006 | yych = *++m_cursor; | ||
8007 | if (yych <= '/') | ||
8008 | { | ||
8009 | goto basic_json_parser_5; | ||
8010 | } | ||
8011 | if (yych <= '0') | ||
8012 | { | ||
8013 | goto basic_json_parser_13; | ||
8014 | } | ||
8015 | if (yych <= '9') | ||
8016 | { | ||
8017 | goto basic_json_parser_15; | ||
8018 | } | ||
8019 | goto basic_json_parser_5; | ||
8020 | basic_json_parser_13: | ||
8021 | yyaccept = 1; | ||
8022 | yych = *(m_marker = ++m_cursor); | ||
8023 | if (yych <= 'D') | ||
8024 | { | ||
8025 | if (yych == '.') | ||
8026 | { | ||
8027 | goto basic_json_parser_43; | ||
8028 | } | ||
8029 | } | ||
8030 | else | ||
8031 | { | ||
8032 | if (yych <= 'E') | ||
8033 | { | ||
8034 | goto basic_json_parser_44; | ||
8035 | } | ||
8036 | if (yych == 'e') | ||
8037 | { | ||
8038 | goto basic_json_parser_44; | ||
8039 | } | ||
8040 | } | ||
8041 | basic_json_parser_14: | ||
8042 | { | ||
8043 | last_token_type = token_type::value_number; | ||
8044 | break; | ||
8045 | } | ||
8046 | basic_json_parser_15: | ||
8047 | yyaccept = 1; | ||
8048 | m_marker = ++m_cursor; | ||
8049 | if ((m_limit - m_cursor) < 3) | ||
8050 | { | ||
8051 | fill_line_buffer(3); // LCOV_EXCL_LINE | ||
8052 | } | ||
8053 | yych = *m_cursor; | ||
8054 | if (yybm[0 + yych] & 64) | ||
8055 | { | ||
8056 | goto basic_json_parser_15; | ||
8057 | } | ||
8058 | if (yych <= 'D') | ||
8059 | { | ||
8060 | if (yych == '.') | ||
8061 | { | ||
8062 | goto basic_json_parser_43; | ||
8063 | } | ||
8064 | goto basic_json_parser_14; | ||
8065 | } | ||
8066 | else | ||
8067 | { | ||
8068 | if (yych <= 'E') | ||
8069 | { | ||
8070 | goto basic_json_parser_44; | ||
8071 | } | ||
8072 | if (yych == 'e') | ||
8073 | { | ||
8074 | goto basic_json_parser_44; | ||
8075 | } | ||
8076 | goto basic_json_parser_14; | ||
8077 | } | ||
8078 | basic_json_parser_17: | ||
8079 | ++m_cursor; | ||
8080 | { | ||
8081 | last_token_type = token_type::name_separator; | ||
8082 | break; | ||
8083 | } | ||
8084 | basic_json_parser_19: | ||
8085 | ++m_cursor; | ||
8086 | { | ||
8087 | last_token_type = token_type::begin_array; | ||
8088 | break; | ||
8089 | } | ||
8090 | basic_json_parser_21: | ||
8091 | ++m_cursor; | ||
8092 | { | ||
8093 | last_token_type = token_type::end_array; | ||
8094 | break; | ||
8095 | } | ||
8096 | basic_json_parser_23: | ||
8097 | yyaccept = 0; | ||
8098 | yych = *(m_marker = ++m_cursor); | ||
8099 | if (yych == 'a') | ||
8100 | { | ||
8101 | goto basic_json_parser_45; | ||
8102 | } | ||
8103 | goto basic_json_parser_5; | ||
8104 | basic_json_parser_24: | ||
8105 | yyaccept = 0; | ||
8106 | yych = *(m_marker = ++m_cursor); | ||
8107 | if (yych == 'u') | ||
8108 | { | ||
8109 | goto basic_json_parser_46; | ||
8110 | } | ||
8111 | goto basic_json_parser_5; | ||
8112 | basic_json_parser_25: | ||
8113 | yyaccept = 0; | ||
8114 | yych = *(m_marker = ++m_cursor); | ||
8115 | if (yych == 'r') | ||
8116 | { | ||
8117 | goto basic_json_parser_47; | ||
8118 | } | ||
8119 | goto basic_json_parser_5; | ||
8120 | basic_json_parser_26: | ||
8121 | ++m_cursor; | ||
8122 | { | ||
8123 | last_token_type = token_type::begin_object; | ||
8124 | break; | ||
8125 | } | ||
8126 | basic_json_parser_28: | ||
8127 | ++m_cursor; | ||
8128 | { | ||
8129 | last_token_type = token_type::end_object; | ||
8130 | break; | ||
8131 | } | ||
8132 | basic_json_parser_30: | ||
8133 | ++m_cursor; | ||
8134 | if (m_limit <= m_cursor) | ||
8135 | { | ||
8136 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8137 | } | ||
8138 | yych = *m_cursor; | ||
8139 | basic_json_parser_31: | ||
8140 | if (yybm[0 + yych] & 128) | ||
8141 | { | ||
8142 | goto basic_json_parser_30; | ||
8143 | } | ||
8144 | if (yych <= 0xE0) | ||
8145 | { | ||
8146 | if (yych <= '\\') | ||
8147 | { | ||
8148 | if (yych <= 0x1F) | ||
8149 | { | ||
8150 | goto basic_json_parser_32; | ||
8151 | } | ||
8152 | if (yych <= '"') | ||
8153 | { | ||
8154 | goto basic_json_parser_33; | ||
8155 | } | ||
8156 | goto basic_json_parser_35; | ||
8157 | } | ||
8158 | else | ||
8159 | { | ||
8160 | if (yych <= 0xC1) | ||
8161 | { | ||
8162 | goto basic_json_parser_32; | ||
8163 | } | ||
8164 | if (yych <= 0xDF) | ||
8165 | { | ||
8166 | goto basic_json_parser_36; | ||
8167 | } | ||
8168 | goto basic_json_parser_37; | ||
8169 | } | ||
8170 | } | ||
8171 | else | ||
8172 | { | ||
8173 | if (yych <= 0xEF) | ||
8174 | { | ||
8175 | if (yych == 0xED) | ||
8176 | { | ||
8177 | goto basic_json_parser_39; | ||
8178 | } | ||
8179 | goto basic_json_parser_38; | ||
8180 | } | ||
8181 | else | ||
8182 | { | ||
8183 | if (yych <= 0xF0) | ||
8184 | { | ||
8185 | goto basic_json_parser_40; | ||
8186 | } | ||
8187 | if (yych <= 0xF3) | ||
8188 | { | ||
8189 | goto basic_json_parser_41; | ||
8190 | } | ||
8191 | if (yych <= 0xF4) | ||
8192 | { | ||
8193 | goto basic_json_parser_42; | ||
8194 | } | ||
8195 | } | ||
8196 | } | ||
8197 | basic_json_parser_32: | ||
8198 | m_cursor = m_marker; | ||
8199 | if (yyaccept == 0) | ||
8200 | { | ||
8201 | goto basic_json_parser_5; | ||
8202 | } | ||
8203 | else | ||
8204 | { | ||
8205 | goto basic_json_parser_14; | ||
8206 | } | ||
8207 | basic_json_parser_33: | ||
8208 | ++m_cursor; | ||
8209 | { | ||
8210 | last_token_type = token_type::value_string; | ||
8211 | break; | ||
8212 | } | ||
8213 | basic_json_parser_35: | ||
8214 | ++m_cursor; | ||
8215 | if (m_limit <= m_cursor) | ||
8216 | { | ||
8217 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8218 | } | ||
8219 | yych = *m_cursor; | ||
8220 | if (yych <= 'e') | ||
8221 | { | ||
8222 | if (yych <= '/') | ||
8223 | { | ||
8224 | if (yych == '"') | ||
8225 | { | ||
8226 | goto basic_json_parser_30; | ||
8227 | } | ||
8228 | if (yych <= '.') | ||
8229 | { | ||
8230 | goto basic_json_parser_32; | ||
8231 | } | ||
8232 | goto basic_json_parser_30; | ||
8233 | } | ||
8234 | else | ||
8235 | { | ||
8236 | if (yych <= '\\') | ||
8237 | { | ||
8238 | if (yych <= '[') | ||
8239 | { | ||
8240 | goto basic_json_parser_32; | ||
8241 | } | ||
8242 | goto basic_json_parser_30; | ||
8243 | } | ||
8244 | else | ||
8245 | { | ||
8246 | if (yych == 'b') | ||
8247 | { | ||
8248 | goto basic_json_parser_30; | ||
8249 | } | ||
8250 | goto basic_json_parser_32; | ||
8251 | } | ||
8252 | } | ||
8253 | } | ||
8254 | else | ||
8255 | { | ||
8256 | if (yych <= 'q') | ||
8257 | { | ||
8258 | if (yych <= 'f') | ||
8259 | { | ||
8260 | goto basic_json_parser_30; | ||
8261 | } | ||
8262 | if (yych == 'n') | ||
8263 | { | ||
8264 | goto basic_json_parser_30; | ||
8265 | } | ||
8266 | goto basic_json_parser_32; | ||
8267 | } | ||
8268 | else | ||
8269 | { | ||
8270 | if (yych <= 's') | ||
8271 | { | ||
8272 | if (yych <= 'r') | ||
8273 | { | ||
8274 | goto basic_json_parser_30; | ||
8275 | } | ||
8276 | goto basic_json_parser_32; | ||
8277 | } | ||
8278 | else | ||
8279 | { | ||
8280 | if (yych <= 't') | ||
8281 | { | ||
8282 | goto basic_json_parser_30; | ||
8283 | } | ||
8284 | if (yych <= 'u') | ||
8285 | { | ||
8286 | goto basic_json_parser_48; | ||
8287 | } | ||
8288 | goto basic_json_parser_32; | ||
8289 | } | ||
8290 | } | ||
8291 | } | ||
8292 | basic_json_parser_36: | ||
8293 | ++m_cursor; | ||
8294 | if (m_limit <= m_cursor) | ||
8295 | { | ||
8296 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8297 | } | ||
8298 | yych = *m_cursor; | ||
8299 | if (yych <= 0x7F) | ||
8300 | { | ||
8301 | goto basic_json_parser_32; | ||
8302 | } | ||
8303 | if (yych <= 0xBF) | ||
8304 | { | ||
8305 | goto basic_json_parser_30; | ||
8306 | } | ||
8307 | goto basic_json_parser_32; | ||
8308 | basic_json_parser_37: | ||
8309 | ++m_cursor; | ||
8310 | if (m_limit <= m_cursor) | ||
8311 | { | ||
8312 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8313 | } | ||
8314 | yych = *m_cursor; | ||
8315 | if (yych <= 0x9F) | ||
8316 | { | ||
8317 | goto basic_json_parser_32; | ||
8318 | } | ||
8319 | if (yych <= 0xBF) | ||
8320 | { | ||
8321 | goto basic_json_parser_36; | ||
8322 | } | ||
8323 | goto basic_json_parser_32; | ||
8324 | basic_json_parser_38: | ||
8325 | ++m_cursor; | ||
8326 | if (m_limit <= m_cursor) | ||
8327 | { | ||
8328 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8329 | } | ||
8330 | yych = *m_cursor; | ||
8331 | if (yych <= 0x7F) | ||
8332 | { | ||
8333 | goto basic_json_parser_32; | ||
8334 | } | ||
8335 | if (yych <= 0xBF) | ||
8336 | { | ||
8337 | goto basic_json_parser_36; | ||
8338 | } | ||
8339 | goto basic_json_parser_32; | ||
8340 | basic_json_parser_39: | ||
8341 | ++m_cursor; | ||
8342 | if (m_limit <= m_cursor) | ||
8343 | { | ||
8344 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8345 | } | ||
8346 | yych = *m_cursor; | ||
8347 | if (yych <= 0x7F) | ||
8348 | { | ||
8349 | goto basic_json_parser_32; | ||
8350 | } | ||
8351 | if (yych <= 0x9F) | ||
8352 | { | ||
8353 | goto basic_json_parser_36; | ||
8354 | } | ||
8355 | goto basic_json_parser_32; | ||
8356 | basic_json_parser_40: | ||
8357 | ++m_cursor; | ||
8358 | if (m_limit <= m_cursor) | ||
8359 | { | ||
8360 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8361 | } | ||
8362 | yych = *m_cursor; | ||
8363 | if (yych <= 0x8F) | ||
8364 | { | ||
8365 | goto basic_json_parser_32; | ||
8366 | } | ||
8367 | if (yych <= 0xBF) | ||
8368 | { | ||
8369 | goto basic_json_parser_38; | ||
8370 | } | ||
8371 | goto basic_json_parser_32; | ||
8372 | basic_json_parser_41: | ||
8373 | ++m_cursor; | ||
8374 | if (m_limit <= m_cursor) | ||
8375 | { | ||
8376 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8377 | } | ||
8378 | yych = *m_cursor; | ||
8379 | if (yych <= 0x7F) | ||
8380 | { | ||
8381 | goto basic_json_parser_32; | ||
8382 | } | ||
8383 | if (yych <= 0xBF) | ||
8384 | { | ||
8385 | goto basic_json_parser_38; | ||
8386 | } | ||
8387 | goto basic_json_parser_32; | ||
8388 | basic_json_parser_42: | ||
8389 | ++m_cursor; | ||
8390 | if (m_limit <= m_cursor) | ||
8391 | { | ||
8392 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8393 | } | ||
8394 | yych = *m_cursor; | ||
8395 | if (yych <= 0x7F) | ||
8396 | { | ||
8397 | goto basic_json_parser_32; | ||
8398 | } | ||
8399 | if (yych <= 0x8F) | ||
8400 | { | ||
8401 | goto basic_json_parser_38; | ||
8402 | } | ||
8403 | goto basic_json_parser_32; | ||
8404 | basic_json_parser_43: | ||
8405 | yych = *++m_cursor; | ||
8406 | if (yych <= '/') | ||
8407 | { | ||
8408 | goto basic_json_parser_32; | ||
8409 | } | ||
8410 | if (yych <= '9') | ||
8411 | { | ||
8412 | goto basic_json_parser_49; | ||
8413 | } | ||
8414 | goto basic_json_parser_32; | ||
8415 | basic_json_parser_44: | ||
8416 | yych = *++m_cursor; | ||
8417 | if (yych <= ',') | ||
8418 | { | ||
8419 | if (yych == '+') | ||
8420 | { | ||
8421 | goto basic_json_parser_51; | ||
8422 | } | ||
8423 | goto basic_json_parser_32; | ||
8424 | } | ||
8425 | else | ||
8426 | { | ||
8427 | if (yych <= '-') | ||
8428 | { | ||
8429 | goto basic_json_parser_51; | ||
8430 | } | ||
8431 | if (yych <= '/') | ||
8432 | { | ||
8433 | goto basic_json_parser_32; | ||
8434 | } | ||
8435 | if (yych <= '9') | ||
8436 | { | ||
8437 | goto basic_json_parser_52; | ||
8438 | } | ||
8439 | goto basic_json_parser_32; | ||
8440 | } | ||
8441 | basic_json_parser_45: | ||
8442 | yych = *++m_cursor; | ||
8443 | if (yych == 'l') | ||
8444 | { | ||
8445 | goto basic_json_parser_54; | ||
8446 | } | ||
8447 | goto basic_json_parser_32; | ||
8448 | basic_json_parser_46: | ||
8449 | yych = *++m_cursor; | ||
8450 | if (yych == 'l') | ||
8451 | { | ||
8452 | goto basic_json_parser_55; | ||
8453 | } | ||
8454 | goto basic_json_parser_32; | ||
8455 | basic_json_parser_47: | ||
8456 | yych = *++m_cursor; | ||
8457 | if (yych == 'u') | ||
8458 | { | ||
8459 | goto basic_json_parser_56; | ||
8460 | } | ||
8461 | goto basic_json_parser_32; | ||
8462 | basic_json_parser_48: | ||
8463 | ++m_cursor; | ||
8464 | if (m_limit <= m_cursor) | ||
8465 | { | ||
8466 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8467 | } | ||
8468 | yych = *m_cursor; | ||
8469 | if (yych <= '@') | ||
8470 | { | ||
8471 | if (yych <= '/') | ||
8472 | { | ||
8473 | goto basic_json_parser_32; | ||
8474 | } | ||
8475 | if (yych <= '9') | ||
8476 | { | ||
8477 | goto basic_json_parser_57; | ||
8478 | } | ||
8479 | goto basic_json_parser_32; | ||
8480 | } | ||
8481 | else | ||
8482 | { | ||
8483 | if (yych <= 'F') | ||
8484 | { | ||
8485 | goto basic_json_parser_57; | ||
8486 | } | ||
8487 | if (yych <= '`') | ||
8488 | { | ||
8489 | goto basic_json_parser_32; | ||
8490 | } | ||
8491 | if (yych <= 'f') | ||
8492 | { | ||
8493 | goto basic_json_parser_57; | ||
8494 | } | ||
8495 | goto basic_json_parser_32; | ||
8496 | } | ||
8497 | basic_json_parser_49: | ||
8498 | yyaccept = 1; | ||
8499 | m_marker = ++m_cursor; | ||
8500 | if ((m_limit - m_cursor) < 3) | ||
8501 | { | ||
8502 | fill_line_buffer(3); // LCOV_EXCL_LINE | ||
8503 | } | ||
8504 | yych = *m_cursor; | ||
8505 | if (yych <= 'D') | ||
8506 | { | ||
8507 | if (yych <= '/') | ||
8508 | { | ||
8509 | goto basic_json_parser_14; | ||
8510 | } | ||
8511 | if (yych <= '9') | ||
8512 | { | ||
8513 | goto basic_json_parser_49; | ||
8514 | } | ||
8515 | goto basic_json_parser_14; | ||
8516 | } | ||
8517 | else | ||
8518 | { | ||
8519 | if (yych <= 'E') | ||
8520 | { | ||
8521 | goto basic_json_parser_44; | ||
8522 | } | ||
8523 | if (yych == 'e') | ||
8524 | { | ||
8525 | goto basic_json_parser_44; | ||
8526 | } | ||
8527 | goto basic_json_parser_14; | ||
8528 | } | ||
8529 | basic_json_parser_51: | ||
8530 | yych = *++m_cursor; | ||
8531 | if (yych <= '/') | ||
8532 | { | ||
8533 | goto basic_json_parser_32; | ||
8534 | } | ||
8535 | if (yych >= ':') | ||
8536 | { | ||
8537 | goto basic_json_parser_32; | ||
8538 | } | ||
8539 | basic_json_parser_52: | ||
8540 | ++m_cursor; | ||
8541 | if (m_limit <= m_cursor) | ||
8542 | { | ||
8543 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8544 | } | ||
8545 | yych = *m_cursor; | ||
8546 | if (yych <= '/') | ||
8547 | { | ||
8548 | goto basic_json_parser_14; | ||
8549 | } | ||
8550 | if (yych <= '9') | ||
8551 | { | ||
8552 | goto basic_json_parser_52; | ||
8553 | } | ||
8554 | goto basic_json_parser_14; | ||
8555 | basic_json_parser_54: | ||
8556 | yych = *++m_cursor; | ||
8557 | if (yych == 's') | ||
8558 | { | ||
8559 | goto basic_json_parser_58; | ||
8560 | } | ||
8561 | goto basic_json_parser_32; | ||
8562 | basic_json_parser_55: | ||
8563 | yych = *++m_cursor; | ||
8564 | if (yych == 'l') | ||
8565 | { | ||
8566 | goto basic_json_parser_59; | ||
8567 | } | ||
8568 | goto basic_json_parser_32; | ||
8569 | basic_json_parser_56: | ||
8570 | yych = *++m_cursor; | ||
8571 | if (yych == 'e') | ||
8572 | { | ||
8573 | goto basic_json_parser_61; | ||
8574 | } | ||
8575 | goto basic_json_parser_32; | ||
8576 | basic_json_parser_57: | ||
8577 | ++m_cursor; | ||
8578 | if (m_limit <= m_cursor) | ||
8579 | { | ||
8580 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8581 | } | ||
8582 | yych = *m_cursor; | ||
8583 | if (yych <= '@') | ||
8584 | { | ||
8585 | if (yych <= '/') | ||
8586 | { | ||
8587 | goto basic_json_parser_32; | ||
8588 | } | ||
8589 | if (yych <= '9') | ||
8590 | { | ||
8591 | goto basic_json_parser_63; | ||
8592 | } | ||
8593 | goto basic_json_parser_32; | ||
8594 | } | ||
8595 | else | ||
8596 | { | ||
8597 | if (yych <= 'F') | ||
8598 | { | ||
8599 | goto basic_json_parser_63; | ||
8600 | } | ||
8601 | if (yych <= '`') | ||
8602 | { | ||
8603 | goto basic_json_parser_32; | ||
8604 | } | ||
8605 | if (yych <= 'f') | ||
8606 | { | ||
8607 | goto basic_json_parser_63; | ||
8608 | } | ||
8609 | goto basic_json_parser_32; | ||
8610 | } | ||
8611 | basic_json_parser_58: | ||
8612 | yych = *++m_cursor; | ||
8613 | if (yych == 'e') | ||
8614 | { | ||
8615 | goto basic_json_parser_64; | ||
8616 | } | ||
8617 | goto basic_json_parser_32; | ||
8618 | basic_json_parser_59: | ||
8619 | ++m_cursor; | ||
8620 | { | ||
8621 | last_token_type = token_type::literal_null; | ||
8622 | break; | ||
8623 | } | ||
8624 | basic_json_parser_61: | ||
8625 | ++m_cursor; | ||
8626 | { | ||
8627 | last_token_type = token_type::literal_true; | ||
8628 | break; | ||
8629 | } | ||
8630 | basic_json_parser_63: | ||
8631 | ++m_cursor; | ||
8632 | if (m_limit <= m_cursor) | ||
8633 | { | ||
8634 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8635 | } | ||
8636 | yych = *m_cursor; | ||
8637 | if (yych <= '@') | ||
8638 | { | ||
8639 | if (yych <= '/') | ||
8640 | { | ||
8641 | goto basic_json_parser_32; | ||
8642 | } | ||
8643 | if (yych <= '9') | ||
8644 | { | ||
8645 | goto basic_json_parser_66; | ||
8646 | } | ||
8647 | goto basic_json_parser_32; | ||
8648 | } | ||
8649 | else | ||
8650 | { | ||
8651 | if (yych <= 'F') | ||
8652 | { | ||
8653 | goto basic_json_parser_66; | ||
8654 | } | ||
8655 | if (yych <= '`') | ||
8656 | { | ||
8657 | goto basic_json_parser_32; | ||
8658 | } | ||
8659 | if (yych <= 'f') | ||
8660 | { | ||
8661 | goto basic_json_parser_66; | ||
8662 | } | ||
8663 | goto basic_json_parser_32; | ||
8664 | } | ||
8665 | basic_json_parser_64: | ||
8666 | ++m_cursor; | ||
8667 | { | ||
8668 | last_token_type = token_type::literal_false; | ||
8669 | break; | ||
8670 | } | ||
8671 | basic_json_parser_66: | ||
8672 | ++m_cursor; | ||
8673 | if (m_limit <= m_cursor) | ||
8674 | { | ||
8675 | fill_line_buffer(1); // LCOV_EXCL_LINE | ||
8676 | } | ||
8677 | yych = *m_cursor; | ||
8678 | if (yych <= '@') | ||
8679 | { | ||
8680 | if (yych <= '/') | ||
8681 | { | ||
8682 | goto basic_json_parser_32; | ||
8683 | } | ||
8684 | if (yych <= '9') | ||
8685 | { | ||
8686 | goto basic_json_parser_30; | ||
8687 | } | ||
8688 | goto basic_json_parser_32; | ||
8689 | } | ||
8690 | else | ||
8691 | { | ||
8692 | if (yych <= 'F') | ||
8693 | { | ||
8694 | goto basic_json_parser_30; | ||
8695 | } | ||
8696 | if (yych <= '`') | ||
8697 | { | ||
8698 | goto basic_json_parser_32; | ||
8699 | } | ||
8700 | if (yych <= 'f') | ||
8701 | { | ||
8702 | goto basic_json_parser_30; | ||
8703 | } | ||
8704 | goto basic_json_parser_32; | ||
8705 | } | ||
8706 | } | ||
8707 | |||
8708 | } | ||
8709 | |||
8710 | return last_token_type; | ||
8711 | } | ||
8712 | |||
8713 | /*! | ||
8714 | @brief append data from the stream to the line buffer | ||
8715 | |||
8716 | This function is called by the scan() function when the end of the | ||
8717 | buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be | ||
8718 | incremented without leaving the limits of the line buffer. Note re2c | ||
8719 | decides when to call this function. | ||
8720 | |||
8721 | If the lexer reads from contiguous storage, there is no trailing null | ||
8722 | byte. Therefore, this function must make sure to add these padding | ||
8723 | null bytes. | ||
8724 | |||
8725 | If the lexer reads from an input stream, this function reads the next | ||
8726 | line of the input. | ||
8727 | |||
8728 | @pre | ||
8729 | p p p p p p u u u u u x . . . . . . | ||
8730 | ^ ^ ^ ^ | ||
8731 | m_content m_start | m_limit | ||
8732 | m_cursor | ||
8733 | |||
8734 | @post | ||
8735 | u u u u u x x x x x x x . . . . . . | ||
8736 | ^ ^ ^ | ||
8737 | | m_cursor m_limit | ||
8738 | m_start | ||
8739 | m_content | ||
8740 | */ | ||
8741 | void fill_line_buffer(size_t n = 0) | ||
8742 | { | ||
8743 | // number of processed characters (p) | ||
8744 | const auto offset_start = m_start - m_content; | ||
8745 | // offset for m_marker wrt. to m_start | ||
8746 | const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; | ||
8747 | // number of unprocessed characters (u) | ||
8748 | const auto offset_cursor = m_cursor - m_start; | ||
8749 | |||
8750 | // no stream is used or end of file is reached | ||
8751 | if (m_stream == nullptr or m_stream->eof()) | ||
8752 | { | ||
8753 | // skip this part if we are already using the line buffer | ||
8754 | if (m_start != reinterpret_cast<const lexer_char_t*>(m_line_buffer.data())) | ||
8755 | { | ||
8756 | // copy unprocessed characters to line buffer | ||
8757 | m_line_buffer.clear(); | ||
8758 | for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor) | ||
8759 | { | ||
8760 | m_line_buffer.append(1, static_cast<const char>(*m_cursor)); | ||
8761 | } | ||
8762 | } | ||
8763 | |||
8764 | // append n characters to make sure that there is sufficient | ||
8765 | // space between m_cursor and m_limit | ||
8766 | m_line_buffer.append(1, '\x00'); | ||
8767 | m_line_buffer.append(n - 1, '\x01'); | ||
8768 | } | ||
8769 | else | ||
8770 | { | ||
8771 | // delete processed characters from line buffer | ||
8772 | m_line_buffer.erase(0, static_cast<size_t>(offset_start)); | ||
8773 | // read next line from input stream | ||
8774 | std::string line; | ||
8775 | std::getline(*m_stream, line, '\n'); | ||
8776 | // add line with newline symbol to the line buffer | ||
8777 | m_line_buffer += line + "\n"; | ||
8778 | } | ||
8779 | |||
8780 | // set pointers | ||
8781 | m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.c_str()); | ||
8782 | assert(m_content != nullptr); | ||
8783 | m_start = m_content; | ||
8784 | m_marker = m_start + offset_marker; | ||
8785 | m_cursor = m_start + offset_cursor; | ||
8786 | m_limit = m_start + m_line_buffer.size(); | ||
8787 | } | ||
8788 | |||
8789 | /// return string representation of last read token | ||
8790 | string_t get_token_string() const | ||
8791 | { | ||
8792 | assert(m_start != nullptr); | ||
8793 | return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start), | ||
8794 | static_cast<size_t>(m_cursor - m_start)); | ||
8795 | } | ||
8796 | |||
8797 | /*! | ||
8798 | @brief return string value for string tokens | ||
8799 | |||
8800 | The function iterates the characters between the opening and closing | ||
8801 | quotes of the string value. The complete string is the range | ||
8802 | [m_start,m_cursor). Consequently, we iterate from m_start+1 to | ||
8803 | m_cursor-1. | ||
8804 | |||
8805 | We differentiate two cases: | ||
8806 | |||
8807 | 1. Escaped characters. In this case, a new character is constructed | ||
8808 | according to the nature of the escape. Some escapes create new | ||
8809 | characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied | ||
8810 | as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape | ||
8811 | `"\\uxxxx"` need special care. In this case, to_unicode takes care | ||
8812 | of the construction of the values. | ||
8813 | 2. Unescaped characters are copied as is. | ||
8814 | |||
8815 | @pre `m_cursor - m_start >= 2`, meaning the length of the last token | ||
8816 | is at least 2 bytes which is trivially true for any string (which | ||
8817 | consists of at least two quotes). | ||
8818 | |||
8819 | " c1 c2 c3 ... " | ||
8820 | ^ ^ | ||
8821 | m_start m_cursor | ||
8822 | |||
8823 | @complexity Linear in the length of the string.\n | ||
8824 | |||
8825 | Lemma: The loop body will always terminate.\n | ||
8826 | |||
8827 | Proof (by contradiction): Assume the loop body does not terminate. As | ||
8828 | the loop body does not contain another loop, one of the called | ||
8829 | functions must never return. The called functions are `std::strtoul` | ||
8830 | and to_unicode. Neither function can loop forever, so the loop body | ||
8831 | will never loop forever which contradicts the assumption that the loop | ||
8832 | body does not terminate, q.e.d.\n | ||
8833 | |||
8834 | Lemma: The loop condition for the for loop is eventually false.\n | ||
8835 | |||
8836 | Proof (by contradiction): Assume the loop does not terminate. Due to | ||
8837 | the above lemma, this can only be due to a tautological loop | ||
8838 | condition; that is, the loop condition i < m_cursor - 1 must always be | ||
8839 | true. Let x be the change of i for any loop iteration. Then | ||
8840 | m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This | ||
8841 | can be rephrased to m_cursor - m_start - 2 > x. With the | ||
8842 | precondition, we x <= 0, meaning that the loop condition holds | ||
8843 | indefinitly if i is always decreased. However, observe that the value | ||
8844 | of i is strictly increasing with each iteration, as it is incremented | ||
8845 | by 1 in the iteration expression and never decremented inside the loop | ||
8846 | body. Hence, the loop condition will eventually be false which | ||
8847 | contradicts the assumption that the loop condition is a tautology, | ||
8848 | q.e.d. | ||
8849 | |||
8850 | @return string value of current token without opening and closing | ||
8851 | quotes | ||
8852 | @throw std::out_of_range if to_unicode fails | ||
8853 | */ | ||
8854 | string_t get_string() const | ||
8855 | { | ||
8856 | assert(m_cursor - m_start >= 2); | ||
8857 | |||
8858 | string_t result; | ||
8859 | result.reserve(static_cast<size_t>(m_cursor - m_start - 2)); | ||
8860 | |||
8861 | // iterate the result between the quotes | ||
8862 | for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) | ||
8863 | { | ||
8864 | // process escaped characters | ||
8865 | if (*i == '\\') | ||
8866 | { | ||
8867 | // read next character | ||
8868 | ++i; | ||
8869 | |||
8870 | switch (*i) | ||
8871 | { | ||
8872 | // the default escapes | ||
8873 | case 't': | ||
8874 | { | ||
8875 | result += "\t"; | ||
8876 | break; | ||
8877 | } | ||
8878 | case 'b': | ||
8879 | { | ||
8880 | result += "\b"; | ||
8881 | break; | ||
8882 | } | ||
8883 | case 'f': | ||
8884 | { | ||
8885 | result += "\f"; | ||
8886 | break; | ||
8887 | } | ||
8888 | case 'n': | ||
8889 | { | ||
8890 | result += "\n"; | ||
8891 | break; | ||
8892 | } | ||
8893 | case 'r': | ||
8894 | { | ||
8895 | result += "\r"; | ||
8896 | break; | ||
8897 | } | ||
8898 | case '\\': | ||
8899 | { | ||
8900 | result += "\\"; | ||
8901 | break; | ||
8902 | } | ||
8903 | case '/': | ||
8904 | { | ||
8905 | result += "/"; | ||
8906 | break; | ||
8907 | } | ||
8908 | case '"': | ||
8909 | { | ||
8910 | result += "\""; | ||
8911 | break; | ||
8912 | } | ||
8913 | |||
8914 | // unicode | ||
8915 | case 'u': | ||
8916 | { | ||
8917 | // get code xxxx from uxxxx | ||
8918 | auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1), | ||
8919 | 4).c_str(), nullptr, 16); | ||
8920 | |||
8921 | // check if codepoint is a high surrogate | ||
8922 | if (codepoint >= 0xD800 and codepoint <= 0xDBFF) | ||
8923 | { | ||
8924 | // make sure there is a subsequent unicode | ||
8925 | if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') | ||
8926 | { | ||
8927 | throw std::invalid_argument("missing low surrogate"); | ||
8928 | } | ||
8929 | |||
8930 | // get code yyyy from uxxxx\uyyyy | ||
8931 | auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer> | ||
8932 | (i + 7), 4).c_str(), nullptr, 16); | ||
8933 | result += to_unicode(codepoint, codepoint2); | ||
8934 | // skip the next 10 characters (xxxx\uyyyy) | ||
8935 | i += 10; | ||
8936 | } | ||
8937 | else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) | ||
8938 | { | ||
8939 | // we found a lone low surrogate | ||
8940 | throw std::invalid_argument("missing high surrogate"); | ||
8941 | } | ||
8942 | else | ||
8943 | { | ||
8944 | // add unicode character(s) | ||
8945 | result += to_unicode(codepoint); | ||
8946 | // skip the next four characters (xxxx) | ||
8947 | i += 4; | ||
8948 | } | ||
8949 | break; | ||
8950 | } | ||
8951 | } | ||
8952 | } | ||
8953 | else | ||
8954 | { | ||
8955 | // all other characters are just copied to the end of the | ||
8956 | // string | ||
8957 | result.append(1, static_cast<typename string_t::value_type>(*i)); | ||
8958 | } | ||
8959 | } | ||
8960 | |||
8961 | return result; | ||
8962 | } | ||
8963 | |||
8964 | /*! | ||
8965 | @brief parse floating point number | ||
8966 | |||
8967 | This function (and its overloads) serves to select the most approprate | ||
8968 | standard floating point number parsing function based on the type | ||
8969 | supplied via the first parameter. Set this to @a | ||
8970 | static_cast<number_float_t*>(nullptr). | ||
8971 | |||
8972 | @param[in] type the @ref number_float_t in use | ||
8973 | |||
8974 | @param[in,out] endptr recieves a pointer to the first character after | ||
8975 | the number | ||
8976 | |||
8977 | @return the floating point number | ||
8978 | */ | ||
8979 | long double str_to_float_t(long double* /* type */, char** endptr) const | ||
8980 | { | ||
8981 | return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr); | ||
8982 | } | ||
8983 | |||
8984 | /*! | ||
8985 | @brief parse floating point number | ||
8986 | |||
8987 | This function (and its overloads) serves to select the most approprate | ||
8988 | standard floating point number parsing function based on the type | ||
8989 | supplied via the first parameter. Set this to @a | ||
8990 | static_cast<number_float_t*>(nullptr). | ||
8991 | |||
8992 | @param[in] type the @ref number_float_t in use | ||
8993 | |||
8994 | @param[in,out] endptr recieves a pointer to the first character after | ||
8995 | the number | ||
8996 | |||
8997 | @return the floating point number | ||
8998 | */ | ||
8999 | double str_to_float_t(double* /* type */, char** endptr) const | ||
9000 | { | ||
9001 | return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr); | ||
9002 | } | ||
9003 | |||
9004 | /*! | ||
9005 | @brief parse floating point number | ||
9006 | |||
9007 | This function (and its overloads) serves to select the most approprate | ||
9008 | standard floating point number parsing function based on the type | ||
9009 | supplied via the first parameter. Set this to @a | ||
9010 | static_cast<number_float_t*>(nullptr). | ||
9011 | |||
9012 | @param[in] type the @ref number_float_t in use | ||
9013 | |||
9014 | @param[in,out] endptr recieves a pointer to the first character after | ||
9015 | the number | ||
9016 | |||
9017 | @return the floating point number | ||
9018 | */ | ||
9019 | float str_to_float_t(float* /* type */, char** endptr) const | ||
9020 | { | ||
9021 | return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr); | ||
9022 | } | ||
9023 | |||
9024 | /*! | ||
9025 | @brief return number value for number tokens | ||
9026 | |||
9027 | This function translates the last token into the most appropriate | ||
9028 | number type (either integer, unsigned integer or floating point), | ||
9029 | which is passed back to the caller via the result parameter. | ||
9030 | |||
9031 | This function parses the integer component up to the radix point or | ||
9032 | exponent while collecting information about the 'floating point | ||
9033 | representation', which it stores in the result parameter. If there is | ||
9034 | no radix point or exponent, and the number can fit into a @ref | ||
9035 | number_integer_t or @ref number_unsigned_t then it sets the result | ||
9036 | parameter accordingly. | ||
9037 | |||
9038 | If the number is a floating point number the number is then parsed | ||
9039 | using @a std:strtod (or @a std:strtof or @a std::strtold). | ||
9040 | |||
9041 | @param[out] result @ref basic_json object to receive the number, or | ||
9042 | NAN if the conversion read past the current token. The latter case | ||
9043 | needs to be treated by the caller function. | ||
9044 | */ | ||
9045 | void get_number(basic_json& result) const | ||
9046 | { | ||
9047 | assert(m_start != nullptr); | ||
9048 | |||
9049 | const lexer::lexer_char_t* curptr = m_start; | ||
9050 | |||
9051 | // accumulate the integer conversion result (unsigned for now) | ||
9052 | number_unsigned_t value = 0; | ||
9053 | |||
9054 | // maximum absolute value of the relevant integer type | ||
9055 | number_unsigned_t max; | ||
9056 | |||
9057 | // temporarily store the type to avoid unecessary bitfield access | ||
9058 | value_t type; | ||
9059 | |||
9060 | // look for sign | ||
9061 | if (*curptr == '-') | ||
9062 | { | ||
9063 | type = value_t::number_integer; | ||
9064 | max = static_cast<uint64_t>((std::numeric_limits<number_integer_t>::max)()) + 1; | ||
9065 | curptr++; | ||
9066 | } | ||
9067 | else | ||
9068 | { | ||
9069 | type = value_t::number_unsigned; | ||
9070 | max = static_cast<uint64_t>((std::numeric_limits<number_unsigned_t>::max)()); | ||
9071 | } | ||
9072 | |||
9073 | // count the significant figures | ||
9074 | for (; curptr < m_cursor; curptr++) | ||
9075 | { | ||
9076 | // quickly skip tests if a digit | ||
9077 | if (*curptr < '0' || *curptr > '9') | ||
9078 | { | ||
9079 | if (*curptr == '.') | ||
9080 | { | ||
9081 | // don't count '.' but change to float | ||
9082 | type = value_t::number_float; | ||
9083 | continue; | ||
9084 | } | ||
9085 | // assume exponent (if not then will fail parse): change to | ||
9086 | // float, stop counting and record exponent details | ||
9087 | type = value_t::number_float; | ||
9088 | break; | ||
9089 | } | ||
9090 | |||
9091 | // skip if definitely not an integer | ||
9092 | if (type != value_t::number_float) | ||
9093 | { | ||
9094 | // multiply last value by ten and add the new digit | ||
9095 | auto temp = value * 10 + *curptr - '0'; | ||
9096 | |||
9097 | // test for overflow | ||
9098 | if (temp < value || temp > max) | ||
9099 | { | ||
9100 | // overflow | ||
9101 | type = value_t::number_float; | ||
9102 | } | ||
9103 | else | ||
9104 | { | ||
9105 | // no overflow - save it | ||
9106 | value = temp; | ||
9107 | } | ||
9108 | } | ||
9109 | } | ||
9110 | |||
9111 | // save the value (if not a float) | ||
9112 | if (type == value_t::number_unsigned) | ||
9113 | { | ||
9114 | result.m_value.number_unsigned = value; | ||
9115 | } | ||
9116 | else if (type == value_t::number_integer) | ||
9117 | { | ||
9118 | result.m_value.number_integer = -static_cast<number_integer_t>(value); | ||
9119 | } | ||
9120 | else | ||
9121 | { | ||
9122 | // parse with strtod | ||
9123 | result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL); | ||
9124 | |||
9125 | // replace infinity and NAN by null | ||
9126 | if (not std::isfinite(result.m_value.number_float)) | ||
9127 | { | ||
9128 | type = value_t::null; | ||
9129 | result.m_value = basic_json::json_value(); | ||
9130 | } | ||
9131 | } | ||
9132 | |||
9133 | // save the type | ||
9134 | result.m_type = type; | ||
9135 | } | ||
9136 | |||
9137 | private: | ||
9138 | /// optional input stream | ||
9139 | std::istream* m_stream = nullptr; | ||
9140 | /// line buffer buffer for m_stream | ||
9141 | string_t m_line_buffer {}; | ||
9142 | /// the buffer pointer | ||
9143 | const lexer_char_t* m_content = nullptr; | ||
9144 | /// pointer to the beginning of the current symbol | ||
9145 | const lexer_char_t* m_start = nullptr; | ||
9146 | /// pointer for backtracking information | ||
9147 | const lexer_char_t* m_marker = nullptr; | ||
9148 | /// pointer to the current symbol | ||
9149 | const lexer_char_t* m_cursor = nullptr; | ||
9150 | /// pointer to the end of the buffer | ||
9151 | const lexer_char_t* m_limit = nullptr; | ||
9152 | /// the last token type | ||
9153 | token_type last_token_type = token_type::end_of_input; | ||
9154 | }; | ||
9155 | |||
9156 | /*! | ||
9157 | @brief syntax analysis | ||
9158 | |||
9159 | This class implements a recursive decent parser. | ||
9160 | */ | ||
9161 | class parser | ||
9162 | { | ||
9163 | public: | ||
9164 | /// a parser reading from a string literal | ||
9165 | parser(const char* buff, const parser_callback_t cb = nullptr) | ||
9166 | : callback(cb), | ||
9167 | m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), strlen(buff)) | ||
9168 | {} | ||
9169 | |||
9170 | /// a parser reading from an input stream | ||
9171 | parser(std::istream& is, const parser_callback_t cb = nullptr) | ||
9172 | : callback(cb), m_lexer(is) | ||
9173 | {} | ||
9174 | |||
9175 | /// a parser reading from an iterator range with contiguous storage | ||
9176 | template<class IteratorType, typename std::enable_if< | ||
9177 | std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value | ||
9178 | , int>::type | ||
9179 | = 0> | ||
9180 | parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr) | ||
9181 | : callback(cb), | ||
9182 | m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)), | ||
9183 | static_cast<size_t>(std::distance(first, last))) | ||
9184 | {} | ||
9185 | |||
9186 | /// public parser interface | ||
9187 | basic_json parse() | ||
9188 | { | ||
9189 | // read first token | ||
9190 | get_token(); | ||
9191 | |||
9192 | basic_json result = parse_internal(true); | ||
9193 | result.assert_invariant(); | ||
9194 | |||
9195 | expect(lexer::token_type::end_of_input); | ||
9196 | |||
9197 | // return parser result and replace it with null in case the | ||
9198 | // top-level value was discarded by the callback function | ||
9199 | return result.is_discarded() ? basic_json() : std::move(result); | ||
9200 | } | ||
9201 | |||
9202 | private: | ||
9203 | /// the actual parser | ||
9204 | basic_json parse_internal(bool keep) | ||
9205 | { | ||
9206 | auto result = basic_json(value_t::discarded); | ||
9207 | |||
9208 | switch (last_token) | ||
9209 | { | ||
9210 | case lexer::token_type::begin_object: | ||
9211 | { | ||
9212 | if (keep and (not callback | ||
9213 | or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) | ||
9214 | { | ||
9215 | // explicitly set result to object to cope with {} | ||
9216 | result.m_type = value_t::object; | ||
9217 | result.m_value = value_t::object; | ||
9218 | } | ||
9219 | |||
9220 | // read next token | ||
9221 | get_token(); | ||
9222 | |||
9223 | // closing } -> we are done | ||
9224 | if (last_token == lexer::token_type::end_object) | ||
9225 | { | ||
9226 | get_token(); | ||
9227 | if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) | ||
9228 | { | ||
9229 | result = basic_json(value_t::discarded); | ||
9230 | } | ||
9231 | return result; | ||
9232 | } | ||
9233 | |||
9234 | // no comma is expected here | ||
9235 | unexpect(lexer::token_type::value_separator); | ||
9236 | |||
9237 | // otherwise: parse key-value pairs | ||
9238 | do | ||
9239 | { | ||
9240 | // ugly, but could be fixed with loop reorganization | ||
9241 | if (last_token == lexer::token_type::value_separator) | ||
9242 | { | ||
9243 | get_token(); | ||
9244 | } | ||
9245 | |||
9246 | // store key | ||
9247 | expect(lexer::token_type::value_string); | ||
9248 | const auto key = m_lexer.get_string(); | ||
9249 | |||
9250 | bool keep_tag = false; | ||
9251 | if (keep) | ||
9252 | { | ||
9253 | if (callback) | ||
9254 | { | ||
9255 | basic_json k(key); | ||
9256 | keep_tag = callback(depth, parse_event_t::key, k); | ||
9257 | } | ||
9258 | else | ||
9259 | { | ||
9260 | keep_tag = true; | ||
9261 | } | ||
9262 | } | ||
9263 | |||
9264 | // parse separator (:) | ||
9265 | get_token(); | ||
9266 | expect(lexer::token_type::name_separator); | ||
9267 | |||
9268 | // parse and add value | ||
9269 | get_token(); | ||
9270 | auto value = parse_internal(keep); | ||
9271 | if (keep and keep_tag and not value.is_discarded()) | ||
9272 | { | ||
9273 | result[key] = std::move(value); | ||
9274 | } | ||
9275 | } | ||
9276 | while (last_token == lexer::token_type::value_separator); | ||
9277 | |||
9278 | // closing } | ||
9279 | expect(lexer::token_type::end_object); | ||
9280 | get_token(); | ||
9281 | if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) | ||
9282 | { | ||
9283 | result = basic_json(value_t::discarded); | ||
9284 | } | ||
9285 | |||
9286 | return result; | ||
9287 | } | ||
9288 | |||
9289 | case lexer::token_type::begin_array: | ||
9290 | { | ||
9291 | if (keep and (not callback | ||
9292 | or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) | ||
9293 | { | ||
9294 | // explicitly set result to object to cope with [] | ||
9295 | result.m_type = value_t::array; | ||
9296 | result.m_value = value_t::array; | ||
9297 | } | ||
9298 | |||
9299 | // read next token | ||
9300 | get_token(); | ||
9301 | |||
9302 | // closing ] -> we are done | ||
9303 | if (last_token == lexer::token_type::end_array) | ||
9304 | { | ||
9305 | get_token(); | ||
9306 | if (callback and not callback(--depth, parse_event_t::array_end, result)) | ||
9307 | { | ||
9308 | result = basic_json(value_t::discarded); | ||
9309 | } | ||
9310 | return result; | ||
9311 | } | ||
9312 | |||
9313 | // no comma is expected here | ||
9314 | unexpect(lexer::token_type::value_separator); | ||
9315 | |||
9316 | // otherwise: parse values | ||
9317 | do | ||
9318 | { | ||
9319 | // ugly, but could be fixed with loop reorganization | ||
9320 | if (last_token == lexer::token_type::value_separator) | ||
9321 | { | ||
9322 | get_token(); | ||
9323 | } | ||
9324 | |||
9325 | // parse value | ||
9326 | auto value = parse_internal(keep); | ||
9327 | if (keep and not value.is_discarded()) | ||
9328 | { | ||
9329 | result.push_back(std::move(value)); | ||
9330 | } | ||
9331 | } | ||
9332 | while (last_token == lexer::token_type::value_separator); | ||
9333 | |||
9334 | // closing ] | ||
9335 | expect(lexer::token_type::end_array); | ||
9336 | get_token(); | ||
9337 | if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) | ||
9338 | { | ||
9339 | result = basic_json(value_t::discarded); | ||
9340 | } | ||
9341 | |||
9342 | return result; | ||
9343 | } | ||
9344 | |||
9345 | case lexer::token_type::literal_null: | ||
9346 | { | ||
9347 | get_token(); | ||
9348 | result.m_type = value_t::null; | ||
9349 | break; | ||
9350 | } | ||
9351 | |||
9352 | case lexer::token_type::value_string: | ||
9353 | { | ||
9354 | const auto s = m_lexer.get_string(); | ||
9355 | get_token(); | ||
9356 | result = basic_json(s); | ||
9357 | break; | ||
9358 | } | ||
9359 | |||
9360 | case lexer::token_type::literal_true: | ||
9361 | { | ||
9362 | get_token(); | ||
9363 | result.m_type = value_t::boolean; | ||
9364 | result.m_value = true; | ||
9365 | break; | ||
9366 | } | ||
9367 | |||
9368 | case lexer::token_type::literal_false: | ||
9369 | { | ||
9370 | get_token(); | ||
9371 | result.m_type = value_t::boolean; | ||
9372 | result.m_value = false; | ||
9373 | break; | ||
9374 | } | ||
9375 | |||
9376 | case lexer::token_type::value_number: | ||
9377 | { | ||
9378 | m_lexer.get_number(result); | ||
9379 | get_token(); | ||
9380 | break; | ||
9381 | } | ||
9382 | |||
9383 | default: | ||
9384 | { | ||
9385 | // the last token was unexpected | ||
9386 | unexpect(last_token); | ||
9387 | } | ||
9388 | } | ||
9389 | |||
9390 | if (keep and callback and not callback(depth, parse_event_t::value, result)) | ||
9391 | { | ||
9392 | result = basic_json(value_t::discarded); | ||
9393 | } | ||
9394 | return result; | ||
9395 | } | ||
9396 | |||
9397 | /// get next token from lexer | ||
9398 | typename lexer::token_type get_token() | ||
9399 | { | ||
9400 | last_token = m_lexer.scan(); | ||
9401 | return last_token; | ||
9402 | } | ||
9403 | |||
9404 | void expect(typename lexer::token_type t) const | ||
9405 | { | ||
9406 | if (t != last_token) | ||
9407 | { | ||
9408 | std::string error_msg = "parse error - unexpected "; | ||
9409 | error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + | ||
9410 | "'") : | ||
9411 | lexer::token_type_name(last_token)); | ||
9412 | error_msg += "; expected " + lexer::token_type_name(t); | ||
9413 | throw std::invalid_argument(error_msg); | ||
9414 | } | ||
9415 | } | ||
9416 | |||
9417 | void unexpect(typename lexer::token_type t) const | ||
9418 | { | ||
9419 | if (t == last_token) | ||
9420 | { | ||
9421 | std::string error_msg = "parse error - unexpected "; | ||
9422 | error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + | ||
9423 | "'") : | ||
9424 | lexer::token_type_name(last_token)); | ||
9425 | throw std::invalid_argument(error_msg); | ||
9426 | } | ||
9427 | } | ||
9428 | |||
9429 | private: | ||
9430 | /// current level of recursion | ||
9431 | int depth = 0; | ||
9432 | /// callback function | ||
9433 | const parser_callback_t callback = nullptr; | ||
9434 | /// the type of the last read token | ||
9435 | typename lexer::token_type last_token = lexer::token_type::uninitialized; | ||
9436 | /// the lexer | ||
9437 | lexer m_lexer; | ||
9438 | }; | ||
9439 | |||
9440 | public: | ||
9441 | /*! | ||
9442 | @brief JSON Pointer | ||
9443 | |||
9444 | A JSON pointer defines a string syntax for identifying a specific value | ||
9445 | within a JSON document. It can be used with functions `at` and | ||
9446 | `operator[]`. Furthermore, JSON pointers are the base for JSON patches. | ||
9447 | |||
9448 | @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) | ||
9449 | |||
9450 | @since version 2.0.0 | ||
9451 | */ | ||
9452 | class json_pointer | ||
9453 | { | ||
9454 | /// allow basic_json to access private members | ||
9455 | friend class basic_json; | ||
9456 | |||
9457 | public: | ||
9458 | /*! | ||
9459 | @brief create JSON pointer | ||
9460 | |||
9461 | Create a JSON pointer according to the syntax described in | ||
9462 | [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). | ||
9463 | |||
9464 | @param[in] s string representing the JSON pointer; if omitted, the | ||
9465 | empty string is assumed which references the whole JSON | ||
9466 | value | ||
9467 | |||
9468 | @throw std::domain_error if reference token is nonempty and does not | ||
9469 | begin with a slash (`/`); example: `"JSON pointer must be empty or | ||
9470 | begin with /"` | ||
9471 | @throw std::domain_error if a tilde (`~`) is not followed by `0` | ||
9472 | (representing `~`) or `1` (representing `/`); example: `"escape error: | ||
9473 | ~ must be followed with 0 or 1"` | ||
9474 | |||
9475 | @liveexample{The example shows the construction several valid JSON | ||
9476 | pointers as well as the exceptional behavior.,json_pointer} | ||
9477 | |||
9478 | @since version 2.0.0 | ||
9479 | */ | ||
9480 | explicit json_pointer(const std::string& s = "") | ||
9481 | : reference_tokens(split(s)) | ||
9482 | {} | ||
9483 | |||
9484 | /*! | ||
9485 | @brief return a string representation of the JSON pointer | ||
9486 | |||
9487 | @invariant For each JSON pointer `ptr`, it holds: | ||
9488 | @code {.cpp} | ||
9489 | ptr == json_pointer(ptr.to_string()); | ||
9490 | @endcode | ||
9491 | |||
9492 | @return a string representation of the JSON pointer | ||
9493 | |||
9494 | @liveexample{The example shows the result of `to_string`., | ||
9495 | json_pointer__to_string} | ||
9496 | |||
9497 | @since version 2.0.0 | ||
9498 | */ | ||
9499 | std::string to_string() const noexcept | ||
9500 | { | ||
9501 | return std::accumulate(reference_tokens.begin(), | ||
9502 | reference_tokens.end(), std::string{}, | ||
9503 | [](const std::string & a, const std::string & b) | ||
9504 | { | ||
9505 | return a + "/" + escape(b); | ||
9506 | }); | ||
9507 | } | ||
9508 | |||
9509 | /// @copydoc to_string() | ||
9510 | operator std::string() const | ||
9511 | { | ||
9512 | return to_string(); | ||
9513 | } | ||
9514 | |||
9515 | private: | ||
9516 | /// remove and return last reference pointer | ||
9517 | std::string pop_back() | ||
9518 | { | ||
9519 | if (is_root()) | ||
9520 | { | ||
9521 | throw std::domain_error("JSON pointer has no parent"); | ||
9522 | } | ||
9523 | |||
9524 | auto last = reference_tokens.back(); | ||
9525 | reference_tokens.pop_back(); | ||
9526 | return last; | ||
9527 | } | ||
9528 | |||
9529 | /// return whether pointer points to the root document | ||
9530 | bool is_root() const | ||
9531 | { | ||
9532 | return reference_tokens.empty(); | ||
9533 | } | ||
9534 | |||
9535 | json_pointer top() const | ||
9536 | { | ||
9537 | if (is_root()) | ||
9538 | { | ||
9539 | throw std::domain_error("JSON pointer has no parent"); | ||
9540 | } | ||
9541 | |||
9542 | json_pointer result = *this; | ||
9543 | result.reference_tokens = {reference_tokens[0]}; | ||
9544 | return result; | ||
9545 | } | ||
9546 | |||
9547 | /*! | ||
9548 | @brief create and return a reference to the pointed to value | ||
9549 | |||
9550 | @complexity Linear in the number of reference tokens. | ||
9551 | */ | ||
9552 | reference get_and_create(reference j) const | ||
9553 | { | ||
9554 | pointer result = &j; | ||
9555 | |||
9556 | // in case no reference tokens exist, return a reference to the | ||
9557 | // JSON value j which will be overwritten by a primitive value | ||
9558 | for (const auto& reference_token : reference_tokens) | ||
9559 | { | ||
9560 | switch (result->m_type) | ||
9561 | { | ||
9562 | case value_t::null: | ||
9563 | { | ||
9564 | if (reference_token == "0") | ||
9565 | { | ||
9566 | // start a new array if reference token is 0 | ||
9567 | result = &result->operator[](0); | ||
9568 | } | ||
9569 | else | ||
9570 | { | ||
9571 | // start a new object otherwise | ||
9572 | result = &result->operator[](reference_token); | ||
9573 | } | ||
9574 | break; | ||
9575 | } | ||
9576 | |||
9577 | case value_t::object: | ||
9578 | { | ||
9579 | // create an entry in the object | ||
9580 | result = &result->operator[](reference_token); | ||
9581 | break; | ||
9582 | } | ||
9583 | |||
9584 | case value_t::array: | ||
9585 | { | ||
9586 | // create an entry in the array | ||
9587 | result = &result->operator[](static_cast<size_type>(std::stoi(reference_token))); | ||
9588 | break; | ||
9589 | } | ||
9590 | |||
9591 | /* | ||
9592 | The following code is only reached if there exists a | ||
9593 | reference token _and_ the current value is primitive. In | ||
9594 | this case, we have an error situation, because primitive | ||
9595 | values may only occur as single value; that is, with an | ||
9596 | empty list of reference tokens. | ||
9597 | */ | ||
9598 | default: | ||
9599 | { | ||
9600 | throw std::domain_error("invalid value to unflatten"); | ||
9601 | } | ||
9602 | } | ||
9603 | } | ||
9604 | |||
9605 | return *result; | ||
9606 | } | ||
9607 | |||
9608 | /*! | ||
9609 | @brief return a reference to the pointed to value | ||
9610 | |||
9611 | @note This version does not throw if a value is not present, but tries | ||
9612 | to create nested values instead. For instance, calling this function | ||
9613 | with pointer `"/this/that"` on a null value is equivalent to calling | ||
9614 | `operator[]("this").operator[]("that")` on that value, effectively | ||
9615 | changing the null value to an object. | ||
9616 | |||
9617 | @param[in] ptr a JSON value | ||
9618 | |||
9619 | @return reference to the JSON value pointed to by the JSON pointer | ||
9620 | |||
9621 | @complexity Linear in the length of the JSON pointer. | ||
9622 | |||
9623 | @throw std::out_of_range if the JSON pointer can not be resolved | ||
9624 | @throw std::domain_error if an array index begins with '0' | ||
9625 | @throw std::invalid_argument if an array index was not a number | ||
9626 | */ | ||
9627 | reference get_unchecked(pointer ptr) const | ||
9628 | { | ||
9629 | for (const auto& reference_token : reference_tokens) | ||
9630 | { | ||
9631 | // convert null values to arrays or objects before continuing | ||
9632 | if (ptr->m_type == value_t::null) | ||
9633 | { | ||
9634 | // check if reference token is a number | ||
9635 | const bool nums = std::all_of(reference_token.begin(), | ||
9636 | reference_token.end(), | ||
9637 | [](const char x) | ||
9638 | { | ||
9639 | return std::isdigit(x); | ||
9640 | }); | ||
9641 | |||
9642 | // change value to array for numbers or "-" or to object | ||
9643 | // otherwise | ||
9644 | if (nums or reference_token == "-") | ||
9645 | { | ||
9646 | *ptr = value_t::array; | ||
9647 | } | ||
9648 | else | ||
9649 | { | ||
9650 | *ptr = value_t::object; | ||
9651 | } | ||
9652 | } | ||
9653 | |||
9654 | switch (ptr->m_type) | ||
9655 | { | ||
9656 | case value_t::object: | ||
9657 | { | ||
9658 | // use unchecked object access | ||
9659 | ptr = &ptr->operator[](reference_token); | ||
9660 | break; | ||
9661 | } | ||
9662 | |||
9663 | case value_t::array: | ||
9664 | { | ||
9665 | // error condition (cf. RFC 6901, Sect. 4) | ||
9666 | if (reference_token.size() > 1 and reference_token[0] == '0') | ||
9667 | { | ||
9668 | throw std::domain_error("array index must not begin with '0'"); | ||
9669 | } | ||
9670 | |||
9671 | if (reference_token == "-") | ||
9672 | { | ||
9673 | // explicityly treat "-" as index beyond the end | ||
9674 | ptr = &ptr->operator[](ptr->m_value.array->size()); | ||
9675 | } | ||
9676 | else | ||
9677 | { | ||
9678 | // convert array index to number; unchecked access | ||
9679 | ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token))); | ||
9680 | } | ||
9681 | break; | ||
9682 | } | ||
9683 | |||
9684 | default: | ||
9685 | { | ||
9686 | throw std::out_of_range("unresolved reference token '" + reference_token + "'"); | ||
9687 | } | ||
9688 | } | ||
9689 | } | ||
9690 | |||
9691 | return *ptr; | ||
9692 | } | ||
9693 | |||
9694 | reference get_checked(pointer ptr) const | ||
9695 | { | ||
9696 | for (const auto& reference_token : reference_tokens) | ||
9697 | { | ||
9698 | switch (ptr->m_type) | ||
9699 | { | ||
9700 | case value_t::object: | ||
9701 | { | ||
9702 | // note: at performs range check | ||
9703 | ptr = &ptr->at(reference_token); | ||
9704 | break; | ||
9705 | } | ||
9706 | |||
9707 | case value_t::array: | ||
9708 | { | ||
9709 | if (reference_token == "-") | ||
9710 | { | ||
9711 | // "-" always fails the range check | ||
9712 | throw std::out_of_range("array index '-' (" + | ||
9713 | std::to_string(ptr->m_value.array->size()) + | ||
9714 | ") is out of range"); | ||
9715 | } | ||
9716 | |||
9717 | // error condition (cf. RFC 6901, Sect. 4) | ||
9718 | if (reference_token.size() > 1 and reference_token[0] == '0') | ||
9719 | { | ||
9720 | throw std::domain_error("array index must not begin with '0'"); | ||
9721 | } | ||
9722 | |||
9723 | // note: at performs range check | ||
9724 | ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token))); | ||
9725 | break; | ||
9726 | } | ||
9727 | |||
9728 | default: | ||
9729 | { | ||
9730 | throw std::out_of_range("unresolved reference token '" + reference_token + "'"); | ||
9731 | } | ||
9732 | } | ||
9733 | } | ||
9734 | |||
9735 | return *ptr; | ||
9736 | } | ||
9737 | |||
9738 | /*! | ||
9739 | @brief return a const reference to the pointed to value | ||
9740 | |||
9741 | @param[in] ptr a JSON value | ||
9742 | |||
9743 | @return const reference to the JSON value pointed to by the JSON | ||
9744 | pointer | ||
9745 | */ | ||
9746 | const_reference get_unchecked(const_pointer ptr) const | ||
9747 | { | ||
9748 | for (const auto& reference_token : reference_tokens) | ||
9749 | { | ||
9750 | switch (ptr->m_type) | ||
9751 | { | ||
9752 | case value_t::object: | ||
9753 | { | ||
9754 | // use unchecked object access | ||
9755 | ptr = &ptr->operator[](reference_token); | ||
9756 | break; | ||
9757 | } | ||
9758 | |||
9759 | case value_t::array: | ||
9760 | { | ||
9761 | if (reference_token == "-") | ||
9762 | { | ||
9763 | // "-" cannot be used for const access | ||
9764 | throw std::out_of_range("array index '-' (" + | ||
9765 | std::to_string(ptr->m_value.array->size()) + | ||
9766 | ") is out of range"); | ||
9767 | } | ||
9768 | |||
9769 | // error condition (cf. RFC 6901, Sect. 4) | ||
9770 | if (reference_token.size() > 1 and reference_token[0] == '0') | ||
9771 | { | ||
9772 | throw std::domain_error("array index must not begin with '0'"); | ||
9773 | } | ||
9774 | |||
9775 | // use unchecked array access | ||
9776 | ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token))); | ||
9777 | break; | ||
9778 | } | ||
9779 | |||
9780 | default: | ||
9781 | { | ||
9782 | throw std::out_of_range("unresolved reference token '" + reference_token + "'"); | ||
9783 | } | ||
9784 | } | ||
9785 | } | ||
9786 | |||
9787 | return *ptr; | ||
9788 | } | ||
9789 | |||
9790 | const_reference get_checked(const_pointer ptr) const | ||
9791 | { | ||
9792 | for (const auto& reference_token : reference_tokens) | ||
9793 | { | ||
9794 | switch (ptr->m_type) | ||
9795 | { | ||
9796 | case value_t::object: | ||
9797 | { | ||
9798 | // note: at performs range check | ||
9799 | ptr = &ptr->at(reference_token); | ||
9800 | break; | ||
9801 | } | ||
9802 | |||
9803 | case value_t::array: | ||
9804 | { | ||
9805 | if (reference_token == "-") | ||
9806 | { | ||
9807 | // "-" always fails the range check | ||
9808 | throw std::out_of_range("array index '-' (" + | ||
9809 | std::to_string(ptr->m_value.array->size()) + | ||
9810 | ") is out of range"); | ||
9811 | } | ||
9812 | |||
9813 | // error condition (cf. RFC 6901, Sect. 4) | ||
9814 | if (reference_token.size() > 1 and reference_token[0] == '0') | ||
9815 | { | ||
9816 | throw std::domain_error("array index must not begin with '0'"); | ||
9817 | } | ||
9818 | |||
9819 | // note: at performs range check | ||
9820 | ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token))); | ||
9821 | break; | ||
9822 | } | ||
9823 | |||
9824 | default: | ||
9825 | { | ||
9826 | throw std::out_of_range("unresolved reference token '" + reference_token + "'"); | ||
9827 | } | ||
9828 | } | ||
9829 | } | ||
9830 | |||
9831 | return *ptr; | ||
9832 | } | ||
9833 | |||
9834 | /// split the string input to reference tokens | ||
9835 | static std::vector<std::string> split(const std::string& reference_string) | ||
9836 | { | ||
9837 | std::vector<std::string> result; | ||
9838 | |||
9839 | // special case: empty reference string -> no reference tokens | ||
9840 | if (reference_string.empty()) | ||
9841 | { | ||
9842 | return result; | ||
9843 | } | ||
9844 | |||
9845 | // check if nonempty reference string begins with slash | ||
9846 | if (reference_string[0] != '/') | ||
9847 | { | ||
9848 | throw std::domain_error("JSON pointer must be empty or begin with '/'"); | ||
9849 | } | ||
9850 | |||
9851 | // extract the reference tokens: | ||
9852 | // - slash: position of the last read slash (or end of string) | ||
9853 | // - start: position after the previous slash | ||
9854 | for ( | ||
9855 | // search for the first slash after the first character | ||
9856 | size_t slash = reference_string.find_first_of("/", 1), | ||
9857 | // set the beginning of the first reference token | ||
9858 | start = 1; | ||
9859 | // we can stop if start == string::npos+1 = 0 | ||
9860 | start != 0; | ||
9861 | // set the beginning of the next reference token | ||
9862 | // (will eventually be 0 if slash == std::string::npos) | ||
9863 | start = slash + 1, | ||
9864 | // find next slash | ||
9865 | slash = reference_string.find_first_of("/", start)) | ||
9866 | { | ||
9867 | // use the text between the beginning of the reference token | ||
9868 | // (start) and the last slash (slash). | ||
9869 | auto reference_token = reference_string.substr(start, slash - start); | ||
9870 | |||
9871 | // check reference tokens are properly escaped | ||
9872 | for (size_t pos = reference_token.find_first_of("~"); | ||
9873 | pos != std::string::npos; | ||
9874 | pos = reference_token.find_first_of("~", pos + 1)) | ||
9875 | { | ||
9876 | assert(reference_token[pos] == '~'); | ||
9877 | |||
9878 | // ~ must be followed by 0 or 1 | ||
9879 | if (pos == reference_token.size() - 1 or | ||
9880 | (reference_token[pos + 1] != '0' and | ||
9881 | reference_token[pos + 1] != '1')) | ||
9882 | { | ||
9883 | throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); | ||
9884 | } | ||
9885 | } | ||
9886 | |||
9887 | // finally, store the reference token | ||
9888 | unescape(reference_token); | ||
9889 | result.push_back(reference_token); | ||
9890 | } | ||
9891 | |||
9892 | return result; | ||
9893 | } | ||
9894 | |||
9895 | private: | ||
9896 | /*! | ||
9897 | @brief replace all occurrences of a substring by another string | ||
9898 | |||
9899 | @param[in,out] s the string to manipulate | ||
9900 | @param[in] f the substring to replace with @a t | ||
9901 | @param[in] t the string to replace @a f | ||
9902 | |||
9903 | @return The string @a s where all occurrences of @a f are replaced | ||
9904 | with @a t. | ||
9905 | |||
9906 | @pre The search string @a f must not be empty. | ||
9907 | |||
9908 | @since version 2.0.0 | ||
9909 | */ | ||
9910 | static void replace_substring(std::string& s, | ||
9911 | const std::string& f, | ||
9912 | const std::string& t) | ||
9913 | { | ||
9914 | assert(not f.empty()); | ||
9915 | |||
9916 | for ( | ||
9917 | size_t pos = s.find(f); // find first occurrence of f | ||
9918 | pos != std::string::npos; // make sure f was found | ||
9919 | s.replace(pos, f.size(), t), // replace with t | ||
9920 | pos = s.find(f, pos + t.size()) // find next occurrence of f | ||
9921 | ); | ||
9922 | } | ||
9923 | |||
9924 | /// escape tilde and slash | ||
9925 | static std::string escape(std::string s) | ||
9926 | { | ||
9927 | // escape "~"" to "~0" and "/" to "~1" | ||
9928 | replace_substring(s, "~", "~0"); | ||
9929 | replace_substring(s, "/", "~1"); | ||
9930 | return s; | ||
9931 | } | ||
9932 | |||
9933 | /// unescape tilde and slash | ||
9934 | static void unescape(std::string& s) | ||
9935 | { | ||
9936 | // first transform any occurrence of the sequence '~1' to '/' | ||
9937 | replace_substring(s, "~1", "/"); | ||
9938 | // then transform any occurrence of the sequence '~0' to '~' | ||
9939 | replace_substring(s, "~0", "~"); | ||
9940 | } | ||
9941 | |||
9942 | /*! | ||
9943 | @param[in] reference_string the reference string to the current value | ||
9944 | @param[in] value the value to consider | ||
9945 | @param[in,out] result the result object to insert values to | ||
9946 | |||
9947 | @note Empty objects or arrays are flattened to `null`. | ||
9948 | */ | ||
9949 | static void flatten(const std::string& reference_string, | ||
9950 | const basic_json& value, | ||
9951 | basic_json& result) | ||
9952 | { | ||
9953 | switch (value.m_type) | ||
9954 | { | ||
9955 | case value_t::array: | ||
9956 | { | ||
9957 | if (value.m_value.array->empty()) | ||
9958 | { | ||
9959 | // flatten empty array as null | ||
9960 | result[reference_string] = nullptr; | ||
9961 | } | ||
9962 | else | ||
9963 | { | ||
9964 | // iterate array and use index as reference string | ||
9965 | for (size_t i = 0; i < value.m_value.array->size(); ++i) | ||
9966 | { | ||
9967 | flatten(reference_string + "/" + std::to_string(i), | ||
9968 | value.m_value.array->operator[](i), result); | ||
9969 | } | ||
9970 | } | ||
9971 | break; | ||
9972 | } | ||
9973 | |||
9974 | case value_t::object: | ||
9975 | { | ||
9976 | if (value.m_value.object->empty()) | ||
9977 | { | ||
9978 | // flatten empty object as null | ||
9979 | result[reference_string] = nullptr; | ||
9980 | } | ||
9981 | else | ||
9982 | { | ||
9983 | // iterate object and use keys as reference string | ||
9984 | for (const auto& element : *value.m_value.object) | ||
9985 | { | ||
9986 | flatten(reference_string + "/" + escape(element.first), | ||
9987 | element.second, result); | ||
9988 | } | ||
9989 | } | ||
9990 | break; | ||
9991 | } | ||
9992 | |||
9993 | default: | ||
9994 | { | ||
9995 | // add primitive value with its reference string | ||
9996 | result[reference_string] = value; | ||
9997 | break; | ||
9998 | } | ||
9999 | } | ||
10000 | } | ||
10001 | |||
10002 | /*! | ||
10003 | @param[in] value flattened JSON | ||
10004 | |||
10005 | @return unflattened JSON | ||
10006 | */ | ||
10007 | static basic_json unflatten(const basic_json& value) | ||
10008 | { | ||
10009 | if (not value.is_object()) | ||
10010 | { | ||
10011 | throw std::domain_error("only objects can be unflattened"); | ||
10012 | } | ||
10013 | |||
10014 | basic_json result; | ||
10015 | |||
10016 | // iterate the JSON object values | ||
10017 | for (const auto& element : *value.m_value.object) | ||
10018 | { | ||
10019 | if (not element.second.is_primitive()) | ||
10020 | { | ||
10021 | throw std::domain_error("values in object must be primitive"); | ||
10022 | } | ||
10023 | |||
10024 | // assign value to reference pointed to by JSON pointer; Note | ||
10025 | // that if the JSON pointer is "" (i.e., points to the whole | ||
10026 | // value), function get_and_create returns a reference to | ||
10027 | // result itself. An assignment will then create a primitive | ||
10028 | // value. | ||
10029 | json_pointer(element.first).get_and_create(result) = element.second; | ||
10030 | } | ||
10031 | |||
10032 | return result; | ||
10033 | } | ||
10034 | |||
10035 | private: | ||
10036 | /// the reference tokens | ||
10037 | std::vector<std::string> reference_tokens {}; | ||
10038 | }; | ||
10039 | |||
10040 | ////////////////////////// | ||
10041 | // JSON Pointer support // | ||
10042 | ////////////////////////// | ||
10043 | |||
10044 | /// @name JSON Pointer functions | ||
10045 | /// @{ | ||
10046 | |||
10047 | /*! | ||
10048 | @brief access specified element via JSON Pointer | ||
10049 | |||
10050 | Uses a JSON pointer to retrieve a reference to the respective JSON value. | ||
10051 | No bound checking is performed. Similar to @ref operator[](const typename | ||
10052 | object_t::key_type&), `null` values are created in arrays and objects if | ||
10053 | necessary. | ||
10054 | |||
10055 | In particular: | ||
10056 | - If the JSON pointer points to an object key that does not exist, it | ||
10057 | is created an filled with a `null` value before a reference to it | ||
10058 | is returned. | ||
10059 | - If the JSON pointer points to an array index that does not exist, it | ||
10060 | is created an filled with a `null` value before a reference to it | ||
10061 | is returned. All indices between the current maximum and the given | ||
10062 | index are also filled with `null`. | ||
10063 | - The special value `-` is treated as a synonym for the index past the | ||
10064 | end. | ||
10065 | |||
10066 | @param[in] ptr a JSON pointer | ||
10067 | |||
10068 | @return reference to the element pointed to by @a ptr | ||
10069 | |||
10070 | @complexity Constant. | ||
10071 | |||
10072 | @throw std::out_of_range if the JSON pointer can not be resolved | ||
10073 | @throw std::domain_error if an array index begins with '0' | ||
10074 | @throw std::invalid_argument if an array index was not a number | ||
10075 | |||
10076 | @liveexample{The behavior is shown in the example.,operatorjson_pointer} | ||
10077 | |||
10078 | @since version 2.0.0 | ||
10079 | */ | ||
10080 | reference operator[](const json_pointer& ptr) | ||
10081 | { | ||
10082 | return ptr.get_unchecked(this); | ||
10083 | } | ||
10084 | |||
10085 | /*! | ||
10086 | @brief access specified element via JSON Pointer | ||
10087 | |||
10088 | Uses a JSON pointer to retrieve a reference to the respective JSON value. | ||
10089 | No bound checking is performed. The function does not change the JSON | ||
10090 | value; no `null` values are created. In particular, the the special value | ||
10091 | `-` yields an exception. | ||
10092 | |||
10093 | @param[in] ptr JSON pointer to the desired element | ||
10094 | |||
10095 | @return const reference to the element pointed to by @a ptr | ||
10096 | |||
10097 | @complexity Constant. | ||
10098 | |||
10099 | @throw std::out_of_range if the JSON pointer can not be resolved | ||
10100 | @throw std::domain_error if an array index begins with '0' | ||
10101 | @throw std::invalid_argument if an array index was not a number | ||
10102 | |||
10103 | @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} | ||
10104 | |||
10105 | @since version 2.0.0 | ||
10106 | */ | ||
10107 | const_reference operator[](const json_pointer& ptr) const | ||
10108 | { | ||
10109 | return ptr.get_unchecked(this); | ||
10110 | } | ||
10111 | |||
10112 | /*! | ||
10113 | @brief access specified element via JSON Pointer | ||
10114 | |||
10115 | Returns a reference to the element at with specified JSON pointer @a ptr, | ||
10116 | with bounds checking. | ||
10117 | |||
10118 | @param[in] ptr JSON pointer to the desired element | ||
10119 | |||
10120 | @return reference to the element pointed to by @a ptr | ||
10121 | |||
10122 | @complexity Constant. | ||
10123 | |||
10124 | @throw std::out_of_range if the JSON pointer can not be resolved | ||
10125 | @throw std::domain_error if an array index begins with '0' | ||
10126 | @throw std::invalid_argument if an array index was not a number | ||
10127 | |||
10128 | @liveexample{The behavior is shown in the example.,at_json_pointer} | ||
10129 | |||
10130 | @since version 2.0.0 | ||
10131 | */ | ||
10132 | reference at(const json_pointer& ptr) | ||
10133 | { | ||
10134 | return ptr.get_checked(this); | ||
10135 | } | ||
10136 | |||
10137 | /*! | ||
10138 | @brief access specified element via JSON Pointer | ||
10139 | |||
10140 | Returns a const reference to the element at with specified JSON pointer @a | ||
10141 | ptr, with bounds checking. | ||
10142 | |||
10143 | @param[in] ptr JSON pointer to the desired element | ||
10144 | |||
10145 | @return reference to the element pointed to by @a ptr | ||
10146 | |||
10147 | @complexity Constant. | ||
10148 | |||
10149 | @throw std::out_of_range if the JSON pointer can not be resolved | ||
10150 | @throw std::domain_error if an array index begins with '0' | ||
10151 | @throw std::invalid_argument if an array index was not a number | ||
10152 | |||
10153 | @liveexample{The behavior is shown in the example.,at_json_pointer_const} | ||
10154 | |||
10155 | @since version 2.0.0 | ||
10156 | */ | ||
10157 | const_reference at(const json_pointer& ptr) const | ||
10158 | { | ||
10159 | return ptr.get_checked(this); | ||
10160 | } | ||
10161 | |||
10162 | /*! | ||
10163 | @brief return flattened JSON value | ||
10164 | |||
10165 | The function creates a JSON object whose keys are JSON pointers (see [RFC | ||
10166 | 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all | ||
10167 | primitive. The original JSON value can be restored using the @ref | ||
10168 | unflatten() function. | ||
10169 | |||
10170 | @return an object that maps JSON pointers to primitve values | ||
10171 | |||
10172 | @note Empty objects and arrays are flattened to `null` and will not be | ||
10173 | reconstructed correctly by the @ref unflatten() function. | ||
10174 | |||
10175 | @complexity Linear in the size the JSON value. | ||
10176 | |||
10177 | @liveexample{The following code shows how a JSON object is flattened to an | ||
10178 | object whose keys consist of JSON pointers.,flatten} | ||
10179 | |||
10180 | @sa @ref unflatten() for the reverse function | ||
10181 | |||
10182 | @since version 2.0.0 | ||
10183 | */ | ||
10184 | basic_json flatten() const | ||
10185 | { | ||
10186 | basic_json result(value_t::object); | ||
10187 | json_pointer::flatten("", *this, result); | ||
10188 | return result; | ||
10189 | } | ||
10190 | |||
10191 | /*! | ||
10192 | @brief unflatten a previously flattened JSON value | ||
10193 | |||
10194 | The function restores the arbitrary nesting of a JSON value that has been | ||
10195 | flattened before using the @ref flatten() function. The JSON value must | ||
10196 | meet certain constraints: | ||
10197 | 1. The value must be an object. | ||
10198 | 2. The keys must be JSON pointers (see | ||
10199 | [RFC 6901](https://tools.ietf.org/html/rfc6901)) | ||
10200 | 3. The mapped values must be primitive JSON types. | ||
10201 | |||
10202 | @return the original JSON from a flattened version | ||
10203 | |||
10204 | @note Empty objects and arrays are flattened by @ref flatten() to `null` | ||
10205 | values and can not unflattened to their original type. Apart from | ||
10206 | this example, for a JSON value `j`, the following is always true: | ||
10207 | `j == j.flatten().unflatten()`. | ||
10208 | |||
10209 | @complexity Linear in the size the JSON value. | ||
10210 | |||
10211 | @liveexample{The following code shows how a flattened JSON object is | ||
10212 | unflattened into the original nested JSON object.,unflatten} | ||
10213 | |||
10214 | @sa @ref flatten() for the reverse function | ||
10215 | |||
10216 | @since version 2.0.0 | ||
10217 | */ | ||
10218 | basic_json unflatten() const | ||
10219 | { | ||
10220 | return json_pointer::unflatten(*this); | ||
10221 | } | ||
10222 | |||
10223 | /// @} | ||
10224 | |||
10225 | ////////////////////////// | ||
10226 | // JSON Patch functions // | ||
10227 | ////////////////////////// | ||
10228 | |||
10229 | /// @name JSON Patch functions | ||
10230 | /// @{ | ||
10231 | |||
10232 | /*! | ||
10233 | @brief applies a JSON patch | ||
10234 | |||
10235 | [JSON Patch](http://jsonpatch.com) defines a JSON document structure for | ||
10236 | expressing a sequence of operations to apply to a JSON) document. With | ||
10237 | this funcion, a JSON Patch is applied to the current JSON value by | ||
10238 | executing all operations from the patch. | ||
10239 | |||
10240 | @param[in] json_patch JSON patch document | ||
10241 | @return patched document | ||
10242 | |||
10243 | @note The application of a patch is atomic: Either all operations succeed | ||
10244 | and the patched document is returned or an exception is thrown. In | ||
10245 | any case, the original value is not changed: the patch is applied | ||
10246 | to a copy of the value. | ||
10247 | |||
10248 | @throw std::out_of_range if a JSON pointer inside the patch could not | ||
10249 | be resolved successfully in the current JSON value; example: `"key baz | ||
10250 | not found"` | ||
10251 | @throw invalid_argument if the JSON patch is malformed (e.g., mandatory | ||
10252 | attributes are missing); example: `"operation add must have member path"` | ||
10253 | |||
10254 | @complexity Linear in the size of the JSON value and the length of the | ||
10255 | JSON patch. As usually only a fraction of the JSON value is affected by | ||
10256 | the patch, the complexity can usually be neglected. | ||
10257 | |||
10258 | @liveexample{The following code shows how a JSON patch is applied to a | ||
10259 | value.,patch} | ||
10260 | |||
10261 | @sa @ref diff -- create a JSON patch by comparing two JSON values | ||
10262 | |||
10263 | @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) | ||
10264 | @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) | ||
10265 | |||
10266 | @since version 2.0.0 | ||
10267 | */ | ||
10268 | basic_json patch(const basic_json& json_patch) const | ||
10269 | { | ||
10270 | // make a working copy to apply the patch to | ||
10271 | basic_json result = *this; | ||
10272 | |||
10273 | // the valid JSON Patch operations | ||
10274 | enum class patch_operations {add, remove, replace, move, copy, test, invalid}; | ||
10275 | |||
10276 | const auto get_op = [](const std::string op) | ||
10277 | { | ||
10278 | if (op == "add") | ||
10279 | { | ||
10280 | return patch_operations::add; | ||
10281 | } | ||
10282 | if (op == "remove") | ||
10283 | { | ||
10284 | return patch_operations::remove; | ||
10285 | } | ||
10286 | if (op == "replace") | ||
10287 | { | ||
10288 | return patch_operations::replace; | ||
10289 | } | ||
10290 | if (op == "move") | ||
10291 | { | ||
10292 | return patch_operations::move; | ||
10293 | } | ||
10294 | if (op == "copy") | ||
10295 | { | ||
10296 | return patch_operations::copy; | ||
10297 | } | ||
10298 | if (op == "test") | ||
10299 | { | ||
10300 | return patch_operations::test; | ||
10301 | } | ||
10302 | |||
10303 | return patch_operations::invalid; | ||
10304 | }; | ||
10305 | |||
10306 | // wrapper for "add" operation; add value at ptr | ||
10307 | const auto operation_add = [&result](json_pointer & ptr, basic_json val) | ||
10308 | { | ||
10309 | // adding to the root of the target document means replacing it | ||
10310 | if (ptr.is_root()) | ||
10311 | { | ||
10312 | result = val; | ||
10313 | } | ||
10314 | else | ||
10315 | { | ||
10316 | // make sure the top element of the pointer exists | ||
10317 | json_pointer top_pointer = ptr.top(); | ||
10318 | if (top_pointer != ptr) | ||
10319 | { | ||
10320 | result.at(top_pointer); | ||
10321 | } | ||
10322 | |||
10323 | // get reference to parent of JSON pointer ptr | ||
10324 | const auto last_path = ptr.pop_back(); | ||
10325 | basic_json& parent = result[ptr]; | ||
10326 | |||
10327 | switch (parent.m_type) | ||
10328 | { | ||
10329 | case value_t::null: | ||
10330 | case value_t::object: | ||
10331 | { | ||
10332 | // use operator[] to add value | ||
10333 | parent[last_path] = val; | ||
10334 | break; | ||
10335 | } | ||
10336 | |||
10337 | case value_t::array: | ||
10338 | { | ||
10339 | if (last_path == "-") | ||
10340 | { | ||
10341 | // special case: append to back | ||
10342 | parent.push_back(val); | ||
10343 | } | ||
10344 | else | ||
10345 | { | ||
10346 | const auto idx = std::stoi(last_path); | ||
10347 | if (static_cast<size_type>(idx) > parent.size()) | ||
10348 | { | ||
10349 | // avoid undefined behavior | ||
10350 | throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); | ||
10351 | } | ||
10352 | else | ||
10353 | { | ||
10354 | // default case: insert add offset | ||
10355 | parent.insert(parent.begin() + static_cast<difference_type>(idx), val); | ||
10356 | } | ||
10357 | } | ||
10358 | break; | ||
10359 | } | ||
10360 | |||
10361 | default: | ||
10362 | { | ||
10363 | // if there exists a parent it cannot be primitive | ||
10364 | assert(false); // LCOV_EXCL_LINE | ||
10365 | } | ||
10366 | } | ||
10367 | } | ||
10368 | }; | ||
10369 | |||
10370 | // wrapper for "remove" operation; remove value at ptr | ||
10371 | const auto operation_remove = [&result](json_pointer & ptr) | ||
10372 | { | ||
10373 | // get reference to parent of JSON pointer ptr | ||
10374 | const auto last_path = ptr.pop_back(); | ||
10375 | basic_json& parent = result.at(ptr); | ||
10376 | |||
10377 | // remove child | ||
10378 | if (parent.is_object()) | ||
10379 | { | ||
10380 | // perform range check | ||
10381 | auto it = parent.find(last_path); | ||
10382 | if (it != parent.end()) | ||
10383 | { | ||
10384 | parent.erase(it); | ||
10385 | } | ||
10386 | else | ||
10387 | { | ||
10388 | throw std::out_of_range("key '" + last_path + "' not found"); | ||
10389 | } | ||
10390 | } | ||
10391 | else if (parent.is_array()) | ||
10392 | { | ||
10393 | // note erase performs range check | ||
10394 | parent.erase(static_cast<size_type>(std::stoi(last_path))); | ||
10395 | } | ||
10396 | }; | ||
10397 | |||
10398 | // type check | ||
10399 | if (not json_patch.is_array()) | ||
10400 | { | ||
10401 | // a JSON patch must be an array of objects | ||
10402 | throw std::invalid_argument("JSON patch must be an array of objects"); | ||
10403 | } | ||
10404 | |||
10405 | // iterate and apply th eoperations | ||
10406 | for (const auto& val : json_patch) | ||
10407 | { | ||
10408 | // wrapper to get a value for an operation | ||
10409 | const auto get_value = [&val](const std::string & op, | ||
10410 | const std::string & member, | ||
10411 | bool string_type) -> basic_json& | ||
10412 | { | ||
10413 | // find value | ||
10414 | auto it = val.m_value.object->find(member); | ||
10415 | |||
10416 | // context-sensitive error message | ||
10417 | const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; | ||
10418 | |||
10419 | // check if desired value is present | ||
10420 | if (it == val.m_value.object->end()) | ||
10421 | { | ||
10422 | throw std::invalid_argument(error_msg + " must have member '" + member + "'"); | ||
10423 | } | ||
10424 | |||
10425 | // check if result is of type string | ||
10426 | if (string_type and not it->second.is_string()) | ||
10427 | { | ||
10428 | throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); | ||
10429 | } | ||
10430 | |||
10431 | // no error: return value | ||
10432 | return it->second; | ||
10433 | }; | ||
10434 | |||
10435 | // type check | ||
10436 | if (not val.is_object()) | ||
10437 | { | ||
10438 | throw std::invalid_argument("JSON patch must be an array of objects"); | ||
10439 | } | ||
10440 | |||
10441 | // collect mandatory members | ||
10442 | const std::string op = get_value("op", "op", true); | ||
10443 | const std::string path = get_value(op, "path", true); | ||
10444 | json_pointer ptr(path); | ||
10445 | |||
10446 | switch (get_op(op)) | ||
10447 | { | ||
10448 | case patch_operations::add: | ||
10449 | { | ||
10450 | operation_add(ptr, get_value("add", "value", false)); | ||
10451 | break; | ||
10452 | } | ||
10453 | |||
10454 | case patch_operations::remove: | ||
10455 | { | ||
10456 | operation_remove(ptr); | ||
10457 | break; | ||
10458 | } | ||
10459 | |||
10460 | case patch_operations::replace: | ||
10461 | { | ||
10462 | // the "path" location must exist - use at() | ||
10463 | result.at(ptr) = get_value("replace", "value", false); | ||
10464 | break; | ||
10465 | } | ||
10466 | |||
10467 | case patch_operations::move: | ||
10468 | { | ||
10469 | const std::string from_path = get_value("move", "from", true); | ||
10470 | json_pointer from_ptr(from_path); | ||
10471 | |||
10472 | // the "from" location must exist - use at() | ||
10473 | basic_json v = result.at(from_ptr); | ||
10474 | |||
10475 | // The move operation is functionally identical to a | ||
10476 | // "remove" operation on the "from" location, followed | ||
10477 | // immediately by an "add" operation at the target | ||
10478 | // location with the value that was just removed. | ||
10479 | operation_remove(from_ptr); | ||
10480 | operation_add(ptr, v); | ||
10481 | break; | ||
10482 | } | ||
10483 | |||
10484 | case patch_operations::copy: | ||
10485 | { | ||
10486 | const std::string from_path = get_value("copy", "from", true);; | ||
10487 | const json_pointer from_ptr(from_path); | ||
10488 | |||
10489 | // the "from" location must exist - use at() | ||
10490 | result[ptr] = result.at(from_ptr); | ||
10491 | break; | ||
10492 | } | ||
10493 | |||
10494 | case patch_operations::test: | ||
10495 | { | ||
10496 | bool success = false; | ||
10497 | try | ||
10498 | { | ||
10499 | // check if "value" matches the one at "path" | ||
10500 | // the "path" location must exist - use at() | ||
10501 | success = (result.at(ptr) == get_value("test", "value", false)); | ||
10502 | } | ||
10503 | catch (std::out_of_range&) | ||
10504 | { | ||
10505 | // ignore out of range errors: success remains false | ||
10506 | } | ||
10507 | |||
10508 | // throw an exception if test fails | ||
10509 | if (not success) | ||
10510 | { | ||
10511 | throw std::domain_error("unsuccessful: " + val.dump()); | ||
10512 | } | ||
10513 | |||
10514 | break; | ||
10515 | } | ||
10516 | |||
10517 | case patch_operations::invalid: | ||
10518 | { | ||
10519 | // op must be "add", "remove", "replace", "move", "copy", or | ||
10520 | // "test" | ||
10521 | throw std::invalid_argument("operation value '" + op + "' is invalid"); | ||
10522 | } | ||
10523 | } | ||
10524 | } | ||
10525 | |||
10526 | return result; | ||
10527 | } | ||
10528 | |||
10529 | /*! | ||
10530 | @brief creates a diff as a JSON patch | ||
10531 | |||
10532 | Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can | ||
10533 | be changed into the value @a target by calling @ref patch function. | ||
10534 | |||
10535 | @invariant For two JSON values @a source and @a target, the following code | ||
10536 | yields always `true`: | ||
10537 | @code {.cpp} | ||
10538 | source.patch(diff(source, target)) == target; | ||
10539 | @endcode | ||
10540 | |||
10541 | @note Currently, only `remove`, `add`, and `replace` operations are | ||
10542 | generated. | ||
10543 | |||
10544 | @param[in] source JSON value to copare from | ||
10545 | @param[in] target JSON value to copare against | ||
10546 | @param[in] path helper value to create JSON pointers | ||
10547 | |||
10548 | @return a JSON patch to convert the @a source to @a target | ||
10549 | |||
10550 | @complexity Linear in the lengths of @a source and @a target. | ||
10551 | |||
10552 | @liveexample{The following code shows how a JSON patch is created as a | ||
10553 | diff for two JSON values.,diff} | ||
10554 | |||
10555 | @sa @ref patch -- apply a JSON patch | ||
10556 | |||
10557 | @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) | ||
10558 | |||
10559 | @since version 2.0.0 | ||
10560 | */ | ||
10561 | static basic_json diff(const basic_json& source, | ||
10562 | const basic_json& target, | ||
10563 | const std::string& path = "") | ||
10564 | { | ||
10565 | // the patch | ||
10566 | basic_json result(value_t::array); | ||
10567 | |||
10568 | // if the values are the same, return empty patch | ||
10569 | if (source == target) | ||
10570 | { | ||
10571 | return result; | ||
10572 | } | ||
10573 | |||
10574 | if (source.type() != target.type()) | ||
10575 | { | ||
10576 | // different types: replace value | ||
10577 | result.push_back( | ||
10578 | { | ||
10579 | {"op", "replace"}, | ||
10580 | {"path", path}, | ||
10581 | {"value", target} | ||
10582 | }); | ||
10583 | } | ||
10584 | else | ||
10585 | { | ||
10586 | switch (source.type()) | ||
10587 | { | ||
10588 | case value_t::array: | ||
10589 | { | ||
10590 | // first pass: traverse common elements | ||
10591 | size_t i = 0; | ||
10592 | while (i < source.size() and i < target.size()) | ||
10593 | { | ||
10594 | // recursive call to compare array values at index i | ||
10595 | auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); | ||
10596 | result.insert(result.end(), temp_diff.begin(), temp_diff.end()); | ||
10597 | ++i; | ||
10598 | } | ||
10599 | |||
10600 | // i now reached the end of at least one array | ||
10601 | // in a second pass, traverse the remaining elements | ||
10602 | |||
10603 | // remove my remaining elements | ||
10604 | const auto end_index = static_cast<difference_type>(result.size()); | ||
10605 | while (i < source.size()) | ||
10606 | { | ||
10607 | // add operations in reverse order to avoid invalid | ||
10608 | // indices | ||
10609 | result.insert(result.begin() + end_index, object( | ||
10610 | { | ||
10611 | {"op", "remove"}, | ||
10612 | {"path", path + "/" + std::to_string(i)} | ||
10613 | })); | ||
10614 | ++i; | ||
10615 | } | ||
10616 | |||
10617 | // add other remaining elements | ||
10618 | while (i < target.size()) | ||
10619 | { | ||
10620 | result.push_back( | ||
10621 | { | ||
10622 | {"op", "add"}, | ||
10623 | {"path", path + "/" + std::to_string(i)}, | ||
10624 | {"value", target[i]} | ||
10625 | }); | ||
10626 | ++i; | ||
10627 | } | ||
10628 | |||
10629 | break; | ||
10630 | } | ||
10631 | |||
10632 | case value_t::object: | ||
10633 | { | ||
10634 | // first pass: traverse this object's elements | ||
10635 | for (auto it = source.begin(); it != source.end(); ++it) | ||
10636 | { | ||
10637 | // escape the key name to be used in a JSON patch | ||
10638 | const auto key = json_pointer::escape(it.key()); | ||
10639 | |||
10640 | if (target.find(it.key()) != target.end()) | ||
10641 | { | ||
10642 | // recursive call to compare object values at key it | ||
10643 | auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); | ||
10644 | result.insert(result.end(), temp_diff.begin(), temp_diff.end()); | ||
10645 | } | ||
10646 | else | ||
10647 | { | ||
10648 | // found a key that is not in o -> remove it | ||
10649 | result.push_back(object( | ||
10650 | { | ||
10651 | {"op", "remove"}, | ||
10652 | {"path", path + "/" + key} | ||
10653 | })); | ||
10654 | } | ||
10655 | } | ||
10656 | |||
10657 | // second pass: traverse other object's elements | ||
10658 | for (auto it = target.begin(); it != target.end(); ++it) | ||
10659 | { | ||
10660 | if (source.find(it.key()) == source.end()) | ||
10661 | { | ||
10662 | // found a key that is not in this -> add it | ||
10663 | const auto key = json_pointer::escape(it.key()); | ||
10664 | result.push_back( | ||
10665 | { | ||
10666 | {"op", "add"}, | ||
10667 | {"path", path + "/" + key}, | ||
10668 | {"value", it.value()} | ||
10669 | }); | ||
10670 | } | ||
10671 | } | ||
10672 | |||
10673 | break; | ||
10674 | } | ||
10675 | |||
10676 | default: | ||
10677 | { | ||
10678 | // both primitive type: replace value | ||
10679 | result.push_back( | ||
10680 | { | ||
10681 | {"op", "replace"}, | ||
10682 | {"path", path}, | ||
10683 | {"value", target} | ||
10684 | }); | ||
10685 | break; | ||
10686 | } | ||
10687 | } | ||
10688 | } | ||
10689 | |||
10690 | return result; | ||
10691 | } | ||
10692 | |||
10693 | /// @} | ||
10694 | }; | ||
10695 | |||
10696 | |||
10697 | ///////////// | ||
10698 | // presets // | ||
10699 | ///////////// | ||
10700 | |||
10701 | /*! | ||
10702 | @brief default JSON class | ||
10703 | |||
10704 | This type is the default specialization of the @ref basic_json class which | ||
10705 | uses the standard template types. | ||
10706 | |||
10707 | @since version 1.0.0 | ||
10708 | */ | ||
10709 | using json = basic_json<>; | ||
10710 | } | ||
10711 | |||
10712 | |||
10713 | /////////////////////// | ||
10714 | // nonmember support // | ||
10715 | /////////////////////// | ||
10716 | |||
10717 | // specialization of std::swap, and std::hash | ||
10718 | namespace std | ||
10719 | { | ||
10720 | /*! | ||
10721 | @brief exchanges the values of two JSON objects | ||
10722 | |||
10723 | @since version 1.0.0 | ||
10724 | */ | ||
10725 | template<> | ||
10726 | inline void swap(nlohmann::json& j1, | ||
10727 | nlohmann::json& j2) noexcept( | ||
10728 | is_nothrow_move_constructible<nlohmann::json>::value and | ||
10729 | is_nothrow_move_assignable<nlohmann::json>::value | ||
10730 | ) | ||
10731 | { | ||
10732 | j1.swap(j2); | ||
10733 | } | ||
10734 | |||
10735 | /// hash value for JSON objects | ||
10736 | template<> | ||
10737 | struct hash<nlohmann::json> | ||
10738 | { | ||
10739 | /*! | ||
10740 | @brief return a hash value for a JSON object | ||
10741 | |||
10742 | @since version 1.0.0 | ||
10743 | */ | ||
10744 | std::size_t operator()(const nlohmann::json& j) const | ||
10745 | { | ||
10746 | // a naive hashing via the string representation | ||
10747 | const auto& h = hash<nlohmann::json::string_t>(); | ||
10748 | return h(j.dump()); | ||
10749 | } | ||
10750 | }; | ||
10751 | } | ||
10752 | |||
10753 | /*! | ||
10754 | @brief user-defined string literal for JSON values | ||
10755 | |||
10756 | This operator implements a user-defined string literal for JSON objects. It | ||
10757 | can be used by adding `"_json"` to a string literal and returns a JSON object | ||
10758 | if no parse error occurred. | ||
10759 | |||
10760 | @param[in] s a string representation of a JSON object | ||
10761 | @param[in] n the length of string @a s | ||
10762 | @return a JSON object | ||
10763 | |||
10764 | @since version 1.0.0 | ||
10765 | */ | ||
10766 | inline nlohmann::json operator "" _json(const char* s, std::size_t n) | ||
10767 | { | ||
10768 | return nlohmann::json::parse(s, s + n); | ||
10769 | } | ||
10770 | |||
10771 | /*! | ||
10772 | @brief user-defined string literal for JSON pointer | ||
10773 | |||
10774 | This operator implements a user-defined string literal for JSON Pointers. It | ||
10775 | can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer | ||
10776 | object if no parse error occurred. | ||
10777 | |||
10778 | @param[in] s a string representation of a JSON Pointer | ||
10779 | @param[in] n the length of string @a s | ||
10780 | @return a JSON pointer object | ||
10781 | |||
10782 | @since version 2.0.0 | ||
10783 | */ | ||
10784 | inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) | ||
10785 | { | ||
10786 | return nlohmann::json::json_pointer(std::string(s, n)); | ||
10787 | } | ||
10788 | |||
10789 | // restore GCC/clang diagnostic settings | ||
10790 | #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) | ||
10791 | #pragma GCC diagnostic pop | ||
10792 | #endif | ||
10793 | |||
10794 | #endif | ||