diff options
-rw-r--r-- | lib/RT.cpp | 23 | ||||
-rw-r--r-- | lib/RT.hpp | 37 | ||||
-rw-r--r-- | lib/json.hpp | 7307 | ||||
-rw-r--r-- | templates/data.cpp.ede | 42 | ||||
-rw-r--r-- | templates/data.hpp.ede | 19 |
5 files changed, 7368 insertions, 60 deletions
diff --git a/lib/RT.cpp b/lib/RT.cpp new file mode 100644 index 0000000..b8a1aea --- /dev/null +++ b/lib/RT.cpp | |||
@@ -0,0 +1,23 @@ | |||
1 | #include "RT.hpp" | ||
2 | |||
3 | template<> json toJSON<String>(String &v) { | ||
4 | return json(v); | ||
5 | } | ||
6 | |||
7 | template<> json toJSON<Float>(Float &v) { | ||
8 | return json(v); | ||
9 | } | ||
10 | |||
11 | template<> json toJSON<bool>(bool &v) { | ||
12 | return json(v); | ||
13 | } | ||
14 | |||
15 | template<> json toJSON<int>(int &v) { | ||
16 | return json(v); | ||
17 | } | ||
18 | |||
19 | template<> json toJSON<unsigned int>(unsigned int &v) { | ||
20 | return json(v); | ||
21 | } | ||
22 | |||
23 | |||
diff --git a/lib/RT.hpp b/lib/RT.hpp new file mode 100644 index 0000000..1d90f7c --- /dev/null +++ b/lib/RT.hpp | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef HEADER_RT_H | ||
2 | #define HEADER_RT_H | ||
3 | |||
4 | #include <vector> | ||
5 | #include <map> | ||
6 | #include <string> | ||
7 | |||
8 | #include "json.hpp" | ||
9 | |||
10 | using json = nlohmann::json; | ||
11 | |||
12 | typedef int Int; | ||
13 | typedef int Int32; | ||
14 | typedef unsigned int Word; | ||
15 | typedef unsigned int Word32; | ||
16 | typedef float Float; | ||
17 | typedef bool Bool; | ||
18 | typedef std::string String; | ||
19 | |||
20 | template<typename T> | ||
21 | json toJSON(T &v); | ||
22 | |||
23 | template<typename any> | ||
24 | json toJSON(std::vector<any> &v) { | ||
25 | json obj = json::array(); | ||
26 | for (any i : v) { | ||
27 | obj.push_back(toJSON(i)); | ||
28 | } | ||
29 | return obj; | ||
30 | } | ||
31 | |||
32 | template<typename k, typename v> | ||
33 | json toJSON(std::map<k,v> &value) { | ||
34 | return json(); | ||
35 | } | ||
36 | |||
37 | #endif \ No newline at end of file | ||
diff --git a/lib/json.hpp b/lib/json.hpp new file mode 100644 index 0000000..bdea958 --- /dev/null +++ b/lib/json.hpp | |||
@@ -0,0 +1,7307 @@ | |||
1 | /*! | ||
2 | @mainpage | ||
3 | |||
4 | These pages contain the API documentation of JSON for Modern C++, a C++11 | ||
5 | header-only JSON class. | ||
6 | |||
7 | Class @ref nlohmann::basic_json is a good entry point for the documentation. | ||
8 | |||
9 | @copyright The code is licensed under the [MIT | ||
10 | License](http://opensource.org/licenses/MIT): | ||
11 | <br> | ||
12 | Copyright © 2013-2015 Niels Lohmann. | ||
13 | <br> | ||
14 | Permission is hereby granted, free of charge, to any person | ||
15 | obtaining a copy of this software and associated documentation files | ||
16 | (the "Software"), to deal in the Software without restriction, | ||
17 | including without limitation the rights to use, copy, modify, merge, | ||
18 | publish, distribute, sublicense, and/or sell copies of the Software, | ||
19 | and to permit persons to whom the Software is furnished to do so, | ||
20 | subject to the following conditions: | ||
21 | <br> | ||
22 | The above copyright notice and this permission notice shall be | ||
23 | included in all copies or substantial portions of the Software. | ||
24 | <br> | ||
25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
26 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
27 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
28 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
29 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
30 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
31 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
32 | SOFTWARE. | ||
33 | |||
34 | @author [Niels Lohmann](http://nlohmann.me) | ||
35 | @see https://github.com/nlohmann/json to download the source code | ||
36 | */ | ||
37 | |||
38 | #ifndef NLOHMANN_JSON_HPP | ||
39 | #define NLOHMANN_JSON_HPP | ||
40 | |||
41 | #include <algorithm> | ||
42 | #include <array> | ||
43 | #include <ciso646> | ||
44 | #include <cmath> | ||
45 | #include <cstdio> | ||
46 | #include <functional> | ||
47 | #include <initializer_list> | ||
48 | #include <iomanip> | ||
49 | #include <iostream> | ||
50 | #include <iterator> | ||
51 | #include <limits> | ||
52 | #include <map> | ||
53 | #include <memory> | ||
54 | #include <sstream> | ||
55 | #include <string> | ||
56 | #include <type_traits> | ||
57 | #include <utility> | ||
58 | #include <vector> | ||
59 | |||
60 | // enable ssize_t on MinGW | ||
61 | #ifdef __GNUC__ | ||
62 | #ifdef __MINGW32__ | ||
63 | #include <sys/types.h> | ||
64 | #endif | ||
65 | #endif | ||
66 | |||
67 | // enable ssize_t for MSVC | ||
68 | #ifdef _MSC_VER | ||
69 | #include <basetsd.h> | ||
70 | using ssize_t = SSIZE_T; | ||
71 | #endif | ||
72 | |||
73 | /*! | ||
74 | @brief namespace for Niels Lohmann | ||
75 | @see https://github.com/nlohmann | ||
76 | */ | ||
77 | namespace nlohmann | ||
78 | { | ||
79 | |||
80 | |||
81 | /*! | ||
82 | @brief unnamed namespace with internal helper functions | ||
83 | */ | ||
84 | namespace | ||
85 | { | ||
86 | /*! | ||
87 | @brief Helper to determine whether there's a key_type for T. | ||
88 | @sa http://stackoverflow.com/a/7728728/266378 | ||
89 | */ | ||
90 | template<typename T> | ||
91 | struct has_mapped_type | ||
92 | { | ||
93 | private: | ||
94 | template<typename C> static char test(typename C::mapped_type*); | ||
95 | template<typename C> static int test(...); | ||
96 | public: | ||
97 | enum { value = sizeof(test<T>(0)) == sizeof(char) }; | ||
98 | }; | ||
99 | |||
100 | /// "equality" comparison for floating point numbers | ||
101 | template<typename T> | ||
102 | static bool approx(const T a, const T b) | ||
103 | { | ||
104 | return not (a > b or a < b); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | /*! | ||
109 | @brief a class to store JSON values | ||
110 | |||
111 | @tparam ObjectType type for JSON objects (@c std::map by default; will be used | ||
112 | in @ref object_t) | ||
113 | @tparam ArrayType type for JSON arrays (@c std::vector by default; will be used | ||
114 | in @ref array_t) | ||
115 | @tparam StringType type for JSON strings and object keys (@c std::string by | ||
116 | default; will be used in @ref string_t) | ||
117 | @tparam BooleanType type for JSON booleans (@c `bool` by default; will be used | ||
118 | in @ref boolean_t) | ||
119 | @tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by | ||
120 | default; will be used in @ref number_integer_t) | ||
121 | @tparam NumberFloatType type for JSON floating-point numbers (@c `double` by | ||
122 | default; will be used in @ref number_float_t) | ||
123 | @tparam AllocatorType type of the allocator to use (@c `std::allocator` by | ||
124 | default) | ||
125 | |||
126 | @requirement The class satisfies the following concept requirements: | ||
127 | - Basic | ||
128 | - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): | ||
129 | JSON values can be default constructed. The result will be a JSON null value. | ||
130 | - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): | ||
131 | A JSON value can be constructed from an rvalue argument. | ||
132 | - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): | ||
133 | A JSON value can be copy-constrcuted from an lvalue expression. | ||
134 | - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): | ||
135 | A JSON value van be assigned from an rvalue argument. | ||
136 | - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): | ||
137 | A JSON value can be copy-assigned from an lvalue expression. | ||
138 | - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): | ||
139 | JSON values can be destructed. | ||
140 | - Layout | ||
141 | - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): | ||
142 | JSON values have | ||
143 | [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): | ||
144 | All non-static data members are private and standard layout types, the class | ||
145 | has no virtual functions or (virtual) base classes. | ||
146 | - Library-wide | ||
147 | - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): | ||
148 | JSON values can be compared with `==`, see @ref | ||
149 | operator==(const_reference,const_reference). | ||
150 | - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): | ||
151 | JSON values can be compared with `<`, see @ref | ||
152 | operator<(const_reference,const_reference). | ||
153 | - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): | ||
154 | Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of | ||
155 | other compatible types, using unqualified function call @ref swap(). | ||
156 | - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): | ||
157 | JSON values can be compared against `std::nullptr_t` objects which are used | ||
158 | to model the `null` value. | ||
159 | - Container | ||
160 | - [Container](http://en.cppreference.com/w/cpp/concept/Container): | ||
161 | JSON values can be used like STL containers and provide iterator access. | ||
162 | - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); | ||
163 | JSON values can be used like STL containers and provide reverse iterator | ||
164 | access. | ||
165 | |||
166 | @internal | ||
167 | @note ObjectType trick from http://stackoverflow.com/a/9860911 | ||
168 | @endinternal | ||
169 | |||
170 | @see RFC 7159 <http://rfc7159.net/rfc7159> | ||
171 | */ | ||
172 | template < | ||
173 | template<typename U, typename V, typename... Args> class ObjectType = std::map, | ||
174 | template<typename U, typename... Args> class ArrayType = std::vector, | ||
175 | class StringType = std::string, | ||
176 | class BooleanType = bool, | ||
177 | class NumberIntegerType = int64_t, | ||
178 | class NumberFloatType = double, | ||
179 | template<typename U> class AllocatorType = std::allocator | ||
180 | > | ||
181 | class basic_json | ||
182 | { | ||
183 | private: | ||
184 | /// workaround type for MSVC | ||
185 | using basic_json_t = basic_json<ObjectType, | ||
186 | ArrayType, | ||
187 | StringType, | ||
188 | BooleanType, | ||
189 | NumberIntegerType, | ||
190 | NumberFloatType, | ||
191 | AllocatorType>; | ||
192 | |||
193 | public: | ||
194 | |||
195 | ///////////////////// | ||
196 | // container types // | ||
197 | ///////////////////// | ||
198 | |||
199 | /// @name container types | ||
200 | /// @{ | ||
201 | |||
202 | /// the type of elements in a basic_json container | ||
203 | using value_type = basic_json; | ||
204 | |||
205 | /// the type of an element reference | ||
206 | using reference = value_type&; | ||
207 | |||
208 | /// the type of an element const reference | ||
209 | using const_reference = const value_type&; | ||
210 | |||
211 | /// a type to represent differences between iterators | ||
212 | using difference_type = std::ptrdiff_t; | ||
213 | |||
214 | /// a type to represent container sizes | ||
215 | using size_type = std::size_t; | ||
216 | |||
217 | /// the allocator type | ||
218 | using allocator_type = AllocatorType<basic_json>; | ||
219 | |||
220 | /// the type of an element pointer | ||
221 | using pointer = typename std::allocator_traits<allocator_type>::pointer; | ||
222 | /// the type of an element const pointer | ||
223 | using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; | ||
224 | |||
225 | // forward declaration | ||
226 | template<typename Base> class json_reverse_iterator; | ||
227 | |||
228 | /// an iterator for a basic_json container | ||
229 | class iterator; | ||
230 | /// a const iterator for a basic_json container | ||
231 | class const_iterator; | ||
232 | /// a reverse iterator for a basic_json container | ||
233 | using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>; | ||
234 | /// a const reverse iterator for a basic_json container | ||
235 | using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>; | ||
236 | |||
237 | /// @} | ||
238 | |||
239 | |||
240 | /*! | ||
241 | @brief returns the allocator associated with the container | ||
242 | */ | ||
243 | static allocator_type get_allocator() | ||
244 | { | ||
245 | return allocator_type(); | ||
246 | } | ||
247 | |||
248 | |||
249 | /////////////////////////// | ||
250 | // JSON value data types // | ||
251 | /////////////////////////// | ||
252 | |||
253 | /// @name JSON value data types | ||
254 | /// @{ | ||
255 | |||
256 | /*! | ||
257 | @brief a type for an object | ||
258 | |||
259 | [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: | ||
260 | > An object is an unordered collection of zero or more name/value pairs, | ||
261 | > where a name is a string and a value is a string, number, boolean, null, | ||
262 | > object, or array. | ||
263 | |||
264 | To store objects in C++, a type is defined by the template parameters @a | ||
265 | ObjectType which chooses the container (e.g., `std::map` or | ||
266 | `std::unordered_map`), @a StringType which chooses the type of the keys or | ||
267 | names, and @a AllocatorType which chooses the allocator to use. | ||
268 | |||
269 | #### Default type | ||
270 | |||
271 | With the default values for @a ObjectType (`std::map`), @a StringType | ||
272 | (`std::string`), and @a AllocatorType (`std::allocator`), the default value | ||
273 | for @a object_t is: | ||
274 | |||
275 | @code {.cpp} | ||
276 | std::map< | ||
277 | std::string, // key_type | ||
278 | basic_json, // value_type | ||
279 | std::less<std::string>, // key_compare | ||
280 | std::allocator<std::pair<const std::string, basic_json>> // allocator_type | ||
281 | > | ||
282 | @endcode | ||
283 | |||
284 | #### Behavior | ||
285 | |||
286 | The choice of @a object_t influences the behavior of the JSON class. With | ||
287 | the default type, objects have the following behavior: | ||
288 | |||
289 | - When all names are unique, objects will be interoperable in the sense | ||
290 | that all software implementations receiving that object will agree on the | ||
291 | name-value mappings. | ||
292 | - When the names within an object are not unique, later stored name/value | ||
293 | pairs overwrite previously stored name/value pairs, leaving the used | ||
294 | names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will | ||
295 | be treated as equal and both stored as `{"key": 1}`. | ||
296 | - Internally, name/value pairs are stored in lexicographical order of the | ||
297 | names. Objects will also be serialized (see @ref dump) in this order. For | ||
298 | instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and | ||
299 | serialized as `{"a": 2, "b": 1}`. | ||
300 | - When comparing objects, the order of the name/value pairs is irrelevant. | ||
301 | This makes objects interoperable in the sense that they will not be | ||
302 | affected by these differences. For instance, `{"b": 1, "a": 2}` and | ||
303 | `{"a": 2, "b": 1}` will be treated as equal. | ||
304 | |||
305 | #### Limits | ||
306 | |||
307 | [RFC 7159](http://rfc7159.net/rfc7159) specifies: | ||
308 | > An implementation may set limits on the maximum depth of nesting. | ||
309 | |||
310 | In this class, the object's limit of nesting is not constraint explicitly. | ||
311 | However, a maximum depth of nesting may be introduced by the compiler or | ||
312 | runtime environment. A theoretical limit can be queried by calling the @ref | ||
313 | max_size function of a JSON object. | ||
314 | |||
315 | #### Storage | ||
316 | |||
317 | Objects are stored as pointers in a `basic_json` type. That is, for any | ||
318 | access to object values, a pointer of type `object_t*` must be dereferenced. | ||
319 | |||
320 | @sa array_t | ||
321 | */ | ||
322 | using object_t = ObjectType<StringType, | ||
323 | basic_json, | ||
324 | std::less<StringType>, | ||
325 | AllocatorType<std::pair<const StringType, | ||
326 | basic_json>>>; | ||
327 | |||
328 | /*! | ||
329 | @brief a type for an array | ||
330 | |||
331 | [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: | ||
332 | > An array is an ordered sequence of zero or more values. | ||
333 | |||
334 | To store objects in C++, a type is defined by the template parameters @a | ||
335 | ArrayType which chooses the container (e.g., `std::vector` or `std::list`) | ||
336 | and @a AllocatorType which chooses the allocator to use. | ||
337 | |||
338 | #### Default type | ||
339 | |||
340 | With the default values for @a ArrayType (`std::vector`) and @a | ||
341 | AllocatorType (`std::allocator`), the default value for @a array_t is: | ||
342 | |||
343 | @code {.cpp} | ||
344 | std::vector< | ||
345 | basic_json, // value_type | ||
346 | std::allocator<basic_json> // allocator_type | ||
347 | > | ||
348 | @endcode | ||
349 | |||
350 | #### Limits | ||
351 | |||
352 | [RFC 7159](http://rfc7159.net/rfc7159) specifies: | ||
353 | > An implementation may set limits on the maximum depth of nesting. | ||
354 | |||
355 | In this class, the array's limit of nesting is not constraint explicitly. | ||
356 | However, a maximum depth of nesting may be introduced by the compiler or | ||
357 | runtime environment. A theoretical limit can be queried by calling the @ref | ||
358 | max_size function of a JSON array. | ||
359 | |||
360 | #### Storage | ||
361 | |||
362 | Arrays are stored as pointers in a `basic_json` type. That is, for any | ||
363 | access to array values, a pointer of type `array_t*` must be dereferenced. | ||
364 | */ | ||
365 | using array_t = ArrayType<basic_json, AllocatorType<basic_json>>; | ||
366 | |||
367 | /*! | ||
368 | @brief a type for a string | ||
369 | |||
370 | [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: | ||
371 | > A string is a sequence of zero or more Unicode characters. | ||
372 | |||
373 | To store objects in C++, a type is defined by the template parameters @a | ||
374 | StringType which chooses the container (e.g., `std::string`) to use. | ||
375 | |||
376 | Unicode values are split by the JSON class into byte-sized characters | ||
377 | during deserialization. | ||
378 | |||
379 | #### Default type | ||
380 | |||
381 | With the default values for @a StringType (`std::string`), the default | ||
382 | value for @a string_t is: | ||
383 | |||
384 | @code {.cpp} | ||
385 | std::string | ||
386 | @endcode | ||
387 | |||
388 | #### String comparison | ||
389 | |||
390 | [RFC 7159](http://rfc7159.net/rfc7159) states: | ||
391 | > Software implementations are typically required to test names of object | ||
392 | > members for equality. Implementations that transform the textual | ||
393 | > representation into sequences of Unicode code units and then perform the | ||
394 | > comparison numerically, code unit by code unit, are interoperable in the | ||
395 | > sense that implementations will agree in all cases on equality or | ||
396 | > inequality of two strings. For example, implementations that compare | ||
397 | > strings with escaped characters unconverted may incorrectly find that | ||
398 | > `"a\\b"` and `"a\u005Cb"` are not equal. | ||
399 | |||
400 | This implementation is interoperable as it does compare strings code unit | ||
401 | by code unit. | ||
402 | |||
403 | #### Storage | ||
404 | |||
405 | String values are stored as pointers in a `basic_json` type. That is, for | ||
406 | any access to string values, a pointer of type `string_t*` must be | ||
407 | dereferenced. | ||
408 | */ | ||
409 | using string_t = StringType; | ||
410 | |||
411 | /*! | ||
412 | @brief a type for a boolean | ||
413 | |||
414 | [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a | ||
415 | type which differentiates the two literals `true` and `false`. | ||
416 | |||
417 | To store objects in C++, a type is defined by the template parameter @a | ||
418 | BooleanType which chooses the type to use. | ||
419 | |||
420 | #### Default type | ||
421 | |||
422 | With the default values for @a BooleanType (`bool`), the default value for | ||
423 | @a boolean_t is: | ||
424 | |||
425 | @code {.cpp} | ||
426 | bool | ||
427 | @endcode | ||
428 | |||
429 | #### Storage | ||
430 | |||
431 | Boolean values are stored directly inside a `basic_json` type. | ||
432 | */ | ||
433 | using boolean_t = BooleanType; | ||
434 | |||
435 | /*! | ||
436 | @brief a type for a number (integer) | ||
437 | |||
438 | [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: | ||
439 | > The representation of numbers is similar to that used in most programming | ||
440 | > languages. A number is represented in base 10 using decimal digits. It | ||
441 | > contains an integer component that may be prefixed with an optional minus | ||
442 | > sign, which may be followed by a fraction part and/or an exponent part. | ||
443 | > Leading zeros are not allowed. (...) Numeric values that cannot be | ||
444 | > represented in the grammar below (such as Infinity and NaN) are not | ||
445 | > permitted. | ||
446 | |||
447 | This description includes both integer and floating-point numbers. However, | ||
448 | C++ allows more precise storage if it is known whether the number is an | ||
449 | integer or a floating-point number. Therefore, two different types, @ref | ||
450 | number_integer_t and @ref number_float_t are used. | ||
451 | |||
452 | To store integer numbers in C++, a type is defined by the template | ||
453 | parameter @a NumberIntegerType which chooses the type to use. | ||
454 | |||
455 | #### Default type | ||
456 | |||
457 | With the default values for @a NumberIntegerType (`int64_t`), the default | ||
458 | value for @a number_integer_t is: | ||
459 | |||
460 | @code {.cpp} | ||
461 | int64_t | ||
462 | @endcode | ||
463 | |||
464 | #### Default behavior | ||
465 | |||
466 | - The restrictions about leading zeros is not enforced in C++. Instead, | ||
467 | leading zeros in integer literals lead to an interpretation as octal | ||
468 | number. Internally, the value will be stored as decimal number. For | ||
469 | instance, the C++ integer literal `010` will be serialized to `8`. During | ||
470 | deserialization, leading zeros yield an error. | ||
471 | - Not-a-number (NaN) values will be serialized to `null`. | ||
472 | |||
473 | #### Limits | ||
474 | |||
475 | [RFC 7159](http://rfc7159.net/rfc7159) specifies: | ||
476 | > An implementation may set limits on the range and precision of numbers. | ||
477 | |||
478 | When the default type is used, the maximal integer number that can be | ||
479 | stored is `9223372036854775807` (INT64_MAX) and the minimal integer number | ||
480 | that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers | ||
481 | that are out of range will yield over/underflow when used in a constructor. | ||
482 | During deserialization, too large or small integer numbers will be | ||
483 | automatically be stored as @ref number_float_t. | ||
484 | |||
485 | [RFC 7159](http://rfc7159.net/rfc7159) further states: | ||
486 | > Note that when such software is used, numbers that are integers and are | ||
487 | > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense | ||
488 | > that implementations will agree exactly on their numeric values. | ||
489 | |||
490 | As this range is a subrange of the exactly supported range [INT64_MIN, | ||
491 | INT64_MAX], this class's integer type is interoperable. | ||
492 | |||
493 | #### Storage | ||
494 | |||
495 | Integer number values are stored directly inside a `basic_json` type. | ||
496 | */ | ||
497 | using number_integer_t = NumberIntegerType; | ||
498 | |||
499 | /*! | ||
500 | @brief a type for a number (floating-point) | ||
501 | |||
502 | [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: | ||
503 | > The representation of numbers is similar to that used in most programming | ||
504 | > languages. A number is represented in base 10 using decimal digits. It | ||
505 | > contains an integer component that may be prefixed with an optional minus | ||
506 | > sign, which may be followed by a fraction part and/or an exponent part. | ||
507 | > Leading zeros are not allowed. (...) Numeric values that cannot be | ||
508 | > represented in the grammar below (such as Infinity and NaN) are not | ||
509 | > permitted. | ||
510 | |||
511 | This description includes both integer and floating-point numbers. However, | ||
512 | C++ allows more precise storage if it is known whether the number is an | ||
513 | integer or a floating-point number. Therefore, two different types, @ref | ||
514 | number_integer_t and @ref number_float_t are used. | ||
515 | |||
516 | To store floating-point numbers in C++, a type is defined by the template | ||
517 | parameter @a NumberFloatType which chooses the type to use. | ||
518 | |||
519 | #### Default type | ||
520 | |||
521 | With the default values for @a NumberFloatType (`double`), the default | ||
522 | value for @a number_float_t is: | ||
523 | |||
524 | @code {.cpp} | ||
525 | double | ||
526 | @endcode | ||
527 | |||
528 | #### Default behavior | ||
529 | |||
530 | - The restrictions about leading zeros is not enforced in C++. Instead, | ||
531 | leading zeros in floating-point literals will be ignored. Internally, the | ||
532 | value will be stored as decimal number. For instance, the C++ | ||
533 | floating-point literal `01.2` will be serialized to `1.2`. During | ||
534 | deserialization, leading zeros yield an error. | ||
535 | - Not-a-number (NaN) values will be serialized to `null`. | ||
536 | |||
537 | #### Limits | ||
538 | |||
539 | [RFC 7159](http://rfc7159.net/rfc7159) states: | ||
540 | > This specification allows implementations to set limits on the range and | ||
541 | > precision of numbers accepted. Since software that implements IEEE | ||
542 | > 754-2008 binary64 (double precision) numbers is generally available and | ||
543 | > widely used, good interoperability can be achieved by implementations that | ||
544 | > expect no more precision or range than these provide, in the sense that | ||
545 | > implementations will approximate JSON numbers within the expected | ||
546 | > precision. | ||
547 | |||
548 | This implementation does exactly follow this approach, as it uses double | ||
549 | precision floating-point numbers. Note values smaller than | ||
550 | `-1.79769313486232e+308` and values greather than `1.79769313486232e+308` | ||
551 | will be stored as NaN internally and be serialized to `null`. | ||
552 | |||
553 | #### Storage | ||
554 | |||
555 | Floating-point number values are stored directly inside a `basic_json` type. | ||
556 | */ | ||
557 | using number_float_t = NumberFloatType; | ||
558 | |||
559 | /// @} | ||
560 | |||
561 | |||
562 | /////////////////////////// | ||
563 | // JSON type enumeration // | ||
564 | /////////////////////////// | ||
565 | |||
566 | /*! | ||
567 | @brief the JSON type enumeration | ||
568 | |||
569 | This enumeration collects the different JSON types. It is internally used | ||
570 | to distinguish the stored values, and the functions is_null, is_object, | ||
571 | is_array, is_string, is_boolean, is_number, and is_discarded rely on it. | ||
572 | */ | ||
573 | enum class value_t : uint8_t | ||
574 | { | ||
575 | null, ///< null value | ||
576 | object, ///< object (unordered set of name/value pairs) | ||
577 | array, ///< array (ordered collection of values) | ||
578 | string, ///< string value | ||
579 | boolean, ///< boolean value | ||
580 | number_integer, ///< number value (integer) | ||
581 | number_float, ///< number value (floating-point) | ||
582 | discarded ///< discarded by the the parser callback function | ||
583 | }; | ||
584 | |||
585 | |||
586 | private: | ||
587 | //////////////////////// | ||
588 | // JSON value storage // | ||
589 | //////////////////////// | ||
590 | |||
591 | /// a JSON value | ||
592 | union json_value | ||
593 | { | ||
594 | /// object (stored with pointer to save storage) | ||
595 | object_t* object; | ||
596 | /// array (stored with pointer to save storage) | ||
597 | array_t* array; | ||
598 | /// string (stored with pointer to save storage) | ||
599 | string_t* string; | ||
600 | /// boolean | ||
601 | boolean_t boolean; | ||
602 | /// number (integer) | ||
603 | number_integer_t number_integer; | ||
604 | /// number (floating-point) | ||
605 | number_float_t number_float; | ||
606 | |||
607 | /// default constructor (for null values) | ||
608 | json_value() noexcept = default; | ||
609 | /// constructor for booleans | ||
610 | json_value(boolean_t v) noexcept : boolean(v) {} | ||
611 | /// constructor for numbers (integer) | ||
612 | json_value(number_integer_t v) noexcept : number_integer(v) {} | ||
613 | /// constructor for numbers (floating-point) | ||
614 | json_value(number_float_t v) noexcept : number_float(v) {} | ||
615 | /// constructor for empty values of a given type | ||
616 | json_value(value_t t) | ||
617 | { | ||
618 | switch (t) | ||
619 | { | ||
620 | case (value_t::null): | ||
621 | case (value_t::discarded): | ||
622 | { | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | case (value_t::object): | ||
627 | { | ||
628 | AllocatorType<object_t> alloc; | ||
629 | object = alloc.allocate(1); | ||
630 | alloc.construct(object); | ||
631 | break; | ||
632 | } | ||
633 | |||
634 | case (value_t::array): | ||
635 | { | ||
636 | AllocatorType<array_t> alloc; | ||
637 | array = alloc.allocate(1); | ||
638 | alloc.construct(array); | ||
639 | break; | ||
640 | } | ||
641 | |||
642 | case (value_t::string): | ||
643 | { | ||
644 | AllocatorType<string_t> alloc; | ||
645 | string = alloc.allocate(1); | ||
646 | alloc.construct(string, ""); | ||
647 | break; | ||
648 | } | ||
649 | |||
650 | case (value_t::boolean): | ||
651 | { | ||
652 | boolean = boolean_t(false); | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | case (value_t::number_integer): | ||
657 | { | ||
658 | number_integer = number_integer_t(0); | ||
659 | break; | ||
660 | } | ||
661 | |||
662 | case (value_t::number_float): | ||
663 | { | ||
664 | number_float = number_float_t(0.0); | ||
665 | break; | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | |||
670 | /// constructor for strings | ||
671 | json_value(const string_t& value) | ||
672 | { | ||
673 | AllocatorType<string_t> alloc; | ||
674 | string = alloc.allocate(1); | ||
675 | alloc.construct(string, value); | ||
676 | } | ||
677 | |||
678 | /// constructor for objects | ||
679 | json_value(const object_t& value) | ||
680 | { | ||
681 | AllocatorType<object_t> alloc; | ||
682 | object = alloc.allocate(1); | ||
683 | alloc.construct(object, value); | ||
684 | } | ||
685 | |||
686 | /// constructor for arrays | ||
687 | json_value(const array_t& value) | ||
688 | { | ||
689 | AllocatorType<array_t> alloc; | ||
690 | array = alloc.allocate(1); | ||
691 | alloc.construct(array, value); | ||
692 | } | ||
693 | }; | ||
694 | |||
695 | |||
696 | public: | ||
697 | ////////////////////////// | ||
698 | // JSON parser callback // | ||
699 | ////////////////////////// | ||
700 | |||
701 | /*! | ||
702 | @brief JSON callback events | ||
703 | |||
704 | This enumeration lists the parser events that can trigger calling a | ||
705 | callback function of type @ref parser_callback_t during parsing. | ||
706 | */ | ||
707 | enum class parse_event_t : uint8_t | ||
708 | { | ||
709 | /// the parser read `{` and started to process a JSON object | ||
710 | object_start, | ||
711 | /// the parser read `}` and finished processing a JSON object | ||
712 | object_end, | ||
713 | /// the parser read `[` and started to process a JSON array | ||
714 | array_start, | ||
715 | /// the parser read `]` and finished processing a JSON array | ||
716 | array_end, | ||
717 | /// the parser read a key of a value in an object | ||
718 | key, | ||
719 | /// the parser finished reading a JSON value | ||
720 | value | ||
721 | }; | ||
722 | |||
723 | /*! | ||
724 | @brief per-element parser callback type | ||
725 | |||
726 | With a parser callback function, the result of parsing a JSON text can be | ||
727 | influenced. When passed to @ref parse(std::istream&, parser_callback_t) or | ||
728 | @ref parse(const string_t&, parser_callback_t), it is called on certain | ||
729 | events (passed as @ref parse_event_t via parameter @a event) with a set | ||
730 | recursion depth @a depth and context JSON value @a parsed. The return value | ||
731 | of the callback function is a boolean indicating whether the element that | ||
732 | emitted the callback shall be kept or not. | ||
733 | |||
734 | We distinguish six scenarios (determined by the event type) in which the | ||
735 | callback function can be called. The following table describes the values | ||
736 | of the parameters @a depth, @a event, and @a parsed. | ||
737 | |||
738 | parameter @a event | description | parameter @a depth | parameter @a parsed | ||
739 | ------------------ | ----------- | ------------------ | ------------------- | ||
740 | 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 | ||
741 | 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 | ||
742 | 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 | ||
743 | 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 | ||
744 | 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 | ||
745 | parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value | ||
746 | |||
747 | Discarding a value (i.e., returning `false`) has different effects depending on the | ||
748 | context in which function was called: | ||
749 | |||
750 | - Discarded values in structured types are skipped. That is, the parser | ||
751 | will behave as if the discarded value was never read. | ||
752 | - In case a value outside a structured type is skipped, it is replaced with | ||
753 | `null`. This case happens if the top-level element is skipped. | ||
754 | |||
755 | @param[in] depth the depth of the recursion during parsing | ||
756 | |||
757 | @param[in] event an event of type parse_event_t indicating the context in | ||
758 | the callback function has been called | ||
759 | |||
760 | @param[in,out] parsed the current intermediate parse result; note that | ||
761 | writing to this value has no effect for parse_event_t::key events | ||
762 | |||
763 | @return Whether the JSON value which called the function during parsing | ||
764 | should be kept (`true`) or not (`false`). In the latter case, it is either | ||
765 | skipped completely or replaced by an empty discarded object. | ||
766 | |||
767 | @sa @ref parse(std::istream&, parser_callback_t) or | ||
768 | @ref parse(const string_t&, parser_callback_t) for examples | ||
769 | */ | ||
770 | using parser_callback_t = std::function<bool( | ||
771 | int depth, parse_event_t event, basic_json& parsed)>; | ||
772 | |||
773 | |||
774 | ////////////////// | ||
775 | // constructors // | ||
776 | ////////////////// | ||
777 | |||
778 | /*! | ||
779 | @brief create an empty value with a given type | ||
780 | |||
781 | Create an empty JSON value with a given type. The value will be default | ||
782 | initialized with an empty value which depends on the type: | ||
783 | |||
784 | Value type | initial value | ||
785 | ----------- | ------------- | ||
786 | null | `null` | ||
787 | boolean | `false` | ||
788 | string | `""` | ||
789 | number | `0` | ||
790 | object | `{}` | ||
791 | array | `[]` | ||
792 | |||
793 | @param[in] value the type of the value to create | ||
794 | |||
795 | @complexity Constant. | ||
796 | |||
797 | @throw std::bad_alloc if allocation for object, array, or string value | ||
798 | fails | ||
799 | |||
800 | @liveexample{The following code shows the constructor for different @ref | ||
801 | value_t values,basic_json__value_t} | ||
802 | */ | ||
803 | basic_json(const value_t value) | ||
804 | : m_type(value), m_value(value) | ||
805 | {} | ||
806 | |||
807 | /*! | ||
808 | @brief create a null object (implicitly) | ||
809 | |||
810 | Create a `null` JSON value. This is the implicit version of the `null` | ||
811 | value constructor as it takes no parameters. | ||
812 | |||
813 | @complexity Constant. | ||
814 | |||
815 | @requirement This function satisfies the Container requirements: | ||
816 | - The complexity is constant. | ||
817 | - As postcondition, it holds: `basic_json().empty() == true`. | ||
818 | |||
819 | @liveexample{The following code shows the constructor for a `null` JSON | ||
820 | value.,basic_json} | ||
821 | |||
822 | @sa basic_json(std::nullptr_t) | ||
823 | */ | ||
824 | basic_json() noexcept = default; | ||
825 | |||
826 | /*! | ||
827 | @brief create a null object (explicitly) | ||
828 | |||
829 | Create a `null` JSON value. This is the explicitly version of the `null` | ||
830 | value constructor as it takes a null pointer as parameter. It allows to | ||
831 | create `null` values by explicitly assigning a @c nullptr to a JSON value. | ||
832 | The passed null pointer itself is not read - it is only used to choose the | ||
833 | right constructor. | ||
834 | |||
835 | @complexity Constant. | ||
836 | |||
837 | @liveexample{The following code shows the constructor with null pointer | ||
838 | parameter.,basic_json__nullptr_t} | ||
839 | |||
840 | @sa basic_json() | ||
841 | */ | ||
842 | basic_json(std::nullptr_t) noexcept | ||
843 | : basic_json(value_t::null) | ||
844 | {} | ||
845 | |||
846 | /*! | ||
847 | @brief create an object (explicit) | ||
848 | |||
849 | Create an object JSON value with a given content. | ||
850 | |||
851 | @param[in] value a value for the object | ||
852 | |||
853 | @complexity Linear in the size of the passed @a value. | ||
854 | |||
855 | @throw std::bad_alloc if allocation for object value fails | ||
856 | |||
857 | @liveexample{The following code shows the constructor with an @ref object_t | ||
858 | parameter.,basic_json__object_t} | ||
859 | |||
860 | @sa basic_json(const CompatibleObjectType&) | ||
861 | */ | ||
862 | basic_json(const object_t& value) | ||
863 | : m_type(value_t::object), m_value(value) | ||
864 | {} | ||
865 | |||
866 | /*! | ||
867 | @brief create an object (implicit) | ||
868 | |||
869 | Create an object JSON value with a given content. This constructor allows | ||
870 | any type that can be used to construct values of type @ref object_t. | ||
871 | Examples include the types `std::map` and `std::unordered_map`. | ||
872 | |||
873 | @tparam CompatibleObjectType an object type whose `key_type` and | ||
874 | `value_type` is compatible to @ref object_t | ||
875 | |||
876 | @param[in] value a value for the object | ||
877 | |||
878 | @complexity Linear in the size of the passed @a value. | ||
879 | |||
880 | @throw std::bad_alloc if allocation for object value fails | ||
881 | |||
882 | @liveexample{The following code shows the constructor with several | ||
883 | compatible object type parameters.,basic_json__CompatibleObjectType} | ||
884 | |||
885 | @sa basic_json(const object_t&) | ||
886 | */ | ||
887 | template <class CompatibleObjectType, typename | ||
888 | std::enable_if< | ||
889 | std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and | ||
890 | std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type | ||
891 | = 0> | ||
892 | basic_json(const CompatibleObjectType& value) | ||
893 | : m_type(value_t::object) | ||
894 | { | ||
895 | AllocatorType<object_t> alloc; | ||
896 | m_value.object = alloc.allocate(1); | ||
897 | using std::begin; | ||
898 | using std::end; | ||
899 | alloc.construct(m_value.object, begin(value), end(value)); | ||
900 | } | ||
901 | |||
902 | /*! | ||
903 | @brief create an array (explicit) | ||
904 | |||
905 | Create an array JSON value with a given content. | ||
906 | |||
907 | @param[in] value a value for the array | ||
908 | |||
909 | @complexity Linear in the size of the passed @a value. | ||
910 | |||
911 | @throw std::bad_alloc if allocation for array value fails | ||
912 | |||
913 | @liveexample{The following code shows the constructor with an @ref array_t | ||
914 | parameter.,basic_json__array_t} | ||
915 | |||
916 | @sa basic_json(const CompatibleArrayType&) | ||
917 | */ | ||
918 | basic_json(const array_t& value) | ||
919 | : m_type(value_t::array), m_value(value) | ||
920 | {} | ||
921 | |||
922 | /*! | ||
923 | @brief create an array (implicit) | ||
924 | |||
925 | Create an array JSON value with a given content. This constructor allows | ||
926 | any type that can be used to construct values of type @ref array_t. | ||
927 | Examples include the types `std::vector`, `std::list`, and `std::set`. | ||
928 | |||
929 | @tparam CompatibleArrayType an object type whose `value_type` is compatible | ||
930 | to @ref array_t | ||
931 | |||
932 | @param[in] value a value for the array | ||
933 | |||
934 | @complexity Linear in the size of the passed @a value. | ||
935 | |||
936 | @throw std::bad_alloc if allocation for array value fails | ||
937 | |||
938 | @liveexample{The following code shows the constructor with several | ||
939 | compatible array type parameters.,basic_json__CompatibleArrayType} | ||
940 | |||
941 | @sa basic_json(const array_t&) | ||
942 | */ | ||
943 | template <class CompatibleArrayType, typename | ||
944 | std::enable_if< | ||
945 | not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and | ||
946 | not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and | ||
947 | not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and | ||
948 | not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and | ||
949 | not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and | ||
950 | not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and | ||
951 | std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type | ||
952 | = 0> | ||
953 | basic_json(const CompatibleArrayType& value) | ||
954 | : m_type(value_t::array) | ||
955 | { | ||
956 | AllocatorType<array_t> alloc; | ||
957 | m_value.array = alloc.allocate(1); | ||
958 | using std::begin; | ||
959 | using std::end; | ||
960 | alloc.construct(m_value.array, begin(value), end(value)); | ||
961 | } | ||
962 | |||
963 | /*! | ||
964 | @brief create a string (explicit) | ||
965 | |||
966 | Create an string JSON value with a given content. | ||
967 | |||
968 | @param[in] value a value for the string | ||
969 | |||
970 | @complexity Linear in the size of the passed @a value. | ||
971 | |||
972 | @throw std::bad_alloc if allocation for string value fails | ||
973 | |||
974 | @liveexample{The following code shows the constructor with an @ref string_t | ||
975 | parameter.,basic_json__string_t} | ||
976 | |||
977 | @sa basic_json(const typename string_t::value_type*) | ||
978 | @sa basic_json(const CompatibleStringType&) | ||
979 | */ | ||
980 | basic_json(const string_t& value) | ||
981 | : m_type(value_t::string), m_value(value) | ||
982 | {} | ||
983 | |||
984 | /*! | ||
985 | @brief create a string (explicit) | ||
986 | |||
987 | Create a string JSON value with a given content. | ||
988 | |||
989 | @param[in] value a literal value for the string | ||
990 | |||
991 | @complexity Linear in the size of the passed @a value. | ||
992 | |||
993 | @throw std::bad_alloc if allocation for string value fails | ||
994 | |||
995 | @liveexample{The following code shows the constructor with string literal | ||
996 | parameter.,basic_json__string_t_value_type} | ||
997 | |||
998 | @sa basic_json(const string_t&) | ||
999 | @sa basic_json(const CompatibleStringType&) | ||
1000 | */ | ||
1001 | basic_json(const typename string_t::value_type* value) | ||
1002 | : basic_json(string_t(value)) | ||
1003 | {} | ||
1004 | |||
1005 | /*! | ||
1006 | @brief create a string (implicit) | ||
1007 | |||
1008 | Create a string JSON value with a given content. | ||
1009 | |||
1010 | @param[in] value a value for the string | ||
1011 | |||
1012 | @tparam CompatibleStringType an string type which is compatible to @ref | ||
1013 | string_t | ||
1014 | |||
1015 | @complexity Linear in the size of the passed @a value. | ||
1016 | |||
1017 | @throw std::bad_alloc if allocation for string value fails | ||
1018 | |||
1019 | @liveexample{The following code shows the construction of a string value | ||
1020 | from a compatible type.,basic_json__CompatibleStringType} | ||
1021 | |||
1022 | @sa basic_json(const string_t&) | ||
1023 | */ | ||
1024 | template <class CompatibleStringType, typename | ||
1025 | std::enable_if< | ||
1026 | std::is_constructible<string_t, CompatibleStringType>::value, int>::type | ||
1027 | = 0> | ||
1028 | basic_json(const CompatibleStringType& value) | ||
1029 | : basic_json(string_t(value)) | ||
1030 | {} | ||
1031 | |||
1032 | /*! | ||
1033 | @brief create a boolean (explicit) | ||
1034 | |||
1035 | Creates a JSON boolean type from a given value. | ||
1036 | |||
1037 | @param[in] value a boolean value to store | ||
1038 | |||
1039 | @complexity Constant. | ||
1040 | |||
1041 | @liveexample{The example below demonstrates boolean | ||
1042 | values.,basic_json__boolean_t} | ||
1043 | */ | ||
1044 | basic_json(boolean_t value) | ||
1045 | : m_type(value_t::boolean), m_value(value) | ||
1046 | {} | ||
1047 | |||
1048 | /*! | ||
1049 | @brief create an integer number (explicit) | ||
1050 | |||
1051 | Create an interger number JSON value with a given content. | ||
1052 | |||
1053 | @tparam T helper type to compare number_integer_t and int (not visible in) | ||
1054 | the interface. | ||
1055 | |||
1056 | @param[in] value an integer to create a JSON number from | ||
1057 | |||
1058 | @note This constructor would have the same signature as @ref | ||
1059 | basic_json(const int value), so we need to switch this one off in case | ||
1060 | number_integer_t is the same as int. This is done via the helper type @a T. | ||
1061 | |||
1062 | @complexity Constant. | ||
1063 | |||
1064 | @liveexample{The example below shows the construction of a JSON integer | ||
1065 | number value.,basic_json__number_integer_t} | ||
1066 | |||
1067 | @sa basic_json(const int) | ||
1068 | */ | ||
1069 | template<typename T, | ||
1070 | typename std::enable_if< | ||
1071 | not (std::is_same<T, int>::value) | ||
1072 | and std::is_same<T, number_integer_t>::value | ||
1073 | , int>::type = 0> | ||
1074 | basic_json(const number_integer_t value) | ||
1075 | : m_type(value_t::number_integer), m_value(value) | ||
1076 | {} | ||
1077 | |||
1078 | /*! | ||
1079 | @brief create an integer number from an enum type (explicit) | ||
1080 | |||
1081 | Create an integer number JSON value with a given content. | ||
1082 | |||
1083 | @param[in] value an integer to create a JSON number from | ||
1084 | |||
1085 | @note This constructor allows to pass enums directly to a constructor. As | ||
1086 | C++ has no way of specifying the type of an anonymous enum explicitly, we | ||
1087 | can only rely on the fact that such values implicitly convert to int. As | ||
1088 | int may already be the same type of number_integer_t, we may need to switch | ||
1089 | off the constructor @ref basic_json(const number_integer_t). | ||
1090 | |||
1091 | @complexity Constant. | ||
1092 | |||
1093 | @liveexample{The example below shows the construction of a JSON integer | ||
1094 | number value from an anonymous enum.,basic_json__const_int} | ||
1095 | |||
1096 | @sa basic_json(const number_integer_t) | ||
1097 | */ | ||
1098 | basic_json(const int value) | ||
1099 | : m_type(value_t::number_integer), | ||
1100 | m_value(static_cast<number_integer_t>(value)) | ||
1101 | {} | ||
1102 | |||
1103 | /*! | ||
1104 | @brief create an integer number (implicit) | ||
1105 | |||
1106 | Create an integer number JSON value with a given content. This constructor | ||
1107 | allows any type that can be used to construct values of type @ref | ||
1108 | number_integer_t. Examples may include the types `int`, `int32_t`, or | ||
1109 | `short`. | ||
1110 | |||
1111 | @tparam CompatibleNumberIntegerType an integer type which is compatible to | ||
1112 | @ref number_integer_t. | ||
1113 | |||
1114 | @param[in] value an integer to create a JSON number from | ||
1115 | |||
1116 | @complexity Constant. | ||
1117 | |||
1118 | @liveexample{The example below shows the construction of several JSON | ||
1119 | integer number values from compatible | ||
1120 | types.,basic_json__CompatibleIntegerNumberType} | ||
1121 | |||
1122 | @sa basic_json(const number_integer_t) | ||
1123 | */ | ||
1124 | template<typename CompatibleNumberIntegerType, typename | ||
1125 | std::enable_if< | ||
1126 | std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and | ||
1127 | std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type | ||
1128 | = 0> | ||
1129 | basic_json(const CompatibleNumberIntegerType value) noexcept | ||
1130 | : m_type(value_t::number_integer), | ||
1131 | m_value(static_cast<number_integer_t>(value)) | ||
1132 | {} | ||
1133 | |||
1134 | /*! | ||
1135 | @brief create a floating-point number (explicit) | ||
1136 | |||
1137 | Create a floating-point number JSON value with a given content. | ||
1138 | |||
1139 | @param[in] value a floating-point value to create a JSON number from | ||
1140 | |||
1141 | @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6 | ||
1142 | disallows NaN values: | ||
1143 | > Numeric values that cannot be represented in the grammar below (such | ||
1144 | > as Infinity and NaN) are not permitted. | ||
1145 | In case the parameter @a value is not a number, a JSON null value is | ||
1146 | created instead. | ||
1147 | |||
1148 | @complexity Constant. | ||
1149 | |||
1150 | @liveexample{The following example creates several floating-point | ||
1151 | values.,basic_json__number_float_t} | ||
1152 | */ | ||
1153 | basic_json(const number_float_t value) | ||
1154 | : m_type(value_t::number_float), m_value(value) | ||
1155 | { | ||
1156 | // replace infinity and NAN by null | ||
1157 | if (not std::isfinite(value)) | ||
1158 | { | ||
1159 | m_type = value_t::null; | ||
1160 | m_value = json_value(); | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | /*! | ||
1165 | @brief create an floating-point number (implicit) | ||
1166 | |||
1167 | Create an floating-point number JSON value with a given content. This | ||
1168 | constructor allows any type that can be used to construct values of type | ||
1169 | @ref number_float_t. Examples may include the types `float`. | ||
1170 | |||
1171 | @tparam CompatibleNumberFloatType a floating-point type which is compatible | ||
1172 | to @ref number_float_t. | ||
1173 | |||
1174 | @param[in] value a floating-point to create a JSON number from | ||
1175 | |||
1176 | @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6 | ||
1177 | disallows NaN values: | ||
1178 | > Numeric values that cannot be represented in the grammar below (such | ||
1179 | > as Infinity and NaN) are not permitted. | ||
1180 | In case the parameter @a value is not a number, a JSON null value is | ||
1181 | created instead. | ||
1182 | |||
1183 | @complexity Constant. | ||
1184 | |||
1185 | @liveexample{The example below shows the construction of several JSON | ||
1186 | floating-point number values from compatible | ||
1187 | types.,basic_json__CompatibleNumberFloatType} | ||
1188 | |||
1189 | @sa basic_json(const number_float_t) | ||
1190 | */ | ||
1191 | template<typename CompatibleNumberFloatType, typename = typename | ||
1192 | std::enable_if< | ||
1193 | std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and | ||
1194 | std::is_floating_point<CompatibleNumberFloatType>::value>::type | ||
1195 | > | ||
1196 | basic_json(const CompatibleNumberFloatType value) noexcept | ||
1197 | : basic_json(number_float_t(value)) | ||
1198 | {} | ||
1199 | |||
1200 | /*! | ||
1201 | @brief create a container (array or object) from an initializer list | ||
1202 | |||
1203 | Creates a JSON value of type array or object from the passed initializer | ||
1204 | list @a init. In case @a type_deduction is `true` (default), the type of | ||
1205 | the JSON value to be created is deducted from the initializer list @a init | ||
1206 | according to the following rules: | ||
1207 | |||
1208 | 1. If the list is empty, an empty JSON object value `{}` is created. | ||
1209 | 2. If the list consists of pairs whose first element is a string, a JSON | ||
1210 | object value is created where the first elements of the pairs are treated | ||
1211 | as keys and the second elements are as values. | ||
1212 | 3. In all other cases, an array is created. | ||
1213 | |||
1214 | The rules aim to create the best fit between a C++ initializer list and | ||
1215 | JSON values. The ratioinale is as follows: | ||
1216 | |||
1217 | 1. The empty initializer list is written as `{}` which is exactly an empty | ||
1218 | JSON object. | ||
1219 | 2. C++ has now way of describing mapped types other than to list a list of | ||
1220 | pairs. As JSON requires that keys must be of type string, rule 2 is the | ||
1221 | weakest constraint one can pose on initializer lists to interpret them as | ||
1222 | an object. | ||
1223 | 3. In all other cases, the initializer list could not be interpreted as | ||
1224 | JSON object type, so interpreting it as JSON array type is safe. | ||
1225 | |||
1226 | With the rules described above, the following JSON values cannot be | ||
1227 | expressed by an initializer list: | ||
1228 | |||
1229 | - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>) | ||
1230 | with an empty initializer list in this case | ||
1231 | - arrays whose elements satisfy rule 2: use @ref | ||
1232 | array(std::initializer_list<basic_json>) with the same initializer list | ||
1233 | in this case | ||
1234 | |||
1235 | @note When used without parentheses around an empty initializer list, @ref | ||
1236 | basic_json() is called instead of this function, yielding the JSON null | ||
1237 | value. | ||
1238 | |||
1239 | @param[in] init initializer list with JSON values | ||
1240 | |||
1241 | @param[in] type_deduction internal parameter; when set to `true`, the type | ||
1242 | of the JSON value is deducted from the initializer list @a init; when set | ||
1243 | to `false`, the type provided via @a manual_type is forced. This mode is | ||
1244 | used by the functions @ref array(std::initializer_list<basic_json>) and | ||
1245 | @ref object(std::initializer_list<basic_json>). | ||
1246 | |||
1247 | @param[in] manual_type internal parameter; when @a type_deduction is set to | ||
1248 | `false`, the created JSON value will use the provided type (only @ref | ||
1249 | value_t::array and @ref value_t::object are valid); when @a type_deduction | ||
1250 | is set to `true`, this parameter has no effect | ||
1251 | |||
1252 | @throw std::domain_error if @a type_deduction is `false`, @a manual_type is | ||
1253 | `value_t::object`, but @a init contains an element which is not a pair | ||
1254 | whose first element is a string | ||
1255 | |||
1256 | @complexity Linear in the size of the initializer list @a init. | ||
1257 | |||
1258 | @liveexample{The example below shows how JSON values are created from | ||
1259 | initializer lists,basic_json__list_init_t} | ||
1260 | |||
1261 | @sa basic_json array(std::initializer_list<basic_json>) - create a JSON | ||
1262 | array value from an initializer list | ||
1263 | @sa basic_json object(std::initializer_list<basic_json>) - create a JSON | ||
1264 | object value from an initializer list | ||
1265 | */ | ||
1266 | basic_json(std::initializer_list<basic_json> init, | ||
1267 | bool type_deduction = true, | ||
1268 | value_t manual_type = value_t::array) | ||
1269 | { | ||
1270 | // the initializer list could describe an object | ||
1271 | bool is_object = true; | ||
1272 | |||
1273 | // check if each element is an array with two elements whose first element | ||
1274 | // is a string | ||
1275 | for (const auto& element : init) | ||
1276 | { | ||
1277 | if (element.m_type != value_t::array or element.size() != 2 | ||
1278 | or element[0].m_type != value_t::string) | ||
1279 | { | ||
1280 | // we found an element that makes it impossible to use the | ||
1281 | // initializer list as object | ||
1282 | is_object = false; | ||
1283 | break; | ||
1284 | } | ||
1285 | } | ||
1286 | |||
1287 | // adjust type if type deduction is not wanted | ||
1288 | if (not type_deduction) | ||
1289 | { | ||
1290 | // if array is wanted, do not create an object though possible | ||
1291 | if (manual_type == value_t::array) | ||
1292 | { | ||
1293 | is_object = false; | ||
1294 | } | ||
1295 | |||
1296 | // if object is wanted but impossible, throw an exception | ||
1297 | if (manual_type == value_t::object and not is_object) | ||
1298 | { | ||
1299 | throw std::domain_error("cannot create object from initializer list"); | ||
1300 | } | ||
1301 | } | ||
1302 | |||
1303 | if (is_object) | ||
1304 | { | ||
1305 | // the initializer list is a list of pairs -> create object | ||
1306 | m_type = value_t::object; | ||
1307 | m_value = value_t::object; | ||
1308 | |||
1309 | for (auto& element : init) | ||
1310 | { | ||
1311 | m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1])); | ||
1312 | } | ||
1313 | } | ||
1314 | else | ||
1315 | { | ||
1316 | // the initializer list describes an array -> create array | ||
1317 | m_type = value_t::array; | ||
1318 | AllocatorType<array_t> alloc; | ||
1319 | m_value.array = alloc.allocate(1); | ||
1320 | alloc.construct(m_value.array, std::move(init)); | ||
1321 | } | ||
1322 | } | ||
1323 | |||
1324 | /*! | ||
1325 | @brief explicitly create an array from an initializer list | ||
1326 | |||
1327 | Creates a JSON array value from a given initializer list. That is, given a | ||
1328 | list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the | ||
1329 | initializer list is empty, the empty array `[]` is created. | ||
1330 | |||
1331 | @note This function is only needed to express two edge cases that cannot be | ||
1332 | realized with the initializer list constructor (@ref | ||
1333 | basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases | ||
1334 | are: | ||
1335 | 1. creating an array whose elements are all pairs whose first element is a | ||
1336 | string - in this case, the initializer list constructor would create an | ||
1337 | object, taking the first elements as keys | ||
1338 | 2. creating an empty array - passing the empty initializer list to the | ||
1339 | initializer list constructor yields an empty object | ||
1340 | |||
1341 | @param[in] init initializer list with JSON values to create an array from | ||
1342 | (optional) | ||
1343 | |||
1344 | @return JSON array value | ||
1345 | |||
1346 | @complexity Linear in the size of @a init. | ||
1347 | |||
1348 | @liveexample{The following code shows an example for the @ref array | ||
1349 | function.,array} | ||
1350 | |||
1351 | @sa basic_json(std::initializer_list<basic_json>, bool, value_t) - create a | ||
1352 | JSON value from an initializer list | ||
1353 | @sa basic_json object(std::initializer_list<basic_json>) - create a JSON | ||
1354 | object value from an initializer list | ||
1355 | */ | ||
1356 | static basic_json array(std::initializer_list<basic_json> init = | ||
1357 | std::initializer_list<basic_json>()) | ||
1358 | { | ||
1359 | return basic_json(init, false, value_t::array); | ||
1360 | } | ||
1361 | |||
1362 | /*! | ||
1363 | @brief explicitly create an object from an initializer list | ||
1364 | |||
1365 | Creates a JSON object value from a given initializer list. The initializer | ||
1366 | lists elements must be pairs, and their first elments must be strings. If | ||
1367 | the initializer list is empty, the empty object `{}` is created. | ||
1368 | |||
1369 | @note This function is only added for symmetry reasons. In contrast to the | ||
1370 | related function @ref basic_json array(std::initializer_list<basic_json>), | ||
1371 | there are no cases which can only be expressed by this function. That is, | ||
1372 | any initializer list @a init can also be passed to the initializer list | ||
1373 | constructor @ref basic_json(std::initializer_list<basic_json>, bool, | ||
1374 | value_t). | ||
1375 | |||
1376 | @param[in] init initializer list to create an object from (optional) | ||
1377 | |||
1378 | @return JSON object value | ||
1379 | |||
1380 | @throw std::domain_error if @a init is not a pair whose first elements are | ||
1381 | strings; thrown by @ref basic_json(std::initializer_list<basic_json>, bool, | ||
1382 | value_t) | ||
1383 | |||
1384 | @complexity Linear in the size of @a init. | ||
1385 | |||
1386 | @liveexample{The following code shows an example for the @ref object | ||
1387 | function.,object} | ||
1388 | |||
1389 | @sa basic_json(std::initializer_list<basic_json>, bool, value_t) - create a | ||
1390 | JSON value from an initializer list | ||
1391 | @sa basic_json array(std::initializer_list<basic_json>) - create a JSON | ||
1392 | array value from an initializer list | ||
1393 | */ | ||
1394 | static basic_json object(std::initializer_list<basic_json> init = | ||
1395 | std::initializer_list<basic_json>()) | ||
1396 | { | ||
1397 | return basic_json(init, false, value_t::object); | ||
1398 | } | ||
1399 | |||
1400 | /*! | ||
1401 | @brief construct an array with count copies of given value | ||
1402 | |||
1403 | Constructs a JSON array value by creating @a count copies of a passed | ||
1404 | value. In case @a count is `0`, an empty array is created. As postcondition, | ||
1405 | `std::distance(begin(),end()) == count` holds. | ||
1406 | |||
1407 | @param[in] count the number of JSON copies of @a value to create | ||
1408 | @param[in] value the JSON value to copy | ||
1409 | |||
1410 | @complexity Linear in @a count. | ||
1411 | |||
1412 | @liveexample{The following code shows examples for the @ref | ||
1413 | basic_json(size_type\, const basic_json&) | ||
1414 | constructor.,basic_json__size_type_basic_json} | ||
1415 | */ | ||
1416 | basic_json(size_type count, const basic_json& value) | ||
1417 | : m_type(value_t::array) | ||
1418 | { | ||
1419 | AllocatorType<array_t> alloc; | ||
1420 | m_value.array = alloc.allocate(1); | ||
1421 | alloc.construct(m_value.array, count, value); | ||
1422 | } | ||
1423 | |||
1424 | /*! | ||
1425 | @brief construct a JSON container given an iterator range | ||
1426 | |||
1427 | Constructs the JSON value with the contents of the range `[first, last)`. | ||
1428 | The semantics depends on the different types a JSON value can have: | ||
1429 | - In case of primitive types (number, boolean, or string), @a first must | ||
1430 | be `begin()` and @a last must be `end()`. In this case, the value is | ||
1431 | copied. Otherwise, std::out_of_range is thrown. | ||
1432 | - In case of structured types (array, object), the constructor behaves | ||
1433 | as similar versions for `std::vector`. | ||
1434 | - In case of a null type, std::domain_error is thrown. | ||
1435 | |||
1436 | @tparam InputIT an input iterator type (@ref iterator or @ref | ||
1437 | const_iterator) | ||
1438 | |||
1439 | @param[in] first begin of the range to copy from (included) | ||
1440 | @param[in] last end of the range to copy from (excluded) | ||
1441 | |||
1442 | @throw std::domain_error if iterators are not compatible; that is, do not | ||
1443 | belong to the same JSON value | ||
1444 | @throw std::out_of_range if iterators are for a primitive type (number, | ||
1445 | boolean, or string) where an out of range error can be detected easily | ||
1446 | @throw std::bad_alloc if allocation for object, array, or string fails | ||
1447 | @throw std::domain_error if called with a null value | ||
1448 | |||
1449 | @complexity Linear in distance between @a first and @a last. | ||
1450 | |||
1451 | @liveexample{The example below shows several ways to create JSON values by | ||
1452 | specifying a subrange with iterators.,basic_json__InputIt_InputIt} | ||
1453 | */ | ||
1454 | template <class InputIT, typename | ||
1455 | std::enable_if< | ||
1456 | std::is_same<InputIT, typename basic_json_t::iterator>::value or | ||
1457 | std::is_same<InputIT, typename basic_json_t::const_iterator>::value | ||
1458 | , int>::type | ||
1459 | = 0> | ||
1460 | basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type) | ||
1461 | { | ||
1462 | // make sure iterator fits the current value | ||
1463 | if (first.m_object != last.m_object) | ||
1464 | { | ||
1465 | throw std::domain_error("iterators are not compatible"); | ||
1466 | } | ||
1467 | |||
1468 | // check if iterator range is complete for primitive values | ||
1469 | switch (m_type) | ||
1470 | { | ||
1471 | case value_t::number_integer: | ||
1472 | case value_t::number_float: | ||
1473 | case value_t::boolean: | ||
1474 | case value_t::string: | ||
1475 | { | ||
1476 | if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) | ||
1477 | { | ||
1478 | throw std::out_of_range("iterators out of range"); | ||
1479 | } | ||
1480 | break; | ||
1481 | } | ||
1482 | |||
1483 | default: | ||
1484 | { | ||
1485 | break; | ||
1486 | } | ||
1487 | } | ||
1488 | |||
1489 | switch (m_type) | ||
1490 | { | ||
1491 | case value_t::number_integer: | ||
1492 | { | ||
1493 | m_value.number_integer = first.m_object->m_value.number_integer; | ||
1494 | break; | ||
1495 | } | ||
1496 | |||
1497 | case value_t::number_float: | ||
1498 | { | ||
1499 | m_value.number_float = first.m_object->m_value.number_float; | ||
1500 | break; | ||
1501 | } | ||
1502 | |||
1503 | case value_t::boolean: | ||
1504 | { | ||
1505 | m_value.boolean = first.m_object->m_value.boolean; | ||
1506 | break; | ||
1507 | } | ||
1508 | |||
1509 | case value_t::string: | ||
1510 | { | ||
1511 | m_value = *first.m_object->m_value.string; | ||
1512 | break; | ||
1513 | } | ||
1514 | |||
1515 | case value_t::object: | ||
1516 | { | ||
1517 | AllocatorType<object_t> alloc; | ||
1518 | m_value.object = alloc.allocate(1); | ||
1519 | alloc.construct(m_value.object, first.m_it.object_iterator, last.m_it.object_iterator); | ||
1520 | break; | ||
1521 | } | ||
1522 | |||
1523 | case value_t::array: | ||
1524 | { | ||
1525 | AllocatorType<array_t> alloc; | ||
1526 | m_value.array = alloc.allocate(1); | ||
1527 | alloc.construct(m_value.array, first.m_it.array_iterator, last.m_it.array_iterator); | ||
1528 | break; | ||
1529 | } | ||
1530 | |||
1531 | default: | ||
1532 | { | ||
1533 | throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); | ||
1534 | } | ||
1535 | } | ||
1536 | } | ||
1537 | |||
1538 | /////////////////////////////////////// | ||
1539 | // other constructors and destructor // | ||
1540 | /////////////////////////////////////// | ||
1541 | |||
1542 | /*! | ||
1543 | @brief copy constructor | ||
1544 | |||
1545 | Creates a copy of a given JSON value. | ||
1546 | |||
1547 | @param[in] other the JSON value to copy | ||
1548 | |||
1549 | @complexity Linear in the size of @a other. | ||
1550 | |||
1551 | @requirement This function satisfies the Container requirements: | ||
1552 | - The complexity is linear. | ||
1553 | - As postcondition, it holds: `other == basic_json(other)`. | ||
1554 | |||
1555 | @throw std::bad_alloc if allocation for object, array, or string fails. | ||
1556 | |||
1557 | @liveexample{The following code shows an example for the copy | ||
1558 | constructor.,basic_json__basic_json} | ||
1559 | */ | ||
1560 | basic_json(const basic_json& other) | ||
1561 | : m_type(other.m_type) | ||
1562 | { | ||
1563 | switch (m_type) | ||
1564 | { | ||
1565 | case (value_t::null): | ||
1566 | case (value_t::discarded): | ||
1567 | { | ||
1568 | break; | ||
1569 | } | ||
1570 | |||
1571 | case (value_t::object): | ||
1572 | { | ||
1573 | m_value = *other.m_value.object; | ||
1574 | break; | ||
1575 | } | ||
1576 | |||
1577 | case (value_t::array): | ||
1578 | { | ||
1579 | m_value = *other.m_value.array; | ||
1580 | break; | ||
1581 | } | ||
1582 | |||
1583 | case (value_t::string): | ||
1584 | { | ||
1585 | m_value = *other.m_value.string; | ||
1586 | break; | ||
1587 | } | ||
1588 | |||
1589 | case (value_t::boolean): | ||
1590 | { | ||
1591 | m_value = other.m_value.boolean; | ||
1592 | break; | ||
1593 | } | ||
1594 | |||
1595 | case (value_t::number_integer): | ||
1596 | { | ||
1597 | m_value = other.m_value.number_integer; | ||
1598 | break; | ||
1599 | } | ||
1600 | |||
1601 | case (value_t::number_float): | ||
1602 | { | ||
1603 | m_value = other.m_value.number_float; | ||
1604 | break; | ||
1605 | } | ||
1606 | } | ||
1607 | } | ||
1608 | |||
1609 | /*! | ||
1610 | @brief move constructor | ||
1611 | |||
1612 | Move constructor. Constructs a JSON value with the contents of the given | ||
1613 | value @a other using move semantics. It "steals" the resources from @a | ||
1614 | other and leaves it as JSON null value. | ||
1615 | |||
1616 | @param[in,out] other value to move to this object | ||
1617 | |||
1618 | @post @a other is a JSON null value | ||
1619 | |||
1620 | @complexity Constant. | ||
1621 | |||
1622 | @liveexample{The code below shows the move constructor explicitly called | ||
1623 | via std::move.,basic_json__moveconstructor} | ||
1624 | */ | ||
1625 | basic_json(basic_json&& other) noexcept | ||
1626 | : m_type(std::move(other.m_type)), | ||
1627 | m_value(std::move(other.m_value)) | ||
1628 | { | ||
1629 | // invalidate payload | ||
1630 | other.m_type = value_t::null; | ||
1631 | other.m_value = {}; | ||
1632 | } | ||
1633 | |||
1634 | /*! | ||
1635 | @brief copy assignment | ||
1636 | |||
1637 | Copy assignment operator. Copies a JSON value via the "copy and swap" | ||
1638 | strategy: It is expressed in terms of the copy constructor, destructor, and | ||
1639 | the swap() member function. | ||
1640 | |||
1641 | @param[in] other value to copy from | ||
1642 | |||
1643 | @complexity Linear. | ||
1644 | |||
1645 | @requirement This function satisfies the Container requirements: | ||
1646 | - The complexity is linear. | ||
1647 | |||
1648 | @liveexample{The code below shows and example for the copy assignment. It | ||
1649 | creates a copy of value `a` which is then swapped with `b`. Finally\, the | ||
1650 | copy of `a` (which is the null value after the swap) is | ||
1651 | destroyed.,basic_json__copyassignment} | ||
1652 | */ | ||
1653 | reference& operator=(basic_json other) noexcept ( | ||
1654 | std::is_nothrow_move_constructible<value_t>::value and | ||
1655 | std::is_nothrow_move_assignable<value_t>::value and | ||
1656 | std::is_nothrow_move_constructible<json_value>::value and | ||
1657 | std::is_nothrow_move_assignable<json_value>::value | ||
1658 | ) | ||
1659 | { | ||
1660 | using std::swap; | ||
1661 | std::swap(m_type, other.m_type); | ||
1662 | std::swap(m_value, other.m_value); | ||
1663 | return *this; | ||
1664 | } | ||
1665 | |||
1666 | /*! | ||
1667 | @brief destructor | ||
1668 | |||
1669 | Destroys the JSON value and frees all allocated memory. | ||
1670 | |||
1671 | @complexity Linear. | ||
1672 | |||
1673 | @requirement This function satisfies the Container requirements: | ||
1674 | - The complexity is linear. | ||
1675 | - All stored elements are destroyed and all memory is freed. | ||
1676 | */ | ||
1677 | ~basic_json() | ||
1678 | { | ||
1679 | switch (m_type) | ||
1680 | { | ||
1681 | case (value_t::object): | ||
1682 | { | ||
1683 | AllocatorType<object_t> alloc; | ||
1684 | alloc.destroy(m_value.object); | ||
1685 | alloc.deallocate(m_value.object, 1); | ||
1686 | m_value.object = nullptr; | ||
1687 | break; | ||
1688 | } | ||
1689 | |||
1690 | case (value_t::array): | ||
1691 | { | ||
1692 | AllocatorType<array_t> alloc; | ||
1693 | alloc.destroy(m_value.array); | ||
1694 | alloc.deallocate(m_value.array, 1); | ||
1695 | m_value.array = nullptr; | ||
1696 | break; | ||
1697 | } | ||
1698 | |||
1699 | case (value_t::string): | ||
1700 | { | ||
1701 | AllocatorType<string_t> alloc; | ||
1702 | alloc.destroy(m_value.string); | ||
1703 | alloc.deallocate(m_value.string, 1); | ||
1704 | m_value.string = nullptr; | ||
1705 | break; | ||
1706 | } | ||
1707 | |||
1708 | default: | ||
1709 | { | ||
1710 | // all other types need no specific destructor | ||
1711 | break; | ||
1712 | } | ||
1713 | } | ||
1714 | } | ||
1715 | |||
1716 | |||
1717 | public: | ||
1718 | /////////////////////// | ||
1719 | // object inspection // | ||
1720 | /////////////////////// | ||
1721 | |||
1722 | /// @name object inspection | ||
1723 | /// @{ | ||
1724 | |||
1725 | /*! | ||
1726 | @brief serialization | ||
1727 | |||
1728 | Serialization function for JSON values. The function tries to mimick | ||
1729 | Python's @p json.dumps() function, and currently supports its @p indent | ||
1730 | parameter. | ||
1731 | |||
1732 | @param[in] indent if indent is nonnegative, then array elements and object | ||
1733 | members will be pretty-printed with that indent level. An indent level of 0 | ||
1734 | will only insert newlines. -1 (the default) selects the most compact | ||
1735 | representation | ||
1736 | |||
1737 | @return string containing the serialization of the JSON value | ||
1738 | |||
1739 | @complexity Linear. | ||
1740 | |||
1741 | @liveexample{The following example shows the effect of different @a indent | ||
1742 | parameters to the result of the serializaion.,dump} | ||
1743 | |||
1744 | @see https://docs.python.org/2/library/json.html#json.dump | ||
1745 | */ | ||
1746 | string_t dump(const int indent = -1) const | ||
1747 | { | ||
1748 | std::stringstream ss; | ||
1749 | |||
1750 | if (indent >= 0) | ||
1751 | { | ||
1752 | dump(ss, true, static_cast<unsigned int>(indent)); | ||
1753 | } | ||
1754 | else | ||
1755 | { | ||
1756 | dump(ss, false, 0); | ||
1757 | } | ||
1758 | |||
1759 | return ss.str(); | ||
1760 | } | ||
1761 | |||
1762 | /*! | ||
1763 | @brief return the type of the JSON value (explicit) | ||
1764 | |||
1765 | Return the type of the JSON value as a value from the @ref value_t | ||
1766 | enumeration. | ||
1767 | |||
1768 | @return the type of the JSON value | ||
1769 | |||
1770 | @complexity Constant. | ||
1771 | |||
1772 | @liveexample{The following code exemplifies @ref type() for all JSON | ||
1773 | types.,type} | ||
1774 | */ | ||
1775 | value_t type() const noexcept | ||
1776 | { | ||
1777 | return m_type; | ||
1778 | } | ||
1779 | |||
1780 | /*! | ||
1781 | @brief return whether type is primitive | ||
1782 | |||
1783 | This function returns true iff the JSON type is primitive (string, number, | ||
1784 | boolean, or null). | ||
1785 | |||
1786 | @return `true` if type is primitive (string, number, boolean, or null), | ||
1787 | `false` otherwise. | ||
1788 | |||
1789 | @complexity Constant. | ||
1790 | |||
1791 | @liveexample{The following code exemplifies @ref is_primitive for all JSON | ||
1792 | types.,is_primitive} | ||
1793 | */ | ||
1794 | bool is_primitive() const noexcept | ||
1795 | { | ||
1796 | return is_null() or is_string() or is_boolean() or is_number(); | ||
1797 | } | ||
1798 | |||
1799 | /*! | ||
1800 | @brief return whether type is structured | ||
1801 | |||
1802 | This function returns true iff the JSON type is structured (array or | ||
1803 | object). | ||
1804 | |||
1805 | @return `true` if type is structured (array or object), `false` otherwise. | ||
1806 | |||
1807 | @complexity Constant. | ||
1808 | |||
1809 | @liveexample{The following code exemplifies @ref is_structured for all JSON | ||
1810 | types.,is_structured} | ||
1811 | */ | ||
1812 | bool is_structured() const noexcept | ||
1813 | { | ||
1814 | return is_array() or is_object(); | ||
1815 | } | ||
1816 | |||
1817 | /*! | ||
1818 | @brief return whether value is null | ||
1819 | |||
1820 | This function returns true iff the JSON value is null. | ||
1821 | |||
1822 | @return `true` if type is null, `false` otherwise. | ||
1823 | |||
1824 | @complexity Constant. | ||
1825 | |||
1826 | @liveexample{The following code exemplifies @ref is_null for all JSON | ||
1827 | types.,is_null} | ||
1828 | */ | ||
1829 | bool is_null() const noexcept | ||
1830 | { | ||
1831 | return m_type == value_t::null; | ||
1832 | } | ||
1833 | |||
1834 | /*! | ||
1835 | @brief return whether value is a boolean | ||
1836 | |||
1837 | This function returns true iff the JSON value is a boolean. | ||
1838 | |||
1839 | @return `true` if type is boolean, `false` otherwise. | ||
1840 | |||
1841 | @complexity Constant. | ||
1842 | |||
1843 | @liveexample{The following code exemplifies @ref is_boolean for all JSON | ||
1844 | types.,is_boolean} | ||
1845 | */ | ||
1846 | bool is_boolean() const noexcept | ||
1847 | { | ||
1848 | return m_type == value_t::boolean; | ||
1849 | } | ||
1850 | |||
1851 | /*! | ||
1852 | @brief return whether value is a number | ||
1853 | |||
1854 | This function returns true iff the JSON value is a number. This includes | ||
1855 | both integer and floating-point values. | ||
1856 | |||
1857 | @return `true` if type is number, `false` otherwise. | ||
1858 | |||
1859 | @complexity Constant. | ||
1860 | |||
1861 | @liveexample{The following code exemplifies @ref is_number for all JSON | ||
1862 | types.,is_number} | ||
1863 | */ | ||
1864 | bool is_number() const noexcept | ||
1865 | { | ||
1866 | return is_number_integer() or is_number_float(); | ||
1867 | } | ||
1868 | |||
1869 | /*! | ||
1870 | @brief return whether value is an integer number | ||
1871 | |||
1872 | This function returns true iff the JSON value is an integer number. This | ||
1873 | excludes floating-point values. | ||
1874 | |||
1875 | @return `true` if type is an integer number, `false` otherwise. | ||
1876 | |||
1877 | @complexity Constant. | ||
1878 | |||
1879 | @liveexample{The following code exemplifies @ref is_number_integer for all | ||
1880 | JSON types.,is_number_integer} | ||
1881 | */ | ||
1882 | bool is_number_integer() const noexcept | ||
1883 | { | ||
1884 | return m_type == value_t::number_integer; | ||
1885 | } | ||
1886 | |||
1887 | /*! | ||
1888 | @brief return whether value is a floating-point number | ||
1889 | |||
1890 | This function returns true iff the JSON value is a floating-point number. | ||
1891 | This excludes integer values. | ||
1892 | |||
1893 | @return `true` if type is a floating-point number, `false` otherwise. | ||
1894 | |||
1895 | @complexity Constant. | ||
1896 | |||
1897 | @liveexample{The following code exemplifies @ref is_number_float for all | ||
1898 | JSON types.,is_number_float} | ||
1899 | */ | ||
1900 | bool is_number_float() const noexcept | ||
1901 | { | ||
1902 | return m_type == value_t::number_float; | ||
1903 | } | ||
1904 | |||
1905 | /*! | ||
1906 | @brief return whether value is an object | ||
1907 | |||
1908 | This function returns true iff the JSON value is an object. | ||
1909 | |||
1910 | @return `true` if type is object, `false` otherwise. | ||
1911 | |||
1912 | @complexity Constant. | ||
1913 | |||
1914 | @liveexample{The following code exemplifies @ref is_object for all JSON | ||
1915 | types.,is_object} | ||
1916 | */ | ||
1917 | bool is_object() const noexcept | ||
1918 | { | ||
1919 | return m_type == value_t::object; | ||
1920 | } | ||
1921 | |||
1922 | /*! | ||
1923 | @brief return whether value is an array | ||
1924 | |||
1925 | This function returns true iff the JSON value is an array. | ||
1926 | |||
1927 | @return `true` if type is array, `false` otherwise. | ||
1928 | |||
1929 | @complexity Constant. | ||
1930 | |||
1931 | @liveexample{The following code exemplifies @ref is_array for all JSON | ||
1932 | types.,is_array} | ||
1933 | */ | ||
1934 | bool is_array() const noexcept | ||
1935 | { | ||
1936 | return m_type == value_t::array; | ||
1937 | } | ||
1938 | |||
1939 | /*! | ||
1940 | @brief return whether value is a string | ||
1941 | |||
1942 | This function returns true iff the JSON value is a string. | ||
1943 | |||
1944 | @return `true` if type is string, `false` otherwise. | ||
1945 | |||
1946 | @complexity Constant. | ||
1947 | |||
1948 | @liveexample{The following code exemplifies @ref is_string for all JSON | ||
1949 | types.,is_string} | ||
1950 | */ | ||
1951 | bool is_string() const noexcept | ||
1952 | { | ||
1953 | return m_type == value_t::string; | ||
1954 | } | ||
1955 | |||
1956 | /*! | ||
1957 | @brief return whether value is discarded | ||
1958 | |||
1959 | This function returns true iff the JSON value was discarded during parsing | ||
1960 | with a callback function (see @ref parser_callback_t). | ||
1961 | |||
1962 | @note This function will always be `false` for JSON values after parsing. | ||
1963 | That is, discarded values can only occur during parsing, but will be | ||
1964 | removed when inside a structured value or replaced by null in other cases. | ||
1965 | |||
1966 | @return `true` if type is discarded, `false` otherwise. | ||
1967 | |||
1968 | @complexity Constant. | ||
1969 | |||
1970 | @liveexample{The following code exemplifies @ref is_discarded for all JSON | ||
1971 | types.,is_discarded} | ||
1972 | */ | ||
1973 | bool is_discarded() const noexcept | ||
1974 | { | ||
1975 | return m_type == value_t::discarded; | ||
1976 | } | ||
1977 | |||
1978 | /*! | ||
1979 | @brief return the type of the JSON value (implicit) | ||
1980 | |||
1981 | Implicitly return the type of the JSON value as a value from the @ref | ||
1982 | value_t enumeration. | ||
1983 | |||
1984 | @return the type of the JSON value | ||
1985 | |||
1986 | @complexity Constant. | ||
1987 | |||
1988 | @liveexample{The following code exemplifies the value_t operator for all | ||
1989 | JSON types.,operator__value_t} | ||
1990 | */ | ||
1991 | operator value_t() const noexcept | ||
1992 | { | ||
1993 | return m_type; | ||
1994 | } | ||
1995 | |||
1996 | /// @} | ||
1997 | |||
1998 | private: | ||
1999 | ////////////////// | ||
2000 | // value access // | ||
2001 | ////////////////// | ||
2002 | |||
2003 | /// get an object (explicit) | ||
2004 | template <class T, typename | ||
2005 | std::enable_if< | ||
2006 | std::is_convertible<typename object_t::key_type, typename T::key_type>::value and | ||
2007 | std::is_convertible<basic_json_t, typename T::mapped_type>::value | ||
2008 | , int>::type = 0> | ||
2009 | T get_impl(T*) const | ||
2010 | { | ||
2011 | switch (m_type) | ||
2012 | { | ||
2013 | case (value_t::object): | ||
2014 | { | ||
2015 | return T(m_value.object->begin(), m_value.object->end()); | ||
2016 | } | ||
2017 | default: | ||
2018 | { | ||
2019 | throw std::domain_error("type must be object, but is " + type_name()); | ||
2020 | } | ||
2021 | } | ||
2022 | } | ||
2023 | |||
2024 | /// get an object (explicit) | ||
2025 | object_t get_impl(object_t*) const | ||
2026 | { | ||
2027 | switch (m_type) | ||
2028 | { | ||
2029 | case (value_t::object): | ||
2030 | { | ||
2031 | return *(m_value.object); | ||
2032 | } | ||
2033 | default: | ||
2034 | { | ||
2035 | throw std::domain_error("type must be object, but is " + type_name()); | ||
2036 | } | ||
2037 | } | ||
2038 | } | ||
2039 | |||
2040 | /// get an array (explicit) | ||
2041 | template <class T, typename | ||
2042 | std::enable_if< | ||
2043 | std::is_convertible<basic_json_t, typename T::value_type>::value and | ||
2044 | not std::is_same<basic_json_t, typename T::value_type>::value and | ||
2045 | not std::is_arithmetic<T>::value and | ||
2046 | not std::is_convertible<std::string, T>::value and | ||
2047 | not has_mapped_type<T>::value | ||
2048 | , int>::type = 0> | ||
2049 | T get_impl(T*) const | ||
2050 | { | ||
2051 | switch (m_type) | ||
2052 | { | ||
2053 | case (value_t::array): | ||
2054 | { | ||
2055 | T to_vector; | ||
2056 | std::transform(m_value.array->begin(), m_value.array->end(), | ||
2057 | std::inserter(to_vector, to_vector.end()), [](basic_json i) | ||
2058 | { | ||
2059 | return i.get<typename T::value_type>(); | ||
2060 | }); | ||
2061 | return to_vector; | ||
2062 | } | ||
2063 | default: | ||
2064 | { | ||
2065 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2066 | } | ||
2067 | } | ||
2068 | } | ||
2069 | |||
2070 | /// get an array (explicit) | ||
2071 | template <class T, typename | ||
2072 | std::enable_if< | ||
2073 | std::is_convertible<basic_json_t, T>::value and | ||
2074 | not std::is_same<basic_json_t, T>::value | ||
2075 | , int>::type = 0> | ||
2076 | std::vector<T> get_impl(std::vector<T>*) const | ||
2077 | { | ||
2078 | switch (m_type) | ||
2079 | { | ||
2080 | case (value_t::array): | ||
2081 | { | ||
2082 | std::vector<T> to_vector; | ||
2083 | to_vector.reserve(m_value.array->size()); | ||
2084 | std::transform(m_value.array->begin(), m_value.array->end(), | ||
2085 | std::inserter(to_vector, to_vector.end()), [](basic_json i) | ||
2086 | { | ||
2087 | return i.get<T>(); | ||
2088 | }); | ||
2089 | return to_vector; | ||
2090 | } | ||
2091 | default: | ||
2092 | { | ||
2093 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2094 | } | ||
2095 | } | ||
2096 | } | ||
2097 | |||
2098 | /// get an array (explicit) | ||
2099 | template <class T, typename | ||
2100 | std::enable_if< | ||
2101 | std::is_same<basic_json, typename T::value_type>::value and | ||
2102 | not has_mapped_type<T>::value | ||
2103 | , int>::type = 0> | ||
2104 | T get_impl(T*) const | ||
2105 | { | ||
2106 | switch (m_type) | ||
2107 | { | ||
2108 | case (value_t::array): | ||
2109 | { | ||
2110 | return T(m_value.array->begin(), m_value.array->end()); | ||
2111 | } | ||
2112 | default: | ||
2113 | { | ||
2114 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2115 | } | ||
2116 | } | ||
2117 | } | ||
2118 | |||
2119 | /// get an array (explicit) | ||
2120 | array_t get_impl(array_t*) const | ||
2121 | { | ||
2122 | switch (m_type) | ||
2123 | { | ||
2124 | case (value_t::array): | ||
2125 | { | ||
2126 | return *(m_value.array); | ||
2127 | } | ||
2128 | default: | ||
2129 | { | ||
2130 | throw std::domain_error("type must be array, but is " + type_name()); | ||
2131 | } | ||
2132 | } | ||
2133 | } | ||
2134 | |||
2135 | /// get a string (explicit) | ||
2136 | template <typename T, typename | ||
2137 | std::enable_if< | ||
2138 | std::is_convertible<string_t, T>::value | ||
2139 | , int>::type = 0> | ||
2140 | T get_impl(T*) const | ||
2141 | { | ||
2142 | switch (m_type) | ||
2143 | { | ||
2144 | case (value_t::string): | ||
2145 | { | ||
2146 | return *m_value.string; | ||
2147 | } | ||
2148 | default: | ||
2149 | { | ||
2150 | throw std::domain_error("type must be string, but is " + type_name()); | ||
2151 | } | ||
2152 | } | ||
2153 | } | ||
2154 | |||
2155 | /// get a number (explicit) | ||
2156 | template<typename T, typename | ||
2157 | std::enable_if< | ||
2158 | std::is_arithmetic<T>::value | ||
2159 | , int>::type = 0> | ||
2160 | T get_impl(T*) const | ||
2161 | { | ||
2162 | switch (m_type) | ||
2163 | { | ||
2164 | case (value_t::number_integer): | ||
2165 | { | ||
2166 | return static_cast<T>(m_value.number_integer); | ||
2167 | } | ||
2168 | case (value_t::number_float): | ||
2169 | { | ||
2170 | return static_cast<T>(m_value.number_float); | ||
2171 | } | ||
2172 | default: | ||
2173 | { | ||
2174 | throw std::domain_error("type must be number, but is " + type_name()); | ||
2175 | } | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2179 | /// get a boolean (explicit) | ||
2180 | boolean_t get_impl(boolean_t*) const | ||
2181 | { | ||
2182 | switch (m_type) | ||
2183 | { | ||
2184 | case (value_t::boolean): | ||
2185 | { | ||
2186 | return m_value.boolean; | ||
2187 | } | ||
2188 | default: | ||
2189 | { | ||
2190 | throw std::domain_error("type must be boolean, but is " + type_name()); | ||
2191 | } | ||
2192 | } | ||
2193 | } | ||
2194 | |||
2195 | /// get a pointer to the value (object) | ||
2196 | object_t* get_impl_ptr(object_t*) noexcept | ||
2197 | { | ||
2198 | return is_object() ? m_value.object : nullptr; | ||
2199 | } | ||
2200 | |||
2201 | /// get a pointer to the value (object) | ||
2202 | const object_t* get_impl_ptr(const object_t*) const noexcept | ||
2203 | { | ||
2204 | return is_object() ? m_value.object : nullptr; | ||
2205 | } | ||
2206 | |||
2207 | /// get a pointer to the value (array) | ||
2208 | array_t* get_impl_ptr(array_t*) noexcept | ||
2209 | { | ||
2210 | return is_array() ? m_value.array : nullptr; | ||
2211 | } | ||
2212 | |||
2213 | /// get a pointer to the value (array) | ||
2214 | const array_t* get_impl_ptr(const array_t*) const noexcept | ||
2215 | { | ||
2216 | return is_array() ? m_value.array : nullptr; | ||
2217 | } | ||
2218 | |||
2219 | /// get a pointer to the value (string) | ||
2220 | string_t* get_impl_ptr(string_t*) noexcept | ||
2221 | { | ||
2222 | return is_string() ? m_value.string : nullptr; | ||
2223 | } | ||
2224 | |||
2225 | /// get a pointer to the value (string) | ||
2226 | const string_t* get_impl_ptr(const string_t*) const noexcept | ||
2227 | { | ||
2228 | return is_string() ? m_value.string : nullptr; | ||
2229 | } | ||
2230 | |||
2231 | /// get a pointer to the value (boolean) | ||
2232 | boolean_t* get_impl_ptr(boolean_t*) noexcept | ||
2233 | { | ||
2234 | return is_boolean() ? &m_value.boolean : nullptr; | ||
2235 | } | ||
2236 | |||
2237 | /// get a pointer to the value (boolean) | ||
2238 | const boolean_t* get_impl_ptr(const boolean_t*) const noexcept | ||
2239 | { | ||
2240 | return is_boolean() ? &m_value.boolean : nullptr; | ||
2241 | } | ||
2242 | |||
2243 | /// get a pointer to the value (integer number) | ||
2244 | number_integer_t* get_impl_ptr(number_integer_t*) noexcept | ||
2245 | { | ||
2246 | return is_number_integer() ? &m_value.number_integer : nullptr; | ||
2247 | } | ||
2248 | |||
2249 | /// get a pointer to the value (integer number) | ||
2250 | const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept | ||
2251 | { | ||
2252 | return is_number_integer() ? &m_value.number_integer : nullptr; | ||
2253 | } | ||
2254 | |||
2255 | /// get a pointer to the value (floating-point number) | ||
2256 | number_float_t* get_impl_ptr(number_float_t*) noexcept | ||
2257 | { | ||
2258 | return is_number_float() ? &m_value.number_float : nullptr; | ||
2259 | } | ||
2260 | |||
2261 | /// get a pointer to the value (floating-point number) | ||
2262 | const number_float_t* get_impl_ptr(const number_float_t*) const noexcept | ||
2263 | { | ||
2264 | return is_number_float() ? &m_value.number_float : nullptr; | ||
2265 | } | ||
2266 | |||
2267 | public: | ||
2268 | |||
2269 | /// @name value access | ||
2270 | /// @{ | ||
2271 | |||
2272 | /*! | ||
2273 | @brief get a value (explicit) | ||
2274 | |||
2275 | Explicit type conversion between the JSON value and a compatible value. | ||
2276 | |||
2277 | @tparam ValueType non-pointer type compatible to the JSON value, for | ||
2278 | instance `int` for JSON integer numbers, `bool` for JSON booleans, or | ||
2279 | `std::vector` types for JSON arrays | ||
2280 | |||
2281 | @return copy of the JSON value, converted to type @a ValueType | ||
2282 | |||
2283 | @throw std::domain_error in case passed type @a ValueType is incompatible | ||
2284 | to JSON | ||
2285 | |||
2286 | @complexity Linear in the size of the JSON value. | ||
2287 | |||
2288 | @liveexample{The example below shows serveral conversions from JSON values | ||
2289 | to other types. There a few things to note: (1) Floating-point numbers can | ||
2290 | be converted to integers\, (2) A JSON array can be converted to a standard | ||
2291 | `std::vector<short>`\, (3) A JSON object can be converted to C++ | ||
2292 | assiciative containers such as `std::unordered_map<std::string\, | ||
2293 | json>`.,get__ValueType_const} | ||
2294 | |||
2295 | @internal | ||
2296 | The idea of using a casted null pointer to choose the correct | ||
2297 | implementation is from <http://stackoverflow.com/a/8315197/266378>. | ||
2298 | @endinternal | ||
2299 | |||
2300 | @sa @ref operator ValueType() const for implicit conversion | ||
2301 | @sa @ref get() for pointer-member access | ||
2302 | */ | ||
2303 | template<typename ValueType, typename | ||
2304 | std::enable_if< | ||
2305 | not std::is_pointer<ValueType>::value | ||
2306 | , int>::type = 0> | ||
2307 | ValueType get() const | ||
2308 | { | ||
2309 | return get_impl(static_cast<ValueType*>(nullptr)); | ||
2310 | } | ||
2311 | |||
2312 | /*! | ||
2313 | @brief get a pointer value (explicit) | ||
2314 | |||
2315 | Explicit pointer access to the internally stored JSON value. No copies are | ||
2316 | made. | ||
2317 | |||
2318 | @warning Writing data to the pointee of the result yields an undefined | ||
2319 | state. | ||
2320 | |||
2321 | @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref | ||
2322 | object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref | ||
2323 | number_float_t. | ||
2324 | |||
2325 | @return pointer to the internally stored JSON value if the requested pointer | ||
2326 | type @a PointerType fits to the JSON value; `nullptr` otherwise | ||
2327 | |||
2328 | @complexity Constant. | ||
2329 | |||
2330 | @liveexample{The example below shows how pointers to internal values of a | ||
2331 | JSON value can be requested. Note that no type conversions are made and a | ||
2332 | `nullptr` is returned if the value and the requested pointer type does not | ||
2333 | match.,get__PointerType} | ||
2334 | |||
2335 | @sa @ref get_ptr() for explicit pointer-member access | ||
2336 | */ | ||
2337 | template<typename PointerType, typename | ||
2338 | std::enable_if< | ||
2339 | std::is_pointer<PointerType>::value | ||
2340 | , int>::type = 0> | ||
2341 | PointerType get() noexcept | ||
2342 | { | ||
2343 | // delegate the call to get_ptr | ||
2344 | return get_ptr<PointerType>(); | ||
2345 | } | ||
2346 | |||
2347 | /*! | ||
2348 | @brief get a pointer value (explicit) | ||
2349 | @copydoc get() | ||
2350 | */ | ||
2351 | template<typename PointerType, typename | ||
2352 | std::enable_if< | ||
2353 | std::is_pointer<PointerType>::value | ||
2354 | , int>::type = 0> | ||
2355 | const PointerType get() const noexcept | ||
2356 | { | ||
2357 | // delegate the call to get_ptr | ||
2358 | return get_ptr<PointerType>(); | ||
2359 | } | ||
2360 | |||
2361 | /*! | ||
2362 | @brief get a pointer value (implicit) | ||
2363 | |||
2364 | Implict pointer access to the internally stored JSON value. No copies are | ||
2365 | made. | ||
2366 | |||
2367 | @warning Writing data to the pointee of the result yields an undefined | ||
2368 | state. | ||
2369 | |||
2370 | @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref | ||
2371 | object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref | ||
2372 | number_float_t. | ||
2373 | |||
2374 | @return pointer to the internally stored JSON value if the requested pointer | ||
2375 | type @a PointerType fits to the JSON value; `nullptr` otherwise | ||
2376 | |||
2377 | @complexity Constant. | ||
2378 | |||
2379 | @liveexample{The example below shows how pointers to internal values of a | ||
2380 | JSON value can be requested. Note that no type conversions are made and a | ||
2381 | `nullptr` is returned if the value and the requested pointer type does not | ||
2382 | match.,get_ptr} | ||
2383 | */ | ||
2384 | template<typename PointerType, typename | ||
2385 | std::enable_if< | ||
2386 | std::is_pointer<PointerType>::value | ||
2387 | , int>::type = 0> | ||
2388 | PointerType get_ptr() noexcept | ||
2389 | { | ||
2390 | // delegate the call to get_impl_ptr<>() | ||
2391 | return get_impl_ptr(static_cast<PointerType>(nullptr)); | ||
2392 | } | ||
2393 | |||
2394 | /*! | ||
2395 | @brief get a pointer value (implicit) | ||
2396 | @copydoc get_ptr() | ||
2397 | */ | ||
2398 | template<typename PointerType, typename | ||
2399 | std::enable_if< | ||
2400 | std::is_pointer<PointerType>::value | ||
2401 | and std::is_const<PointerType>::value | ||
2402 | , int>::type = 0> | ||
2403 | const PointerType get_ptr() const noexcept | ||
2404 | { | ||
2405 | // delegate the call to get_impl_ptr<>() const | ||
2406 | return get_impl_ptr(static_cast<const PointerType>(nullptr)); | ||
2407 | } | ||
2408 | |||
2409 | /*! | ||
2410 | @brief get a value (implicit) | ||
2411 | |||
2412 | Implict type conversion between the JSON value and a compatible value. The | ||
2413 | call is realized by calling @ref get() const. | ||
2414 | |||
2415 | @tparam ValueType non-pointer type compatible to the JSON value, for | ||
2416 | instance `int` for JSON integer numbers, `bool` for JSON booleans, or | ||
2417 | `std::vector` types for JSON arrays | ||
2418 | |||
2419 | @return copy of the JSON value, converted to type @a ValueType | ||
2420 | |||
2421 | @throw std::domain_error in case passed type @a ValueType is incompatible | ||
2422 | to JSON, thrown by @ref get() const | ||
2423 | |||
2424 | @complexity Linear in the size of the JSON value. | ||
2425 | |||
2426 | @liveexample{The example below shows serveral conversions from JSON values | ||
2427 | to other types. There a few things to note: (1) Floating-point numbers can | ||
2428 | be converted to integers\, (2) A JSON array can be converted to a standard | ||
2429 | `std::vector<short>`\, (3) A JSON object can be converted to C++ | ||
2430 | assiciative containers such as `std::unordered_map<std::string\, | ||
2431 | json>`.,operator__ValueType} | ||
2432 | */ | ||
2433 | template<typename ValueType, typename | ||
2434 | std::enable_if< | ||
2435 | not std::is_pointer<ValueType>::value | ||
2436 | , int>::type = 0> | ||
2437 | operator ValueType() const | ||
2438 | { | ||
2439 | // delegate the call to get<>() const | ||
2440 | return get<ValueType>(); | ||
2441 | } | ||
2442 | |||
2443 | /// @} | ||
2444 | |||
2445 | |||
2446 | //////////////////// | ||
2447 | // element access // | ||
2448 | //////////////////// | ||
2449 | |||
2450 | /// @name element access | ||
2451 | /// @{ | ||
2452 | |||
2453 | /*! | ||
2454 | @brief access specified array element with bounds checking | ||
2455 | |||
2456 | Returns a reference to the element at specified location @a idx, with | ||
2457 | bounds checking. | ||
2458 | |||
2459 | @param[in] idx index of the element to access | ||
2460 | |||
2461 | @return reference to the element at index @a idx | ||
2462 | |||
2463 | @throw std::domain_error if JSON is not an array | ||
2464 | @throw std::out_of_range if the index @a idx is out of range of the array; | ||
2465 | that is, `idx >= size()` | ||
2466 | |||
2467 | @complexity Constant. | ||
2468 | |||
2469 | @liveexample{The example below shows how array elements can be read and | ||
2470 | written using at.,at__size_type} | ||
2471 | */ | ||
2472 | reference at(size_type idx) | ||
2473 | { | ||
2474 | // at only works for arrays | ||
2475 | if (m_type != value_t::array) | ||
2476 | { | ||
2477 | throw std::domain_error("cannot use at() with " + type_name()); | ||
2478 | } | ||
2479 | |||
2480 | return m_value.array->at(idx); | ||
2481 | } | ||
2482 | |||
2483 | /*! | ||
2484 | @brief access specified array element with bounds checking | ||
2485 | |||
2486 | Returns a const reference to the element at specified location @a idx, with | ||
2487 | bounds checking. | ||
2488 | |||
2489 | @param[in] idx index of the element to access | ||
2490 | |||
2491 | @return const reference to the element at index @a idx | ||
2492 | |||
2493 | @throw std::domain_error if JSON is not an array | ||
2494 | @throw std::out_of_range if the index @a idx is out of range of the array; | ||
2495 | that is, `idx >= size()` | ||
2496 | |||
2497 | @complexity Constant. | ||
2498 | |||
2499 | @liveexample{The example below shows how array elements can be read using | ||
2500 | at.,at__size_type_const} | ||
2501 | */ | ||
2502 | const_reference at(size_type idx) const | ||
2503 | { | ||
2504 | // at only works for arrays | ||
2505 | if (m_type != value_t::array) | ||
2506 | { | ||
2507 | throw std::domain_error("cannot use at() with " + type_name()); | ||
2508 | } | ||
2509 | |||
2510 | return m_value.array->at(idx); | ||
2511 | } | ||
2512 | |||
2513 | /*! | ||
2514 | @brief access specified object element with bounds checking | ||
2515 | |||
2516 | Returns a reference to the element at with specified key @a key, with | ||
2517 | bounds checking. | ||
2518 | |||
2519 | @param[in] key key of the element to access | ||
2520 | |||
2521 | @return reference to the element at key @a key | ||
2522 | |||
2523 | @throw std::domain_error if JSON is not an object | ||
2524 | @throw std::out_of_range if the key @a key is is not stored in the object; | ||
2525 | that is, `find(key) == end()` | ||
2526 | |||
2527 | @complexity Logarithmic in the size of the container. | ||
2528 | |||
2529 | @liveexample{The example below shows how object elements can be read and | ||
2530 | written using at.,at__object_t_key_type} | ||
2531 | */ | ||
2532 | reference at(const typename object_t::key_type& key) | ||
2533 | { | ||
2534 | // at only works for objects | ||
2535 | if (m_type != value_t::object) | ||
2536 | { | ||
2537 | throw std::domain_error("cannot use at() with " + type_name()); | ||
2538 | } | ||
2539 | |||
2540 | return m_value.object->at(key); | ||
2541 | } | ||
2542 | |||
2543 | /*! | ||
2544 | @brief access specified object element with bounds checking | ||
2545 | |||
2546 | Returns a const reference to the element at with specified key @a key, with | ||
2547 | bounds checking. | ||
2548 | |||
2549 | @param[in] key key of the element to access | ||
2550 | |||
2551 | @return const reference to the element at key @a key | ||
2552 | |||
2553 | @throw std::domain_error if JSON is not an object | ||
2554 | @throw std::out_of_range if the key @a key is is not stored in the object; | ||
2555 | that is, `find(key) == end()` | ||
2556 | |||
2557 | @complexity Logarithmic in the size of the container. | ||
2558 | |||
2559 | @liveexample{The example below shows how object elements can be read using | ||
2560 | at.,at__object_t_key_type_const} | ||
2561 | */ | ||
2562 | const_reference at(const typename object_t::key_type& key) const | ||
2563 | { | ||
2564 | // at only works for objects | ||
2565 | if (m_type != value_t::object) | ||
2566 | { | ||
2567 | throw std::domain_error("cannot use at() with " + type_name()); | ||
2568 | } | ||
2569 | |||
2570 | return m_value.object->at(key); | ||
2571 | } | ||
2572 | |||
2573 | /*! | ||
2574 | @brief access specified array element | ||
2575 | |||
2576 | Returns a reference to the element at specified location @a idx. | ||
2577 | |||
2578 | @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), | ||
2579 | then the array is silently filled up with `null` values to make `idx` a | ||
2580 | valid reference to the last stored element. | ||
2581 | |||
2582 | @param[in] idx index of the element to access | ||
2583 | |||
2584 | @return reference to the element at index @a idx | ||
2585 | |||
2586 | @throw std::domain_error if JSON is not an array or null | ||
2587 | |||
2588 | @complexity Constant if @a idx is in the range of the array. Otherwise | ||
2589 | linear in `idx - size()`. | ||
2590 | |||
2591 | @liveexample{The example below shows how array elements can be read and | ||
2592 | written using [] operator. Note the addition of `null` | ||
2593 | values.,operatorarray__size_type} | ||
2594 | */ | ||
2595 | reference operator[](size_type idx) | ||
2596 | { | ||
2597 | // implicitly convert null to object | ||
2598 | if (m_type == value_t::null) | ||
2599 | { | ||
2600 | m_type = value_t::array; | ||
2601 | AllocatorType<array_t> alloc; | ||
2602 | m_value.array = alloc.allocate(1); | ||
2603 | alloc.construct(m_value.array); | ||
2604 | } | ||
2605 | |||
2606 | // [] only works for arrays | ||
2607 | if (m_type != value_t::array) | ||
2608 | { | ||
2609 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
2610 | } | ||
2611 | |||
2612 | for (size_t i = m_value.array->size(); i <= idx; ++i) | ||
2613 | { | ||
2614 | m_value.array->push_back(basic_json()); | ||
2615 | } | ||
2616 | |||
2617 | return m_value.array->operator[](idx); | ||
2618 | } | ||
2619 | |||
2620 | /*! | ||
2621 | @brief access specified array element | ||
2622 | |||
2623 | Returns a const reference to the element at specified location @a idx. | ||
2624 | |||
2625 | @param[in] idx index of the element to access | ||
2626 | |||
2627 | @return const reference to the element at index @a idx | ||
2628 | |||
2629 | @throw std::domain_error if JSON is not an array | ||
2630 | |||
2631 | @complexity Constant. | ||
2632 | |||
2633 | @liveexample{The example below shows how array elements can be read using | ||
2634 | the [] operator.,operatorarray__size_type_const} | ||
2635 | */ | ||
2636 | const_reference operator[](size_type idx) const | ||
2637 | { | ||
2638 | // at only works for arrays | ||
2639 | if (m_type != value_t::array) | ||
2640 | { | ||
2641 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
2642 | } | ||
2643 | |||
2644 | return m_value.array->operator[](idx); | ||
2645 | } | ||
2646 | |||
2647 | /*! | ||
2648 | @brief access specified object element | ||
2649 | |||
2650 | Returns a reference to the element at with specified key @a key. | ||
2651 | |||
2652 | @note If @a key is not found in the object, then it is silently added to | ||
2653 | the object and filled with a `null` value to make `key` a valid reference. | ||
2654 | In case the value was `null` before, it is converted to an object. | ||
2655 | |||
2656 | @param[in] key key of the element to access | ||
2657 | |||
2658 | @return reference to the element at key @a key | ||
2659 | |||
2660 | @throw std::domain_error if JSON is not an object or null | ||
2661 | |||
2662 | @complexity Logarithmic in the size of the container. | ||
2663 | |||
2664 | @liveexample{The example below shows how object elements can be read and | ||
2665 | written using the [] operator.,operatorarray__key_type} | ||
2666 | */ | ||
2667 | reference operator[](const typename object_t::key_type& key) | ||
2668 | { | ||
2669 | // implicitly convert null to object | ||
2670 | if (m_type == value_t::null) | ||
2671 | { | ||
2672 | m_type = value_t::object; | ||
2673 | AllocatorType<object_t> alloc; | ||
2674 | m_value.object = alloc.allocate(1); | ||
2675 | alloc.construct(m_value.object); | ||
2676 | } | ||
2677 | |||
2678 | // [] only works for objects | ||
2679 | if (m_type != value_t::object) | ||
2680 | { | ||
2681 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
2682 | } | ||
2683 | |||
2684 | return m_value.object->operator[](key); | ||
2685 | } | ||
2686 | |||
2687 | /*! | ||
2688 | @brief access specified object element | ||
2689 | |||
2690 | Returns a reference to the element at with specified key @a key. | ||
2691 | |||
2692 | @param[in] key key of the element to access | ||
2693 | |||
2694 | @return reference to the element at key @a key | ||
2695 | |||
2696 | @throw std::domain_error if JSON is not an object or null | ||
2697 | |||
2698 | @complexity Logarithmic in the size of the container. | ||
2699 | |||
2700 | @liveexample{The example below shows how object elements can be read using | ||
2701 | the [] operator.,operatorarray__key_type_const} | ||
2702 | */ | ||
2703 | const_reference operator[](const typename object_t::key_type& key) const | ||
2704 | { | ||
2705 | // at only works for objects | ||
2706 | if (m_type != value_t::object) | ||
2707 | { | ||
2708 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
2709 | } | ||
2710 | |||
2711 | return m_value.object->operator[](key); | ||
2712 | } | ||
2713 | |||
2714 | /*! | ||
2715 | @brief access specified object element | ||
2716 | |||
2717 | Returns a reference to the element at with specified key @a key. | ||
2718 | |||
2719 | @note If @a key is not found in the object, then it is silently added to | ||
2720 | the object and filled with a `null` value to make `key` a valid reference. | ||
2721 | In case the value was `null` before, it is converted to an object. | ||
2722 | |||
2723 | @note This function is required for compatibility reasons with Clang. | ||
2724 | |||
2725 | @param[in] key key of the element to access | ||
2726 | |||
2727 | @return reference to the element at key @a key | ||
2728 | |||
2729 | @throw std::domain_error if JSON is not an object or null | ||
2730 | |||
2731 | @complexity Logarithmic in the size of the container. | ||
2732 | |||
2733 | @liveexample{The example below shows how object elements can be read and | ||
2734 | written using the [] operator.,operatorarray__key_type} | ||
2735 | */ | ||
2736 | template<typename T, std::size_t n> | ||
2737 | reference operator[](const T (&key)[n]) | ||
2738 | { | ||
2739 | // implicitly convert null to object | ||
2740 | if (m_type == value_t::null) | ||
2741 | { | ||
2742 | m_type = value_t::object; | ||
2743 | m_value = value_t::object; | ||
2744 | } | ||
2745 | |||
2746 | // at only works for objects | ||
2747 | if (m_type != value_t::object) | ||
2748 | { | ||
2749 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
2750 | } | ||
2751 | |||
2752 | return m_value.object->operator[](key); | ||
2753 | } | ||
2754 | |||
2755 | /*! | ||
2756 | @brief access specified object element | ||
2757 | |||
2758 | Returns a reference to the element at with specified key @a key. | ||
2759 | |||
2760 | @note This function is required for compatibility reasons with Clang. | ||
2761 | |||
2762 | @param[in] key key of the element to access | ||
2763 | |||
2764 | @return reference to the element at key @a key | ||
2765 | |||
2766 | @throw std::domain_error if JSON is not an object or null | ||
2767 | |||
2768 | @complexity Logarithmic in the size of the container. | ||
2769 | |||
2770 | @liveexample{The example below shows how object elements can be read using | ||
2771 | the [] operator.,operatorarray__key_type_const} | ||
2772 | */ | ||
2773 | template<typename T, std::size_t n> | ||
2774 | const_reference operator[](const T (&key)[n]) const | ||
2775 | { | ||
2776 | // at only works for objects | ||
2777 | if (m_type != value_t::object) | ||
2778 | { | ||
2779 | throw std::domain_error("cannot use operator[] with " + type_name()); | ||
2780 | } | ||
2781 | |||
2782 | return m_value.object->operator[](key); | ||
2783 | } | ||
2784 | |||
2785 | /*! | ||
2786 | @brief access the first element | ||
2787 | |||
2788 | Returns a reference to the first element in the container. For a JSON | ||
2789 | container `c`, the expression `c.front()` is equivalent to `*c.begin()`. | ||
2790 | |||
2791 | @return In case of a structured type (array or object), a reference to the | ||
2792 | first element is returned. In cast of number, string, or boolean values, a | ||
2793 | reference to the value is returned. | ||
2794 | |||
2795 | @complexity Constant. | ||
2796 | |||
2797 | @note Calling `front` on an empty container is undefined. | ||
2798 | |||
2799 | @throw std::out_of_range when called on null value | ||
2800 | |||
2801 | @liveexample{The following code shows an example for @ref front.,front} | ||
2802 | */ | ||
2803 | reference front() | ||
2804 | { | ||
2805 | return *begin(); | ||
2806 | } | ||
2807 | |||
2808 | /*! | ||
2809 | @copydoc basic_json::front() | ||
2810 | */ | ||
2811 | const_reference front() const | ||
2812 | { | ||
2813 | return *cbegin(); | ||
2814 | } | ||
2815 | |||
2816 | /*! | ||
2817 | @brief access the last element | ||
2818 | |||
2819 | Returns a reference to the last element in the container. For a JSON | ||
2820 | container `c`, the expression `c.back()` is equivalent to `{ auto tmp = | ||
2821 | c.end(); --tmp; return *tmp; }`. | ||
2822 | |||
2823 | @return In case of a structured type (array or object), a reference to the | ||
2824 | last element is returned. In cast of number, string, or boolean values, a | ||
2825 | reference to the value is returned. | ||
2826 | |||
2827 | @complexity Constant. | ||
2828 | |||
2829 | @note Calling `back` on an empty container is undefined. | ||
2830 | |||
2831 | @throw std::out_of_range when called on null value. | ||
2832 | |||
2833 | @liveexample{The following code shows an example for @ref back.,back} | ||
2834 | */ | ||
2835 | reference back() | ||
2836 | { | ||
2837 | auto tmp = end(); | ||
2838 | --tmp; | ||
2839 | return *tmp; | ||
2840 | } | ||
2841 | |||
2842 | /*! | ||
2843 | @copydoc basic_json::back() | ||
2844 | */ | ||
2845 | const_reference back() const | ||
2846 | { | ||
2847 | auto tmp = cend(); | ||
2848 | --tmp; | ||
2849 | return *tmp; | ||
2850 | } | ||
2851 | |||
2852 | /*! | ||
2853 | @brief remove element given an iterator | ||
2854 | |||
2855 | Removes the element specified by iterator @a pos. Invalidates iterators and | ||
2856 | references at or after the point of the erase, including the end() | ||
2857 | iterator. The iterator @a pos must be valid and dereferenceable. Thus the | ||
2858 | end() iterator (which is valid, but is not dereferencable) cannot be used | ||
2859 | as a value for @a pos. | ||
2860 | |||
2861 | If called on a primitive type other than null, the resulting JSON value | ||
2862 | will be `null`. | ||
2863 | |||
2864 | @param[in] pos iterator to the element to remove | ||
2865 | @return Iterator following the last removed element. If the iterator @a pos | ||
2866 | refers to the last element, the end() iterator is returned. | ||
2867 | |||
2868 | @tparam InteratorType an @ref iterator or @ref const_iterator | ||
2869 | |||
2870 | @throw std::domain_error if called on a `null` value | ||
2871 | @throw std::domain_error if called on an iterator which does not belong to | ||
2872 | the current JSON value | ||
2873 | @throw std::out_of_range if called on a primitive type with invalid iterator | ||
2874 | (i.e., any iterator which is not end()) | ||
2875 | |||
2876 | @complexity The complexity depends on the type: | ||
2877 | - objects: amortized constant | ||
2878 | - arrays: linear in distance between pos and the end of the container | ||
2879 | - strings: linear in the length of the string | ||
2880 | - other types: constant | ||
2881 | |||
2882 | @liveexample{The example shows the result of erase for different JSON | ||
2883 | types.,erase__IteratorType} | ||
2884 | */ | ||
2885 | template <class InteratorType, typename | ||
2886 | std::enable_if< | ||
2887 | std::is_same<InteratorType, typename basic_json_t::iterator>::value or | ||
2888 | std::is_same<InteratorType, typename basic_json_t::const_iterator>::value | ||
2889 | , int>::type | ||
2890 | = 0> | ||
2891 | InteratorType erase(InteratorType pos) | ||
2892 | { | ||
2893 | // make sure iterator fits the current value | ||
2894 | if (this != pos.m_object) | ||
2895 | { | ||
2896 | throw std::domain_error("iterator does not fit current value"); | ||
2897 | } | ||
2898 | |||
2899 | InteratorType result = end(); | ||
2900 | |||
2901 | switch (m_type) | ||
2902 | { | ||
2903 | case value_t::number_integer: | ||
2904 | case value_t::number_float: | ||
2905 | case value_t::boolean: | ||
2906 | case value_t::string: | ||
2907 | { | ||
2908 | if (not pos.m_it.primitive_iterator.is_begin()) | ||
2909 | { | ||
2910 | throw std::out_of_range("iterator out of range"); | ||
2911 | } | ||
2912 | |||
2913 | if (m_type == value_t::string) | ||
2914 | { | ||
2915 | delete m_value.string; | ||
2916 | m_value.string = nullptr; | ||
2917 | } | ||
2918 | |||
2919 | m_type = value_t::null; | ||
2920 | break; | ||
2921 | } | ||
2922 | |||
2923 | case value_t::object: | ||
2924 | { | ||
2925 | result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); | ||
2926 | break; | ||
2927 | } | ||
2928 | |||
2929 | case value_t::array: | ||
2930 | { | ||
2931 | result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); | ||
2932 | break; | ||
2933 | } | ||
2934 | |||
2935 | default: | ||
2936 | { | ||
2937 | throw std::domain_error("cannot use erase() with " + type_name()); | ||
2938 | } | ||
2939 | } | ||
2940 | |||
2941 | return result; | ||
2942 | } | ||
2943 | |||
2944 | /*! | ||
2945 | @brief remove elements given an iterator range | ||
2946 | |||
2947 | Removes the element specified by the range `[first; last)`. Invalidates | ||
2948 | iterators and references at or after the point of the erase, including the | ||
2949 | end() iterator. The iterator @a first does not need to be dereferenceable | ||
2950 | if `first == last`: erasing an empty range is a no-op. | ||
2951 | |||
2952 | If called on a primitive type other than null, the resulting JSON value | ||
2953 | will be `null`. | ||
2954 | |||
2955 | @param[in] first iterator to the beginning of the range to remove | ||
2956 | @param[in] last iterator past the end of the range to remove | ||
2957 | @return Iterator following the last removed element. If the iterator @a | ||
2958 | second refers to the last element, the end() iterator is returned. | ||
2959 | |||
2960 | @tparam InteratorType an @ref iterator or @ref const_iterator | ||
2961 | |||
2962 | @throw std::domain_error if called on a `null` value | ||
2963 | @throw std::domain_error if called on iterators which does not belong to | ||
2964 | the current JSON value | ||
2965 | @throw std::out_of_range if called on a primitive type with invalid iterators | ||
2966 | (i.e., if `first != begin()` and `last != end()`) | ||
2967 | |||
2968 | @complexity The complexity depends on the type: | ||
2969 | - objects: `log(size()) + std::distance(first, last)` | ||
2970 | - arrays: linear in the distance between @a first and @a last, plus linear | ||
2971 | in the distance between @a last and end of the container | ||
2972 | - strings: linear in the length of the string | ||
2973 | - other types: constant | ||
2974 | |||
2975 | @liveexample{The example shows the result of erase for different JSON | ||
2976 | types.,erase__IteratorType_IteratorType} | ||
2977 | */ | ||
2978 | template <class InteratorType, typename | ||
2979 | std::enable_if< | ||
2980 | std::is_same<InteratorType, typename basic_json_t::iterator>::value or | ||
2981 | std::is_same<InteratorType, typename basic_json_t::const_iterator>::value | ||
2982 | , int>::type | ||
2983 | = 0> | ||
2984 | InteratorType erase(InteratorType first, InteratorType last) | ||
2985 | { | ||
2986 | // make sure iterator fits the current value | ||
2987 | if (this != first.m_object or this != last.m_object) | ||
2988 | { | ||
2989 | throw std::domain_error("iterators do not fit current value"); | ||
2990 | } | ||
2991 | |||
2992 | InteratorType result = end(); | ||
2993 | |||
2994 | switch (m_type) | ||
2995 | { | ||
2996 | case value_t::number_integer: | ||
2997 | case value_t::number_float: | ||
2998 | case value_t::boolean: | ||
2999 | case value_t::string: | ||
3000 | { | ||
3001 | if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) | ||
3002 | { | ||
3003 | throw std::out_of_range("iterators out of range"); | ||
3004 | } | ||
3005 | |||
3006 | if (m_type == value_t::string) | ||
3007 | { | ||
3008 | delete m_value.string; | ||
3009 | m_value.string = nullptr; | ||
3010 | } | ||
3011 | |||
3012 | m_type = value_t::null; | ||
3013 | break; | ||
3014 | } | ||
3015 | |||
3016 | case value_t::object: | ||
3017 | { | ||
3018 | result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, | ||
3019 | last.m_it.object_iterator); | ||
3020 | break; | ||
3021 | } | ||
3022 | |||
3023 | case value_t::array: | ||
3024 | { | ||
3025 | result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, | ||
3026 | last.m_it.array_iterator); | ||
3027 | break; | ||
3028 | } | ||
3029 | |||
3030 | default: | ||
3031 | { | ||
3032 | throw std::domain_error("cannot use erase with " + type_name()); | ||
3033 | } | ||
3034 | } | ||
3035 | |||
3036 | return result; | ||
3037 | } | ||
3038 | |||
3039 | /*! | ||
3040 | @brief remove element from a JSON object given a key | ||
3041 | |||
3042 | Removes elements from a JSON object with the key value @a key. | ||
3043 | |||
3044 | @param[in] key value of the elements to remove | ||
3045 | |||
3046 | @return Number of elements removed. If ObjectType is the default `std::map` | ||
3047 | type, the return value will always be `0` (@a key was not found) or `1` (@a | ||
3048 | key was found). | ||
3049 | |||
3050 | @throw std::domain_error when called on a type other than JSON object | ||
3051 | |||
3052 | @complexity `log(size()) + count(key)` | ||
3053 | |||
3054 | @liveexample{The example shows the effect of erase.,erase__key_type} | ||
3055 | */ | ||
3056 | size_type erase(const typename object_t::key_type& key) | ||
3057 | { | ||
3058 | // this erase only works for objects | ||
3059 | if (m_type != value_t::object) | ||
3060 | { | ||
3061 | throw std::domain_error("cannot use erase() with " + type_name()); | ||
3062 | } | ||
3063 | |||
3064 | return m_value.object->erase(key); | ||
3065 | } | ||
3066 | |||
3067 | /*! | ||
3068 | @brief remove element from a JSON array given an index | ||
3069 | |||
3070 | Removes element from a JSON array at the index @a idx. | ||
3071 | |||
3072 | @param[in] idx index of the element to remove | ||
3073 | |||
3074 | @throw std::domain_error when called on a type other than JSON array | ||
3075 | @throw std::out_of_range when `idx >= size()` | ||
3076 | |||
3077 | @complexity Linear in distance between @a idx and the end of the container. | ||
3078 | |||
3079 | @liveexample{The example shows the effect of erase.,erase__size_type} | ||
3080 | */ | ||
3081 | void erase(const size_type idx) | ||
3082 | { | ||
3083 | // this erase only works for arrays | ||
3084 | if (m_type != value_t::array) | ||
3085 | { | ||
3086 | throw std::domain_error("cannot use erase() with " + type_name()); | ||
3087 | } | ||
3088 | |||
3089 | if (idx >= size()) | ||
3090 | { | ||
3091 | throw std::out_of_range("index out of range"); | ||
3092 | } | ||
3093 | |||
3094 | m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx)); | ||
3095 | } | ||
3096 | |||
3097 | /*! | ||
3098 | @brief find an element in a JSON object | ||
3099 | |||
3100 | Finds an element in a JSON object with key equivalent to @a key. If the | ||
3101 | element is not found or the JSON value is not an object, end() is returned. | ||
3102 | |||
3103 | @param[in] key key value of the element to search for | ||
3104 | |||
3105 | @return Iterator to an element with key equivalent to @a key. If no such | ||
3106 | element is found, past-the-end (see end()) iterator is returned. | ||
3107 | |||
3108 | @complexity Logarithmic in the size of the JSON object. | ||
3109 | |||
3110 | @liveexample{The example shows how find is used.,find__key_type} | ||
3111 | */ | ||
3112 | iterator find(typename object_t::key_type key) | ||
3113 | { | ||
3114 | auto result = end(); | ||
3115 | |||
3116 | if (m_type == value_t::object) | ||
3117 | { | ||
3118 | result.m_it.object_iterator = m_value.object->find(key); | ||
3119 | } | ||
3120 | |||
3121 | return result; | ||
3122 | } | ||
3123 | |||
3124 | /*! | ||
3125 | @brief find an element in a JSON object | ||
3126 | @copydoc find(typename object_t::key_type) | ||
3127 | */ | ||
3128 | const_iterator find(typename object_t::key_type key) const | ||
3129 | { | ||
3130 | auto result = cend(); | ||
3131 | |||
3132 | if (m_type == value_t::object) | ||
3133 | { | ||
3134 | result.m_it.object_iterator = m_value.object->find(key); | ||
3135 | } | ||
3136 | |||
3137 | return result; | ||
3138 | } | ||
3139 | |||
3140 | /*! | ||
3141 | @brief returns the number of occurrences of a key in a JSON object | ||
3142 | |||
3143 | Returns the number of elements with key @a key. If ObjectType is the | ||
3144 | default `std::map` type, the return value will always be `0` (@a key was | ||
3145 | not found) or `1` (@a key was found). | ||
3146 | |||
3147 | @param[in] key key value of the element to count | ||
3148 | |||
3149 | @return Number of elements with key @a key. If the JSON value is not an | ||
3150 | object, the return value will be `0`. | ||
3151 | |||
3152 | @complexity Logarithmic in the size of the JSON object. | ||
3153 | |||
3154 | @liveexample{The example shows how count is used.,count} | ||
3155 | */ | ||
3156 | size_type count(typename object_t::key_type key) const | ||
3157 | { | ||
3158 | // return 0 for all nonobject types | ||
3159 | return (m_type == value_t::object) ? m_value.object->count(key) : 0; | ||
3160 | } | ||
3161 | |||
3162 | /// @} | ||
3163 | |||
3164 | |||
3165 | /////////////// | ||
3166 | // iterators // | ||
3167 | /////////////// | ||
3168 | |||
3169 | /// @name iterators | ||
3170 | /// @{ | ||
3171 | |||
3172 | /*! | ||
3173 | @brief returns an iterator to the first element | ||
3174 | |||
3175 | Returns an iterator to the first element. | ||
3176 | |||
3177 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
3178 | |||
3179 | @return iterator to the first element | ||
3180 | |||
3181 | @complexity Constant. | ||
3182 | |||
3183 | @requirement This function satisfies the Container requirements: | ||
3184 | - The complexity is constant. | ||
3185 | |||
3186 | @liveexample{The following code shows an example for @ref begin.,begin} | ||
3187 | */ | ||
3188 | iterator begin() | ||
3189 | { | ||
3190 | iterator result(this); | ||
3191 | result.set_begin(); | ||
3192 | return result; | ||
3193 | } | ||
3194 | |||
3195 | /*! | ||
3196 | @copydoc basic_json::cbegin() | ||
3197 | */ | ||
3198 | const_iterator begin() const | ||
3199 | { | ||
3200 | return cbegin(); | ||
3201 | } | ||
3202 | |||
3203 | /*! | ||
3204 | @brief returns a const iterator to the first element | ||
3205 | |||
3206 | Returns a const iterator to the first element. | ||
3207 | |||
3208 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
3209 | |||
3210 | @return const iterator to the first element | ||
3211 | |||
3212 | @complexity Constant. | ||
3213 | |||
3214 | @requirement This function satisfies the Container requirements: | ||
3215 | - The complexity is constant. | ||
3216 | - Has the semantics of `const_cast<const basic_json&>(*this).begin()`. | ||
3217 | |||
3218 | @liveexample{The following code shows an example for @ref cbegin.,cbegin} | ||
3219 | */ | ||
3220 | const_iterator cbegin() const | ||
3221 | { | ||
3222 | const_iterator result(this); | ||
3223 | result.set_begin(); | ||
3224 | return result; | ||
3225 | } | ||
3226 | |||
3227 | /*! | ||
3228 | @brief returns an iterator to one past the last element | ||
3229 | |||
3230 | Returns an iterator to one past the last element. | ||
3231 | |||
3232 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
3233 | |||
3234 | @return iterator one past the last element | ||
3235 | |||
3236 | @complexity Constant. | ||
3237 | |||
3238 | @requirement This function satisfies the Container requirements: | ||
3239 | - The complexity is constant. | ||
3240 | |||
3241 | @liveexample{The following code shows an example for @ref end.,end} | ||
3242 | */ | ||
3243 | iterator end() | ||
3244 | { | ||
3245 | iterator result(this); | ||
3246 | result.set_end(); | ||
3247 | return result; | ||
3248 | } | ||
3249 | |||
3250 | /*! | ||
3251 | @copydoc basic_json::cend() | ||
3252 | */ | ||
3253 | const_iterator end() const | ||
3254 | { | ||
3255 | return cend(); | ||
3256 | } | ||
3257 | |||
3258 | /*! | ||
3259 | @brief returns a const iterator to one past the last element | ||
3260 | |||
3261 | Returns a const iterator to one past the last element. | ||
3262 | |||
3263 | @image html range-begin-end.svg "Illustration from cppreference.com" | ||
3264 | |||
3265 | @return const iterator one past the last element | ||
3266 | |||
3267 | @complexity Constant. | ||
3268 | |||
3269 | @requirement This function satisfies the Container requirements: | ||
3270 | - The complexity is constant. | ||
3271 | - Has the semantics of `const_cast<const basic_json&>(*this).end()`. | ||
3272 | |||
3273 | @liveexample{The following code shows an example for @ref cend.,cend} | ||
3274 | */ | ||
3275 | const_iterator cend() const | ||
3276 | { | ||
3277 | const_iterator result(this); | ||
3278 | result.set_end(); | ||
3279 | return result; | ||
3280 | } | ||
3281 | |||
3282 | /*! | ||
3283 | @brief returns an iterator to the reverse-beginning | ||
3284 | |||
3285 | Returns an iterator to the reverse-beginning; that is, the last element. | ||
3286 | |||
3287 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
3288 | |||
3289 | @complexity Constant. | ||
3290 | |||
3291 | @requirement This function satisfies the ReversibleContainer requirements: | ||
3292 | - The complexity is constant. | ||
3293 | - Has the semantics of `reverse_iterator(end())`. | ||
3294 | |||
3295 | @liveexample{The following code shows an example for @ref rbegin.,rbegin} | ||
3296 | */ | ||
3297 | reverse_iterator rbegin() | ||
3298 | { | ||
3299 | return reverse_iterator(end()); | ||
3300 | } | ||
3301 | |||
3302 | /*! | ||
3303 | @copydoc basic_json::crbegin() | ||
3304 | */ | ||
3305 | const_reverse_iterator rbegin() const | ||
3306 | { | ||
3307 | return crbegin(); | ||
3308 | } | ||
3309 | |||
3310 | /*! | ||
3311 | @brief returns an iterator to the reverse-end | ||
3312 | |||
3313 | Returns an iterator to the reverse-end; that is, one before the first | ||
3314 | element. | ||
3315 | |||
3316 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
3317 | |||
3318 | @complexity Constant. | ||
3319 | |||
3320 | @requirement This function satisfies the ReversibleContainer requirements: | ||
3321 | - The complexity is constant. | ||
3322 | - Has the semantics of `reverse_iterator(begin())`. | ||
3323 | |||
3324 | @liveexample{The following code shows an example for @ref rend.,rend} | ||
3325 | */ | ||
3326 | reverse_iterator rend() | ||
3327 | { | ||
3328 | return reverse_iterator(begin()); | ||
3329 | } | ||
3330 | |||
3331 | /*! | ||
3332 | @copydoc basic_json::crend() | ||
3333 | */ | ||
3334 | const_reverse_iterator rend() const | ||
3335 | { | ||
3336 | return crend(); | ||
3337 | } | ||
3338 | |||
3339 | /*! | ||
3340 | @brief returns a const reverse iterator to the last element | ||
3341 | |||
3342 | Returns a const iterator to the reverse-beginning; that is, the last | ||
3343 | element. | ||
3344 | |||
3345 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
3346 | |||
3347 | @complexity Constant. | ||
3348 | |||
3349 | @requirement This function satisfies the ReversibleContainer requirements: | ||
3350 | - The complexity is constant. | ||
3351 | - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`. | ||
3352 | |||
3353 | @liveexample{The following code shows an example for @ref crbegin.,crbegin} | ||
3354 | */ | ||
3355 | const_reverse_iterator crbegin() const | ||
3356 | { | ||
3357 | return const_reverse_iterator(cend()); | ||
3358 | } | ||
3359 | |||
3360 | /*! | ||
3361 | @brief returns a const reverse iterator to one before the first | ||
3362 | |||
3363 | Returns a const reverse iterator to the reverse-end; that is, one before | ||
3364 | the first element. | ||
3365 | |||
3366 | @image html range-rbegin-rend.svg "Illustration from cppreference.com" | ||
3367 | |||
3368 | @complexity Constant. | ||
3369 | |||
3370 | @requirement This function satisfies the ReversibleContainer requirements: | ||
3371 | - The complexity is constant. | ||
3372 | - Has the semantics of `const_cast<const basic_json&>(*this).rend()`. | ||
3373 | |||
3374 | @liveexample{The following code shows an example for @ref crend.,crend} | ||
3375 | */ | ||
3376 | const_reverse_iterator crend() const | ||
3377 | { | ||
3378 | return const_reverse_iterator(cbegin()); | ||
3379 | } | ||
3380 | |||
3381 | /// @} | ||
3382 | |||
3383 | |||
3384 | ////////////// | ||
3385 | // capacity // | ||
3386 | ////////////// | ||
3387 | |||
3388 | /// @name capacity | ||
3389 | /// @{ | ||
3390 | |||
3391 | /*! | ||
3392 | @brief checks whether the container is empty | ||
3393 | |||
3394 | Checks if a JSON value has no elements. | ||
3395 | |||
3396 | @return The return value depends on the different types and is | ||
3397 | defined as follows: | ||
3398 | Value type | return value | ||
3399 | ----------- | ------------- | ||
3400 | null | @c true | ||
3401 | boolean | @c false | ||
3402 | string | @c false | ||
3403 | number | @c false | ||
3404 | object | result of function object_t::empty() | ||
3405 | array | result of function array_t::empty() | ||
3406 | |||
3407 | @complexity Constant, as long as @ref array_t and @ref object_t satisfy the | ||
3408 | Container concept; that is, their empty() functions have | ||
3409 | constant complexity. | ||
3410 | |||
3411 | @requirement This function satisfies the Container requirements: | ||
3412 | - The complexity is constant. | ||
3413 | - Has the semantics of `begin() == end()`. | ||
3414 | |||
3415 | @liveexample{The following code uses @ref empty to check if a @ref json | ||
3416 | object contains any elements.,empty} | ||
3417 | */ | ||
3418 | bool empty() const noexcept | ||
3419 | { | ||
3420 | switch (m_type) | ||
3421 | { | ||
3422 | case (value_t::null): | ||
3423 | { | ||
3424 | return true; | ||
3425 | } | ||
3426 | |||
3427 | case (value_t::array): | ||
3428 | { | ||
3429 | return m_value.array->empty(); | ||
3430 | } | ||
3431 | |||
3432 | case (value_t::object): | ||
3433 | { | ||
3434 | return m_value.object->empty(); | ||
3435 | } | ||
3436 | |||
3437 | default: | ||
3438 | { | ||
3439 | // all other types are nonempty | ||
3440 | return false; | ||
3441 | } | ||
3442 | } | ||
3443 | } | ||
3444 | |||
3445 | /*! | ||
3446 | @brief returns the number of elements | ||
3447 | |||
3448 | Returns the number of elements in a JSON value. | ||
3449 | |||
3450 | @return The return value depends on the different types and is | ||
3451 | defined as follows: | ||
3452 | Value type | return value | ||
3453 | ----------- | ------------- | ||
3454 | null | @c 0 | ||
3455 | boolean | @c 1 | ||
3456 | string | @c 1 | ||
3457 | number | @c 1 | ||
3458 | object | result of function object_t::size() | ||
3459 | array | result of function array_t::size() | ||
3460 | |||
3461 | @complexity Constant, as long as @ref array_t and @ref object_t satisfy the | ||
3462 | Container concept; that is, their size() functions have | ||
3463 | constant complexity. | ||
3464 | |||
3465 | @requirement This function satisfies the Container requirements: | ||
3466 | - The complexity is constant. | ||
3467 | - Has the semantics of `std::distance(begin(), end())`. | ||
3468 | |||
3469 | @liveexample{The following code calls @ref size on the different value | ||
3470 | types.,size} | ||
3471 | */ | ||
3472 | size_type size() const noexcept | ||
3473 | { | ||
3474 | switch (m_type) | ||
3475 | { | ||
3476 | case (value_t::null): | ||
3477 | { | ||
3478 | return 0; | ||
3479 | } | ||
3480 | |||
3481 | case (value_t::array): | ||
3482 | { | ||
3483 | return m_value.array->size(); | ||
3484 | } | ||
3485 | |||
3486 | case (value_t::object): | ||
3487 | { | ||
3488 | return m_value.object->size(); | ||
3489 | } | ||
3490 | |||
3491 | default: | ||
3492 | { | ||
3493 | // all other types have size 1 | ||
3494 | return 1; | ||
3495 | } | ||
3496 | } | ||
3497 | } | ||
3498 | |||
3499 | /*! | ||
3500 | @brief returns the maximum possible number of elements | ||
3501 | |||
3502 | Returns the maximum number of elements a JSON value is able to hold due to | ||
3503 | system or library implementation limitations, i.e. `std::distance(begin(), | ||
3504 | end())` for the JSON value. | ||
3505 | |||
3506 | @return The return value depends on the different types and is | ||
3507 | defined as follows: | ||
3508 | Value type | return value | ||
3509 | ----------- | ------------- | ||
3510 | null | @c 0 (same as size()) | ||
3511 | boolean | @c 1 (same as size()) | ||
3512 | string | @c 1 (same as size()) | ||
3513 | number | @c 1 (same as size()) | ||
3514 | object | result of function object_t::max_size() | ||
3515 | array | result of function array_t::max_size() | ||
3516 | |||
3517 | @complexity Constant, as long as @ref array_t and @ref object_t satisfy the | ||
3518 | Container concept; that is, their max_size() functions have | ||
3519 | constant complexity. | ||
3520 | |||
3521 | @requirement This function satisfies the Container requirements: | ||
3522 | - The complexity is constant. | ||
3523 | - Has the semantics of returning `b.size()` where `b` is the largest | ||
3524 | possible JSON value. | ||
3525 | |||
3526 | @liveexample{The following code calls @ref max_size on the different value | ||
3527 | types. Note the output is implementation specific.,max_size} | ||
3528 | */ | ||
3529 | size_type max_size() const noexcept | ||
3530 | { | ||
3531 | switch (m_type) | ||
3532 | { | ||
3533 | case (value_t::array): | ||
3534 | { | ||
3535 | return m_value.array->max_size(); | ||
3536 | } | ||
3537 | |||
3538 | case (value_t::object): | ||
3539 | { | ||
3540 | return m_value.object->max_size(); | ||
3541 | } | ||
3542 | |||
3543 | default: | ||
3544 | { | ||
3545 | // all other types have max_size() == size() | ||
3546 | return size(); | ||
3547 | } | ||
3548 | } | ||
3549 | } | ||
3550 | |||
3551 | /// @} | ||
3552 | |||
3553 | |||
3554 | /////////////// | ||
3555 | // modifiers // | ||
3556 | /////////////// | ||
3557 | |||
3558 | /// @name modifiers | ||
3559 | /// @{ | ||
3560 | |||
3561 | /*! | ||
3562 | @brief clears the contents | ||
3563 | |||
3564 | Clears the content of a JSON value and resets it to the default value as | ||
3565 | if @ref basic_json(value_t) would have been called: | ||
3566 | |||
3567 | Value type | initial value | ||
3568 | ----------- | ------------- | ||
3569 | null | `null` | ||
3570 | boolean | `false` | ||
3571 | string | `""` | ||
3572 | number | `0` | ||
3573 | object | `{}` | ||
3574 | array | `[]` | ||
3575 | |||
3576 | @note Floating-point numbers are set to `0.0` which will be serialized to | ||
3577 | `0`. The vale type remains @ref number_float_t. | ||
3578 | |||
3579 | @complexity Linear in the size of the JSON value. | ||
3580 | |||
3581 | @liveexample{The example below shows the effect of @ref clear to different | ||
3582 | JSON types.,clear} | ||
3583 | */ | ||
3584 | void clear() noexcept | ||
3585 | { | ||
3586 | switch (m_type) | ||
3587 | { | ||
3588 | case (value_t::null): | ||
3589 | case (value_t::discarded): | ||
3590 | { | ||
3591 | break; | ||
3592 | } | ||
3593 | |||
3594 | case (value_t::number_integer): | ||
3595 | { | ||
3596 | m_value.number_integer = 0; | ||
3597 | break; | ||
3598 | } | ||
3599 | |||
3600 | case (value_t::number_float): | ||
3601 | { | ||
3602 | m_value.number_float = 0.0; | ||
3603 | break; | ||
3604 | } | ||
3605 | |||
3606 | case (value_t::boolean): | ||
3607 | { | ||
3608 | m_value.boolean = false; | ||
3609 | break; | ||
3610 | } | ||
3611 | |||
3612 | case (value_t::string): | ||
3613 | { | ||
3614 | m_value.string->clear(); | ||
3615 | break; | ||
3616 | } | ||
3617 | |||
3618 | case (value_t::array): | ||
3619 | { | ||
3620 | m_value.array->clear(); | ||
3621 | break; | ||
3622 | } | ||
3623 | |||
3624 | case (value_t::object): | ||
3625 | { | ||
3626 | m_value.object->clear(); | ||
3627 | break; | ||
3628 | } | ||
3629 | } | ||
3630 | } | ||
3631 | |||
3632 | /*! | ||
3633 | @brief add an object to an array | ||
3634 | |||
3635 | Appends the given element @a value to the end of the JSON value. If the | ||
3636 | function is called on a JSON null value, an empty array is created before | ||
3637 | appending @a value. | ||
3638 | |||
3639 | @param value the value to add to the JSON array | ||
3640 | |||
3641 | @throw std::domain_error when called on a type other than JSON array or null | ||
3642 | |||
3643 | @complexity Amortized constant. | ||
3644 | |||
3645 | @liveexample{The example shows how `push_back` and `+=` can be used to add | ||
3646 | elements to a JSON array. Note how the `null` value was silently converted | ||
3647 | to a JSON array.,push_back} | ||
3648 | */ | ||
3649 | void push_back(basic_json&& value) | ||
3650 | { | ||
3651 | // push_back only works for null objects or arrays | ||
3652 | if (not(m_type == value_t::null or m_type == value_t::array)) | ||
3653 | { | ||
3654 | throw std::domain_error("cannot use push_back() with " + type_name()); | ||
3655 | } | ||
3656 | |||
3657 | // transform null object into an array | ||
3658 | if (m_type == value_t::null) | ||
3659 | { | ||
3660 | m_type = value_t::array; | ||
3661 | m_value = value_t::array; | ||
3662 | } | ||
3663 | |||
3664 | // add element to array (move semantics) | ||
3665 | m_value.array->push_back(std::move(value)); | ||
3666 | // invalidate object | ||
3667 | value.m_type = value_t::null; | ||
3668 | } | ||
3669 | |||
3670 | /*! | ||
3671 | @brief add an object to an array | ||
3672 | @copydoc push_back(basic_json&&) | ||
3673 | */ | ||
3674 | reference operator+=(basic_json&& value) | ||
3675 | { | ||
3676 | push_back(std::move(value)); | ||
3677 | return *this; | ||
3678 | } | ||
3679 | |||
3680 | /*! | ||
3681 | @brief add an object to an array | ||
3682 | @copydoc push_back(basic_json&&) | ||
3683 | */ | ||
3684 | void push_back(const basic_json& value) | ||
3685 | { | ||
3686 | // push_back only works for null objects or arrays | ||
3687 | if (not(m_type == value_t::null or m_type == value_t::array)) | ||
3688 | { | ||
3689 | throw std::domain_error("cannot use push_back() with " + type_name()); | ||
3690 | } | ||
3691 | |||
3692 | // transform null object into an array | ||
3693 | if (m_type == value_t::null) | ||
3694 | { | ||
3695 | m_type = value_t::array; | ||
3696 | m_value = value_t::array; | ||
3697 | } | ||
3698 | |||
3699 | // add element to array | ||
3700 | m_value.array->push_back(value); | ||
3701 | } | ||
3702 | |||
3703 | /*! | ||
3704 | @brief add an object to an array | ||
3705 | @copydoc push_back(basic_json&&) | ||
3706 | */ | ||
3707 | reference operator+=(const basic_json& value) | ||
3708 | { | ||
3709 | push_back(value); | ||
3710 | return *this; | ||
3711 | } | ||
3712 | |||
3713 | /*! | ||
3714 | @brief add an object to an object | ||
3715 | |||
3716 | Inserts the given element @a value to the JSON object. If the function is | ||
3717 | called on a JSON null value, an empty object is created before inserting @a | ||
3718 | value. | ||
3719 | |||
3720 | @param[in] value the value to add to the JSON object | ||
3721 | |||
3722 | @throw std::domain_error when called on a type other than JSON object or | ||
3723 | null | ||
3724 | |||
3725 | @complexity Logarithmic in the size of the container, O(log(`size()`)). | ||
3726 | |||
3727 | @liveexample{The example shows how `push_back` and `+=` can be used to add | ||
3728 | elements to a JSON object. Note how the `null` value was silently converted | ||
3729 | to a JSON object.,push_back__object_t__value} | ||
3730 | */ | ||
3731 | void push_back(const typename object_t::value_type& value) | ||
3732 | { | ||
3733 | // push_back only works for null objects or objects | ||
3734 | if (not(m_type == value_t::null or m_type == value_t::object)) | ||
3735 | { | ||
3736 | throw std::domain_error("cannot use push_back() with " + type_name()); | ||
3737 | } | ||
3738 | |||
3739 | // transform null object into an object | ||
3740 | if (m_type == value_t::null) | ||
3741 | { | ||
3742 | m_type = value_t::object; | ||
3743 | m_value = value_t::object; | ||
3744 | } | ||
3745 | |||
3746 | // add element to array | ||
3747 | m_value.object->insert(value); | ||
3748 | } | ||
3749 | |||
3750 | /*! | ||
3751 | @brief add an object to an object | ||
3752 | @copydoc push_back(const typename object_t::value_type&) | ||
3753 | */ | ||
3754 | reference operator+=(const typename object_t::value_type& value) | ||
3755 | { | ||
3756 | push_back(value); | ||
3757 | return operator[](value.first); | ||
3758 | } | ||
3759 | |||
3760 | /*! | ||
3761 | @brief inserts element | ||
3762 | |||
3763 | Inserts element @a value before iterator @a pos. | ||
3764 | |||
3765 | @param[in] pos iterator before which the content will be inserted; may be | ||
3766 | the end() iterator | ||
3767 | @param[in] value element to insert | ||
3768 | @return iterator pointing to the inserted @a value. | ||
3769 | |||
3770 | @throw std::domain_error if called on JSON values other than arrays | ||
3771 | @throw std::domain_error if @a pos is not an iterator of *this | ||
3772 | |||
3773 | @complexity Constant plus linear in the distance between pos and end of the | ||
3774 | container. | ||
3775 | |||
3776 | @liveexample{The example shows how insert is used.,insert} | ||
3777 | */ | ||
3778 | iterator insert(const_iterator pos, const basic_json& value) | ||
3779 | { | ||
3780 | // insert only works for arrays | ||
3781 | if (m_type != value_t::array) | ||
3782 | { | ||
3783 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
3784 | } | ||
3785 | |||
3786 | // check if iterator pos fits to this JSON value | ||
3787 | if (pos.m_object != this) | ||
3788 | { | ||
3789 | throw std::domain_error("iterator does not fit current value"); | ||
3790 | } | ||
3791 | |||
3792 | // insert to array and return iterator | ||
3793 | iterator result(this); | ||
3794 | result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, value); | ||
3795 | return result; | ||
3796 | } | ||
3797 | |||
3798 | /*! | ||
3799 | @brief inserts element | ||
3800 | @copydoc insert(const_iterator, const basic_json&) | ||
3801 | */ | ||
3802 | iterator insert(const_iterator pos, basic_json&& value) | ||
3803 | { | ||
3804 | return insert(pos, value); | ||
3805 | } | ||
3806 | |||
3807 | /*! | ||
3808 | @brief inserts elements | ||
3809 | |||
3810 | Inserts @a count copies of @a value before iterator @a pos. | ||
3811 | |||
3812 | @param[in] pos iterator before which the content will be inserted; may be | ||
3813 | the end() iterator | ||
3814 | @param[in] count number of copies of @a value to insert | ||
3815 | @param[in] value element to insert | ||
3816 | @return iterator pointing to the first element inserted, or @a pos if | ||
3817 | `count==0` | ||
3818 | |||
3819 | @throw std::domain_error if called on JSON values other than arrays | ||
3820 | @throw std::domain_error if @a pos is not an iterator of *this | ||
3821 | |||
3822 | @complexity Linear in @a count plus linear in the distance between @a pos | ||
3823 | and end of the container. | ||
3824 | |||
3825 | @liveexample{The example shows how insert is used.,insert__count} | ||
3826 | */ | ||
3827 | iterator insert(const_iterator pos, size_type count, const basic_json& value) | ||
3828 | { | ||
3829 | // insert only works for arrays | ||
3830 | if (m_type != value_t::array) | ||
3831 | { | ||
3832 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
3833 | } | ||
3834 | |||
3835 | // check if iterator pos fits to this JSON value | ||
3836 | if (pos.m_object != this) | ||
3837 | { | ||
3838 | throw std::domain_error("iterator does not fit current value"); | ||
3839 | } | ||
3840 | |||
3841 | // insert to array and return iterator | ||
3842 | iterator result(this); | ||
3843 | result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, count, value); | ||
3844 | return result; | ||
3845 | } | ||
3846 | |||
3847 | /*! | ||
3848 | @brief inserts elements | ||
3849 | |||
3850 | Inserts elements from range `[first, last)` before iterator @a pos. | ||
3851 | |||
3852 | @param[in] pos iterator before which the content will be inserted; may be | ||
3853 | the end() iterator | ||
3854 | @param[in] first begin of the range of elements to insert | ||
3855 | @param[in] last end of the range of elements to insert | ||
3856 | |||
3857 | @throw std::domain_error if called on JSON values other than arrays | ||
3858 | @throw std::domain_error if @a pos is not an iterator of *this | ||
3859 | @throw std::domain_error if @a first and @a last do not belong to the same | ||
3860 | JSON value | ||
3861 | @throw std::domain_error if @a first or @a last are iterators into | ||
3862 | container for which insert is called | ||
3863 | @return iterator pointing to the first element inserted, or @a pos if | ||
3864 | `first==last` | ||
3865 | |||
3866 | @complexity Linear in `std::distance(first, last)` plus linear in the | ||
3867 | distance between @a pos and end of the container. | ||
3868 | |||
3869 | @liveexample{The example shows how insert is used.,insert__range} | ||
3870 | */ | ||
3871 | iterator insert(const_iterator pos, const_iterator first, const_iterator last) | ||
3872 | { | ||
3873 | // insert only works for arrays | ||
3874 | if (m_type != value_t::array) | ||
3875 | { | ||
3876 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
3877 | } | ||
3878 | |||
3879 | // check if iterator pos fits to this JSON value | ||
3880 | if (pos.m_object != this) | ||
3881 | { | ||
3882 | throw std::domain_error("iterator does not fit current value"); | ||
3883 | } | ||
3884 | |||
3885 | if (first.m_object != last.m_object) | ||
3886 | { | ||
3887 | throw std::domain_error("iterators does not fit"); | ||
3888 | } | ||
3889 | |||
3890 | if (first.m_object == this or last.m_object == this) | ||
3891 | { | ||
3892 | throw std::domain_error("passed iterators may not belong to container"); | ||
3893 | } | ||
3894 | |||
3895 | // insert to array and return iterator | ||
3896 | iterator result(this); | ||
3897 | result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, | ||
3898 | first.m_it.array_iterator, last.m_it.array_iterator); | ||
3899 | return result; | ||
3900 | } | ||
3901 | |||
3902 | /*! | ||
3903 | @brief inserts elements | ||
3904 | |||
3905 | Inserts elements from initializer list @a ilist before iterator @a pos. | ||
3906 | |||
3907 | @param[in] pos iterator before which the content will be inserted; may be | ||
3908 | the end() iterator | ||
3909 | @param[in] ilist initializer list to insert the values from | ||
3910 | |||
3911 | @throw std::domain_error if called on JSON values other than arrays | ||
3912 | @throw std::domain_error if @a pos is not an iterator of *this | ||
3913 | @return iterator pointing to the first element inserted, or @a pos if | ||
3914 | `ilist` is empty | ||
3915 | |||
3916 | @complexity Linear in `ilist.size()` plus linear in the distance between @a | ||
3917 | pos and end of the container. | ||
3918 | |||
3919 | @liveexample{The example shows how insert is used.,insert__ilist} | ||
3920 | */ | ||
3921 | iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist) | ||
3922 | { | ||
3923 | // insert only works for arrays | ||
3924 | if (m_type != value_t::array) | ||
3925 | { | ||
3926 | throw std::domain_error("cannot use insert() with " + type_name()); | ||
3927 | } | ||
3928 | |||
3929 | // check if iterator pos fits to this JSON value | ||
3930 | if (pos.m_object != this) | ||
3931 | { | ||
3932 | throw std::domain_error("iterator does not fit current value"); | ||
3933 | } | ||
3934 | |||
3935 | // insert to array and return iterator | ||
3936 | iterator result(this); | ||
3937 | result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); | ||
3938 | return result; | ||
3939 | } | ||
3940 | |||
3941 | /*! | ||
3942 | @brief exchanges the values | ||
3943 | |||
3944 | Exchanges the contents of the JSON value with those of @a other. Does not | ||
3945 | invoke any move, copy, or swap operations on individual elements. All | ||
3946 | iterators and references remain valid. The past-the-end iterator is | ||
3947 | invalidated. | ||
3948 | |||
3949 | @param[in,out] other JSON value to exchange the contents with | ||
3950 | |||
3951 | @complexity Constant. | ||
3952 | |||
3953 | @liveexample{The example below shows how JSON arrays can be | ||
3954 | swapped.,swap__reference} | ||
3955 | */ | ||
3956 | void swap(reference other) noexcept ( | ||
3957 | std::is_nothrow_move_constructible<value_t>::value and | ||
3958 | std::is_nothrow_move_assignable<value_t>::value and | ||
3959 | std::is_nothrow_move_constructible<json_value>::value and | ||
3960 | std::is_nothrow_move_assignable<json_value>::value | ||
3961 | ) | ||
3962 | { | ||
3963 | std::swap(m_type, other.m_type); | ||
3964 | std::swap(m_value, other.m_value); | ||
3965 | } | ||
3966 | |||
3967 | /*! | ||
3968 | @brief exchanges the values | ||
3969 | |||
3970 | Exchanges the contents of a JSON array with those of @a other. Does not | ||
3971 | invoke any move, copy, or swap operations on individual elements. All | ||
3972 | iterators and references remain valid. The past-the-end iterator is | ||
3973 | invalidated. | ||
3974 | |||
3975 | @param[in,out] other array to exchange the contents with | ||
3976 | |||
3977 | @throw std::domain_error when JSON value is not an array | ||
3978 | |||
3979 | @complexity Constant. | ||
3980 | |||
3981 | @liveexample{The example below shows how JSON values can be | ||
3982 | swapped.,swap__array_t} | ||
3983 | */ | ||
3984 | void swap(array_t& other) | ||
3985 | { | ||
3986 | // swap only works for arrays | ||
3987 | if (m_type != value_t::array) | ||
3988 | { | ||
3989 | throw std::domain_error("cannot use swap() with " + type_name()); | ||
3990 | } | ||
3991 | |||
3992 | // swap arrays | ||
3993 | std::swap(*(m_value.array), other); | ||
3994 | } | ||
3995 | |||
3996 | /*! | ||
3997 | @brief exchanges the values | ||
3998 | |||
3999 | Exchanges the contents of a JSON object with those of @a other. Does not | ||
4000 | invoke any move, copy, or swap operations on individual elements. All | ||
4001 | iterators and references remain valid. The past-the-end iterator is | ||
4002 | invalidated. | ||
4003 | |||
4004 | @param[in,out] other object to exchange the contents with | ||
4005 | |||
4006 | @throw std::domain_error when JSON value is not an object | ||
4007 | |||
4008 | @complexity Constant. | ||
4009 | |||
4010 | @liveexample{The example below shows how JSON values can be | ||
4011 | swapped.,swap__object_t} | ||
4012 | */ | ||
4013 | void swap(object_t& other) | ||
4014 | { | ||
4015 | // swap only works for objects | ||
4016 | if (m_type != value_t::object) | ||
4017 | { | ||
4018 | throw std::domain_error("cannot use swap() with " + type_name()); | ||
4019 | } | ||
4020 | |||
4021 | // swap objects | ||
4022 | std::swap(*(m_value.object), other); | ||
4023 | } | ||
4024 | |||
4025 | /*! | ||
4026 | @brief exchanges the values | ||
4027 | |||
4028 | Exchanges the contents of a JSON string with those of @a other. Does not | ||
4029 | invoke any move, copy, or swap operations on individual elements. All | ||
4030 | iterators and references remain valid. The past-the-end iterator is | ||
4031 | invalidated. | ||
4032 | |||
4033 | @param[in,out] other string to exchange the contents with | ||
4034 | |||
4035 | @throw std::domain_error when JSON value is not a string | ||
4036 | |||
4037 | @complexity Constant. | ||
4038 | |||
4039 | @liveexample{The example below shows how JSON values can be | ||
4040 | swapped.,swap__string_t} | ||
4041 | */ | ||
4042 | void swap(string_t& other) | ||
4043 | { | ||
4044 | // swap only works for strings | ||
4045 | if (m_type != value_t::string) | ||
4046 | { | ||
4047 | throw std::domain_error("cannot use swap() with " + type_name()); | ||
4048 | } | ||
4049 | |||
4050 | // swap strings | ||
4051 | std::swap(*(m_value.string), other); | ||
4052 | } | ||
4053 | |||
4054 | /// @} | ||
4055 | |||
4056 | |||
4057 | ////////////////////////////////////////// | ||
4058 | // lexicographical comparison operators // | ||
4059 | ////////////////////////////////////////// | ||
4060 | |||
4061 | /// @name lexicographical comparison operators | ||
4062 | /// @{ | ||
4063 | |||
4064 | private: | ||
4065 | /*! | ||
4066 | @brief comparison operator for JSON types | ||
4067 | |||
4068 | Returns an ordering that is similar to Python: | ||
4069 | - order: null < boolean < number < object < array < string | ||
4070 | - furthermore, each type is not smaller than itself | ||
4071 | */ | ||
4072 | friend bool operator<(const value_t lhs, const value_t rhs) | ||
4073 | { | ||
4074 | static constexpr std::array<uint8_t, 7> order = {{ | ||
4075 | 0, // null | ||
4076 | 3, // object | ||
4077 | 4, // array | ||
4078 | 5, // string | ||
4079 | 1, // boolean | ||
4080 | 2, // integer | ||
4081 | 2 // float | ||
4082 | } | ||
4083 | }; | ||
4084 | |||
4085 | // discarded values are not comparable | ||
4086 | if (lhs == value_t::discarded or rhs == value_t::discarded) | ||
4087 | { | ||
4088 | return false; | ||
4089 | } | ||
4090 | |||
4091 | return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)]; | ||
4092 | } | ||
4093 | |||
4094 | public: | ||
4095 | /*! | ||
4096 | @brief comparison: equal | ||
4097 | |||
4098 | Compares two JSON values for equality according to the following rules: | ||
4099 | - Two JSON values are equal if (1) they are from the same type and (2) | ||
4100 | their stored values are the same. | ||
4101 | - Integer and floating-point numbers are automatically converted before | ||
4102 | comparison. Floating-point numbers are compared indirectly: two | ||
4103 | floating-point numbers `f1` and `f2` are considered equal if neither | ||
4104 | `f1 > f2` nor `f2 > f1` holds. | ||
4105 | - Two JSON null values are equal. | ||
4106 | |||
4107 | @param[in] lhs first JSON value to consider | ||
4108 | @param[in] rhs second JSON value to consider | ||
4109 | @return whether the values @a lhs and @a rhs are equal | ||
4110 | |||
4111 | @complexity Linear. | ||
4112 | |||
4113 | @liveexample{The example demonstrates comparing several JSON | ||
4114 | types.,operator__equal} | ||
4115 | */ | ||
4116 | friend bool operator==(const_reference lhs, const_reference rhs) noexcept | ||
4117 | { | ||
4118 | const auto lhs_type = lhs.type(); | ||
4119 | const auto rhs_type = rhs.type(); | ||
4120 | |||
4121 | if (lhs_type == rhs_type) | ||
4122 | { | ||
4123 | switch (lhs_type) | ||
4124 | { | ||
4125 | case (value_t::array): | ||
4126 | return *lhs.m_value.array == *rhs.m_value.array; | ||
4127 | case (value_t::object): | ||
4128 | return *lhs.m_value.object == *rhs.m_value.object; | ||
4129 | case (value_t::null): | ||
4130 | return true; | ||
4131 | case (value_t::string): | ||
4132 | return *lhs.m_value.string == *rhs.m_value.string; | ||
4133 | case (value_t::boolean): | ||
4134 | return lhs.m_value.boolean == rhs.m_value.boolean; | ||
4135 | case (value_t::number_integer): | ||
4136 | return lhs.m_value.number_integer == rhs.m_value.number_integer; | ||
4137 | case (value_t::number_float): | ||
4138 | return approx(lhs.m_value.number_float, rhs.m_value.number_float); | ||
4139 | case (value_t::discarded): | ||
4140 | return false; | ||
4141 | } | ||
4142 | } | ||
4143 | else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) | ||
4144 | { | ||
4145 | return approx(static_cast<number_float_t>(lhs.m_value.number_integer), | ||
4146 | rhs.m_value.number_float); | ||
4147 | } | ||
4148 | else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) | ||
4149 | { | ||
4150 | return approx(lhs.m_value.number_float, | ||
4151 | static_cast<number_float_t>(rhs.m_value.number_integer)); | ||
4152 | } | ||
4153 | return false; | ||
4154 | } | ||
4155 | |||
4156 | /*! | ||
4157 | @brief comparison: equal | ||
4158 | |||
4159 | The functions compares the given JSON value against a null pointer. As the | ||
4160 | null pointer can be used to initialize a JSON value to null, a comparison | ||
4161 | of JSON value @a v with a null pointer should be equivalent to call | ||
4162 | `v.is_null()`. | ||
4163 | |||
4164 | @param[in] v JSON value to consider | ||
4165 | @return whether @a v is null | ||
4166 | |||
4167 | @complexity Constant. | ||
4168 | |||
4169 | @liveexample{The example compares several JSON types to the null pointer. | ||
4170 | ,operator__equal__nullptr_t} | ||
4171 | */ | ||
4172 | friend bool operator==(const_reference v, std::nullptr_t) noexcept | ||
4173 | { | ||
4174 | return v.is_null(); | ||
4175 | } | ||
4176 | |||
4177 | /*! | ||
4178 | @brief comparison: equal | ||
4179 | @copydoc operator==(const_reference, std::nullptr_t) | ||
4180 | */ | ||
4181 | friend bool operator==(std::nullptr_t, const_reference v) noexcept | ||
4182 | { | ||
4183 | return v.is_null(); | ||
4184 | } | ||
4185 | |||
4186 | /*! | ||
4187 | @brief comparison: not equal | ||
4188 | |||
4189 | Compares two JSON values for inequality by calculating `not (lhs == rhs)`. | ||
4190 | |||
4191 | @param[in] lhs first JSON value to consider | ||
4192 | @param[in] rhs second JSON value to consider | ||
4193 | @return whether the values @a lhs and @a rhs are not equal | ||
4194 | |||
4195 | @complexity Linear. | ||
4196 | |||
4197 | @liveexample{The example demonstrates comparing several JSON | ||
4198 | types.,operator__notequal} | ||
4199 | */ | ||
4200 | friend bool operator!=(const_reference lhs, const_reference rhs) noexcept | ||
4201 | { | ||
4202 | return not (lhs == rhs); | ||
4203 | } | ||
4204 | |||
4205 | /*! | ||
4206 | @brief comparison: not equal | ||
4207 | |||
4208 | The functions compares the given JSON value against a null pointer. As the | ||
4209 | null pointer can be used to initialize a JSON value to null, a comparison | ||
4210 | of JSON value @a v with a null pointer should be equivalent to call | ||
4211 | `not v.is_null()`. | ||
4212 | |||
4213 | @param[in] v JSON value to consider | ||
4214 | @return whether @a v is not null | ||
4215 | |||
4216 | @complexity Constant. | ||
4217 | |||
4218 | @liveexample{The example compares several JSON types to the null pointer. | ||
4219 | ,operator__notequal__nullptr_t} | ||
4220 | */ | ||
4221 | friend bool operator!=(const_reference v, std::nullptr_t) noexcept | ||
4222 | { | ||
4223 | return not v.is_null(); | ||
4224 | } | ||
4225 | |||
4226 | /*! | ||
4227 | @brief comparison: not equal | ||
4228 | @copydoc operator!=(const_reference, std::nullptr_t) | ||
4229 | */ | ||
4230 | friend bool operator!=(std::nullptr_t, const_reference v) noexcept | ||
4231 | { | ||
4232 | return not v.is_null(); | ||
4233 | } | ||
4234 | |||
4235 | /*! | ||
4236 | @brief comparison: less than | ||
4237 | |||
4238 | Compares whether one JSON value @a lhs is less than another JSON value @a | ||
4239 | rhs according to the following rules: | ||
4240 | - If @a lhs and @a rhs have the same type, the values are compared using | ||
4241 | the default `<` operator. | ||
4242 | - Integer and floating-point numbers are automatically converted before | ||
4243 | comparison | ||
4244 | - In case @a lhs and @a rhs have different types, the values are ignored | ||
4245 | and the order of the types is considered, see | ||
4246 | @ref operator<(const value_t, const value_t). | ||
4247 | |||
4248 | @param[in] lhs first JSON value to consider | ||
4249 | @param[in] rhs second JSON value to consider | ||
4250 | @return whether @a lhs is less than @a rhs | ||
4251 | |||
4252 | @complexity Linear. | ||
4253 | |||
4254 | @liveexample{The example demonstrates comparing several JSON | ||
4255 | types.,operator__less} | ||
4256 | */ | ||
4257 | friend bool operator<(const_reference lhs, const_reference rhs) noexcept | ||
4258 | { | ||
4259 | const auto lhs_type = lhs.type(); | ||
4260 | const auto rhs_type = rhs.type(); | ||
4261 | |||
4262 | if (lhs_type == rhs_type) | ||
4263 | { | ||
4264 | switch (lhs_type) | ||
4265 | { | ||
4266 | case (value_t::array): | ||
4267 | return *lhs.m_value.array < *rhs.m_value.array; | ||
4268 | case (value_t::object): | ||
4269 | return *lhs.m_value.object < *rhs.m_value.object; | ||
4270 | case (value_t::null): | ||
4271 | return false; | ||
4272 | case (value_t::string): | ||
4273 | return *lhs.m_value.string < *rhs.m_value.string; | ||
4274 | case (value_t::boolean): | ||
4275 | return lhs.m_value.boolean < rhs.m_value.boolean; | ||
4276 | case (value_t::number_integer): | ||
4277 | return lhs.m_value.number_integer < rhs.m_value.number_integer; | ||
4278 | case (value_t::number_float): | ||
4279 | return lhs.m_value.number_float < rhs.m_value.number_float; | ||
4280 | case (value_t::discarded): | ||
4281 | return false; | ||
4282 | } | ||
4283 | } | ||
4284 | else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) | ||
4285 | { | ||
4286 | return static_cast<number_float_t>(lhs.m_value.number_integer) < | ||
4287 | rhs.m_value.number_float; | ||
4288 | } | ||
4289 | else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) | ||
4290 | { | ||
4291 | return lhs.m_value.number_float < | ||
4292 | static_cast<number_float_t>(rhs.m_value.number_integer); | ||
4293 | } | ||
4294 | |||
4295 | // We only reach this line if we cannot compare values. In that case, | ||
4296 | // we compare types. Note we have to call the operator explicitly, | ||
4297 | // because MSVC has problems otherwise. | ||
4298 | return operator<(lhs_type, rhs_type); | ||
4299 | } | ||
4300 | |||
4301 | /*! | ||
4302 | @brief comparison: less than or equal | ||
4303 | |||
4304 | Compares whether one JSON value @a lhs is less than or equal to another | ||
4305 | JSON value by calculating `not (rhs < lhs)`. | ||
4306 | |||
4307 | @param[in] lhs first JSON value to consider | ||
4308 | @param[in] rhs second JSON value to consider | ||
4309 | @return whether @a lhs is less than or equal to @a rhs | ||
4310 | |||
4311 | @complexity Linear. | ||
4312 | |||
4313 | @liveexample{The example demonstrates comparing several JSON | ||
4314 | types.,operator__greater} | ||
4315 | */ | ||
4316 | friend bool operator<=(const_reference lhs, const_reference rhs) noexcept | ||
4317 | { | ||
4318 | return not (rhs < lhs); | ||
4319 | } | ||
4320 | |||
4321 | /*! | ||
4322 | @brief comparison: greater than | ||
4323 | |||
4324 | Compares whether one JSON value @a lhs is greater than another | ||
4325 | JSON value by calculating `not (lhs <= rhs)`. | ||
4326 | |||
4327 | @param[in] lhs first JSON value to consider | ||
4328 | @param[in] rhs second JSON value to consider | ||
4329 | @return whether @a lhs is greater than to @a rhs | ||
4330 | |||
4331 | @complexity Linear. | ||
4332 | |||
4333 | @liveexample{The example demonstrates comparing several JSON | ||
4334 | types.,operator__lessequal} | ||
4335 | */ | ||
4336 | friend bool operator>(const_reference lhs, const_reference rhs) noexcept | ||
4337 | { | ||
4338 | return not (lhs <= rhs); | ||
4339 | } | ||
4340 | |||
4341 | /*! | ||
4342 | @brief comparison: greater than or equal | ||
4343 | |||
4344 | Compares whether one JSON value @a lhs is greater than or equal to another | ||
4345 | JSON value by calculating `not (lhs < rhs)`. | ||
4346 | |||
4347 | @param[in] lhs first JSON value to consider | ||
4348 | @param[in] rhs second JSON value to consider | ||
4349 | @return whether @a lhs is greater than or equal to @a rhs | ||
4350 | |||
4351 | @complexity Linear. | ||
4352 | |||
4353 | @liveexample{The example demonstrates comparing several JSON | ||
4354 | types.,operator__greaterequal} | ||
4355 | */ | ||
4356 | friend bool operator>=(const_reference lhs, const_reference rhs) noexcept | ||
4357 | { | ||
4358 | return not (lhs < rhs); | ||
4359 | } | ||
4360 | |||
4361 | /// @} | ||
4362 | |||
4363 | |||
4364 | /////////////////// | ||
4365 | // serialization // | ||
4366 | /////////////////// | ||
4367 | |||
4368 | /// @name serialization | ||
4369 | /// @{ | ||
4370 | |||
4371 | /*! | ||
4372 | @brief serialize to stream | ||
4373 | |||
4374 | Serialize the given JSON value @a j to the output stream @a o. The JSON | ||
4375 | value will be serialized using the @ref dump member function. The | ||
4376 | indentation of the output can be controlled with the member variable | ||
4377 | `width` of the output stream @a o. For instance, using the manipulator | ||
4378 | `std::setw(4)` on @a o sets the indentation level to `4` and the | ||
4379 | serialization result is the same as calling `dump(4)`. | ||
4380 | |||
4381 | @param[in,out] o stream to serialize to | ||
4382 | @param[in] j JSON value to serialize | ||
4383 | |||
4384 | @return the stream @a o | ||
4385 | |||
4386 | @complexity Linear. | ||
4387 | |||
4388 | @liveexample{The example below shows the serialization with different | ||
4389 | parameters to `width` to adjust the indentation level.,operator_serialize} | ||
4390 | */ | ||
4391 | friend std::ostream& operator<<(std::ostream& o, const basic_json& j) | ||
4392 | { | ||
4393 | // read width member and use it as indentation parameter if nonzero | ||
4394 | const bool pretty_print = (o.width() > 0); | ||
4395 | const auto indentation = (pretty_print ? o.width() : 0); | ||
4396 | |||
4397 | // reset width to 0 for subsequent calls to this stream | ||
4398 | o.width(0); | ||
4399 | |||
4400 | // do the actual serialization | ||
4401 | j.dump(o, pretty_print, static_cast<unsigned int>(indentation)); | ||
4402 | return o; | ||
4403 | } | ||
4404 | |||
4405 | /*! | ||
4406 | @brief serialize to stream | ||
4407 | @copydoc operator<<(std::ostream&, const basic_json&) | ||
4408 | */ | ||
4409 | friend std::ostream& operator>>(const basic_json& j, std::ostream& o) | ||
4410 | { | ||
4411 | return o << j; | ||
4412 | } | ||
4413 | |||
4414 | /// @} | ||
4415 | |||
4416 | |||
4417 | ///////////////////// | ||
4418 | // deserialization // | ||
4419 | ///////////////////// | ||
4420 | |||
4421 | /// @name deserialization | ||
4422 | /// @{ | ||
4423 | |||
4424 | /*! | ||
4425 | @brief deserialize from string | ||
4426 | |||
4427 | @param[in] s string to read a serialized JSON value from | ||
4428 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
4429 | which is used to control the deserialization by filtering unwanted values | ||
4430 | (optional) | ||
4431 | |||
4432 | @return result of the deserialization | ||
4433 | |||
4434 | @complexity Linear in the length of the input. The parser is a predictive | ||
4435 | LL(1) parser. The complexity can be higher if the parser callback function | ||
4436 | @a cb has a super-linear complexity. | ||
4437 | |||
4438 | @liveexample{The example below demonstrates the parse function with and | ||
4439 | without callback function.,parse__string__parser_callback_t} | ||
4440 | |||
4441 | @sa parse(std::istream&, parser_callback_t) for a version that reads from | ||
4442 | an input stream | ||
4443 | */ | ||
4444 | static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) | ||
4445 | { | ||
4446 | return parser(s, cb).parse(); | ||
4447 | } | ||
4448 | |||
4449 | /*! | ||
4450 | @brief deserialize from stream | ||
4451 | |||
4452 | @param[in,out] i stream to read a serialized JSON value from | ||
4453 | @param[in] cb a parser callback function of type @ref parser_callback_t | ||
4454 | which is used to control the deserialization by filtering unwanted values | ||
4455 | (optional) | ||
4456 | |||
4457 | @return result of the deserialization | ||
4458 | |||
4459 | @complexity Linear in the length of the input. The parser is a predictive | ||
4460 | LL(1) parser. The complexity can be higher if the parser callback function | ||
4461 | @a cb has a super-linear complexity. | ||
4462 | |||
4463 | @liveexample{The example below demonstrates the parse function with and | ||
4464 | without callback function.,parse__istream__parser_callback_t} | ||
4465 | |||
4466 | @sa parse(const string_t&, parser_callback_t) for a version that reads | ||
4467 | from a string | ||
4468 | */ | ||
4469 | static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) | ||
4470 | { | ||
4471 | return parser(i, cb).parse(); | ||
4472 | } | ||
4473 | |||
4474 | /*! | ||
4475 | @brief deserialize from stream | ||
4476 | |||
4477 | Deserializes an input stream to a JSON value. | ||
4478 | |||
4479 | @param[in,out] i input stream to read a serialized JSON value from | ||
4480 | @param[in,out] j JSON value to write the deserialized input to | ||
4481 | |||
4482 | @throw std::invalid_argument in case of parse errors | ||
4483 | |||
4484 | @complexity Linear in the length of the input. The parser is a predictive | ||
4485 | LL(1) parser. | ||
4486 | |||
4487 | @liveexample{The example below shows how a JSON value is constructed by | ||
4488 | reading a serialization from a stream.,operator_deserialize} | ||
4489 | |||
4490 | @sa parse(std::istream&, parser_callback_t) for a variant with a parser | ||
4491 | callback function to filter values while parsing | ||
4492 | */ | ||
4493 | friend std::istream& operator<<(basic_json& j, std::istream& i) | ||
4494 | { | ||
4495 | j = parser(i).parse(); | ||
4496 | return i; | ||
4497 | } | ||
4498 | |||
4499 | /*! | ||
4500 | @brief deserialize from stream | ||
4501 | @copydoc operator<<(basic_json&, std::istream&) | ||
4502 | */ | ||
4503 | friend std::istream& operator>>(std::istream& i, basic_json& j) | ||
4504 | { | ||
4505 | j = parser(i).parse(); | ||
4506 | return i; | ||
4507 | } | ||
4508 | |||
4509 | /// @} | ||
4510 | |||
4511 | |||
4512 | private: | ||
4513 | /////////////////////////// | ||
4514 | // convenience functions // | ||
4515 | /////////////////////////// | ||
4516 | |||
4517 | /// return the type as string | ||
4518 | string_t type_name() const | ||
4519 | { | ||
4520 | switch (m_type) | ||
4521 | { | ||
4522 | case (value_t::null): | ||
4523 | { | ||
4524 | return "null"; | ||
4525 | } | ||
4526 | |||
4527 | case (value_t::object): | ||
4528 | { | ||
4529 | return "object"; | ||
4530 | } | ||
4531 | |||
4532 | case (value_t::array): | ||
4533 | { | ||
4534 | return "array"; | ||
4535 | } | ||
4536 | |||
4537 | case (value_t::string): | ||
4538 | { | ||
4539 | return "string"; | ||
4540 | } | ||
4541 | |||
4542 | case (value_t::boolean): | ||
4543 | { | ||
4544 | return "boolean"; | ||
4545 | } | ||
4546 | |||
4547 | case (value_t::discarded): | ||
4548 | { | ||
4549 | return "discarded"; | ||
4550 | } | ||
4551 | |||
4552 | default: | ||
4553 | { | ||
4554 | return "number"; | ||
4555 | } | ||
4556 | } | ||
4557 | } | ||
4558 | |||
4559 | /*! | ||
4560 | @brief calculates the extra space to escape a JSON string | ||
4561 | |||
4562 | @param[in] s the string to escape | ||
4563 | @return the number of characters required to escape string @a s | ||
4564 | |||
4565 | @complexity Linear in the length of string @a s. | ||
4566 | */ | ||
4567 | static std::size_t extra_space(const string_t& s) noexcept | ||
4568 | { | ||
4569 | std::size_t result = 0; | ||
4570 | |||
4571 | for (const auto& c : s) | ||
4572 | { | ||
4573 | switch (c) | ||
4574 | { | ||
4575 | case '"': | ||
4576 | case '\\': | ||
4577 | case '\b': | ||
4578 | case '\f': | ||
4579 | case '\n': | ||
4580 | case '\r': | ||
4581 | case '\t': | ||
4582 | { | ||
4583 | // from c (1 byte) to \x (2 bytes) | ||
4584 | result += 1; | ||
4585 | break; | ||
4586 | } | ||
4587 | |||
4588 | default: | ||
4589 | { | ||
4590 | if (c >= 0x00 and c <= 0x1f) | ||
4591 | { | ||
4592 | // from c (1 byte) to \uxxxx (6 bytes) | ||
4593 | result += 5; | ||
4594 | } | ||
4595 | break; | ||
4596 | } | ||
4597 | } | ||
4598 | } | ||
4599 | |||
4600 | return result; | ||
4601 | } | ||
4602 | |||
4603 | /*! | ||
4604 | @brief escape a string | ||
4605 | |||
4606 | Escape a string by replacing certain special characters by a sequence of an | ||
4607 | escape character (backslash) and another character and other control | ||
4608 | characters by a sequence of "\u" followed by a four-digit hex | ||
4609 | representation. | ||
4610 | |||
4611 | @param[in] s the string to escape | ||
4612 | @return the escaped string | ||
4613 | |||
4614 | @complexity Linear in the length of string @a s. | ||
4615 | */ | ||
4616 | static string_t escape_string(const string_t& s) noexcept | ||
4617 | { | ||
4618 | const auto space = extra_space(s); | ||
4619 | if (space == 0) | ||
4620 | { | ||
4621 | return s; | ||
4622 | } | ||
4623 | |||
4624 | // create a result string of necessary size | ||
4625 | string_t result(s.size() + space, '\\'); | ||
4626 | std::size_t pos = 0; | ||
4627 | |||
4628 | for (const auto& c : s) | ||
4629 | { | ||
4630 | switch (c) | ||
4631 | { | ||
4632 | // quotation mark (0x22) | ||
4633 | case '"': | ||
4634 | { | ||
4635 | result[pos + 1] = '"'; | ||
4636 | pos += 2; | ||
4637 | break; | ||
4638 | } | ||
4639 | |||
4640 | // reverse solidus (0x5c) | ||
4641 | case '\\': | ||
4642 | { | ||
4643 | // nothing to change | ||
4644 | pos += 2; | ||
4645 | break; | ||
4646 | } | ||
4647 | |||
4648 | // backspace (0x08) | ||
4649 | case '\b': | ||
4650 | { | ||
4651 | result[pos + 1] = 'b'; | ||
4652 | pos += 2; | ||
4653 | break; | ||
4654 | } | ||
4655 | |||
4656 | // formfeed (0x0c) | ||
4657 | case '\f': | ||
4658 | { | ||
4659 | result[pos + 1] = 'f'; | ||
4660 | pos += 2; | ||
4661 | break; | ||
4662 | } | ||
4663 | |||
4664 | // newline (0x0a) | ||
4665 | case '\n': | ||
4666 | { | ||
4667 | result[pos + 1] = 'n'; | ||
4668 | pos += 2; | ||
4669 | break; | ||
4670 | } | ||
4671 | |||
4672 | // carriage return (0x0d) | ||
4673 | case '\r': | ||
4674 | { | ||
4675 | result[pos + 1] = 'r'; | ||
4676 | pos += 2; | ||
4677 | break; | ||
4678 | } | ||
4679 | |||
4680 | // horizontal tab (0x09) | ||
4681 | case '\t': | ||
4682 | { | ||
4683 | result[pos + 1] = 't'; | ||
4684 | pos += 2; | ||
4685 | break; | ||
4686 | } | ||
4687 | |||
4688 | default: | ||
4689 | { | ||
4690 | if (c >= 0x00 and c <= 0x1f) | ||
4691 | { | ||
4692 | // print character c as \uxxxx | ||
4693 | sprintf(&result[pos + 1], "u%04x", int(c)); | ||
4694 | pos += 6; | ||
4695 | // overwrite trailing null character | ||
4696 | result[pos] = '\\'; | ||
4697 | } | ||
4698 | else | ||
4699 | { | ||
4700 | // all other characters are added as-is | ||
4701 | result[pos++] = c; | ||
4702 | } | ||
4703 | break; | ||
4704 | } | ||
4705 | } | ||
4706 | } | ||
4707 | |||
4708 | return result; | ||
4709 | } | ||
4710 | |||
4711 | /*! | ||
4712 | @brief internal implementation of the serialization function | ||
4713 | |||
4714 | This function is called by the public member function dump and organizes | ||
4715 | the serializaion internally. The indentation level is propagated as | ||
4716 | additional parameter. In case of arrays and objects, the function is called | ||
4717 | recursively. Note that | ||
4718 | |||
4719 | - strings and object keys are escaped using escape_string() | ||
4720 | - integer numbers are converted implictly via operator<< | ||
4721 | - floating-point numbers are converted to a string using "%g" format | ||
4722 | |||
4723 | @param[out] o stream to write to | ||
4724 | @param[in] pretty_print whether the output shall be pretty-printed | ||
4725 | @param[in] indent_step the indent level | ||
4726 | @param[in] current_indent the current indent level (only used internally) | ||
4727 | */ | ||
4728 | void dump(std::ostream& o, const bool pretty_print, const unsigned int indent_step, | ||
4729 | const unsigned int current_indent = 0) const | ||
4730 | { | ||
4731 | // variable to hold indentation for recursive calls | ||
4732 | unsigned int new_indent = current_indent; | ||
4733 | |||
4734 | switch (m_type) | ||
4735 | { | ||
4736 | case (value_t::object): | ||
4737 | { | ||
4738 | if (m_value.object->empty()) | ||
4739 | { | ||
4740 | o << "{}"; | ||
4741 | return; | ||
4742 | } | ||
4743 | |||
4744 | o << "{"; | ||
4745 | |||
4746 | // increase indentation | ||
4747 | if (pretty_print) | ||
4748 | { | ||
4749 | new_indent += indent_step; | ||
4750 | o << "\n"; | ||
4751 | } | ||
4752 | |||
4753 | for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) | ||
4754 | { | ||
4755 | if (i != m_value.object->cbegin()) | ||
4756 | { | ||
4757 | o << (pretty_print ? ",\n" : ","); | ||
4758 | } | ||
4759 | o << string_t(new_indent, ' ') << "\"" | ||
4760 | << escape_string(i->first) << "\":" | ||
4761 | << (pretty_print ? " " : ""); | ||
4762 | i->second.dump(o, pretty_print, indent_step, new_indent); | ||
4763 | } | ||
4764 | |||
4765 | // decrease indentation | ||
4766 | if (pretty_print) | ||
4767 | { | ||
4768 | new_indent -= indent_step; | ||
4769 | o << "\n"; | ||
4770 | } | ||
4771 | |||
4772 | o << string_t(new_indent, ' ') + "}"; | ||
4773 | return; | ||
4774 | } | ||
4775 | |||
4776 | case (value_t::array): | ||
4777 | { | ||
4778 | if (m_value.array->empty()) | ||
4779 | { | ||
4780 | o << "[]"; | ||
4781 | return; | ||
4782 | } | ||
4783 | |||
4784 | o << "["; | ||
4785 | |||
4786 | // increase indentation | ||
4787 | if (pretty_print) | ||
4788 | { | ||
4789 | new_indent += indent_step; | ||
4790 | o << "\n"; | ||
4791 | } | ||
4792 | |||
4793 | for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) | ||
4794 | { | ||
4795 | if (i != m_value.array->cbegin()) | ||
4796 | { | ||
4797 | o << (pretty_print ? ",\n" : ","); | ||
4798 | } | ||
4799 | o << string_t(new_indent, ' '); | ||
4800 | i->dump(o, pretty_print, indent_step, new_indent); | ||
4801 | } | ||
4802 | |||
4803 | // decrease indentation | ||
4804 | if (pretty_print) | ||
4805 | { | ||
4806 | new_indent -= indent_step; | ||
4807 | o << "\n"; | ||
4808 | } | ||
4809 | |||
4810 | o << string_t(new_indent, ' ') << "]"; | ||
4811 | return; | ||
4812 | } | ||
4813 | |||
4814 | case (value_t::string): | ||
4815 | { | ||
4816 | o << string_t("\"") << escape_string(*m_value.string) << "\""; | ||
4817 | return; | ||
4818 | } | ||
4819 | |||
4820 | case (value_t::boolean): | ||
4821 | { | ||
4822 | o << (m_value.boolean ? "true" : "false"); | ||
4823 | return; | ||
4824 | } | ||
4825 | |||
4826 | case (value_t::number_integer): | ||
4827 | { | ||
4828 | o << m_value.number_integer; | ||
4829 | return; | ||
4830 | } | ||
4831 | |||
4832 | case (value_t::number_float): | ||
4833 | { | ||
4834 | // 15 digits of precision allows round-trip IEEE 754 | ||
4835 | // string->double->string; to be safe, we read this value from | ||
4836 | // std::numeric_limits<number_float_t>::digits10 | ||
4837 | o << std::setprecision(std::numeric_limits<number_float_t>::digits10) << m_value.number_float; | ||
4838 | return; | ||
4839 | } | ||
4840 | |||
4841 | case (value_t::discarded): | ||
4842 | { | ||
4843 | o << "<discarded>"; | ||
4844 | return; | ||
4845 | } | ||
4846 | |||
4847 | default: | ||
4848 | { | ||
4849 | o << "null"; | ||
4850 | return; | ||
4851 | } | ||
4852 | } | ||
4853 | } | ||
4854 | |||
4855 | private: | ||
4856 | ////////////////////// | ||
4857 | // member variables // | ||
4858 | ////////////////////// | ||
4859 | |||
4860 | /// the type of the current element | ||
4861 | value_t m_type = value_t::null; | ||
4862 | |||
4863 | /// the value of the current element | ||
4864 | json_value m_value = {}; | ||
4865 | |||
4866 | |||
4867 | private: | ||
4868 | /////////////// | ||
4869 | // iterators // | ||
4870 | /////////////// | ||
4871 | |||
4872 | /*! | ||
4873 | @brief an iterator for primitive JSON types | ||
4874 | |||
4875 | This class models an iterator for primitive JSON types (boolean, number, | ||
4876 | string). It's only purpose is to allow the iterator/const_iterator classes | ||
4877 | to "iterate" over primitive values. Internally, the iterator is modeled by | ||
4878 | a `difference_type` variable. Value begin_value (`0`) models the begin, | ||
4879 | end_value (`1`) models past the end. | ||
4880 | */ | ||
4881 | class primitive_iterator_t | ||
4882 | { | ||
4883 | public: | ||
4884 | /// set iterator to a defined beginning | ||
4885 | void set_begin() | ||
4886 | { | ||
4887 | m_it = begin_value; | ||
4888 | } | ||
4889 | |||
4890 | /// set iterator to a defined past the end | ||
4891 | void set_end() | ||
4892 | { | ||
4893 | m_it = end_value; | ||
4894 | } | ||
4895 | |||
4896 | /// return whether the iterator can be dereferenced | ||
4897 | bool is_begin() const | ||
4898 | { | ||
4899 | return (m_it == begin_value); | ||
4900 | } | ||
4901 | |||
4902 | /// return whether the iterator is at end | ||
4903 | bool is_end() const | ||
4904 | { | ||
4905 | return (m_it == end_value); | ||
4906 | } | ||
4907 | |||
4908 | /// return reference to the value to change and compare | ||
4909 | operator difference_type& () | ||
4910 | { | ||
4911 | return m_it; | ||
4912 | } | ||
4913 | |||
4914 | /// return value to compare | ||
4915 | operator difference_type () const | ||
4916 | { | ||
4917 | return m_it; | ||
4918 | } | ||
4919 | |||
4920 | private: | ||
4921 | static constexpr difference_type begin_value = 0; | ||
4922 | static constexpr difference_type end_value = begin_value + 1; | ||
4923 | |||
4924 | /// iterator as signed integer type | ||
4925 | difference_type m_it = std::numeric_limits<std::ptrdiff_t>::min(); | ||
4926 | }; | ||
4927 | |||
4928 | /*! | ||
4929 | @brief an iterator value | ||
4930 | |||
4931 | @note This structure could easily be a union, but MSVC currently does not | ||
4932 | allow unions members with complex constructors, see | ||
4933 | https://github.com/nlohmann/json/pull/105. | ||
4934 | */ | ||
4935 | struct internal_iterator | ||
4936 | { | ||
4937 | /// iterator for JSON objects | ||
4938 | typename object_t::iterator object_iterator; | ||
4939 | /// iterator for JSON arrays | ||
4940 | typename array_t::iterator array_iterator; | ||
4941 | /// generic iterator for all other types | ||
4942 | primitive_iterator_t primitive_iterator; | ||
4943 | |||
4944 | /// create an uninitialized internal_iterator | ||
4945 | internal_iterator() | ||
4946 | : object_iterator(), array_iterator(), primitive_iterator() | ||
4947 | {} | ||
4948 | }; | ||
4949 | |||
4950 | public: | ||
4951 | /*! | ||
4952 | @brief a const random access iterator for the @ref basic_json class | ||
4953 | |||
4954 | This class implements a const iterator for the @ref basic_json class. From | ||
4955 | this class, the @ref iterator class is derived. | ||
4956 | |||
4957 | @requirement The class satisfies the following concept requirements: | ||
4958 | - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): | ||
4959 | The iterator that can be moved to point (forward and backward) to any | ||
4960 | element in constant time. | ||
4961 | */ | ||
4962 | class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json> | ||
4963 | { | ||
4964 | /// allow basic_json to access private members | ||
4965 | friend class basic_json; | ||
4966 | |||
4967 | public: | ||
4968 | /// the type of the values when the iterator is dereferenced | ||
4969 | using value_type = typename basic_json::value_type; | ||
4970 | /// a type to represent differences between iterators | ||
4971 | using difference_type = typename basic_json::difference_type; | ||
4972 | /// defines a pointer to the type iterated over (value_type) | ||
4973 | using pointer = typename basic_json::const_pointer; | ||
4974 | /// defines a reference to the type iterated over (value_type) | ||
4975 | using reference = typename basic_json::const_reference; | ||
4976 | /// the category of the iterator | ||
4977 | using iterator_category = std::bidirectional_iterator_tag; | ||
4978 | |||
4979 | /// default constructor | ||
4980 | const_iterator() = default; | ||
4981 | |||
4982 | /// constructor for a given JSON instance | ||
4983 | const_iterator(pointer object) : m_object(object) | ||
4984 | { | ||
4985 | switch (m_object->m_type) | ||
4986 | { | ||
4987 | case (basic_json::value_t::object): | ||
4988 | { | ||
4989 | m_it.object_iterator = typename object_t::iterator(); | ||
4990 | break; | ||
4991 | } | ||
4992 | case (basic_json::value_t::array): | ||
4993 | { | ||
4994 | m_it.array_iterator = typename array_t::iterator(); | ||
4995 | break; | ||
4996 | } | ||
4997 | default: | ||
4998 | { | ||
4999 | m_it.primitive_iterator = primitive_iterator_t(); | ||
5000 | break; | ||
5001 | } | ||
5002 | } | ||
5003 | } | ||
5004 | |||
5005 | /// copy constructor given a nonconst iterator | ||
5006 | const_iterator(const iterator& other) : m_object(other.m_object) | ||
5007 | { | ||
5008 | switch (m_object->m_type) | ||
5009 | { | ||
5010 | case (basic_json::value_t::object): | ||
5011 | { | ||
5012 | m_it.object_iterator = other.m_it.object_iterator; | ||
5013 | break; | ||
5014 | } | ||
5015 | |||
5016 | case (basic_json::value_t::array): | ||
5017 | { | ||
5018 | m_it.array_iterator = other.m_it.array_iterator; | ||
5019 | break; | ||
5020 | } | ||
5021 | |||
5022 | default: | ||
5023 | { | ||
5024 | m_it.primitive_iterator = other.m_it.primitive_iterator; | ||
5025 | break; | ||
5026 | } | ||
5027 | } | ||
5028 | } | ||
5029 | |||
5030 | /// copy constructor | ||
5031 | const_iterator(const const_iterator& other) noexcept | ||
5032 | : m_object(other.m_object), m_it(other.m_it) | ||
5033 | {} | ||
5034 | |||
5035 | /// copy assignment | ||
5036 | const_iterator& operator=(const_iterator other) noexcept( | ||
5037 | std::is_nothrow_move_constructible<pointer>::value and | ||
5038 | std::is_nothrow_move_assignable<pointer>::value and | ||
5039 | std::is_nothrow_move_constructible<internal_iterator>::value and | ||
5040 | std::is_nothrow_move_assignable<internal_iterator>::value | ||
5041 | ) | ||
5042 | { | ||
5043 | std::swap(m_object, other.m_object); | ||
5044 | std::swap(m_it, other.m_it); | ||
5045 | return *this; | ||
5046 | } | ||
5047 | |||
5048 | private: | ||
5049 | /// set the iterator to the first value | ||
5050 | void set_begin() | ||
5051 | { | ||
5052 | switch (m_object->m_type) | ||
5053 | { | ||
5054 | case (basic_json::value_t::object): | ||
5055 | { | ||
5056 | m_it.object_iterator = m_object->m_value.object->begin(); | ||
5057 | break; | ||
5058 | } | ||
5059 | |||
5060 | case (basic_json::value_t::array): | ||
5061 | { | ||
5062 | m_it.array_iterator = m_object->m_value.array->begin(); | ||
5063 | break; | ||
5064 | } | ||
5065 | |||
5066 | case (basic_json::value_t::null): | ||
5067 | { | ||
5068 | // set to end so begin()==end() is true: null is empty | ||
5069 | m_it.primitive_iterator.set_end(); | ||
5070 | break; | ||
5071 | } | ||
5072 | |||
5073 | default: | ||
5074 | { | ||
5075 | m_it.primitive_iterator.set_begin(); | ||
5076 | break; | ||
5077 | } | ||
5078 | } | ||
5079 | } | ||
5080 | |||
5081 | /// set the iterator past the last value | ||
5082 | void set_end() | ||
5083 | { | ||
5084 | switch (m_object->m_type) | ||
5085 | { | ||
5086 | case (basic_json::value_t::object): | ||
5087 | { | ||
5088 | m_it.object_iterator = m_object->m_value.object->end(); | ||
5089 | break; | ||
5090 | } | ||
5091 | |||
5092 | case (basic_json::value_t::array): | ||
5093 | { | ||
5094 | m_it.array_iterator = m_object->m_value.array->end(); | ||
5095 | break; | ||
5096 | } | ||
5097 | |||
5098 | default: | ||
5099 | { | ||
5100 | m_it.primitive_iterator.set_end(); | ||
5101 | break; | ||
5102 | } | ||
5103 | } | ||
5104 | } | ||
5105 | |||
5106 | public: | ||
5107 | /// return a reference to the value pointed to by the iterator | ||
5108 | reference operator*() const | ||
5109 | { | ||
5110 | switch (m_object->m_type) | ||
5111 | { | ||
5112 | case (basic_json::value_t::object): | ||
5113 | { | ||
5114 | return m_it.object_iterator->second; | ||
5115 | } | ||
5116 | |||
5117 | case (basic_json::value_t::array): | ||
5118 | { | ||
5119 | return *m_it.array_iterator; | ||
5120 | } | ||
5121 | |||
5122 | case (basic_json::value_t::null): | ||
5123 | { | ||
5124 | throw std::out_of_range("cannot get value"); | ||
5125 | } | ||
5126 | |||
5127 | default: | ||
5128 | { | ||
5129 | if (m_it.primitive_iterator.is_begin()) | ||
5130 | { | ||
5131 | return *m_object; | ||
5132 | } | ||
5133 | else | ||
5134 | { | ||
5135 | throw std::out_of_range("cannot get value"); | ||
5136 | } | ||
5137 | } | ||
5138 | } | ||
5139 | } | ||
5140 | |||
5141 | /// dereference the iterator | ||
5142 | pointer operator->() const | ||
5143 | { | ||
5144 | switch (m_object->m_type) | ||
5145 | { | ||
5146 | case (basic_json::value_t::object): | ||
5147 | { | ||
5148 | return &(m_it.object_iterator->second); | ||
5149 | } | ||
5150 | |||
5151 | case (basic_json::value_t::array): | ||
5152 | { | ||
5153 | return &*m_it.array_iterator; | ||
5154 | } | ||
5155 | |||
5156 | default: | ||
5157 | { | ||
5158 | if (m_it.primitive_iterator.is_begin()) | ||
5159 | { | ||
5160 | return m_object; | ||
5161 | } | ||
5162 | else | ||
5163 | { | ||
5164 | throw std::out_of_range("cannot get value"); | ||
5165 | } | ||
5166 | } | ||
5167 | } | ||
5168 | } | ||
5169 | |||
5170 | /// post-increment (it++) | ||
5171 | const_iterator operator++(int) | ||
5172 | { | ||
5173 | auto result = *this; | ||
5174 | ++(*this); | ||
5175 | |||
5176 | return result; | ||
5177 | } | ||
5178 | |||
5179 | /// pre-increment (++it) | ||
5180 | const_iterator& operator++() | ||
5181 | { | ||
5182 | switch (m_object->m_type) | ||
5183 | { | ||
5184 | case (basic_json::value_t::object): | ||
5185 | { | ||
5186 | ++m_it.object_iterator; | ||
5187 | break; | ||
5188 | } | ||
5189 | |||
5190 | case (basic_json::value_t::array): | ||
5191 | { | ||
5192 | ++m_it.array_iterator; | ||
5193 | break; | ||
5194 | } | ||
5195 | |||
5196 | default: | ||
5197 | { | ||
5198 | ++m_it.primitive_iterator; | ||
5199 | break; | ||
5200 | } | ||
5201 | } | ||
5202 | |||
5203 | return *this; | ||
5204 | } | ||
5205 | |||
5206 | /// post-decrement (it--) | ||
5207 | const_iterator operator--(int) | ||
5208 | { | ||
5209 | auto result = *this; | ||
5210 | --(*this); | ||
5211 | |||
5212 | return result; | ||
5213 | } | ||
5214 | |||
5215 | /// pre-decrement (--it) | ||
5216 | const_iterator& operator--() | ||
5217 | { | ||
5218 | switch (m_object->m_type) | ||
5219 | { | ||
5220 | case (basic_json::value_t::object): | ||
5221 | { | ||
5222 | --m_it.object_iterator; | ||
5223 | break; | ||
5224 | } | ||
5225 | |||
5226 | case (basic_json::value_t::array): | ||
5227 | { | ||
5228 | --m_it.array_iterator; | ||
5229 | break; | ||
5230 | } | ||
5231 | |||
5232 | default: | ||
5233 | { | ||
5234 | --m_it.primitive_iterator; | ||
5235 | break; | ||
5236 | } | ||
5237 | } | ||
5238 | |||
5239 | return *this; | ||
5240 | } | ||
5241 | |||
5242 | /// comparison: equal | ||
5243 | bool operator==(const const_iterator& other) const | ||
5244 | { | ||
5245 | // if objects are not the same, the comparison is undefined | ||
5246 | if (m_object != other.m_object) | ||
5247 | { | ||
5248 | throw std::domain_error("cannot compare iterators of different containers"); | ||
5249 | } | ||
5250 | |||
5251 | switch (m_object->m_type) | ||
5252 | { | ||
5253 | case (basic_json::value_t::object): | ||
5254 | { | ||
5255 | return (m_it.object_iterator == other.m_it.object_iterator); | ||
5256 | } | ||
5257 | |||
5258 | case (basic_json::value_t::array): | ||
5259 | { | ||
5260 | return (m_it.array_iterator == other.m_it.array_iterator); | ||
5261 | } | ||
5262 | |||
5263 | default: | ||
5264 | { | ||
5265 | return (m_it.primitive_iterator == other.m_it.primitive_iterator); | ||
5266 | } | ||
5267 | } | ||
5268 | } | ||
5269 | |||
5270 | /// comparison: not equal | ||
5271 | bool operator!=(const const_iterator& other) const | ||
5272 | { | ||
5273 | return not operator==(other); | ||
5274 | } | ||
5275 | |||
5276 | /// comparison: smaller | ||
5277 | bool operator<(const const_iterator& other) const | ||
5278 | { | ||
5279 | // if objects are not the same, the comparison is undefined | ||
5280 | if (m_object != other.m_object) | ||
5281 | { | ||
5282 | throw std::domain_error("cannot compare iterators of different containers"); | ||
5283 | } | ||
5284 | |||
5285 | switch (m_object->m_type) | ||
5286 | { | ||
5287 | case (basic_json::value_t::object): | ||
5288 | { | ||
5289 | throw std::domain_error("cannot use operator< for object iterators"); | ||
5290 | } | ||
5291 | |||
5292 | case (basic_json::value_t::array): | ||
5293 | { | ||
5294 | return (m_it.array_iterator < other.m_it.array_iterator); | ||
5295 | } | ||
5296 | |||
5297 | default: | ||
5298 | { | ||
5299 | return (m_it.primitive_iterator < other.m_it.primitive_iterator); | ||
5300 | } | ||
5301 | } | ||
5302 | } | ||
5303 | |||
5304 | /// comparison: less than or equal | ||
5305 | bool operator<=(const const_iterator& other) const | ||
5306 | { | ||
5307 | return not other.operator < (*this); | ||
5308 | } | ||
5309 | |||
5310 | /// comparison: greater than | ||
5311 | bool operator>(const const_iterator& other) const | ||
5312 | { | ||
5313 | return not operator<=(other); | ||
5314 | } | ||
5315 | |||
5316 | /// comparison: greater than or equal | ||
5317 | bool operator>=(const const_iterator& other) const | ||
5318 | { | ||
5319 | return not operator<(other); | ||
5320 | } | ||
5321 | |||
5322 | /// add to iterator | ||
5323 | const_iterator& operator+=(difference_type i) | ||
5324 | { | ||
5325 | switch (m_object->m_type) | ||
5326 | { | ||
5327 | case (basic_json::value_t::object): | ||
5328 | { | ||
5329 | throw std::domain_error("cannot use operator+= for object iterators"); | ||
5330 | } | ||
5331 | |||
5332 | case (basic_json::value_t::array): | ||
5333 | { | ||
5334 | m_it.array_iterator += i; | ||
5335 | break; | ||
5336 | } | ||
5337 | |||
5338 | default: | ||
5339 | { | ||
5340 | m_it.primitive_iterator += i; | ||
5341 | break; | ||
5342 | } | ||
5343 | } | ||
5344 | |||
5345 | return *this; | ||
5346 | } | ||
5347 | |||
5348 | /// subtract from iterator | ||
5349 | const_iterator& operator-=(difference_type i) | ||
5350 | { | ||
5351 | return operator+=(-i); | ||
5352 | } | ||
5353 | |||
5354 | /// add to iterator | ||
5355 | const_iterator operator+(difference_type i) | ||
5356 | { | ||
5357 | auto result = *this; | ||
5358 | result += i; | ||
5359 | return result; | ||
5360 | } | ||
5361 | |||
5362 | /// subtract from iterator | ||
5363 | const_iterator operator-(difference_type i) | ||
5364 | { | ||
5365 | auto result = *this; | ||
5366 | result -= i; | ||
5367 | return result; | ||
5368 | } | ||
5369 | |||
5370 | /// return difference | ||
5371 | difference_type operator-(const const_iterator& other) const | ||
5372 | { | ||
5373 | switch (m_object->m_type) | ||
5374 | { | ||
5375 | case (basic_json::value_t::object): | ||
5376 | { | ||
5377 | throw std::domain_error("cannot use operator- for object iterators"); | ||
5378 | } | ||
5379 | |||
5380 | case (basic_json::value_t::array): | ||
5381 | { | ||
5382 | return m_it.array_iterator - other.m_it.array_iterator; | ||
5383 | } | ||
5384 | |||
5385 | default: | ||
5386 | { | ||
5387 | return m_it.primitive_iterator - other.m_it.primitive_iterator; | ||
5388 | } | ||
5389 | } | ||
5390 | } | ||
5391 | |||
5392 | /// access to successor | ||
5393 | reference operator[](difference_type n) const | ||
5394 | { | ||
5395 | switch (m_object->m_type) | ||
5396 | { | ||
5397 | case (basic_json::value_t::object): | ||
5398 | { | ||
5399 | throw std::domain_error("cannot use operator[] for object iterators"); | ||
5400 | } | ||
5401 | |||
5402 | case (basic_json::value_t::array): | ||
5403 | { | ||
5404 | return *(m_it.array_iterator + n); | ||
5405 | } | ||
5406 | |||
5407 | case (basic_json::value_t::null): | ||
5408 | { | ||
5409 | throw std::out_of_range("cannot get value"); | ||
5410 | } | ||
5411 | |||
5412 | default: | ||
5413 | { | ||
5414 | if (m_it.primitive_iterator == -n) | ||
5415 | { | ||
5416 | return *m_object; | ||
5417 | } | ||
5418 | else | ||
5419 | { | ||
5420 | throw std::out_of_range("cannot get value"); | ||
5421 | } | ||
5422 | } | ||
5423 | } | ||
5424 | } | ||
5425 | |||
5426 | /// return the key of an object iterator | ||
5427 | typename object_t::key_type key() const | ||
5428 | { | ||
5429 | switch (m_object->m_type) | ||
5430 | { | ||
5431 | case (basic_json::value_t::object): | ||
5432 | { | ||
5433 | return m_it.object_iterator->first; | ||
5434 | } | ||
5435 | |||
5436 | default: | ||
5437 | { | ||
5438 | throw std::domain_error("cannot use key() for non-object iterators"); | ||
5439 | } | ||
5440 | } | ||
5441 | } | ||
5442 | |||
5443 | /// return the value of an iterator | ||
5444 | reference value() const | ||
5445 | { | ||
5446 | return operator*(); | ||
5447 | } | ||
5448 | |||
5449 | private: | ||
5450 | /// associated JSON instance | ||
5451 | pointer m_object = nullptr; | ||
5452 | /// the actual iterator of the associated instance | ||
5453 | internal_iterator m_it = internal_iterator(); | ||
5454 | }; | ||
5455 | |||
5456 | /*! | ||
5457 | @brief a mutable random access iterator for the @ref basic_json class | ||
5458 | |||
5459 | @requirement The class satisfies the following concept requirements: | ||
5460 | - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): | ||
5461 | The iterator that can be moved to point (forward and backward) to any | ||
5462 | element in constant time. | ||
5463 | - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): | ||
5464 | It is possible to write to the pointed-to element. | ||
5465 | */ | ||
5466 | class iterator : public const_iterator | ||
5467 | { | ||
5468 | public: | ||
5469 | using base_iterator = const_iterator; | ||
5470 | using pointer = typename basic_json::pointer; | ||
5471 | using reference = typename basic_json::reference; | ||
5472 | |||
5473 | /// default constructor | ||
5474 | iterator() = default; | ||
5475 | |||
5476 | /// constructor for a given JSON instance | ||
5477 | iterator(pointer object) noexcept : base_iterator(object) | ||
5478 | {} | ||
5479 | |||
5480 | /// copy constructor | ||
5481 | iterator(const iterator& other) noexcept | ||
5482 | : base_iterator(other) | ||
5483 | {} | ||
5484 | |||
5485 | /// copy assignment | ||
5486 | iterator& operator=(iterator other) noexcept( | ||
5487 | std::is_nothrow_move_constructible<pointer>::value and | ||
5488 | std::is_nothrow_move_assignable<pointer>::value and | ||
5489 | std::is_nothrow_move_constructible<internal_iterator>::value and | ||
5490 | std::is_nothrow_move_assignable<internal_iterator>::value | ||
5491 | ) | ||
5492 | { | ||
5493 | base_iterator::operator=(other); | ||
5494 | return *this; | ||
5495 | } | ||
5496 | |||
5497 | /// return a reference to the value pointed to by the iterator | ||
5498 | reference operator*() | ||
5499 | { | ||
5500 | return const_cast<reference>(base_iterator::operator*()); | ||
5501 | } | ||
5502 | |||
5503 | /// dereference the iterator | ||
5504 | pointer operator->() | ||
5505 | { | ||
5506 | return const_cast<pointer>(base_iterator::operator->()); | ||
5507 | } | ||
5508 | |||
5509 | /// post-increment (it++) | ||
5510 | iterator operator++(int) | ||
5511 | { | ||
5512 | iterator result = *this; | ||
5513 | base_iterator::operator++(); | ||
5514 | return result; | ||
5515 | } | ||
5516 | |||
5517 | /// pre-increment (++it) | ||
5518 | iterator& operator++() | ||
5519 | { | ||
5520 | base_iterator::operator++(); | ||
5521 | return *this; | ||
5522 | } | ||
5523 | |||
5524 | /// post-decrement (it--) | ||
5525 | iterator operator--(int) | ||
5526 | { | ||
5527 | iterator result = *this; | ||
5528 | base_iterator::operator--(); | ||
5529 | return result; | ||
5530 | } | ||
5531 | |||
5532 | /// pre-decrement (--it) | ||
5533 | iterator& operator--() | ||
5534 | { | ||
5535 | base_iterator::operator--(); | ||
5536 | return *this; | ||
5537 | } | ||
5538 | |||
5539 | /// add to iterator | ||
5540 | iterator& operator+=(difference_type i) | ||
5541 | { | ||
5542 | base_iterator::operator+=(i); | ||
5543 | return *this; | ||
5544 | } | ||
5545 | |||
5546 | /// subtract from iterator | ||
5547 | iterator& operator-=(difference_type i) | ||
5548 | { | ||
5549 | base_iterator::operator-=(i); | ||
5550 | return *this; | ||
5551 | } | ||
5552 | |||
5553 | /// add to iterator | ||
5554 | iterator operator+(difference_type i) | ||
5555 | { | ||
5556 | auto result = *this; | ||
5557 | result += i; | ||
5558 | return result; | ||
5559 | } | ||
5560 | |||
5561 | /// subtract from iterator | ||
5562 | iterator operator-(difference_type i) | ||
5563 | { | ||
5564 | auto result = *this; | ||
5565 | result -= i; | ||
5566 | return result; | ||
5567 | } | ||
5568 | |||
5569 | difference_type operator-(const iterator& other) const | ||
5570 | { | ||
5571 | return base_iterator::operator-(other); | ||
5572 | } | ||
5573 | |||
5574 | /// access to successor | ||
5575 | reference operator[](difference_type n) const | ||
5576 | { | ||
5577 | return const_cast<reference>(base_iterator::operator[](n)); | ||
5578 | } | ||
5579 | |||
5580 | /// return the value of an iterator | ||
5581 | reference value() const | ||
5582 | { | ||
5583 | return const_cast<reference>(base_iterator::value()); | ||
5584 | } | ||
5585 | }; | ||
5586 | |||
5587 | /*! | ||
5588 | @brief a template for a reverse iterator class | ||
5589 | |||
5590 | @tparam Base the base iterator type to reverse. Valid types are @ref | ||
5591 | iterator (to create @ref reverse_iterator) and @ref const_iterator (to | ||
5592 | create @ref const_reverse_iterator). | ||
5593 | |||
5594 | @requirement The class satisfies the following concept requirements: | ||
5595 | - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): | ||
5596 | The iterator that can be moved to point (forward and backward) to any | ||
5597 | element in constant time. | ||
5598 | - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): | ||
5599 | It is possible to write to the pointed-to element (only if @a Base is | ||
5600 | @ref iterator). | ||
5601 | */ | ||
5602 | template<typename Base> | ||
5603 | class json_reverse_iterator : public std::reverse_iterator<Base> | ||
5604 | { | ||
5605 | public: | ||
5606 | /// shortcut to the reverse iterator adaptor | ||
5607 | using base_iterator = std::reverse_iterator<Base>; | ||
5608 | /// the reference type for the pointed-to element | ||
5609 | using reference = typename Base::reference; | ||
5610 | |||
5611 | /// create reverse iterator from iterator | ||
5612 | json_reverse_iterator(const typename base_iterator::iterator_type& it) | ||
5613 | : base_iterator(it) {} | ||
5614 | |||
5615 | /// create reverse iterator from base class | ||
5616 | json_reverse_iterator(const base_iterator& it) : base_iterator(it) {} | ||
5617 | |||
5618 | /// post-increment (it++) | ||
5619 | json_reverse_iterator operator++(int) | ||
5620 | { | ||
5621 | return base_iterator::operator++(1); | ||
5622 | } | ||
5623 | |||
5624 | /// pre-increment (++it) | ||
5625 | json_reverse_iterator& operator++() | ||
5626 | { | ||
5627 | base_iterator::operator++(); | ||
5628 | return *this; | ||
5629 | } | ||
5630 | |||
5631 | /// post-decrement (it--) | ||
5632 | json_reverse_iterator operator--(int) | ||
5633 | { | ||
5634 | return base_iterator::operator--(1); | ||
5635 | } | ||
5636 | |||
5637 | /// pre-decrement (--it) | ||
5638 | json_reverse_iterator& operator--() | ||
5639 | { | ||
5640 | base_iterator::operator--(); | ||
5641 | return *this; | ||
5642 | } | ||
5643 | |||
5644 | /// add to iterator | ||
5645 | json_reverse_iterator& operator+=(difference_type i) | ||
5646 | { | ||
5647 | base_iterator::operator+=(i); | ||
5648 | return *this; | ||
5649 | } | ||
5650 | |||
5651 | /// add to iterator | ||
5652 | json_reverse_iterator operator+(difference_type i) const | ||
5653 | { | ||
5654 | auto result = *this; | ||
5655 | result += i; | ||
5656 | return result; | ||
5657 | } | ||
5658 | |||
5659 | /// subtract from iterator | ||
5660 | json_reverse_iterator operator-(difference_type i) const | ||
5661 | { | ||
5662 | auto result = *this; | ||
5663 | result -= i; | ||
5664 | return result; | ||
5665 | } | ||
5666 | |||
5667 | /// return difference | ||
5668 | difference_type operator-(const json_reverse_iterator& other) const | ||
5669 | { | ||
5670 | return this->base() - other.base(); | ||
5671 | } | ||
5672 | |||
5673 | /// access to successor | ||
5674 | reference operator[](difference_type n) const | ||
5675 | { | ||
5676 | return *(this->operator+(n)); | ||
5677 | } | ||
5678 | |||
5679 | /// return the key of an object iterator | ||
5680 | typename object_t::key_type key() const | ||
5681 | { | ||
5682 | auto it = --this->base(); | ||
5683 | return it.key(); | ||
5684 | } | ||
5685 | |||
5686 | /// return the value of an iterator | ||
5687 | reference value() const | ||
5688 | { | ||
5689 | auto it = --this->base(); | ||
5690 | return it.operator * (); | ||
5691 | } | ||
5692 | }; | ||
5693 | |||
5694 | /*! | ||
5695 | @brief wrapper to access iterator member functions in range-based for | ||
5696 | |||
5697 | This class allows to access @ref key() and @ref value() during range-based | ||
5698 | for loops. In these loops, a reference to the JSON values is returned, so | ||
5699 | there is no access to the underlying iterator. | ||
5700 | */ | ||
5701 | class iterator_wrapper | ||
5702 | { | ||
5703 | private: | ||
5704 | /// the container to iterate | ||
5705 | basic_json& container; | ||
5706 | /// the type of the iterator to use while iteration | ||
5707 | using json_iterator = decltype(std::begin(container)); | ||
5708 | |||
5709 | /// internal iterator wrapper | ||
5710 | class iterator_wrapper_internal | ||
5711 | { | ||
5712 | private: | ||
5713 | /// the iterator | ||
5714 | json_iterator anchor; | ||
5715 | /// an index for arrays | ||
5716 | size_t array_index = 0; | ||
5717 | |||
5718 | public: | ||
5719 | /// construct wrapper given an iterator | ||
5720 | iterator_wrapper_internal(json_iterator i) : anchor(i) | ||
5721 | {} | ||
5722 | |||
5723 | /// dereference operator (needed for range-based for) | ||
5724 | iterator_wrapper_internal& operator*() | ||
5725 | { | ||
5726 | return *this; | ||
5727 | } | ||
5728 | |||
5729 | /// increment operator (needed for range-based for) | ||
5730 | iterator_wrapper_internal& operator++() | ||
5731 | { | ||
5732 | ++anchor; | ||
5733 | ++array_index; | ||
5734 | |||
5735 | return *this; | ||
5736 | } | ||
5737 | |||
5738 | /// inequality operator (needed for range-based for) | ||
5739 | bool operator!= (const iterator_wrapper_internal& o) | ||
5740 | { | ||
5741 | return anchor != o.anchor; | ||
5742 | } | ||
5743 | |||
5744 | /// stream operator | ||
5745 | friend std::ostream& operator<<(std::ostream& o, const iterator_wrapper_internal& w) | ||
5746 | { | ||
5747 | return o << w.value(); | ||
5748 | } | ||
5749 | |||
5750 | /// return key of the iterator | ||
5751 | typename basic_json::string_t key() const | ||
5752 | { | ||
5753 | switch (anchor.m_object->type()) | ||
5754 | { | ||
5755 | /// use integer array index as key | ||
5756 | case (value_t::array): | ||
5757 | { | ||
5758 | return std::to_string(array_index); | ||
5759 | } | ||
5760 | |||
5761 | /// use key from the object | ||
5762 | case (value_t::object): | ||
5763 | { | ||
5764 | return anchor.key(); | ||
5765 | } | ||
5766 | |||
5767 | /// use an empty key for all primitive types | ||
5768 | default: | ||
5769 | { | ||
5770 | return ""; | ||
5771 | } | ||
5772 | } | ||
5773 | } | ||
5774 | |||
5775 | /// return value of the iterator | ||
5776 | typename json_iterator::reference value() const | ||
5777 | { | ||
5778 | return anchor.value(); | ||
5779 | } | ||
5780 | }; | ||
5781 | |||
5782 | public: | ||
5783 | /// construct iterator wrapper from a container | ||
5784 | iterator_wrapper(basic_json& cont) | ||
5785 | : container(cont) | ||
5786 | {} | ||
5787 | |||
5788 | /// return iterator begin (needed for range-based for) | ||
5789 | iterator_wrapper_internal begin() | ||
5790 | { | ||
5791 | return iterator_wrapper_internal(container.begin()); | ||
5792 | } | ||
5793 | |||
5794 | /// return iterator end (needed for range-based for) | ||
5795 | iterator_wrapper_internal end() | ||
5796 | { | ||
5797 | return iterator_wrapper_internal(container.end()); | ||
5798 | } | ||
5799 | }; | ||
5800 | |||
5801 | private: | ||
5802 | ////////////////////// | ||
5803 | // lexer and parser // | ||
5804 | ////////////////////// | ||
5805 | |||
5806 | /*! | ||
5807 | @brief lexical analysis | ||
5808 | |||
5809 | This class organizes the lexical analysis during JSON deserialization. The | ||
5810 | core of it is a scanner generated by re2c <http://re2c.org> that processes | ||
5811 | a buffer and recognizes tokens according to RFC 7159. | ||
5812 | */ | ||
5813 | class lexer | ||
5814 | { | ||
5815 | public: | ||
5816 | /// token types for the parser | ||
5817 | enum class token_type | ||
5818 | { | ||
5819 | uninitialized, ///< indicating the scanner is uninitialized | ||
5820 | literal_true, ///< the "true" literal | ||
5821 | literal_false, ///< the "false" literal | ||
5822 | literal_null, ///< the "null" literal | ||
5823 | value_string, ///< a string - use get_string() for actual value | ||
5824 | value_number, ///< a number - use get_number() for actual value | ||
5825 | begin_array, ///< the character for array begin "[" | ||
5826 | begin_object, ///< the character for object begin "{" | ||
5827 | end_array, ///< the character for array end "]" | ||
5828 | end_object, ///< the character for object end "}" | ||
5829 | name_separator, ///< the name separator ":" | ||
5830 | value_separator, ///< the value separator "," | ||
5831 | parse_error, ///< indicating a parse error | ||
5832 | end_of_input ///< indicating the end of the input buffer | ||
5833 | }; | ||
5834 | |||
5835 | /// the char type to use in the lexer | ||
5836 | using lexer_char_t = unsigned char; | ||
5837 | |||
5838 | /// constructor with a given buffer | ||
5839 | explicit lexer(const string_t& s) noexcept | ||
5840 | : m_stream(nullptr), m_buffer(s) | ||
5841 | { | ||
5842 | m_content = reinterpret_cast<const lexer_char_t*>(s.c_str()); | ||
5843 | m_start = m_cursor = m_content; | ||
5844 | m_limit = m_content + s.size(); | ||
5845 | } | ||
5846 | explicit lexer(std::istream* s) noexcept | ||
5847 | : m_stream(s), m_buffer() | ||
5848 | { | ||
5849 | getline(*m_stream, m_buffer); | ||
5850 | m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str()); | ||
5851 | m_start = m_cursor = m_content; | ||
5852 | m_limit = m_content + m_buffer.size(); | ||
5853 | } | ||
5854 | |||
5855 | /// default constructor | ||
5856 | lexer() = default; | ||
5857 | |||
5858 | // switch of unwanted functions | ||
5859 | lexer(const lexer&) = delete; | ||
5860 | lexer operator=(const lexer&) = delete; | ||
5861 | |||
5862 | /*! | ||
5863 | @brief create a string from a Unicode code point | ||
5864 | |||
5865 | @param[in] codepoint1 the code point (can be high surrogate) | ||
5866 | @param[in] codepoint2 the code point (can be low surrogate or 0) | ||
5867 | @return string representation of the code point | ||
5868 | @throw std::out_of_range if code point is >0x10ffff | ||
5869 | @throw std::invalid_argument if the low surrogate is invalid | ||
5870 | |||
5871 | @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code> | ||
5872 | */ | ||
5873 | static string_t to_unicode(const std::size_t codepoint1, | ||
5874 | const std::size_t codepoint2 = 0) | ||
5875 | { | ||
5876 | string_t result; | ||
5877 | |||
5878 | // calculate the codepoint from the given code points | ||
5879 | std::size_t codepoint = codepoint1; | ||
5880 | |||
5881 | // check if codepoint1 is a high surrogate | ||
5882 | if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) | ||
5883 | { | ||
5884 | // check if codepoint2 is a low surrogate | ||
5885 | if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) | ||
5886 | { | ||
5887 | codepoint = | ||
5888 | // high surrogate occupies the most significant 22 bits | ||
5889 | (codepoint1 << 10) | ||
5890 | // low surrogate occupies the least significant 15 bits | ||
5891 | + codepoint2 | ||
5892 | // there is still the 0xD800, 0xDC00 and 0x10000 noise | ||
5893 | // in the result so we have to substract with: | ||
5894 | // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 | ||
5895 | - 0x35FDC00; | ||
5896 | } | ||
5897 | else | ||
5898 | { | ||
5899 | throw std::invalid_argument("missing or wrong low surrogate"); | ||
5900 | } | ||
5901 | } | ||
5902 | |||
5903 | if (codepoint < 0x80) | ||
5904 | { | ||
5905 | // 1-byte characters: 0xxxxxxx (ASCII) | ||
5906 | result.append(1, static_cast<typename string_t::value_type>(codepoint)); | ||
5907 | } | ||
5908 | else if (codepoint <= 0x7ff) | ||
5909 | { | ||
5910 | // 2-byte characters: 110xxxxx 10xxxxxx | ||
5911 | result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F))); | ||
5912 | result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); | ||
5913 | } | ||
5914 | else if (codepoint <= 0xffff) | ||
5915 | { | ||
5916 | // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx | ||
5917 | result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F))); | ||
5918 | result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F))); | ||
5919 | result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); | ||
5920 | } | ||
5921 | else if (codepoint <= 0x10ffff) | ||
5922 | { | ||
5923 | // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | ||
5924 | result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07))); | ||
5925 | result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F))); | ||
5926 | result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F))); | ||
5927 | result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F))); | ||
5928 | } | ||
5929 | else | ||
5930 | { | ||
5931 | throw std::out_of_range("code points above 0x10FFFF are invalid"); | ||
5932 | } | ||
5933 | |||
5934 | return result; | ||
5935 | } | ||
5936 | |||
5937 | /// return name of values of type token_type | ||
5938 | static std::string token_type_name(token_type t) | ||
5939 | { | ||
5940 | switch (t) | ||
5941 | { | ||
5942 | case (token_type::uninitialized): | ||
5943 | return "<uninitialized>"; | ||
5944 | case (token_type::literal_true): | ||
5945 | return "true literal"; | ||
5946 | case (token_type::literal_false): | ||
5947 | return "false literal"; | ||
5948 | case (token_type::literal_null): | ||
5949 | return "null literal"; | ||
5950 | case (token_type::value_string): | ||
5951 | return "string literal"; | ||
5952 | case (token_type::value_number): | ||
5953 | return "number literal"; | ||
5954 | case (token_type::begin_array): | ||
5955 | return "["; | ||
5956 | case (token_type::begin_object): | ||
5957 | return "{"; | ||
5958 | case (token_type::end_array): | ||
5959 | return "]"; | ||
5960 | case (token_type::end_object): | ||
5961 | return "}"; | ||
5962 | case (token_type::name_separator): | ||
5963 | return ":"; | ||
5964 | case (token_type::value_separator): | ||
5965 | return ","; | ||
5966 | case (token_type::end_of_input): | ||
5967 | return "<end of input>"; | ||
5968 | default: | ||
5969 | return "<parse error>"; | ||
5970 | } | ||
5971 | } | ||
5972 | |||
5973 | /*! | ||
5974 | This function implements a scanner for JSON. It is specified using | ||
5975 | regular expressions that try to follow RFC 7159 as close as possible. | ||
5976 | These regular expressions are then translated into a deterministic | ||
5977 | finite automaton (DFA) by the tool re2c <http://re2c.org>. As a result, | ||
5978 | the translated code for this function consists of a large block of code | ||
5979 | with goto jumps. | ||
5980 | |||
5981 | @return the class of the next token read from the buffer | ||
5982 | */ | ||
5983 | token_type scan() noexcept | ||
5984 | { | ||
5985 | // pointer for backtracking information | ||
5986 | m_marker = nullptr; | ||
5987 | |||
5988 | // remember the begin of the token | ||
5989 | m_start = m_cursor; | ||
5990 | |||
5991 | |||
5992 | { | ||
5993 | lexer_char_t yych; | ||
5994 | unsigned int yyaccept = 0; | ||
5995 | static const unsigned char yybm[] = | ||
5996 | { | ||
5997 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
5998 | 0, 32, 32, 0, 0, 32, 0, 0, | ||
5999 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6000 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6001 | 96, 64, 0, 64, 64, 64, 64, 64, | ||
6002 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6003 | 192, 192, 192, 192, 192, 192, 192, 192, | ||
6004 | 192, 192, 64, 64, 64, 64, 64, 64, | ||
6005 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6006 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6007 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6008 | 64, 64, 64, 64, 0, 64, 64, 64, | ||
6009 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6010 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6011 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6012 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6013 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6014 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6015 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6016 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6017 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6018 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6019 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6020 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6021 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6022 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6023 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6024 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6025 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6026 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6027 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6028 | 64, 64, 64, 64, 64, 64, 64, 64, | ||
6029 | }; | ||
6030 | |||
6031 | if ((m_limit - m_cursor) < 5) | ||
6032 | { | ||
6033 | yyfill(); // LCOV_EXCL_LINE; | ||
6034 | } | ||
6035 | yych = *m_cursor; | ||
6036 | if (yych <= '9') | ||
6037 | { | ||
6038 | if (yych <= ' ') | ||
6039 | { | ||
6040 | if (yych <= '\n') | ||
6041 | { | ||
6042 | if (yych <= 0x00) | ||
6043 | { | ||
6044 | goto basic_json_parser_27; | ||
6045 | } | ||
6046 | if (yych <= 0x08) | ||
6047 | { | ||
6048 | goto basic_json_parser_29; | ||
6049 | } | ||
6050 | if (yych >= '\n') | ||
6051 | { | ||
6052 | goto basic_json_parser_4; | ||
6053 | } | ||
6054 | } | ||
6055 | else | ||
6056 | { | ||
6057 | if (yych == '\r') | ||
6058 | { | ||
6059 | goto basic_json_parser_2; | ||
6060 | } | ||
6061 | if (yych <= 0x1F) | ||
6062 | { | ||
6063 | goto basic_json_parser_29; | ||
6064 | } | ||
6065 | } | ||
6066 | } | ||
6067 | else | ||
6068 | { | ||
6069 | if (yych <= ',') | ||
6070 | { | ||
6071 | if (yych == '"') | ||
6072 | { | ||
6073 | goto basic_json_parser_26; | ||
6074 | } | ||
6075 | if (yych <= '+') | ||
6076 | { | ||
6077 | goto basic_json_parser_29; | ||
6078 | } | ||
6079 | goto basic_json_parser_14; | ||
6080 | } | ||
6081 | else | ||
6082 | { | ||
6083 | if (yych <= '-') | ||
6084 | { | ||
6085 | goto basic_json_parser_22; | ||
6086 | } | ||
6087 | if (yych <= '/') | ||
6088 | { | ||
6089 | goto basic_json_parser_29; | ||
6090 | } | ||
6091 | if (yych <= '0') | ||
6092 | { | ||
6093 | goto basic_json_parser_23; | ||
6094 | } | ||
6095 | goto basic_json_parser_25; | ||
6096 | } | ||
6097 | } | ||
6098 | } | ||
6099 | else | ||
6100 | { | ||
6101 | if (yych <= 'm') | ||
6102 | { | ||
6103 | if (yych <= '\\') | ||
6104 | { | ||
6105 | if (yych <= ':') | ||
6106 | { | ||
6107 | goto basic_json_parser_16; | ||
6108 | } | ||
6109 | if (yych == '[') | ||
6110 | { | ||
6111 | goto basic_json_parser_6; | ||
6112 | } | ||
6113 | goto basic_json_parser_29; | ||
6114 | } | ||
6115 | else | ||
6116 | { | ||
6117 | if (yych <= ']') | ||
6118 | { | ||
6119 | goto basic_json_parser_8; | ||
6120 | } | ||
6121 | if (yych == 'f') | ||
6122 | { | ||
6123 | goto basic_json_parser_21; | ||
6124 | } | ||
6125 | goto basic_json_parser_29; | ||
6126 | } | ||
6127 | } | ||
6128 | else | ||
6129 | { | ||
6130 | if (yych <= 'z') | ||
6131 | { | ||
6132 | if (yych <= 'n') | ||
6133 | { | ||
6134 | goto basic_json_parser_18; | ||
6135 | } | ||
6136 | if (yych == 't') | ||
6137 | { | ||
6138 | goto basic_json_parser_20; | ||
6139 | } | ||
6140 | goto basic_json_parser_29; | ||
6141 | } | ||
6142 | else | ||
6143 | { | ||
6144 | if (yych <= '{') | ||
6145 | { | ||
6146 | goto basic_json_parser_10; | ||
6147 | } | ||
6148 | if (yych == '}') | ||
6149 | { | ||
6150 | goto basic_json_parser_12; | ||
6151 | } | ||
6152 | goto basic_json_parser_29; | ||
6153 | } | ||
6154 | } | ||
6155 | } | ||
6156 | basic_json_parser_2: | ||
6157 | ++m_cursor; | ||
6158 | yych = *m_cursor; | ||
6159 | goto basic_json_parser_5; | ||
6160 | basic_json_parser_3: | ||
6161 | { | ||
6162 | return scan(); | ||
6163 | } | ||
6164 | basic_json_parser_4: | ||
6165 | ++m_cursor; | ||
6166 | if (m_limit <= m_cursor) | ||
6167 | { | ||
6168 | yyfill(); // LCOV_EXCL_LINE; | ||
6169 | } | ||
6170 | yych = *m_cursor; | ||
6171 | basic_json_parser_5: | ||
6172 | if (yybm[0 + yych] & 32) | ||
6173 | { | ||
6174 | goto basic_json_parser_4; | ||
6175 | } | ||
6176 | goto basic_json_parser_3; | ||
6177 | basic_json_parser_6: | ||
6178 | ++m_cursor; | ||
6179 | { | ||
6180 | return token_type::begin_array; | ||
6181 | } | ||
6182 | basic_json_parser_8: | ||
6183 | ++m_cursor; | ||
6184 | { | ||
6185 | return token_type::end_array; | ||
6186 | } | ||
6187 | basic_json_parser_10: | ||
6188 | ++m_cursor; | ||
6189 | { | ||
6190 | return token_type::begin_object; | ||
6191 | } | ||
6192 | basic_json_parser_12: | ||
6193 | ++m_cursor; | ||
6194 | { | ||
6195 | return token_type::end_object; | ||
6196 | } | ||
6197 | basic_json_parser_14: | ||
6198 | ++m_cursor; | ||
6199 | { | ||
6200 | return token_type::value_separator; | ||
6201 | } | ||
6202 | basic_json_parser_16: | ||
6203 | ++m_cursor; | ||
6204 | { | ||
6205 | return token_type::name_separator; | ||
6206 | } | ||
6207 | basic_json_parser_18: | ||
6208 | yyaccept = 0; | ||
6209 | yych = *(m_marker = ++m_cursor); | ||
6210 | if (yych == 'u') | ||
6211 | { | ||
6212 | goto basic_json_parser_59; | ||
6213 | } | ||
6214 | basic_json_parser_19: | ||
6215 | { | ||
6216 | return token_type::parse_error; | ||
6217 | } | ||
6218 | basic_json_parser_20: | ||
6219 | yyaccept = 0; | ||
6220 | yych = *(m_marker = ++m_cursor); | ||
6221 | if (yych == 'r') | ||
6222 | { | ||
6223 | goto basic_json_parser_55; | ||
6224 | } | ||
6225 | goto basic_json_parser_19; | ||
6226 | basic_json_parser_21: | ||
6227 | yyaccept = 0; | ||
6228 | yych = *(m_marker = ++m_cursor); | ||
6229 | if (yych == 'a') | ||
6230 | { | ||
6231 | goto basic_json_parser_50; | ||
6232 | } | ||
6233 | goto basic_json_parser_19; | ||
6234 | basic_json_parser_22: | ||
6235 | yych = *++m_cursor; | ||
6236 | if (yych <= '/') | ||
6237 | { | ||
6238 | goto basic_json_parser_19; | ||
6239 | } | ||
6240 | if (yych <= '0') | ||
6241 | { | ||
6242 | goto basic_json_parser_49; | ||
6243 | } | ||
6244 | if (yych <= '9') | ||
6245 | { | ||
6246 | goto basic_json_parser_40; | ||
6247 | } | ||
6248 | goto basic_json_parser_19; | ||
6249 | basic_json_parser_23: | ||
6250 | yyaccept = 1; | ||
6251 | yych = *(m_marker = ++m_cursor); | ||
6252 | if (yych <= 'D') | ||
6253 | { | ||
6254 | if (yych == '.') | ||
6255 | { | ||
6256 | goto basic_json_parser_42; | ||
6257 | } | ||
6258 | } | ||
6259 | else | ||
6260 | { | ||
6261 | if (yych <= 'E') | ||
6262 | { | ||
6263 | goto basic_json_parser_43; | ||
6264 | } | ||
6265 | if (yych == 'e') | ||
6266 | { | ||
6267 | goto basic_json_parser_43; | ||
6268 | } | ||
6269 | } | ||
6270 | basic_json_parser_24: | ||
6271 | { | ||
6272 | return token_type::value_number; | ||
6273 | } | ||
6274 | basic_json_parser_25: | ||
6275 | yyaccept = 1; | ||
6276 | yych = *(m_marker = ++m_cursor); | ||
6277 | goto basic_json_parser_41; | ||
6278 | basic_json_parser_26: | ||
6279 | yyaccept = 0; | ||
6280 | yych = *(m_marker = ++m_cursor); | ||
6281 | if (yych <= 0x0F) | ||
6282 | { | ||
6283 | goto basic_json_parser_19; | ||
6284 | } | ||
6285 | goto basic_json_parser_31; | ||
6286 | basic_json_parser_27: | ||
6287 | ++m_cursor; | ||
6288 | { | ||
6289 | return token_type::end_of_input; | ||
6290 | } | ||
6291 | basic_json_parser_29: | ||
6292 | yych = *++m_cursor; | ||
6293 | goto basic_json_parser_19; | ||
6294 | basic_json_parser_30: | ||
6295 | ++m_cursor; | ||
6296 | if (m_limit <= m_cursor) | ||
6297 | { | ||
6298 | yyfill(); // LCOV_EXCL_LINE; | ||
6299 | } | ||
6300 | yych = *m_cursor; | ||
6301 | basic_json_parser_31: | ||
6302 | if (yybm[0 + yych] & 64) | ||
6303 | { | ||
6304 | goto basic_json_parser_30; | ||
6305 | } | ||
6306 | if (yych <= 0x0F) | ||
6307 | { | ||
6308 | goto basic_json_parser_32; | ||
6309 | } | ||
6310 | if (yych <= '"') | ||
6311 | { | ||
6312 | goto basic_json_parser_34; | ||
6313 | } | ||
6314 | goto basic_json_parser_33; | ||
6315 | basic_json_parser_32: | ||
6316 | m_cursor = m_marker; | ||
6317 | if (yyaccept == 0) | ||
6318 | { | ||
6319 | goto basic_json_parser_19; | ||
6320 | } | ||
6321 | else | ||
6322 | { | ||
6323 | goto basic_json_parser_24; | ||
6324 | } | ||
6325 | basic_json_parser_33: | ||
6326 | ++m_cursor; | ||
6327 | if (m_limit <= m_cursor) | ||
6328 | { | ||
6329 | yyfill(); // LCOV_EXCL_LINE; | ||
6330 | } | ||
6331 | yych = *m_cursor; | ||
6332 | if (yych <= 'e') | ||
6333 | { | ||
6334 | if (yych <= '/') | ||
6335 | { | ||
6336 | if (yych == '"') | ||
6337 | { | ||
6338 | goto basic_json_parser_30; | ||
6339 | } | ||
6340 | if (yych <= '.') | ||
6341 | { | ||
6342 | goto basic_json_parser_32; | ||
6343 | } | ||
6344 | goto basic_json_parser_30; | ||
6345 | } | ||
6346 | else | ||
6347 | { | ||
6348 | if (yych <= '\\') | ||
6349 | { | ||
6350 | if (yych <= '[') | ||
6351 | { | ||
6352 | goto basic_json_parser_32; | ||
6353 | } | ||
6354 | goto basic_json_parser_30; | ||
6355 | } | ||
6356 | else | ||
6357 | { | ||
6358 | if (yych == 'b') | ||
6359 | { | ||
6360 | goto basic_json_parser_30; | ||
6361 | } | ||
6362 | goto basic_json_parser_32; | ||
6363 | } | ||
6364 | } | ||
6365 | } | ||
6366 | else | ||
6367 | { | ||
6368 | if (yych <= 'q') | ||
6369 | { | ||
6370 | if (yych <= 'f') | ||
6371 | { | ||
6372 | goto basic_json_parser_30; | ||
6373 | } | ||
6374 | if (yych == 'n') | ||
6375 | { | ||
6376 | goto basic_json_parser_30; | ||
6377 | } | ||
6378 | goto basic_json_parser_32; | ||
6379 | } | ||
6380 | else | ||
6381 | { | ||
6382 | if (yych <= 's') | ||
6383 | { | ||
6384 | if (yych <= 'r') | ||
6385 | { | ||
6386 | goto basic_json_parser_30; | ||
6387 | } | ||
6388 | goto basic_json_parser_32; | ||
6389 | } | ||
6390 | else | ||
6391 | { | ||
6392 | if (yych <= 't') | ||
6393 | { | ||
6394 | goto basic_json_parser_30; | ||
6395 | } | ||
6396 | if (yych <= 'u') | ||
6397 | { | ||
6398 | goto basic_json_parser_36; | ||
6399 | } | ||
6400 | goto basic_json_parser_32; | ||
6401 | } | ||
6402 | } | ||
6403 | } | ||
6404 | basic_json_parser_34: | ||
6405 | ++m_cursor; | ||
6406 | { | ||
6407 | return token_type::value_string; | ||
6408 | } | ||
6409 | basic_json_parser_36: | ||
6410 | ++m_cursor; | ||
6411 | if (m_limit <= m_cursor) | ||
6412 | { | ||
6413 | yyfill(); // LCOV_EXCL_LINE; | ||
6414 | } | ||
6415 | yych = *m_cursor; | ||
6416 | if (yych <= '@') | ||
6417 | { | ||
6418 | if (yych <= '/') | ||
6419 | { | ||
6420 | goto basic_json_parser_32; | ||
6421 | } | ||
6422 | if (yych >= ':') | ||
6423 | { | ||
6424 | goto basic_json_parser_32; | ||
6425 | } | ||
6426 | } | ||
6427 | else | ||
6428 | { | ||
6429 | if (yych <= 'F') | ||
6430 | { | ||
6431 | goto basic_json_parser_37; | ||
6432 | } | ||
6433 | if (yych <= '`') | ||
6434 | { | ||
6435 | goto basic_json_parser_32; | ||
6436 | } | ||
6437 | if (yych >= 'g') | ||
6438 | { | ||
6439 | goto basic_json_parser_32; | ||
6440 | } | ||
6441 | } | ||
6442 | basic_json_parser_37: | ||
6443 | ++m_cursor; | ||
6444 | if (m_limit <= m_cursor) | ||
6445 | { | ||
6446 | yyfill(); // LCOV_EXCL_LINE; | ||
6447 | } | ||
6448 | yych = *m_cursor; | ||
6449 | if (yych <= '@') | ||
6450 | { | ||
6451 | if (yych <= '/') | ||
6452 | { | ||
6453 | goto basic_json_parser_32; | ||
6454 | } | ||
6455 | if (yych >= ':') | ||
6456 | { | ||
6457 | goto basic_json_parser_32; | ||
6458 | } | ||
6459 | } | ||
6460 | else | ||
6461 | { | ||
6462 | if (yych <= 'F') | ||
6463 | { | ||
6464 | goto basic_json_parser_38; | ||
6465 | } | ||
6466 | if (yych <= '`') | ||
6467 | { | ||
6468 | goto basic_json_parser_32; | ||
6469 | } | ||
6470 | if (yych >= 'g') | ||
6471 | { | ||
6472 | goto basic_json_parser_32; | ||
6473 | } | ||
6474 | } | ||
6475 | basic_json_parser_38: | ||
6476 | ++m_cursor; | ||
6477 | if (m_limit <= m_cursor) | ||
6478 | { | ||
6479 | yyfill(); // LCOV_EXCL_LINE; | ||
6480 | } | ||
6481 | yych = *m_cursor; | ||
6482 | if (yych <= '@') | ||
6483 | { | ||
6484 | if (yych <= '/') | ||
6485 | { | ||
6486 | goto basic_json_parser_32; | ||
6487 | } | ||
6488 | if (yych >= ':') | ||
6489 | { | ||
6490 | goto basic_json_parser_32; | ||
6491 | } | ||
6492 | } | ||
6493 | else | ||
6494 | { | ||
6495 | if (yych <= 'F') | ||
6496 | { | ||
6497 | goto basic_json_parser_39; | ||
6498 | } | ||
6499 | if (yych <= '`') | ||
6500 | { | ||
6501 | goto basic_json_parser_32; | ||
6502 | } | ||
6503 | if (yych >= 'g') | ||
6504 | { | ||
6505 | goto basic_json_parser_32; | ||
6506 | } | ||
6507 | } | ||
6508 | basic_json_parser_39: | ||
6509 | ++m_cursor; | ||
6510 | if (m_limit <= m_cursor) | ||
6511 | { | ||
6512 | yyfill(); // LCOV_EXCL_LINE; | ||
6513 | } | ||
6514 | yych = *m_cursor; | ||
6515 | if (yych <= '@') | ||
6516 | { | ||
6517 | if (yych <= '/') | ||
6518 | { | ||
6519 | goto basic_json_parser_32; | ||
6520 | } | ||
6521 | if (yych <= '9') | ||
6522 | { | ||
6523 | goto basic_json_parser_30; | ||
6524 | } | ||
6525 | goto basic_json_parser_32; | ||
6526 | } | ||
6527 | else | ||
6528 | { | ||
6529 | if (yych <= 'F') | ||
6530 | { | ||
6531 | goto basic_json_parser_30; | ||
6532 | } | ||
6533 | if (yych <= '`') | ||
6534 | { | ||
6535 | goto basic_json_parser_32; | ||
6536 | } | ||
6537 | if (yych <= 'f') | ||
6538 | { | ||
6539 | goto basic_json_parser_30; | ||
6540 | } | ||
6541 | goto basic_json_parser_32; | ||
6542 | } | ||
6543 | basic_json_parser_40: | ||
6544 | yyaccept = 1; | ||
6545 | m_marker = ++m_cursor; | ||
6546 | if ((m_limit - m_cursor) < 3) | ||
6547 | { | ||
6548 | yyfill(); // LCOV_EXCL_LINE; | ||
6549 | } | ||
6550 | yych = *m_cursor; | ||
6551 | basic_json_parser_41: | ||
6552 | if (yybm[0 + yych] & 128) | ||
6553 | { | ||
6554 | goto basic_json_parser_40; | ||
6555 | } | ||
6556 | if (yych <= 'D') | ||
6557 | { | ||
6558 | if (yych != '.') | ||
6559 | { | ||
6560 | goto basic_json_parser_24; | ||
6561 | } | ||
6562 | } | ||
6563 | else | ||
6564 | { | ||
6565 | if (yych <= 'E') | ||
6566 | { | ||
6567 | goto basic_json_parser_43; | ||
6568 | } | ||
6569 | if (yych == 'e') | ||
6570 | { | ||
6571 | goto basic_json_parser_43; | ||
6572 | } | ||
6573 | goto basic_json_parser_24; | ||
6574 | } | ||
6575 | basic_json_parser_42: | ||
6576 | yych = *++m_cursor; | ||
6577 | if (yych <= '/') | ||
6578 | { | ||
6579 | goto basic_json_parser_32; | ||
6580 | } | ||
6581 | if (yych <= '9') | ||
6582 | { | ||
6583 | goto basic_json_parser_47; | ||
6584 | } | ||
6585 | goto basic_json_parser_32; | ||
6586 | basic_json_parser_43: | ||
6587 | yych = *++m_cursor; | ||
6588 | if (yych <= ',') | ||
6589 | { | ||
6590 | if (yych != '+') | ||
6591 | { | ||
6592 | goto basic_json_parser_32; | ||
6593 | } | ||
6594 | } | ||
6595 | else | ||
6596 | { | ||
6597 | if (yych <= '-') | ||
6598 | { | ||
6599 | goto basic_json_parser_44; | ||
6600 | } | ||
6601 | if (yych <= '/') | ||
6602 | { | ||
6603 | goto basic_json_parser_32; | ||
6604 | } | ||
6605 | if (yych <= '9') | ||
6606 | { | ||
6607 | goto basic_json_parser_45; | ||
6608 | } | ||
6609 | goto basic_json_parser_32; | ||
6610 | } | ||
6611 | basic_json_parser_44: | ||
6612 | yych = *++m_cursor; | ||
6613 | if (yych <= '/') | ||
6614 | { | ||
6615 | goto basic_json_parser_32; | ||
6616 | } | ||
6617 | if (yych >= ':') | ||
6618 | { | ||
6619 | goto basic_json_parser_32; | ||
6620 | } | ||
6621 | basic_json_parser_45: | ||
6622 | ++m_cursor; | ||
6623 | if (m_limit <= m_cursor) | ||
6624 | { | ||
6625 | yyfill(); // LCOV_EXCL_LINE; | ||
6626 | } | ||
6627 | yych = *m_cursor; | ||
6628 | if (yych <= '/') | ||
6629 | { | ||
6630 | goto basic_json_parser_24; | ||
6631 | } | ||
6632 | if (yych <= '9') | ||
6633 | { | ||
6634 | goto basic_json_parser_45; | ||
6635 | } | ||
6636 | goto basic_json_parser_24; | ||
6637 | basic_json_parser_47: | ||
6638 | yyaccept = 1; | ||
6639 | m_marker = ++m_cursor; | ||
6640 | if ((m_limit - m_cursor) < 3) | ||
6641 | { | ||
6642 | yyfill(); // LCOV_EXCL_LINE; | ||
6643 | } | ||
6644 | yych = *m_cursor; | ||
6645 | if (yych <= 'D') | ||
6646 | { | ||
6647 | if (yych <= '/') | ||
6648 | { | ||
6649 | goto basic_json_parser_24; | ||
6650 | } | ||
6651 | if (yych <= '9') | ||
6652 | { | ||
6653 | goto basic_json_parser_47; | ||
6654 | } | ||
6655 | goto basic_json_parser_24; | ||
6656 | } | ||
6657 | else | ||
6658 | { | ||
6659 | if (yych <= 'E') | ||
6660 | { | ||
6661 | goto basic_json_parser_43; | ||
6662 | } | ||
6663 | if (yych == 'e') | ||
6664 | { | ||
6665 | goto basic_json_parser_43; | ||
6666 | } | ||
6667 | goto basic_json_parser_24; | ||
6668 | } | ||
6669 | basic_json_parser_49: | ||
6670 | yyaccept = 1; | ||
6671 | yych = *(m_marker = ++m_cursor); | ||
6672 | if (yych <= 'D') | ||
6673 | { | ||
6674 | if (yych == '.') | ||
6675 | { | ||
6676 | goto basic_json_parser_42; | ||
6677 | } | ||
6678 | goto basic_json_parser_24; | ||
6679 | } | ||
6680 | else | ||
6681 | { | ||
6682 | if (yych <= 'E') | ||
6683 | { | ||
6684 | goto basic_json_parser_43; | ||
6685 | } | ||
6686 | if (yych == 'e') | ||
6687 | { | ||
6688 | goto basic_json_parser_43; | ||
6689 | } | ||
6690 | goto basic_json_parser_24; | ||
6691 | } | ||
6692 | basic_json_parser_50: | ||
6693 | yych = *++m_cursor; | ||
6694 | if (yych != 'l') | ||
6695 | { | ||
6696 | goto basic_json_parser_32; | ||
6697 | } | ||
6698 | yych = *++m_cursor; | ||
6699 | if (yych != 's') | ||
6700 | { | ||
6701 | goto basic_json_parser_32; | ||
6702 | } | ||
6703 | yych = *++m_cursor; | ||
6704 | if (yych != 'e') | ||
6705 | { | ||
6706 | goto basic_json_parser_32; | ||
6707 | } | ||
6708 | ++m_cursor; | ||
6709 | { | ||
6710 | return token_type::literal_false; | ||
6711 | } | ||
6712 | basic_json_parser_55: | ||
6713 | yych = *++m_cursor; | ||
6714 | if (yych != 'u') | ||
6715 | { | ||
6716 | goto basic_json_parser_32; | ||
6717 | } | ||
6718 | yych = *++m_cursor; | ||
6719 | if (yych != 'e') | ||
6720 | { | ||
6721 | goto basic_json_parser_32; | ||
6722 | } | ||
6723 | ++m_cursor; | ||
6724 | { | ||
6725 | return token_type::literal_true; | ||
6726 | } | ||
6727 | basic_json_parser_59: | ||
6728 | yych = *++m_cursor; | ||
6729 | if (yych != 'l') | ||
6730 | { | ||
6731 | goto basic_json_parser_32; | ||
6732 | } | ||
6733 | yych = *++m_cursor; | ||
6734 | if (yych != 'l') | ||
6735 | { | ||
6736 | goto basic_json_parser_32; | ||
6737 | } | ||
6738 | ++m_cursor; | ||
6739 | { | ||
6740 | return token_type::literal_null; | ||
6741 | } | ||
6742 | } | ||
6743 | |||
6744 | |||
6745 | } | ||
6746 | |||
6747 | /// append data from the stream to the internal buffer | ||
6748 | void yyfill() noexcept | ||
6749 | { | ||
6750 | if (not m_stream or not * m_stream) | ||
6751 | { | ||
6752 | return; | ||
6753 | } | ||
6754 | |||
6755 | const ssize_t offset_start = m_start - m_content; | ||
6756 | const ssize_t offset_marker = m_marker - m_start; | ||
6757 | const ssize_t offset_cursor = m_cursor - m_start; | ||
6758 | |||
6759 | m_buffer.erase(0, static_cast<size_t>(offset_start)); | ||
6760 | std::string line; | ||
6761 | std::getline(*m_stream, line); | ||
6762 | m_buffer += "\n" + line; // add line with newline symbol | ||
6763 | |||
6764 | m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str()); | ||
6765 | m_start = m_content; | ||
6766 | m_marker = m_start + offset_marker; | ||
6767 | m_cursor = m_start + offset_cursor; | ||
6768 | m_limit = m_start + m_buffer.size() - 1; | ||
6769 | } | ||
6770 | |||
6771 | /// return string representation of last read token | ||
6772 | string_t get_token() const noexcept | ||
6773 | { | ||
6774 | return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start), | ||
6775 | static_cast<size_t>(m_cursor - m_start)); | ||
6776 | } | ||
6777 | |||
6778 | /*! | ||
6779 | @brief return string value for string tokens | ||
6780 | |||
6781 | The function iterates the characters between the opening and closing | ||
6782 | quotes of the string value. The complete string is the range | ||
6783 | [m_start,m_cursor). Consequently, we iterate from m_start+1 to | ||
6784 | m_cursor-1. | ||
6785 | |||
6786 | We differentiate two cases: | ||
6787 | |||
6788 | 1. Escaped characters. In this case, a new character is constructed | ||
6789 | according to the nature of the escape. Some escapes create new | ||
6790 | characters (e.g., @c "\\n" is replaced by @c "\n"), some are copied | ||
6791 | as is (e.g., @c "\\\\"). Furthermore, Unicode escapes of the shape | ||
6792 | @c "\\uxxxx" need special care. In this case, to_unicode takes care | ||
6793 | of the construction of the values. | ||
6794 | 2. Unescaped characters are copied as is. | ||
6795 | |||
6796 | @return string value of current token without opening and closing quotes | ||
6797 | @throw std::out_of_range if to_unicode fails | ||
6798 | */ | ||
6799 | string_t get_string() const | ||
6800 | { | ||
6801 | string_t result; | ||
6802 | result.reserve(static_cast<size_t>(m_cursor - m_start - 2)); | ||
6803 | |||
6804 | // iterate the result between the quotes | ||
6805 | for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) | ||
6806 | { | ||
6807 | // process escaped characters | ||
6808 | if (*i == '\\') | ||
6809 | { | ||
6810 | // read next character | ||
6811 | ++i; | ||
6812 | |||
6813 | switch (*i) | ||
6814 | { | ||
6815 | // the default escapes | ||
6816 | case 't': | ||
6817 | { | ||
6818 | result += "\t"; | ||
6819 | break; | ||
6820 | } | ||
6821 | case 'b': | ||
6822 | { | ||
6823 | result += "\b"; | ||
6824 | break; | ||
6825 | } | ||
6826 | case 'f': | ||
6827 | { | ||
6828 | result += "\f"; | ||
6829 | break; | ||
6830 | } | ||
6831 | case 'n': | ||
6832 | { | ||
6833 | result += "\n"; | ||
6834 | break; | ||
6835 | } | ||
6836 | case 'r': | ||
6837 | { | ||
6838 | result += "\r"; | ||
6839 | break; | ||
6840 | } | ||
6841 | case '\\': | ||
6842 | { | ||
6843 | result += "\\"; | ||
6844 | break; | ||
6845 | } | ||
6846 | case '/': | ||
6847 | { | ||
6848 | result += "/"; | ||
6849 | break; | ||
6850 | } | ||
6851 | case '"': | ||
6852 | { | ||
6853 | result += "\""; | ||
6854 | break; | ||
6855 | } | ||
6856 | |||
6857 | // unicode | ||
6858 | case 'u': | ||
6859 | { | ||
6860 | // get code xxxx from uxxxx | ||
6861 | auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1), | ||
6862 | 4).c_str(), nullptr, 16); | ||
6863 | |||
6864 | // check if codepoint is a high surrogate | ||
6865 | if (codepoint >= 0xD800 and codepoint <= 0xDBFF) | ||
6866 | { | ||
6867 | // make sure there is a subsequent unicode | ||
6868 | if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') | ||
6869 | { | ||
6870 | throw std::invalid_argument("missing low surrogate"); | ||
6871 | } | ||
6872 | |||
6873 | // get code yyyy from uxxxx\uyyyy | ||
6874 | auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer> | ||
6875 | (i + 7), 4).c_str(), nullptr, 16); | ||
6876 | result += to_unicode(codepoint, codepoint2); | ||
6877 | // skip the next 11 characters (xxxx\uyyyy) | ||
6878 | i += 11; | ||
6879 | } | ||
6880 | else | ||
6881 | { | ||
6882 | // add unicode character(s) | ||
6883 | result += to_unicode(codepoint); | ||
6884 | // skip the next four characters (xxxx) | ||
6885 | i += 4; | ||
6886 | } | ||
6887 | break; | ||
6888 | } | ||
6889 | } | ||
6890 | } | ||
6891 | else | ||
6892 | { | ||
6893 | // all other characters are just copied to the end of the | ||
6894 | // string | ||
6895 | result.append(1, static_cast<typename string_t::value_type>(*i)); | ||
6896 | } | ||
6897 | } | ||
6898 | |||
6899 | return result; | ||
6900 | } | ||
6901 | |||
6902 | /*! | ||
6903 | @brief return number value for number tokens | ||
6904 | |||
6905 | This function translates the last token into a floating point number. | ||
6906 | The pointer m_begin points to the beginning of the parsed number. We | ||
6907 | pass this pointer to std::strtod which sets endptr to the first | ||
6908 | character past the converted number. If this pointer is not the same as | ||
6909 | m_cursor, then either more or less characters have been used during the | ||
6910 | comparison. This can happen for inputs like "01" which will be treated | ||
6911 | like number 0 followed by number 1. | ||
6912 | |||
6913 | @return the result of the number conversion or NAN if the conversion | ||
6914 | read past the current token. The latter case needs to be treated by the | ||
6915 | caller function. | ||
6916 | |||
6917 | @throw std::range_error if passed value is out of range | ||
6918 | */ | ||
6919 | long double get_number() const | ||
6920 | { | ||
6921 | // conversion | ||
6922 | typename string_t::value_type* endptr; | ||
6923 | const auto float_val = std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), | ||
6924 | &endptr); | ||
6925 | |||
6926 | // return float_val if the whole number was translated and NAN | ||
6927 | // otherwise | ||
6928 | return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN; | ||
6929 | } | ||
6930 | |||
6931 | private: | ||
6932 | /// optional input stream | ||
6933 | std::istream* m_stream; | ||
6934 | /// the buffer | ||
6935 | string_t m_buffer; | ||
6936 | /// the buffer pointer | ||
6937 | const lexer_char_t* m_content = nullptr; | ||
6938 | /// pointer to the beginning of the current symbol | ||
6939 | const lexer_char_t* m_start = nullptr; | ||
6940 | /// pointer for backtracking information | ||
6941 | const lexer_char_t* m_marker = nullptr; | ||
6942 | /// pointer to the current symbol | ||
6943 | const lexer_char_t* m_cursor = nullptr; | ||
6944 | /// pointer to the end of the buffer | ||
6945 | const lexer_char_t* m_limit = nullptr; | ||
6946 | }; | ||
6947 | |||
6948 | /*! | ||
6949 | @brief syntax analysis | ||
6950 | */ | ||
6951 | class parser | ||
6952 | { | ||
6953 | public: | ||
6954 | /// constructor for strings | ||
6955 | parser(const string_t& s, parser_callback_t cb = nullptr) | ||
6956 | : callback(cb), m_lexer(s) | ||
6957 | { | ||
6958 | // read first token | ||
6959 | get_token(); | ||
6960 | } | ||
6961 | |||
6962 | /// a parser reading from an input stream | ||
6963 | parser(std::istream& _is, parser_callback_t cb = nullptr) | ||
6964 | : callback(cb), m_lexer(&_is) | ||
6965 | { | ||
6966 | // read first token | ||
6967 | get_token(); | ||
6968 | } | ||
6969 | |||
6970 | /// public parser interface | ||
6971 | basic_json parse() | ||
6972 | { | ||
6973 | basic_json result = parse_internal(true); | ||
6974 | |||
6975 | expect(lexer::token_type::end_of_input); | ||
6976 | |||
6977 | // return parser result and replace it with null in case the | ||
6978 | // top-level value was discarded by the callback function | ||
6979 | return result.is_discarded() ? basic_json() : result; | ||
6980 | } | ||
6981 | |||
6982 | private: | ||
6983 | /// the actual parser | ||
6984 | basic_json parse_internal(bool keep) | ||
6985 | { | ||
6986 | auto result = basic_json(value_t::discarded); | ||
6987 | |||
6988 | switch (last_token) | ||
6989 | { | ||
6990 | case (lexer::token_type::begin_object): | ||
6991 | { | ||
6992 | if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) | ||
6993 | { | ||
6994 | // explicitly set result to object to cope with {} | ||
6995 | result.m_type = value_t::object; | ||
6996 | result.m_value = json_value(value_t::object); | ||
6997 | } | ||
6998 | |||
6999 | // read next token | ||
7000 | get_token(); | ||
7001 | |||
7002 | // closing } -> we are done | ||
7003 | if (last_token == lexer::token_type::end_object) | ||
7004 | { | ||
7005 | get_token(); | ||
7006 | if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) | ||
7007 | { | ||
7008 | result = basic_json(value_t::discarded); | ||
7009 | } | ||
7010 | return result; | ||
7011 | } | ||
7012 | |||
7013 | // no comma is expected here | ||
7014 | unexpect(lexer::token_type::value_separator); | ||
7015 | |||
7016 | // otherwise: parse key-value pairs | ||
7017 | do | ||
7018 | { | ||
7019 | // ugly, but could be fixed with loop reorganization | ||
7020 | if (last_token == lexer::token_type::value_separator) | ||
7021 | { | ||
7022 | get_token(); | ||
7023 | } | ||
7024 | |||
7025 | // store key | ||
7026 | expect(lexer::token_type::value_string); | ||
7027 | const auto key = m_lexer.get_string(); | ||
7028 | |||
7029 | bool keep_tag = false; | ||
7030 | if (keep) | ||
7031 | { | ||
7032 | if (callback) | ||
7033 | { | ||
7034 | basic_json k(key); | ||
7035 | keep_tag = callback(depth, parse_event_t::key, k); | ||
7036 | } | ||
7037 | else | ||
7038 | { | ||
7039 | keep_tag = true; | ||
7040 | } | ||
7041 | } | ||
7042 | |||
7043 | // parse separator (:) | ||
7044 | get_token(); | ||
7045 | expect(lexer::token_type::name_separator); | ||
7046 | |||
7047 | // parse and add value | ||
7048 | get_token(); | ||
7049 | auto value = parse_internal(keep); | ||
7050 | if (keep and keep_tag and not value.is_discarded()) | ||
7051 | { | ||
7052 | result[key] = std::move(value); | ||
7053 | } | ||
7054 | } | ||
7055 | while (last_token == lexer::token_type::value_separator); | ||
7056 | |||
7057 | // closing } | ||
7058 | expect(lexer::token_type::end_object); | ||
7059 | get_token(); | ||
7060 | if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) | ||
7061 | { | ||
7062 | result = basic_json(value_t::discarded); | ||
7063 | } | ||
7064 | |||
7065 | return result; | ||
7066 | } | ||
7067 | |||
7068 | case (lexer::token_type::begin_array): | ||
7069 | { | ||
7070 | if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) | ||
7071 | { | ||
7072 | // explicitly set result to object to cope with [] | ||
7073 | result.m_type = value_t::array; | ||
7074 | result.m_value = json_value(value_t::array); | ||
7075 | } | ||
7076 | |||
7077 | // read next token | ||
7078 | get_token(); | ||
7079 | |||
7080 | // closing ] -> we are done | ||
7081 | if (last_token == lexer::token_type::end_array) | ||
7082 | { | ||
7083 | get_token(); | ||
7084 | if (callback and not callback(--depth, parse_event_t::array_end, result)) | ||
7085 | { | ||
7086 | result = basic_json(value_t::discarded); | ||
7087 | } | ||
7088 | return result; | ||
7089 | } | ||
7090 | |||
7091 | // no comma is expected here | ||
7092 | unexpect(lexer::token_type::value_separator); | ||
7093 | |||
7094 | // otherwise: parse values | ||
7095 | do | ||
7096 | { | ||
7097 | // ugly, but could be fixed with loop reorganization | ||
7098 | if (last_token == lexer::token_type::value_separator) | ||
7099 | { | ||
7100 | get_token(); | ||
7101 | } | ||
7102 | |||
7103 | // parse value | ||
7104 | auto value = parse_internal(keep); | ||
7105 | if (keep and not value.is_discarded()) | ||
7106 | { | ||
7107 | result.push_back(std::move(value)); | ||
7108 | } | ||
7109 | } | ||
7110 | while (last_token == lexer::token_type::value_separator); | ||
7111 | |||
7112 | // closing ] | ||
7113 | expect(lexer::token_type::end_array); | ||
7114 | get_token(); | ||
7115 | if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) | ||
7116 | { | ||
7117 | result = basic_json(value_t::discarded); | ||
7118 | } | ||
7119 | |||
7120 | return result; | ||
7121 | } | ||
7122 | |||
7123 | case (lexer::token_type::literal_null): | ||
7124 | { | ||
7125 | get_token(); | ||
7126 | result.m_type = value_t::null; | ||
7127 | break; | ||
7128 | } | ||
7129 | |||
7130 | case (lexer::token_type::value_string): | ||
7131 | { | ||
7132 | const auto s = m_lexer.get_string(); | ||
7133 | get_token(); | ||
7134 | result = basic_json(s); | ||
7135 | break; | ||
7136 | } | ||
7137 | |||
7138 | case (lexer::token_type::literal_true): | ||
7139 | { | ||
7140 | get_token(); | ||
7141 | result.m_type = value_t::boolean; | ||
7142 | result.m_value = true; | ||
7143 | break; | ||
7144 | } | ||
7145 | |||
7146 | case (lexer::token_type::literal_false): | ||
7147 | { | ||
7148 | get_token(); | ||
7149 | result.m_type = value_t::boolean; | ||
7150 | result.m_value = false; | ||
7151 | break; | ||
7152 | } | ||
7153 | |||
7154 | case (lexer::token_type::value_number): | ||
7155 | { | ||
7156 | auto float_val = m_lexer.get_number(); | ||
7157 | |||
7158 | // NAN is returned if token could not be translated | ||
7159 | // completely | ||
7160 | if (std::isnan(float_val)) | ||
7161 | { | ||
7162 | throw std::invalid_argument(std::string("parse error - ") + | ||
7163 | m_lexer.get_token() + " is not a number"); | ||
7164 | } | ||
7165 | |||
7166 | get_token(); | ||
7167 | |||
7168 | // check if conversion loses precision | ||
7169 | const auto int_val = static_cast<number_integer_t>(float_val); | ||
7170 | if (approx(float_val, static_cast<long double>(int_val))) | ||
7171 | { | ||
7172 | // we basic_json not lose precision -> return int | ||
7173 | result.m_type = value_t::number_integer; | ||
7174 | result.m_value = int_val; | ||
7175 | } | ||
7176 | else | ||
7177 | { | ||
7178 | // we would lose precision -> returnfloat | ||
7179 | result.m_type = value_t::number_float; | ||
7180 | result.m_value = static_cast<number_float_t>(float_val); | ||
7181 | } | ||
7182 | break; | ||
7183 | } | ||
7184 | |||
7185 | default: | ||
7186 | { | ||
7187 | // the last token was unexpected | ||
7188 | unexpect(last_token); | ||
7189 | } | ||
7190 | } | ||
7191 | |||
7192 | if (keep and callback and not callback(depth, parse_event_t::value, result)) | ||
7193 | { | ||
7194 | result = basic_json(value_t::discarded); | ||
7195 | } | ||
7196 | return result; | ||
7197 | } | ||
7198 | |||
7199 | /// get next token from lexer | ||
7200 | typename lexer::token_type get_token() | ||
7201 | { | ||
7202 | last_token = m_lexer.scan(); | ||
7203 | return last_token; | ||
7204 | } | ||
7205 | |||
7206 | void expect(typename lexer::token_type t) const | ||
7207 | { | ||
7208 | if (t != last_token) | ||
7209 | { | ||
7210 | std::string error_msg = "parse error - unexpected \'"; | ||
7211 | error_msg += m_lexer.get_token(); | ||
7212 | error_msg += "\' (" + lexer::token_type_name(last_token); | ||
7213 | error_msg += "); expected " + lexer::token_type_name(t); | ||
7214 | throw std::invalid_argument(error_msg); | ||
7215 | } | ||
7216 | } | ||
7217 | |||
7218 | void unexpect(typename lexer::token_type t) const | ||
7219 | { | ||
7220 | if (t == last_token) | ||
7221 | { | ||
7222 | std::string error_msg = "parse error - unexpected \'"; | ||
7223 | error_msg += m_lexer.get_token(); | ||
7224 | error_msg += "\' ("; | ||
7225 | error_msg += lexer::token_type_name(last_token) + ")"; | ||
7226 | throw std::invalid_argument(error_msg); | ||
7227 | } | ||
7228 | } | ||
7229 | |||
7230 | private: | ||
7231 | /// current level of recursion | ||
7232 | int depth = 0; | ||
7233 | /// callback function | ||
7234 | parser_callback_t callback; | ||
7235 | /// the type of the last read token | ||
7236 | typename lexer::token_type last_token = lexer::token_type::uninitialized; | ||
7237 | /// the lexer | ||
7238 | lexer m_lexer; | ||
7239 | }; | ||
7240 | }; | ||
7241 | |||
7242 | |||
7243 | ///////////// | ||
7244 | // presets // | ||
7245 | ///////////// | ||
7246 | |||
7247 | /*! | ||
7248 | @brief default JSON class | ||
7249 | |||
7250 | This type is the default specialization of the @ref basic_json class which uses | ||
7251 | the standard template types. | ||
7252 | */ | ||
7253 | using json = basic_json<>; | ||
7254 | } | ||
7255 | |||
7256 | |||
7257 | ///////////////////////// | ||
7258 | // nonmember functions // | ||
7259 | ///////////////////////// | ||
7260 | |||
7261 | // specialization of std::swap, and std::hash | ||
7262 | namespace std | ||
7263 | { | ||
7264 | /*! | ||
7265 | @brief exchanges the values of two JSON objects | ||
7266 | */ | ||
7267 | template <> | ||
7268 | inline void swap(nlohmann::json& j1, | ||
7269 | nlohmann::json& j2) noexcept( | ||
7270 | is_nothrow_move_constructible<nlohmann::json>::value and | ||
7271 | is_nothrow_move_assignable<nlohmann::json>::value | ||
7272 | ) | ||
7273 | { | ||
7274 | j1.swap(j2); | ||
7275 | } | ||
7276 | |||
7277 | /// hash value for JSON objects | ||
7278 | template <> | ||
7279 | struct hash<nlohmann::json> | ||
7280 | { | ||
7281 | /// return a hash value for a JSON object | ||
7282 | std::size_t operator()(const nlohmann::json& j) const | ||
7283 | { | ||
7284 | // a naive hashing via the string representation | ||
7285 | const auto& h = hash<nlohmann::json::string_t>(); | ||
7286 | return h(j.dump()); | ||
7287 | } | ||
7288 | }; | ||
7289 | } | ||
7290 | |||
7291 | /*! | ||
7292 | @brief user-defined string literal for JSON values | ||
7293 | |||
7294 | This operator implements a user-defined string literal for JSON objects. It can | ||
7295 | be used by adding \p "_json" to a string literal and returns a JSON object if | ||
7296 | no parse error occurred. | ||
7297 | |||
7298 | @param[in] s a string representation of a JSON object | ||
7299 | @return a JSON object | ||
7300 | */ | ||
7301 | inline nlohmann::json operator "" _json(const char* s, std::size_t) | ||
7302 | { | ||
7303 | return nlohmann::json::parse(reinterpret_cast<nlohmann::json::string_t::value_type*> | ||
7304 | (const_cast<char*>(s))); | ||
7305 | } | ||
7306 | |||
7307 | #endif | ||
diff --git a/templates/data.cpp.ede b/templates/data.cpp.ede index 8e106a6..a7447d6 100644 --- a/templates/data.cpp.ede +++ b/templates/data.cpp.ede | |||
@@ -3,40 +3,6 @@ | |||
3 | 3 | ||
4 | #include "{{ moduleName }}.hpp" | 4 | #include "{{ moduleName }}.hpp" |
5 | 5 | ||
6 | template<> json toJSON<String>(String &v) { | ||
7 | return json(v); | ||
8 | } | ||
9 | |||
10 | template<> json toJSON<Float>(Float &v) { | ||
11 | return json(v); | ||
12 | } | ||
13 | |||
14 | template<> json toJSON<bool>(bool &v) { | ||
15 | return json(v); | ||
16 | } | ||
17 | |||
18 | template<> json toJSON<int>(int &v) { | ||
19 | return json(v); | ||
20 | } | ||
21 | |||
22 | template<> json toJSON<unsigned int>(unsigned int &v) { | ||
23 | return json(v); | ||
24 | } | ||
25 | |||
26 | template<typename any> | ||
27 | json toJSON(std::vector<any> &v) { | ||
28 | json obj = json::array(); | ||
29 | for (any i : v) { | ||
30 | obj.push_back(toJSON(i)); | ||
31 | } | ||
32 | return obj; | ||
33 | } | ||
34 | |||
35 | template<typename k, typename v> | ||
36 | json toJSON(std::map<k,v> &value) { | ||
37 | return json(); | ||
38 | } | ||
39 | |||
40 | {% for t in definitions %} | 6 | {% for t in definitions %} |
41 | template<> json toJSON<{{ t.value.dataName }}>({{ t.value.dataName }} &v) { | 7 | template<> json toJSON<{{ t.value.dataName }}>({{ t.value.dataName }} &v) { |
42 | json obj; | 8 | json obj; |
@@ -53,11 +19,3 @@ template<> json toJSON<{{ t.value.dataName }}>({{ t.value.dataName }} &v) { | |||
53 | return obj; | 19 | return obj; |
54 | } | 20 | } |
55 | {% endfor %} | 21 | {% endfor %} |
56 | |||
57 | {# | ||
58 | {% for c in t.value.constructors %} | ||
59 | json data::{{ c.value.name }}::toJSON() { | ||
60 | return obj; | ||
61 | } | ||
62 | {% endif %}{% endfor %}{% endfor %} | ||
63 | #} \ No newline at end of file | ||
diff --git a/templates/data.hpp.ede b/templates/data.hpp.ede index 10e1ff4..0dcb02c 100644 --- a/templates/data.hpp.ede +++ b/templates/data.hpp.ede | |||
@@ -4,24 +4,7 @@ | |||
4 | #ifndef HEADER_{{ moduleName }}_H | 4 | #ifndef HEADER_{{ moduleName }}_H |
5 | #define HEADER_{{ moduleName }}_H | 5 | #define HEADER_{{ moduleName }}_H |
6 | 6 | ||
7 | #include <vector> | 7 | #include "RT.hpp" |
8 | #include <map> | ||
9 | #include <string> | ||
10 | |||
11 | #include "json.hpp" | ||
12 | |||
13 | typedef int Int; | ||
14 | typedef int Int32; | ||
15 | typedef unsigned int Word; | ||
16 | typedef unsigned int Word32; | ||
17 | typedef float Float; | ||
18 | typedef bool Bool; | ||
19 | typedef std::string String; | ||
20 | |||
21 | using json = nlohmann::json; | ||
22 | |||
23 | template<typename T> | ||
24 | json toJSON(T &v); | ||
25 | 8 | ||
26 | {% for m in imports %} | 9 | {% for m in imports %} |
27 | #include "{{ m.value }}.hpp" | 10 | #include "{{ m.value }}.hpp" |