Mercurial > minori
comparison dep/json/json.h @ 1:1ae666fdf9e2
*: initial commit
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Tue, 08 Aug 2023 19:49:15 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:5a76e1b94163 | 1:1ae666fdf9e2 |
---|---|
1 // __ _____ _____ _____ | |
2 // __| | __| | | | JSON for Modern C++ | |
3 // | | |__ | | | | | | version 3.11.2 | |
4 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
5 // | |
6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
7 // SPDX-License-Identifier: MIT | |
8 | |
9 /****************************************************************************\ | |
10 * Note on documentation: The source files contain links to the online * | |
11 * documentation of the public API at https://json.nlohmann.me. This URL * | |
12 * contains the most recent documentation and should also be applicable to * | |
13 * previous versions; documentation for deprecated functions is not * | |
14 * removed, but marked deprecated. See "Generate documentation" section in * | |
15 * file docs/README.md. * | |
16 \****************************************************************************/ | |
17 | |
18 #ifndef INCLUDE_NLOHMANN_JSON_HPP_ | |
19 #define INCLUDE_NLOHMANN_JSON_HPP_ | |
20 | |
21 #include <algorithm> // all_of, find, for_each | |
22 #include <cstddef> // nullptr_t, ptrdiff_t, size_t | |
23 #include <functional> // hash, less | |
24 #include <initializer_list> // initializer_list | |
25 #ifndef JSON_NO_IO | |
26 #include <iosfwd> // istream, ostream | |
27 #endif // JSON_NO_IO | |
28 #include <iterator> // random_access_iterator_tag | |
29 #include <memory> // unique_ptr | |
30 #include <numeric> // accumulate | |
31 #include <string> // string, stoi, to_string | |
32 #include <utility> // declval, forward, move, pair, swap | |
33 #include <vector> // vector | |
34 | |
35 // #include <nlohmann/adl_serializer.hpp> | |
36 // __ _____ _____ _____ | |
37 // __| | __| | | | JSON for Modern C++ | |
38 // | | |__ | | | | | | version 3.11.2 | |
39 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
40 // | |
41 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
42 // SPDX-License-Identifier: MIT | |
43 | |
44 | |
45 | |
46 #include <utility> | |
47 | |
48 // #include <nlohmann/detail/abi_macros.hpp> | |
49 // __ _____ _____ _____ | |
50 // __| | __| | | | JSON for Modern C++ | |
51 // | | |__ | | | | | | version 3.11.2 | |
52 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
53 // | |
54 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
55 // SPDX-License-Identifier: MIT | |
56 | |
57 | |
58 | |
59 // This file contains all macro definitions affecting or depending on the ABI | |
60 | |
61 #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK | |
62 #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) | |
63 #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2 | |
64 #warning "Already included a different version of the library!" | |
65 #endif | |
66 #endif | |
67 #endif | |
68 | |
69 #define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) | |
70 #define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) | |
71 #define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum) | |
72 | |
73 #ifndef JSON_DIAGNOSTICS | |
74 #define JSON_DIAGNOSTICS 0 | |
75 #endif | |
76 | |
77 #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON | |
78 #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 | |
79 #endif | |
80 | |
81 #if JSON_DIAGNOSTICS | |
82 #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag | |
83 #else | |
84 #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS | |
85 #endif | |
86 | |
87 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON | |
88 #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp | |
89 #else | |
90 #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON | |
91 #endif | |
92 | |
93 #ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION | |
94 #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 | |
95 #endif | |
96 | |
97 // Construct the namespace ABI tags component | |
98 #define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b | |
99 #define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ | |
100 NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) | |
101 | |
102 #define NLOHMANN_JSON_ABI_TAGS \ | |
103 NLOHMANN_JSON_ABI_TAGS_CONCAT( \ | |
104 NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ | |
105 NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) | |
106 | |
107 // Construct the namespace version component | |
108 #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ | |
109 _v ## major ## _ ## minor ## _ ## patch | |
110 #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ | |
111 NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) | |
112 | |
113 #if NLOHMANN_JSON_NAMESPACE_NO_VERSION | |
114 #define NLOHMANN_JSON_NAMESPACE_VERSION | |
115 #else | |
116 #define NLOHMANN_JSON_NAMESPACE_VERSION \ | |
117 NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ | |
118 NLOHMANN_JSON_VERSION_MINOR, \ | |
119 NLOHMANN_JSON_VERSION_PATCH) | |
120 #endif | |
121 | |
122 // Combine namespace components | |
123 #define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b | |
124 #define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ | |
125 NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) | |
126 | |
127 #ifndef NLOHMANN_JSON_NAMESPACE | |
128 #define NLOHMANN_JSON_NAMESPACE \ | |
129 nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ | |
130 NLOHMANN_JSON_ABI_TAGS, \ | |
131 NLOHMANN_JSON_NAMESPACE_VERSION) | |
132 #endif | |
133 | |
134 #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN | |
135 #define NLOHMANN_JSON_NAMESPACE_BEGIN \ | |
136 namespace nlohmann \ | |
137 { \ | |
138 inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ | |
139 NLOHMANN_JSON_ABI_TAGS, \ | |
140 NLOHMANN_JSON_NAMESPACE_VERSION) \ | |
141 { | |
142 #endif | |
143 | |
144 #ifndef NLOHMANN_JSON_NAMESPACE_END | |
145 #define NLOHMANN_JSON_NAMESPACE_END \ | |
146 } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ | |
147 } // namespace nlohmann | |
148 #endif | |
149 | |
150 // #include <nlohmann/detail/conversions/from_json.hpp> | |
151 // __ _____ _____ _____ | |
152 // __| | __| | | | JSON for Modern C++ | |
153 // | | |__ | | | | | | version 3.11.2 | |
154 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
155 // | |
156 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
157 // SPDX-License-Identifier: MIT | |
158 | |
159 | |
160 | |
161 #include <algorithm> // transform | |
162 #include <array> // array | |
163 #include <forward_list> // forward_list | |
164 #include <iterator> // inserter, front_inserter, end | |
165 #include <map> // map | |
166 #include <string> // string | |
167 #include <tuple> // tuple, make_tuple | |
168 #include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible | |
169 #include <unordered_map> // unordered_map | |
170 #include <utility> // pair, declval | |
171 #include <valarray> // valarray | |
172 | |
173 // #include <nlohmann/detail/exceptions.hpp> | |
174 // __ _____ _____ _____ | |
175 // __| | __| | | | JSON for Modern C++ | |
176 // | | |__ | | | | | | version 3.11.2 | |
177 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
178 // | |
179 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
180 // SPDX-License-Identifier: MIT | |
181 | |
182 | |
183 | |
184 #include <cstddef> // nullptr_t | |
185 #include <exception> // exception | |
186 #include <stdexcept> // runtime_error | |
187 #include <string> // to_string | |
188 #include <vector> // vector | |
189 | |
190 // #include <nlohmann/detail/value_t.hpp> | |
191 // __ _____ _____ _____ | |
192 // __| | __| | | | JSON for Modern C++ | |
193 // | | |__ | | | | | | version 3.11.2 | |
194 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
195 // | |
196 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
197 // SPDX-License-Identifier: MIT | |
198 | |
199 | |
200 | |
201 #include <array> // array | |
202 #include <cstddef> // size_t | |
203 #include <cstdint> // uint8_t | |
204 #include <string> // string | |
205 | |
206 // #include <nlohmann/detail/macro_scope.hpp> | |
207 // __ _____ _____ _____ | |
208 // __| | __| | | | JSON for Modern C++ | |
209 // | | |__ | | | | | | version 3.11.2 | |
210 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
211 // | |
212 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
213 // SPDX-License-Identifier: MIT | |
214 | |
215 | |
216 | |
217 #include <utility> // declval, pair | |
218 // #include <nlohmann/detail/meta/detected.hpp> | |
219 // __ _____ _____ _____ | |
220 // __| | __| | | | JSON for Modern C++ | |
221 // | | |__ | | | | | | version 3.11.2 | |
222 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
223 // | |
224 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
225 // SPDX-License-Identifier: MIT | |
226 | |
227 | |
228 | |
229 #include <type_traits> | |
230 | |
231 // #include <nlohmann/detail/meta/void_t.hpp> | |
232 // __ _____ _____ _____ | |
233 // __| | __| | | | JSON for Modern C++ | |
234 // | | |__ | | | | | | version 3.11.2 | |
235 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
236 // | |
237 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
238 // SPDX-License-Identifier: MIT | |
239 | |
240 | |
241 | |
242 // #include <nlohmann/detail/abi_macros.hpp> | |
243 | |
244 | |
245 NLOHMANN_JSON_NAMESPACE_BEGIN | |
246 namespace detail | |
247 { | |
248 | |
249 template<typename ...Ts> struct make_void | |
250 { | |
251 using type = void; | |
252 }; | |
253 template<typename ...Ts> using void_t = typename make_void<Ts...>::type; | |
254 | |
255 } // namespace detail | |
256 NLOHMANN_JSON_NAMESPACE_END | |
257 | |
258 | |
259 NLOHMANN_JSON_NAMESPACE_BEGIN | |
260 namespace detail | |
261 { | |
262 | |
263 // https://en.cppreference.com/w/cpp/experimental/is_detected | |
264 struct nonesuch | |
265 { | |
266 nonesuch() = delete; | |
267 ~nonesuch() = delete; | |
268 nonesuch(nonesuch const&) = delete; | |
269 nonesuch(nonesuch const&&) = delete; | |
270 void operator=(nonesuch const&) = delete; | |
271 void operator=(nonesuch&&) = delete; | |
272 }; | |
273 | |
274 template<class Default, | |
275 class AlwaysVoid, | |
276 template<class...> class Op, | |
277 class... Args> | |
278 struct detector | |
279 { | |
280 using value_t = std::false_type; | |
281 using type = Default; | |
282 }; | |
283 | |
284 template<class Default, template<class...> class Op, class... Args> | |
285 struct detector<Default, void_t<Op<Args...>>, Op, Args...> | |
286 { | |
287 using value_t = std::true_type; | |
288 using type = Op<Args...>; | |
289 }; | |
290 | |
291 template<template<class...> class Op, class... Args> | |
292 using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; | |
293 | |
294 template<template<class...> class Op, class... Args> | |
295 struct is_detected_lazy : is_detected<Op, Args...> { }; | |
296 | |
297 template<template<class...> class Op, class... Args> | |
298 using detected_t = typename detector<nonesuch, void, Op, Args...>::type; | |
299 | |
300 template<class Default, template<class...> class Op, class... Args> | |
301 using detected_or = detector<Default, void, Op, Args...>; | |
302 | |
303 template<class Default, template<class...> class Op, class... Args> | |
304 using detected_or_t = typename detected_or<Default, Op, Args...>::type; | |
305 | |
306 template<class Expected, template<class...> class Op, class... Args> | |
307 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; | |
308 | |
309 template<class To, template<class...> class Op, class... Args> | |
310 using is_detected_convertible = | |
311 std::is_convertible<detected_t<Op, Args...>, To>; | |
312 | |
313 } // namespace detail | |
314 NLOHMANN_JSON_NAMESPACE_END | |
315 | |
316 // #include <nlohmann/thirdparty/hedley/hedley.hpp> | |
317 | |
318 | |
319 // __ _____ _____ _____ | |
320 // __| | __| | | | JSON for Modern C++ | |
321 // | | |__ | | | | | | version 3.11.2 | |
322 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
323 // | |
324 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
325 // SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com> | |
326 // SPDX-License-Identifier: MIT | |
327 | |
328 /* Hedley - https://nemequ.github.io/hedley | |
329 * Created by Evan Nemerson <evan@nemerson.com> | |
330 */ | |
331 | |
332 #if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) | |
333 #if defined(JSON_HEDLEY_VERSION) | |
334 #undef JSON_HEDLEY_VERSION | |
335 #endif | |
336 #define JSON_HEDLEY_VERSION 15 | |
337 | |
338 #if defined(JSON_HEDLEY_STRINGIFY_EX) | |
339 #undef JSON_HEDLEY_STRINGIFY_EX | |
340 #endif | |
341 #define JSON_HEDLEY_STRINGIFY_EX(x) #x | |
342 | |
343 #if defined(JSON_HEDLEY_STRINGIFY) | |
344 #undef JSON_HEDLEY_STRINGIFY | |
345 #endif | |
346 #define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) | |
347 | |
348 #if defined(JSON_HEDLEY_CONCAT_EX) | |
349 #undef JSON_HEDLEY_CONCAT_EX | |
350 #endif | |
351 #define JSON_HEDLEY_CONCAT_EX(a,b) a##b | |
352 | |
353 #if defined(JSON_HEDLEY_CONCAT) | |
354 #undef JSON_HEDLEY_CONCAT | |
355 #endif | |
356 #define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) | |
357 | |
358 #if defined(JSON_HEDLEY_CONCAT3_EX) | |
359 #undef JSON_HEDLEY_CONCAT3_EX | |
360 #endif | |
361 #define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c | |
362 | |
363 #if defined(JSON_HEDLEY_CONCAT3) | |
364 #undef JSON_HEDLEY_CONCAT3 | |
365 #endif | |
366 #define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) | |
367 | |
368 #if defined(JSON_HEDLEY_VERSION_ENCODE) | |
369 #undef JSON_HEDLEY_VERSION_ENCODE | |
370 #endif | |
371 #define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) | |
372 | |
373 #if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) | |
374 #undef JSON_HEDLEY_VERSION_DECODE_MAJOR | |
375 #endif | |
376 #define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) | |
377 | |
378 #if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) | |
379 #undef JSON_HEDLEY_VERSION_DECODE_MINOR | |
380 #endif | |
381 #define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) | |
382 | |
383 #if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) | |
384 #undef JSON_HEDLEY_VERSION_DECODE_REVISION | |
385 #endif | |
386 #define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) | |
387 | |
388 #if defined(JSON_HEDLEY_GNUC_VERSION) | |
389 #undef JSON_HEDLEY_GNUC_VERSION | |
390 #endif | |
391 #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) | |
392 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) | |
393 #elif defined(__GNUC__) | |
394 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) | |
395 #endif | |
396 | |
397 #if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) | |
398 #undef JSON_HEDLEY_GNUC_VERSION_CHECK | |
399 #endif | |
400 #if defined(JSON_HEDLEY_GNUC_VERSION) | |
401 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
402 #else | |
403 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) | |
404 #endif | |
405 | |
406 #if defined(JSON_HEDLEY_MSVC_VERSION) | |
407 #undef JSON_HEDLEY_MSVC_VERSION | |
408 #endif | |
409 #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) | |
410 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) | |
411 #elif defined(_MSC_FULL_VER) && !defined(__ICL) | |
412 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) | |
413 #elif defined(_MSC_VER) && !defined(__ICL) | |
414 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) | |
415 #endif | |
416 | |
417 #if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) | |
418 #undef JSON_HEDLEY_MSVC_VERSION_CHECK | |
419 #endif | |
420 #if !defined(JSON_HEDLEY_MSVC_VERSION) | |
421 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) | |
422 #elif defined(_MSC_VER) && (_MSC_VER >= 1400) | |
423 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) | |
424 #elif defined(_MSC_VER) && (_MSC_VER >= 1200) | |
425 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) | |
426 #else | |
427 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) | |
428 #endif | |
429 | |
430 #if defined(JSON_HEDLEY_INTEL_VERSION) | |
431 #undef JSON_HEDLEY_INTEL_VERSION | |
432 #endif | |
433 #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) | |
434 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) | |
435 #elif defined(__INTEL_COMPILER) && !defined(__ICL) | |
436 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) | |
437 #endif | |
438 | |
439 #if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) | |
440 #undef JSON_HEDLEY_INTEL_VERSION_CHECK | |
441 #endif | |
442 #if defined(JSON_HEDLEY_INTEL_VERSION) | |
443 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
444 #else | |
445 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) | |
446 #endif | |
447 | |
448 #if defined(JSON_HEDLEY_INTEL_CL_VERSION) | |
449 #undef JSON_HEDLEY_INTEL_CL_VERSION | |
450 #endif | |
451 #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) | |
452 #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) | |
453 #endif | |
454 | |
455 #if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) | |
456 #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK | |
457 #endif | |
458 #if defined(JSON_HEDLEY_INTEL_CL_VERSION) | |
459 #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
460 #else | |
461 #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) | |
462 #endif | |
463 | |
464 #if defined(JSON_HEDLEY_PGI_VERSION) | |
465 #undef JSON_HEDLEY_PGI_VERSION | |
466 #endif | |
467 #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) | |
468 #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) | |
469 #endif | |
470 | |
471 #if defined(JSON_HEDLEY_PGI_VERSION_CHECK) | |
472 #undef JSON_HEDLEY_PGI_VERSION_CHECK | |
473 #endif | |
474 #if defined(JSON_HEDLEY_PGI_VERSION) | |
475 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
476 #else | |
477 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) | |
478 #endif | |
479 | |
480 #if defined(JSON_HEDLEY_SUNPRO_VERSION) | |
481 #undef JSON_HEDLEY_SUNPRO_VERSION | |
482 #endif | |
483 #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) | |
484 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) | |
485 #elif defined(__SUNPRO_C) | |
486 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) | |
487 #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) | |
488 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) | |
489 #elif defined(__SUNPRO_CC) | |
490 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) | |
491 #endif | |
492 | |
493 #if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) | |
494 #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK | |
495 #endif | |
496 #if defined(JSON_HEDLEY_SUNPRO_VERSION) | |
497 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
498 #else | |
499 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) | |
500 #endif | |
501 | |
502 #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) | |
503 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION | |
504 #endif | |
505 #if defined(__EMSCRIPTEN__) | |
506 #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) | |
507 #endif | |
508 | |
509 #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) | |
510 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK | |
511 #endif | |
512 #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) | |
513 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
514 #else | |
515 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) | |
516 #endif | |
517 | |
518 #if defined(JSON_HEDLEY_ARM_VERSION) | |
519 #undef JSON_HEDLEY_ARM_VERSION | |
520 #endif | |
521 #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) | |
522 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) | |
523 #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) | |
524 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) | |
525 #endif | |
526 | |
527 #if defined(JSON_HEDLEY_ARM_VERSION_CHECK) | |
528 #undef JSON_HEDLEY_ARM_VERSION_CHECK | |
529 #endif | |
530 #if defined(JSON_HEDLEY_ARM_VERSION) | |
531 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
532 #else | |
533 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) | |
534 #endif | |
535 | |
536 #if defined(JSON_HEDLEY_IBM_VERSION) | |
537 #undef JSON_HEDLEY_IBM_VERSION | |
538 #endif | |
539 #if defined(__ibmxl__) | |
540 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) | |
541 #elif defined(__xlC__) && defined(__xlC_ver__) | |
542 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) | |
543 #elif defined(__xlC__) | |
544 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) | |
545 #endif | |
546 | |
547 #if defined(JSON_HEDLEY_IBM_VERSION_CHECK) | |
548 #undef JSON_HEDLEY_IBM_VERSION_CHECK | |
549 #endif | |
550 #if defined(JSON_HEDLEY_IBM_VERSION) | |
551 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
552 #else | |
553 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) | |
554 #endif | |
555 | |
556 #if defined(JSON_HEDLEY_TI_VERSION) | |
557 #undef JSON_HEDLEY_TI_VERSION | |
558 #endif | |
559 #if \ | |
560 defined(__TI_COMPILER_VERSION__) && \ | |
561 ( \ | |
562 defined(__TMS470__) || defined(__TI_ARM__) || \ | |
563 defined(__MSP430__) || \ | |
564 defined(__TMS320C2000__) \ | |
565 ) | |
566 #if (__TI_COMPILER_VERSION__ >= 16000000) | |
567 #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) | |
568 #endif | |
569 #endif | |
570 | |
571 #if defined(JSON_HEDLEY_TI_VERSION_CHECK) | |
572 #undef JSON_HEDLEY_TI_VERSION_CHECK | |
573 #endif | |
574 #if defined(JSON_HEDLEY_TI_VERSION) | |
575 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
576 #else | |
577 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) | |
578 #endif | |
579 | |
580 #if defined(JSON_HEDLEY_TI_CL2000_VERSION) | |
581 #undef JSON_HEDLEY_TI_CL2000_VERSION | |
582 #endif | |
583 #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) | |
584 #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) | |
585 #endif | |
586 | |
587 #if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) | |
588 #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK | |
589 #endif | |
590 #if defined(JSON_HEDLEY_TI_CL2000_VERSION) | |
591 #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
592 #else | |
593 #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) | |
594 #endif | |
595 | |
596 #if defined(JSON_HEDLEY_TI_CL430_VERSION) | |
597 #undef JSON_HEDLEY_TI_CL430_VERSION | |
598 #endif | |
599 #if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) | |
600 #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) | |
601 #endif | |
602 | |
603 #if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) | |
604 #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK | |
605 #endif | |
606 #if defined(JSON_HEDLEY_TI_CL430_VERSION) | |
607 #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
608 #else | |
609 #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) | |
610 #endif | |
611 | |
612 #if defined(JSON_HEDLEY_TI_ARMCL_VERSION) | |
613 #undef JSON_HEDLEY_TI_ARMCL_VERSION | |
614 #endif | |
615 #if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) | |
616 #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) | |
617 #endif | |
618 | |
619 #if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) | |
620 #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK | |
621 #endif | |
622 #if defined(JSON_HEDLEY_TI_ARMCL_VERSION) | |
623 #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
624 #else | |
625 #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) | |
626 #endif | |
627 | |
628 #if defined(JSON_HEDLEY_TI_CL6X_VERSION) | |
629 #undef JSON_HEDLEY_TI_CL6X_VERSION | |
630 #endif | |
631 #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) | |
632 #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) | |
633 #endif | |
634 | |
635 #if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) | |
636 #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK | |
637 #endif | |
638 #if defined(JSON_HEDLEY_TI_CL6X_VERSION) | |
639 #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
640 #else | |
641 #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) | |
642 #endif | |
643 | |
644 #if defined(JSON_HEDLEY_TI_CL7X_VERSION) | |
645 #undef JSON_HEDLEY_TI_CL7X_VERSION | |
646 #endif | |
647 #if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) | |
648 #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) | |
649 #endif | |
650 | |
651 #if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) | |
652 #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK | |
653 #endif | |
654 #if defined(JSON_HEDLEY_TI_CL7X_VERSION) | |
655 #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
656 #else | |
657 #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) | |
658 #endif | |
659 | |
660 #if defined(JSON_HEDLEY_TI_CLPRU_VERSION) | |
661 #undef JSON_HEDLEY_TI_CLPRU_VERSION | |
662 #endif | |
663 #if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) | |
664 #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) | |
665 #endif | |
666 | |
667 #if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) | |
668 #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK | |
669 #endif | |
670 #if defined(JSON_HEDLEY_TI_CLPRU_VERSION) | |
671 #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
672 #else | |
673 #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) | |
674 #endif | |
675 | |
676 #if defined(JSON_HEDLEY_CRAY_VERSION) | |
677 #undef JSON_HEDLEY_CRAY_VERSION | |
678 #endif | |
679 #if defined(_CRAYC) | |
680 #if defined(_RELEASE_PATCHLEVEL) | |
681 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) | |
682 #else | |
683 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) | |
684 #endif | |
685 #endif | |
686 | |
687 #if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) | |
688 #undef JSON_HEDLEY_CRAY_VERSION_CHECK | |
689 #endif | |
690 #if defined(JSON_HEDLEY_CRAY_VERSION) | |
691 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
692 #else | |
693 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) | |
694 #endif | |
695 | |
696 #if defined(JSON_HEDLEY_IAR_VERSION) | |
697 #undef JSON_HEDLEY_IAR_VERSION | |
698 #endif | |
699 #if defined(__IAR_SYSTEMS_ICC__) | |
700 #if __VER__ > 1000 | |
701 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) | |
702 #else | |
703 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) | |
704 #endif | |
705 #endif | |
706 | |
707 #if defined(JSON_HEDLEY_IAR_VERSION_CHECK) | |
708 #undef JSON_HEDLEY_IAR_VERSION_CHECK | |
709 #endif | |
710 #if defined(JSON_HEDLEY_IAR_VERSION) | |
711 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
712 #else | |
713 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) | |
714 #endif | |
715 | |
716 #if defined(JSON_HEDLEY_TINYC_VERSION) | |
717 #undef JSON_HEDLEY_TINYC_VERSION | |
718 #endif | |
719 #if defined(__TINYC__) | |
720 #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) | |
721 #endif | |
722 | |
723 #if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) | |
724 #undef JSON_HEDLEY_TINYC_VERSION_CHECK | |
725 #endif | |
726 #if defined(JSON_HEDLEY_TINYC_VERSION) | |
727 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
728 #else | |
729 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) | |
730 #endif | |
731 | |
732 #if defined(JSON_HEDLEY_DMC_VERSION) | |
733 #undef JSON_HEDLEY_DMC_VERSION | |
734 #endif | |
735 #if defined(__DMC__) | |
736 #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) | |
737 #endif | |
738 | |
739 #if defined(JSON_HEDLEY_DMC_VERSION_CHECK) | |
740 #undef JSON_HEDLEY_DMC_VERSION_CHECK | |
741 #endif | |
742 #if defined(JSON_HEDLEY_DMC_VERSION) | |
743 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
744 #else | |
745 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) | |
746 #endif | |
747 | |
748 #if defined(JSON_HEDLEY_COMPCERT_VERSION) | |
749 #undef JSON_HEDLEY_COMPCERT_VERSION | |
750 #endif | |
751 #if defined(__COMPCERT_VERSION__) | |
752 #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) | |
753 #endif | |
754 | |
755 #if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) | |
756 #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK | |
757 #endif | |
758 #if defined(JSON_HEDLEY_COMPCERT_VERSION) | |
759 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
760 #else | |
761 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) | |
762 #endif | |
763 | |
764 #if defined(JSON_HEDLEY_PELLES_VERSION) | |
765 #undef JSON_HEDLEY_PELLES_VERSION | |
766 #endif | |
767 #if defined(__POCC__) | |
768 #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) | |
769 #endif | |
770 | |
771 #if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) | |
772 #undef JSON_HEDLEY_PELLES_VERSION_CHECK | |
773 #endif | |
774 #if defined(JSON_HEDLEY_PELLES_VERSION) | |
775 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
776 #else | |
777 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) | |
778 #endif | |
779 | |
780 #if defined(JSON_HEDLEY_MCST_LCC_VERSION) | |
781 #undef JSON_HEDLEY_MCST_LCC_VERSION | |
782 #endif | |
783 #if defined(__LCC__) && defined(__LCC_MINOR__) | |
784 #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) | |
785 #endif | |
786 | |
787 #if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) | |
788 #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK | |
789 #endif | |
790 #if defined(JSON_HEDLEY_MCST_LCC_VERSION) | |
791 #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
792 #else | |
793 #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) | |
794 #endif | |
795 | |
796 #if defined(JSON_HEDLEY_GCC_VERSION) | |
797 #undef JSON_HEDLEY_GCC_VERSION | |
798 #endif | |
799 #if \ | |
800 defined(JSON_HEDLEY_GNUC_VERSION) && \ | |
801 !defined(__clang__) && \ | |
802 !defined(JSON_HEDLEY_INTEL_VERSION) && \ | |
803 !defined(JSON_HEDLEY_PGI_VERSION) && \ | |
804 !defined(JSON_HEDLEY_ARM_VERSION) && \ | |
805 !defined(JSON_HEDLEY_CRAY_VERSION) && \ | |
806 !defined(JSON_HEDLEY_TI_VERSION) && \ | |
807 !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ | |
808 !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ | |
809 !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ | |
810 !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ | |
811 !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ | |
812 !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ | |
813 !defined(__COMPCERT__) && \ | |
814 !defined(JSON_HEDLEY_MCST_LCC_VERSION) | |
815 #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION | |
816 #endif | |
817 | |
818 #if defined(JSON_HEDLEY_GCC_VERSION_CHECK) | |
819 #undef JSON_HEDLEY_GCC_VERSION_CHECK | |
820 #endif | |
821 #if defined(JSON_HEDLEY_GCC_VERSION) | |
822 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) | |
823 #else | |
824 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) | |
825 #endif | |
826 | |
827 #if defined(JSON_HEDLEY_HAS_ATTRIBUTE) | |
828 #undef JSON_HEDLEY_HAS_ATTRIBUTE | |
829 #endif | |
830 #if \ | |
831 defined(__has_attribute) && \ | |
832 ( \ | |
833 (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ | |
834 ) | |
835 # define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) | |
836 #else | |
837 # define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) | |
838 #endif | |
839 | |
840 #if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) | |
841 #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE | |
842 #endif | |
843 #if defined(__has_attribute) | |
844 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) | |
845 #else | |
846 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) | |
847 #endif | |
848 | |
849 #if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) | |
850 #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE | |
851 #endif | |
852 #if defined(__has_attribute) | |
853 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) | |
854 #else | |
855 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
856 #endif | |
857 | |
858 #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) | |
859 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE | |
860 #endif | |
861 #if \ | |
862 defined(__has_cpp_attribute) && \ | |
863 defined(__cplusplus) && \ | |
864 (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) | |
865 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) | |
866 #else | |
867 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) | |
868 #endif | |
869 | |
870 #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) | |
871 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS | |
872 #endif | |
873 #if !defined(__cplusplus) || !defined(__has_cpp_attribute) | |
874 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) | |
875 #elif \ | |
876 !defined(JSON_HEDLEY_PGI_VERSION) && \ | |
877 !defined(JSON_HEDLEY_IAR_VERSION) && \ | |
878 (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ | |
879 (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) | |
880 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) | |
881 #else | |
882 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) | |
883 #endif | |
884 | |
885 #if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) | |
886 #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE | |
887 #endif | |
888 #if defined(__has_cpp_attribute) && defined(__cplusplus) | |
889 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) | |
890 #else | |
891 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) | |
892 #endif | |
893 | |
894 #if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) | |
895 #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE | |
896 #endif | |
897 #if defined(__has_cpp_attribute) && defined(__cplusplus) | |
898 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) | |
899 #else | |
900 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
901 #endif | |
902 | |
903 #if defined(JSON_HEDLEY_HAS_BUILTIN) | |
904 #undef JSON_HEDLEY_HAS_BUILTIN | |
905 #endif | |
906 #if defined(__has_builtin) | |
907 #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) | |
908 #else | |
909 #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) | |
910 #endif | |
911 | |
912 #if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) | |
913 #undef JSON_HEDLEY_GNUC_HAS_BUILTIN | |
914 #endif | |
915 #if defined(__has_builtin) | |
916 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) | |
917 #else | |
918 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) | |
919 #endif | |
920 | |
921 #if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) | |
922 #undef JSON_HEDLEY_GCC_HAS_BUILTIN | |
923 #endif | |
924 #if defined(__has_builtin) | |
925 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) | |
926 #else | |
927 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
928 #endif | |
929 | |
930 #if defined(JSON_HEDLEY_HAS_FEATURE) | |
931 #undef JSON_HEDLEY_HAS_FEATURE | |
932 #endif | |
933 #if defined(__has_feature) | |
934 #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) | |
935 #else | |
936 #define JSON_HEDLEY_HAS_FEATURE(feature) (0) | |
937 #endif | |
938 | |
939 #if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) | |
940 #undef JSON_HEDLEY_GNUC_HAS_FEATURE | |
941 #endif | |
942 #if defined(__has_feature) | |
943 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) | |
944 #else | |
945 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) | |
946 #endif | |
947 | |
948 #if defined(JSON_HEDLEY_GCC_HAS_FEATURE) | |
949 #undef JSON_HEDLEY_GCC_HAS_FEATURE | |
950 #endif | |
951 #if defined(__has_feature) | |
952 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) | |
953 #else | |
954 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
955 #endif | |
956 | |
957 #if defined(JSON_HEDLEY_HAS_EXTENSION) | |
958 #undef JSON_HEDLEY_HAS_EXTENSION | |
959 #endif | |
960 #if defined(__has_extension) | |
961 #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) | |
962 #else | |
963 #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) | |
964 #endif | |
965 | |
966 #if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) | |
967 #undef JSON_HEDLEY_GNUC_HAS_EXTENSION | |
968 #endif | |
969 #if defined(__has_extension) | |
970 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) | |
971 #else | |
972 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) | |
973 #endif | |
974 | |
975 #if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) | |
976 #undef JSON_HEDLEY_GCC_HAS_EXTENSION | |
977 #endif | |
978 #if defined(__has_extension) | |
979 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) | |
980 #else | |
981 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
982 #endif | |
983 | |
984 #if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) | |
985 #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE | |
986 #endif | |
987 #if defined(__has_declspec_attribute) | |
988 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) | |
989 #else | |
990 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) | |
991 #endif | |
992 | |
993 #if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) | |
994 #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE | |
995 #endif | |
996 #if defined(__has_declspec_attribute) | |
997 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) | |
998 #else | |
999 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) | |
1000 #endif | |
1001 | |
1002 #if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) | |
1003 #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE | |
1004 #endif | |
1005 #if defined(__has_declspec_attribute) | |
1006 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) | |
1007 #else | |
1008 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
1009 #endif | |
1010 | |
1011 #if defined(JSON_HEDLEY_HAS_WARNING) | |
1012 #undef JSON_HEDLEY_HAS_WARNING | |
1013 #endif | |
1014 #if defined(__has_warning) | |
1015 #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) | |
1016 #else | |
1017 #define JSON_HEDLEY_HAS_WARNING(warning) (0) | |
1018 #endif | |
1019 | |
1020 #if defined(JSON_HEDLEY_GNUC_HAS_WARNING) | |
1021 #undef JSON_HEDLEY_GNUC_HAS_WARNING | |
1022 #endif | |
1023 #if defined(__has_warning) | |
1024 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) | |
1025 #else | |
1026 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) | |
1027 #endif | |
1028 | |
1029 #if defined(JSON_HEDLEY_GCC_HAS_WARNING) | |
1030 #undef JSON_HEDLEY_GCC_HAS_WARNING | |
1031 #endif | |
1032 #if defined(__has_warning) | |
1033 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) | |
1034 #else | |
1035 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
1036 #endif | |
1037 | |
1038 #if \ | |
1039 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ | |
1040 defined(__clang__) || \ | |
1041 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ | |
1042 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1043 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ | |
1044 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ | |
1045 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1046 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1047 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ | |
1048 JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ | |
1049 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ | |
1050 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ | |
1051 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1052 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1053 JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ | |
1054 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ | |
1055 JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ | |
1056 (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) | |
1057 #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) | |
1058 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) | |
1059 #define JSON_HEDLEY_PRAGMA(value) __pragma(value) | |
1060 #else | |
1061 #define JSON_HEDLEY_PRAGMA(value) | |
1062 #endif | |
1063 | |
1064 #if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) | |
1065 #undef JSON_HEDLEY_DIAGNOSTIC_PUSH | |
1066 #endif | |
1067 #if defined(JSON_HEDLEY_DIAGNOSTIC_POP) | |
1068 #undef JSON_HEDLEY_DIAGNOSTIC_POP | |
1069 #endif | |
1070 #if defined(__clang__) | |
1071 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") | |
1072 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") | |
1073 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) | |
1074 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") | |
1075 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") | |
1076 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) | |
1077 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") | |
1078 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") | |
1079 #elif \ | |
1080 JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ | |
1081 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1082 #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) | |
1083 #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) | |
1084 #elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) | |
1085 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") | |
1086 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") | |
1087 #elif \ | |
1088 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1089 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1090 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ | |
1091 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ | |
1092 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1093 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) | |
1094 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") | |
1095 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") | |
1096 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) | |
1097 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") | |
1098 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") | |
1099 #else | |
1100 #define JSON_HEDLEY_DIAGNOSTIC_PUSH | |
1101 #define JSON_HEDLEY_DIAGNOSTIC_POP | |
1102 #endif | |
1103 | |
1104 /* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for | |
1105 HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ | |
1106 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) | |
1107 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ | |
1108 #endif | |
1109 #if defined(__cplusplus) | |
1110 # if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") | |
1111 # if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") | |
1112 # if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") | |
1113 # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ | |
1114 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
1115 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ | |
1116 _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ | |
1117 _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ | |
1118 xpr \ | |
1119 JSON_HEDLEY_DIAGNOSTIC_POP | |
1120 # else | |
1121 # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ | |
1122 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
1123 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ | |
1124 _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ | |
1125 xpr \ | |
1126 JSON_HEDLEY_DIAGNOSTIC_POP | |
1127 # endif | |
1128 # else | |
1129 # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ | |
1130 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
1131 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ | |
1132 xpr \ | |
1133 JSON_HEDLEY_DIAGNOSTIC_POP | |
1134 # endif | |
1135 # endif | |
1136 #endif | |
1137 #if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) | |
1138 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x | |
1139 #endif | |
1140 | |
1141 #if defined(JSON_HEDLEY_CONST_CAST) | |
1142 #undef JSON_HEDLEY_CONST_CAST | |
1143 #endif | |
1144 #if defined(__cplusplus) | |
1145 # define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr)) | |
1146 #elif \ | |
1147 JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ | |
1148 JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ | |
1149 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) | |
1150 # define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ | |
1151 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
1152 JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ | |
1153 ((T) (expr)); \ | |
1154 JSON_HEDLEY_DIAGNOSTIC_POP \ | |
1155 })) | |
1156 #else | |
1157 # define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) | |
1158 #endif | |
1159 | |
1160 #if defined(JSON_HEDLEY_REINTERPRET_CAST) | |
1161 #undef JSON_HEDLEY_REINTERPRET_CAST | |
1162 #endif | |
1163 #if defined(__cplusplus) | |
1164 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr)) | |
1165 #else | |
1166 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) | |
1167 #endif | |
1168 | |
1169 #if defined(JSON_HEDLEY_STATIC_CAST) | |
1170 #undef JSON_HEDLEY_STATIC_CAST | |
1171 #endif | |
1172 #if defined(__cplusplus) | |
1173 #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr)) | |
1174 #else | |
1175 #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) | |
1176 #endif | |
1177 | |
1178 #if defined(JSON_HEDLEY_CPP_CAST) | |
1179 #undef JSON_HEDLEY_CPP_CAST | |
1180 #endif | |
1181 #if defined(__cplusplus) | |
1182 # if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") | |
1183 # define JSON_HEDLEY_CPP_CAST(T, expr) \ | |
1184 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
1185 _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ | |
1186 ((T) (expr)) \ | |
1187 JSON_HEDLEY_DIAGNOSTIC_POP | |
1188 # elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) | |
1189 # define JSON_HEDLEY_CPP_CAST(T, expr) \ | |
1190 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
1191 _Pragma("diag_suppress=Pe137") \ | |
1192 JSON_HEDLEY_DIAGNOSTIC_POP | |
1193 # else | |
1194 # define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) | |
1195 # endif | |
1196 #else | |
1197 # define JSON_HEDLEY_CPP_CAST(T, expr) (expr) | |
1198 #endif | |
1199 | |
1200 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) | |
1201 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED | |
1202 #endif | |
1203 #if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") | |
1204 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") | |
1205 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) | |
1206 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") | |
1207 #elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1208 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) | |
1209 #elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) | |
1210 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") | |
1211 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | |
1212 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") | |
1213 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) | |
1214 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") | |
1215 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) | |
1216 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) | |
1217 #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1218 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") | |
1219 #elif \ | |
1220 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1221 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1222 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1223 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1224 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1225 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1226 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1227 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1228 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1229 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1230 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) | |
1231 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") | |
1232 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) | |
1233 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") | |
1234 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) | |
1235 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") | |
1236 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
1237 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") | |
1238 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) | |
1239 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") | |
1240 #else | |
1241 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED | |
1242 #endif | |
1243 | |
1244 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) | |
1245 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS | |
1246 #endif | |
1247 #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") | |
1248 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") | |
1249 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) | |
1250 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") | |
1251 #elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1252 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) | |
1253 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | |
1254 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") | |
1255 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) | |
1256 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") | |
1257 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) | |
1258 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) | |
1259 #elif \ | |
1260 JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ | |
1261 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ | |
1262 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1263 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) | |
1264 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") | |
1265 #elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) | |
1266 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") | |
1267 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
1268 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") | |
1269 #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1270 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") | |
1271 #else | |
1272 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS | |
1273 #endif | |
1274 | |
1275 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) | |
1276 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES | |
1277 #endif | |
1278 #if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") | |
1279 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") | |
1280 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) | |
1281 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") | |
1282 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) | |
1283 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") | |
1284 #elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1285 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) | |
1286 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) | |
1287 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) | |
1288 #elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) | |
1289 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") | |
1290 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | |
1291 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") | |
1292 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) | |
1293 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") | |
1294 #elif \ | |
1295 JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ | |
1296 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ | |
1297 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) | |
1298 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") | |
1299 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
1300 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") | |
1301 #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1302 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") | |
1303 #else | |
1304 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES | |
1305 #endif | |
1306 | |
1307 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) | |
1308 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL | |
1309 #endif | |
1310 #if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") | |
1311 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") | |
1312 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) | |
1313 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") | |
1314 #elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) | |
1315 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") | |
1316 #else | |
1317 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL | |
1318 #endif | |
1319 | |
1320 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) | |
1321 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION | |
1322 #endif | |
1323 #if JSON_HEDLEY_HAS_WARNING("-Wunused-function") | |
1324 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") | |
1325 #elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) | |
1326 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") | |
1327 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) | |
1328 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) | |
1329 #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1330 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") | |
1331 #else | |
1332 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION | |
1333 #endif | |
1334 | |
1335 #if defined(JSON_HEDLEY_DEPRECATED) | |
1336 #undef JSON_HEDLEY_DEPRECATED | |
1337 #endif | |
1338 #if defined(JSON_HEDLEY_DEPRECATED_FOR) | |
1339 #undef JSON_HEDLEY_DEPRECATED_FOR | |
1340 #endif | |
1341 #if \ | |
1342 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ | |
1343 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1344 #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) | |
1345 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) | |
1346 #elif \ | |
1347 (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ | |
1348 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ | |
1349 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1350 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ | |
1351 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ | |
1352 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ | |
1353 JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ | |
1354 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ | |
1355 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ | |
1356 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1357 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ | |
1358 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1359 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) | |
1360 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) | |
1361 #elif defined(__cplusplus) && (__cplusplus >= 201402L) | |
1362 #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) | |
1363 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) | |
1364 #elif \ | |
1365 JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ | |
1366 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ | |
1367 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1368 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1369 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1370 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1371 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1372 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1373 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1374 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1375 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1376 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1377 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1378 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1379 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ | |
1380 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) | |
1381 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) | |
1382 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) | |
1383 #elif \ | |
1384 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ | |
1385 JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ | |
1386 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1387 #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) | |
1388 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) | |
1389 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
1390 #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") | |
1391 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") | |
1392 #else | |
1393 #define JSON_HEDLEY_DEPRECATED(since) | |
1394 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) | |
1395 #endif | |
1396 | |
1397 #if defined(JSON_HEDLEY_UNAVAILABLE) | |
1398 #undef JSON_HEDLEY_UNAVAILABLE | |
1399 #endif | |
1400 #if \ | |
1401 JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ | |
1402 JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ | |
1403 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1404 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1405 #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) | |
1406 #else | |
1407 #define JSON_HEDLEY_UNAVAILABLE(available_since) | |
1408 #endif | |
1409 | |
1410 #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) | |
1411 #undef JSON_HEDLEY_WARN_UNUSED_RESULT | |
1412 #endif | |
1413 #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) | |
1414 #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG | |
1415 #endif | |
1416 #if \ | |
1417 JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ | |
1418 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ | |
1419 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1420 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1421 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1422 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1423 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1424 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1425 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1426 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1427 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1428 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1429 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1430 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1431 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ | |
1432 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ | |
1433 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1434 #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) | |
1435 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) | |
1436 #elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) | |
1437 #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) | |
1438 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) | |
1439 #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) | |
1440 #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) | |
1441 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) | |
1442 #elif defined(_Check_return_) /* SAL */ | |
1443 #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ | |
1444 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ | |
1445 #else | |
1446 #define JSON_HEDLEY_WARN_UNUSED_RESULT | |
1447 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) | |
1448 #endif | |
1449 | |
1450 #if defined(JSON_HEDLEY_SENTINEL) | |
1451 #undef JSON_HEDLEY_SENTINEL | |
1452 #endif | |
1453 #if \ | |
1454 JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ | |
1455 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ | |
1456 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1457 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ | |
1458 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1459 #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) | |
1460 #else | |
1461 #define JSON_HEDLEY_SENTINEL(position) | |
1462 #endif | |
1463 | |
1464 #if defined(JSON_HEDLEY_NO_RETURN) | |
1465 #undef JSON_HEDLEY_NO_RETURN | |
1466 #endif | |
1467 #if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
1468 #define JSON_HEDLEY_NO_RETURN __noreturn | |
1469 #elif \ | |
1470 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1471 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1472 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) | |
1473 #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L | |
1474 #define JSON_HEDLEY_NO_RETURN _Noreturn | |
1475 #elif defined(__cplusplus) && (__cplusplus >= 201103L) | |
1476 #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) | |
1477 #elif \ | |
1478 JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ | |
1479 JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ | |
1480 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ | |
1481 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1482 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1483 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1484 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1485 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1486 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1487 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1488 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1489 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1490 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1491 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1492 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1493 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1494 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) | |
1495 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) | |
1496 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |
1497 #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") | |
1498 #elif \ | |
1499 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ | |
1500 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1501 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) | |
1502 #elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) | |
1503 #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") | |
1504 #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) | |
1505 #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) | |
1506 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) | |
1507 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) | |
1508 #else | |
1509 #define JSON_HEDLEY_NO_RETURN | |
1510 #endif | |
1511 | |
1512 #if defined(JSON_HEDLEY_NO_ESCAPE) | |
1513 #undef JSON_HEDLEY_NO_ESCAPE | |
1514 #endif | |
1515 #if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) | |
1516 #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) | |
1517 #else | |
1518 #define JSON_HEDLEY_NO_ESCAPE | |
1519 #endif | |
1520 | |
1521 #if defined(JSON_HEDLEY_UNREACHABLE) | |
1522 #undef JSON_HEDLEY_UNREACHABLE | |
1523 #endif | |
1524 #if defined(JSON_HEDLEY_UNREACHABLE_RETURN) | |
1525 #undef JSON_HEDLEY_UNREACHABLE_RETURN | |
1526 #endif | |
1527 #if defined(JSON_HEDLEY_ASSUME) | |
1528 #undef JSON_HEDLEY_ASSUME | |
1529 #endif | |
1530 #if \ | |
1531 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ | |
1532 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1533 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1534 #define JSON_HEDLEY_ASSUME(expr) __assume(expr) | |
1535 #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) | |
1536 #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) | |
1537 #elif \ | |
1538 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ | |
1539 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) | |
1540 #if defined(__cplusplus) | |
1541 #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) | |
1542 #else | |
1543 #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) | |
1544 #endif | |
1545 #endif | |
1546 #if \ | |
1547 (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ | |
1548 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ | |
1549 JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ | |
1550 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1551 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ | |
1552 JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ | |
1553 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1554 #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() | |
1555 #elif defined(JSON_HEDLEY_ASSUME) | |
1556 #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) | |
1557 #endif | |
1558 #if !defined(JSON_HEDLEY_ASSUME) | |
1559 #if defined(JSON_HEDLEY_UNREACHABLE) | |
1560 #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) | |
1561 #else | |
1562 #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) | |
1563 #endif | |
1564 #endif | |
1565 #if defined(JSON_HEDLEY_UNREACHABLE) | |
1566 #if \ | |
1567 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ | |
1568 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) | |
1569 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) | |
1570 #else | |
1571 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() | |
1572 #endif | |
1573 #else | |
1574 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) | |
1575 #endif | |
1576 #if !defined(JSON_HEDLEY_UNREACHABLE) | |
1577 #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) | |
1578 #endif | |
1579 | |
1580 JSON_HEDLEY_DIAGNOSTIC_PUSH | |
1581 #if JSON_HEDLEY_HAS_WARNING("-Wpedantic") | |
1582 #pragma clang diagnostic ignored "-Wpedantic" | |
1583 #endif | |
1584 #if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) | |
1585 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" | |
1586 #endif | |
1587 #if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) | |
1588 #if defined(__clang__) | |
1589 #pragma clang diagnostic ignored "-Wvariadic-macros" | |
1590 #elif defined(JSON_HEDLEY_GCC_VERSION) | |
1591 #pragma GCC diagnostic ignored "-Wvariadic-macros" | |
1592 #endif | |
1593 #endif | |
1594 #if defined(JSON_HEDLEY_NON_NULL) | |
1595 #undef JSON_HEDLEY_NON_NULL | |
1596 #endif | |
1597 #if \ | |
1598 JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ | |
1599 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ | |
1600 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1601 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) | |
1602 #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) | |
1603 #else | |
1604 #define JSON_HEDLEY_NON_NULL(...) | |
1605 #endif | |
1606 JSON_HEDLEY_DIAGNOSTIC_POP | |
1607 | |
1608 #if defined(JSON_HEDLEY_PRINTF_FORMAT) | |
1609 #undef JSON_HEDLEY_PRINTF_FORMAT | |
1610 #endif | |
1611 #if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) | |
1612 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) | |
1613 #elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) | |
1614 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) | |
1615 #elif \ | |
1616 JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ | |
1617 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ | |
1618 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1619 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ | |
1620 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1621 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1622 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1623 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1624 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1625 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1626 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1627 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1628 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1629 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1630 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1631 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1632 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1633 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) | |
1634 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) | |
1635 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) | |
1636 #else | |
1637 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) | |
1638 #endif | |
1639 | |
1640 #if defined(JSON_HEDLEY_CONSTEXPR) | |
1641 #undef JSON_HEDLEY_CONSTEXPR | |
1642 #endif | |
1643 #if defined(__cplusplus) | |
1644 #if __cplusplus >= 201103L | |
1645 #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) | |
1646 #endif | |
1647 #endif | |
1648 #if !defined(JSON_HEDLEY_CONSTEXPR) | |
1649 #define JSON_HEDLEY_CONSTEXPR | |
1650 #endif | |
1651 | |
1652 #if defined(JSON_HEDLEY_PREDICT) | |
1653 #undef JSON_HEDLEY_PREDICT | |
1654 #endif | |
1655 #if defined(JSON_HEDLEY_LIKELY) | |
1656 #undef JSON_HEDLEY_LIKELY | |
1657 #endif | |
1658 #if defined(JSON_HEDLEY_UNLIKELY) | |
1659 #undef JSON_HEDLEY_UNLIKELY | |
1660 #endif | |
1661 #if defined(JSON_HEDLEY_UNPREDICTABLE) | |
1662 #undef JSON_HEDLEY_UNPREDICTABLE | |
1663 #endif | |
1664 #if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) | |
1665 #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) | |
1666 #endif | |
1667 #if \ | |
1668 (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ | |
1669 JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ | |
1670 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1671 # define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) | |
1672 # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) | |
1673 # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) | |
1674 # define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) | |
1675 # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) | |
1676 #elif \ | |
1677 (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ | |
1678 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ | |
1679 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1680 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ | |
1681 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1682 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1683 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1684 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ | |
1685 JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ | |
1686 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ | |
1687 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ | |
1688 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1689 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1690 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ | |
1691 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ | |
1692 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1693 # define JSON_HEDLEY_PREDICT(expr, expected, probability) \ | |
1694 (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) | |
1695 # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ | |
1696 (__extension__ ({ \ | |
1697 double hedley_probability_ = (probability); \ | |
1698 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ | |
1699 })) | |
1700 # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ | |
1701 (__extension__ ({ \ | |
1702 double hedley_probability_ = (probability); \ | |
1703 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ | |
1704 })) | |
1705 # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) | |
1706 # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) | |
1707 #else | |
1708 # define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) | |
1709 # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) | |
1710 # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) | |
1711 # define JSON_HEDLEY_LIKELY(expr) (!!(expr)) | |
1712 # define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) | |
1713 #endif | |
1714 #if !defined(JSON_HEDLEY_UNPREDICTABLE) | |
1715 #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) | |
1716 #endif | |
1717 | |
1718 #if defined(JSON_HEDLEY_MALLOC) | |
1719 #undef JSON_HEDLEY_MALLOC | |
1720 #endif | |
1721 #if \ | |
1722 JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ | |
1723 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ | |
1724 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1725 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ | |
1726 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1727 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ | |
1728 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1729 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1730 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1731 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1732 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1733 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1734 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1735 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1736 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1737 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1738 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1739 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1740 #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) | |
1741 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |
1742 #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") | |
1743 #elif \ | |
1744 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ | |
1745 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1746 #define JSON_HEDLEY_MALLOC __declspec(restrict) | |
1747 #else | |
1748 #define JSON_HEDLEY_MALLOC | |
1749 #endif | |
1750 | |
1751 #if defined(JSON_HEDLEY_PURE) | |
1752 #undef JSON_HEDLEY_PURE | |
1753 #endif | |
1754 #if \ | |
1755 JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ | |
1756 JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ | |
1757 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1758 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ | |
1759 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1760 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1761 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1762 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1763 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1764 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1765 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1766 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1767 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1768 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1769 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1770 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1771 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1772 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ | |
1773 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1774 # define JSON_HEDLEY_PURE __attribute__((__pure__)) | |
1775 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |
1776 # define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") | |
1777 #elif defined(__cplusplus) && \ | |
1778 ( \ | |
1779 JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ | |
1780 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ | |
1781 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ | |
1782 ) | |
1783 # define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") | |
1784 #else | |
1785 # define JSON_HEDLEY_PURE | |
1786 #endif | |
1787 | |
1788 #if defined(JSON_HEDLEY_CONST) | |
1789 #undef JSON_HEDLEY_CONST | |
1790 #endif | |
1791 #if \ | |
1792 JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ | |
1793 JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ | |
1794 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1795 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ | |
1796 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1797 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1798 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1799 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1800 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1801 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1802 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1803 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1804 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1805 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1806 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1807 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1808 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1809 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ | |
1810 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1811 #define JSON_HEDLEY_CONST __attribute__((__const__)) | |
1812 #elif \ | |
1813 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |
1814 #define JSON_HEDLEY_CONST _Pragma("no_side_effect") | |
1815 #else | |
1816 #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE | |
1817 #endif | |
1818 | |
1819 #if defined(JSON_HEDLEY_RESTRICT) | |
1820 #undef JSON_HEDLEY_RESTRICT | |
1821 #endif | |
1822 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) | |
1823 #define JSON_HEDLEY_RESTRICT restrict | |
1824 #elif \ | |
1825 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ | |
1826 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ | |
1827 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1828 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ | |
1829 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1830 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1831 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ | |
1832 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1833 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ | |
1834 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ | |
1835 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1836 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ | |
1837 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ | |
1838 defined(__clang__) || \ | |
1839 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1840 #define JSON_HEDLEY_RESTRICT __restrict | |
1841 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) | |
1842 #define JSON_HEDLEY_RESTRICT _Restrict | |
1843 #else | |
1844 #define JSON_HEDLEY_RESTRICT | |
1845 #endif | |
1846 | |
1847 #if defined(JSON_HEDLEY_INLINE) | |
1848 #undef JSON_HEDLEY_INLINE | |
1849 #endif | |
1850 #if \ | |
1851 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ | |
1852 (defined(__cplusplus) && (__cplusplus >= 199711L)) | |
1853 #define JSON_HEDLEY_INLINE inline | |
1854 #elif \ | |
1855 defined(JSON_HEDLEY_GCC_VERSION) || \ | |
1856 JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) | |
1857 #define JSON_HEDLEY_INLINE __inline__ | |
1858 #elif \ | |
1859 JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ | |
1860 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ | |
1861 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1862 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ | |
1863 JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ | |
1864 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ | |
1865 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ | |
1866 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1867 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1868 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1869 #define JSON_HEDLEY_INLINE __inline | |
1870 #else | |
1871 #define JSON_HEDLEY_INLINE | |
1872 #endif | |
1873 | |
1874 #if defined(JSON_HEDLEY_ALWAYS_INLINE) | |
1875 #undef JSON_HEDLEY_ALWAYS_INLINE | |
1876 #endif | |
1877 #if \ | |
1878 JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ | |
1879 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ | |
1880 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1881 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ | |
1882 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1883 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1884 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1885 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1886 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1887 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1888 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1889 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1890 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1891 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1892 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1893 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1894 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1895 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ | |
1896 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) | |
1897 # define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE | |
1898 #elif \ | |
1899 JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ | |
1900 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1901 # define JSON_HEDLEY_ALWAYS_INLINE __forceinline | |
1902 #elif defined(__cplusplus) && \ | |
1903 ( \ | |
1904 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1905 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1906 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1907 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ | |
1908 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1909 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ | |
1910 ) | |
1911 # define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") | |
1912 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
1913 # define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") | |
1914 #else | |
1915 # define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE | |
1916 #endif | |
1917 | |
1918 #if defined(JSON_HEDLEY_NEVER_INLINE) | |
1919 #undef JSON_HEDLEY_NEVER_INLINE | |
1920 #endif | |
1921 #if \ | |
1922 JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ | |
1923 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ | |
1924 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1925 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ | |
1926 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1927 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ | |
1928 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ | |
1929 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1930 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ | |
1931 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1932 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ | |
1933 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1934 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ | |
1935 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1936 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ | |
1937 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ | |
1938 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ | |
1939 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ | |
1940 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) | |
1941 #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) | |
1942 #elif \ | |
1943 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ | |
1944 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
1945 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) | |
1946 #elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) | |
1947 #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") | |
1948 #elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) | |
1949 #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") | |
1950 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
1951 #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") | |
1952 #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) | |
1953 #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) | |
1954 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) | |
1955 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) | |
1956 #else | |
1957 #define JSON_HEDLEY_NEVER_INLINE | |
1958 #endif | |
1959 | |
1960 #if defined(JSON_HEDLEY_PRIVATE) | |
1961 #undef JSON_HEDLEY_PRIVATE | |
1962 #endif | |
1963 #if defined(JSON_HEDLEY_PUBLIC) | |
1964 #undef JSON_HEDLEY_PUBLIC | |
1965 #endif | |
1966 #if defined(JSON_HEDLEY_IMPORT) | |
1967 #undef JSON_HEDLEY_IMPORT | |
1968 #endif | |
1969 #if defined(_WIN32) || defined(__CYGWIN__) | |
1970 # define JSON_HEDLEY_PRIVATE | |
1971 # define JSON_HEDLEY_PUBLIC __declspec(dllexport) | |
1972 # define JSON_HEDLEY_IMPORT __declspec(dllimport) | |
1973 #else | |
1974 # if \ | |
1975 JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ | |
1976 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ | |
1977 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ | |
1978 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
1979 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
1980 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ | |
1981 ( \ | |
1982 defined(__TI_EABI__) && \ | |
1983 ( \ | |
1984 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | |
1985 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ | |
1986 ) \ | |
1987 ) || \ | |
1988 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
1989 # define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) | |
1990 # define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) | |
1991 # else | |
1992 # define JSON_HEDLEY_PRIVATE | |
1993 # define JSON_HEDLEY_PUBLIC | |
1994 # endif | |
1995 # define JSON_HEDLEY_IMPORT extern | |
1996 #endif | |
1997 | |
1998 #if defined(JSON_HEDLEY_NO_THROW) | |
1999 #undef JSON_HEDLEY_NO_THROW | |
2000 #endif | |
2001 #if \ | |
2002 JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ | |
2003 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ | |
2004 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
2005 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
2006 #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) | |
2007 #elif \ | |
2008 JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ | |
2009 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ | |
2010 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) | |
2011 #define JSON_HEDLEY_NO_THROW __declspec(nothrow) | |
2012 #else | |
2013 #define JSON_HEDLEY_NO_THROW | |
2014 #endif | |
2015 | |
2016 #if defined(JSON_HEDLEY_FALL_THROUGH) | |
2017 #undef JSON_HEDLEY_FALL_THROUGH | |
2018 #endif | |
2019 #if \ | |
2020 JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ | |
2021 JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ | |
2022 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
2023 #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) | |
2024 #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) | |
2025 #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) | |
2026 #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) | |
2027 #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) | |
2028 #elif defined(__fallthrough) /* SAL */ | |
2029 #define JSON_HEDLEY_FALL_THROUGH __fallthrough | |
2030 #else | |
2031 #define JSON_HEDLEY_FALL_THROUGH | |
2032 #endif | |
2033 | |
2034 #if defined(JSON_HEDLEY_RETURNS_NON_NULL) | |
2035 #undef JSON_HEDLEY_RETURNS_NON_NULL | |
2036 #endif | |
2037 #if \ | |
2038 JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ | |
2039 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ | |
2040 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
2041 #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) | |
2042 #elif defined(_Ret_notnull_) /* SAL */ | |
2043 #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ | |
2044 #else | |
2045 #define JSON_HEDLEY_RETURNS_NON_NULL | |
2046 #endif | |
2047 | |
2048 #if defined(JSON_HEDLEY_ARRAY_PARAM) | |
2049 #undef JSON_HEDLEY_ARRAY_PARAM | |
2050 #endif | |
2051 #if \ | |
2052 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ | |
2053 !defined(__STDC_NO_VLA__) && \ | |
2054 !defined(__cplusplus) && \ | |
2055 !defined(JSON_HEDLEY_PGI_VERSION) && \ | |
2056 !defined(JSON_HEDLEY_TINYC_VERSION) | |
2057 #define JSON_HEDLEY_ARRAY_PARAM(name) (name) | |
2058 #else | |
2059 #define JSON_HEDLEY_ARRAY_PARAM(name) | |
2060 #endif | |
2061 | |
2062 #if defined(JSON_HEDLEY_IS_CONSTANT) | |
2063 #undef JSON_HEDLEY_IS_CONSTANT | |
2064 #endif | |
2065 #if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) | |
2066 #undef JSON_HEDLEY_REQUIRE_CONSTEXPR | |
2067 #endif | |
2068 /* JSON_HEDLEY_IS_CONSTEXPR_ is for | |
2069 HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ | |
2070 #if defined(JSON_HEDLEY_IS_CONSTEXPR_) | |
2071 #undef JSON_HEDLEY_IS_CONSTEXPR_ | |
2072 #endif | |
2073 #if \ | |
2074 JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ | |
2075 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ | |
2076 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
2077 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ | |
2078 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | |
2079 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ | |
2080 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ | |
2081 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ | |
2082 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ | |
2083 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) | |
2084 #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) | |
2085 #endif | |
2086 #if !defined(__cplusplus) | |
2087 # if \ | |
2088 JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ | |
2089 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ | |
2090 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
2091 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ | |
2092 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ | |
2093 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ | |
2094 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) | |
2095 #if defined(__INTPTR_TYPE__) | |
2096 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) | |
2097 #else | |
2098 #include <stdint.h> | |
2099 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) | |
2100 #endif | |
2101 # elif \ | |
2102 ( \ | |
2103 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ | |
2104 !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ | |
2105 !defined(JSON_HEDLEY_PGI_VERSION) && \ | |
2106 !defined(JSON_HEDLEY_IAR_VERSION)) || \ | |
2107 (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ | |
2108 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ | |
2109 JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ | |
2110 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ | |
2111 JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) | |
2112 #if defined(__INTPTR_TYPE__) | |
2113 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) | |
2114 #else | |
2115 #include <stdint.h> | |
2116 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) | |
2117 #endif | |
2118 # elif \ | |
2119 defined(JSON_HEDLEY_GCC_VERSION) || \ | |
2120 defined(JSON_HEDLEY_INTEL_VERSION) || \ | |
2121 defined(JSON_HEDLEY_TINYC_VERSION) || \ | |
2122 defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ | |
2123 JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ | |
2124 defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ | |
2125 defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ | |
2126 defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ | |
2127 defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ | |
2128 defined(__clang__) | |
2129 # define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ | |
2130 sizeof(void) != \ | |
2131 sizeof(*( \ | |
2132 1 ? \ | |
2133 ((void*) ((expr) * 0L) ) : \ | |
2134 ((struct { char v[sizeof(void) * 2]; } *) 1) \ | |
2135 ) \ | |
2136 ) \ | |
2137 ) | |
2138 # endif | |
2139 #endif | |
2140 #if defined(JSON_HEDLEY_IS_CONSTEXPR_) | |
2141 #if !defined(JSON_HEDLEY_IS_CONSTANT) | |
2142 #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) | |
2143 #endif | |
2144 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) | |
2145 #else | |
2146 #if !defined(JSON_HEDLEY_IS_CONSTANT) | |
2147 #define JSON_HEDLEY_IS_CONSTANT(expr) (0) | |
2148 #endif | |
2149 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) | |
2150 #endif | |
2151 | |
2152 #if defined(JSON_HEDLEY_BEGIN_C_DECLS) | |
2153 #undef JSON_HEDLEY_BEGIN_C_DECLS | |
2154 #endif | |
2155 #if defined(JSON_HEDLEY_END_C_DECLS) | |
2156 #undef JSON_HEDLEY_END_C_DECLS | |
2157 #endif | |
2158 #if defined(JSON_HEDLEY_C_DECL) | |
2159 #undef JSON_HEDLEY_C_DECL | |
2160 #endif | |
2161 #if defined(__cplusplus) | |
2162 #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { | |
2163 #define JSON_HEDLEY_END_C_DECLS } | |
2164 #define JSON_HEDLEY_C_DECL extern "C" | |
2165 #else | |
2166 #define JSON_HEDLEY_BEGIN_C_DECLS | |
2167 #define JSON_HEDLEY_END_C_DECLS | |
2168 #define JSON_HEDLEY_C_DECL | |
2169 #endif | |
2170 | |
2171 #if defined(JSON_HEDLEY_STATIC_ASSERT) | |
2172 #undef JSON_HEDLEY_STATIC_ASSERT | |
2173 #endif | |
2174 #if \ | |
2175 !defined(__cplusplus) && ( \ | |
2176 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ | |
2177 (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ | |
2178 JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ | |
2179 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ | |
2180 defined(_Static_assert) \ | |
2181 ) | |
2182 # define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) | |
2183 #elif \ | |
2184 (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ | |
2185 JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ | |
2186 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
2187 # define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) | |
2188 #else | |
2189 # define JSON_HEDLEY_STATIC_ASSERT(expr, message) | |
2190 #endif | |
2191 | |
2192 #if defined(JSON_HEDLEY_NULL) | |
2193 #undef JSON_HEDLEY_NULL | |
2194 #endif | |
2195 #if defined(__cplusplus) | |
2196 #if __cplusplus >= 201103L | |
2197 #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) | |
2198 #elif defined(NULL) | |
2199 #define JSON_HEDLEY_NULL NULL | |
2200 #else | |
2201 #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) | |
2202 #endif | |
2203 #elif defined(NULL) | |
2204 #define JSON_HEDLEY_NULL NULL | |
2205 #else | |
2206 #define JSON_HEDLEY_NULL ((void*) 0) | |
2207 #endif | |
2208 | |
2209 #if defined(JSON_HEDLEY_MESSAGE) | |
2210 #undef JSON_HEDLEY_MESSAGE | |
2211 #endif | |
2212 #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") | |
2213 # define JSON_HEDLEY_MESSAGE(msg) \ | |
2214 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
2215 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ | |
2216 JSON_HEDLEY_PRAGMA(message msg) \ | |
2217 JSON_HEDLEY_DIAGNOSTIC_POP | |
2218 #elif \ | |
2219 JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ | |
2220 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) | |
2221 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) | |
2222 #elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) | |
2223 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) | |
2224 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | |
2225 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) | |
2226 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) | |
2227 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) | |
2228 #else | |
2229 # define JSON_HEDLEY_MESSAGE(msg) | |
2230 #endif | |
2231 | |
2232 #if defined(JSON_HEDLEY_WARNING) | |
2233 #undef JSON_HEDLEY_WARNING | |
2234 #endif | |
2235 #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") | |
2236 # define JSON_HEDLEY_WARNING(msg) \ | |
2237 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
2238 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ | |
2239 JSON_HEDLEY_PRAGMA(clang warning msg) \ | |
2240 JSON_HEDLEY_DIAGNOSTIC_POP | |
2241 #elif \ | |
2242 JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ | |
2243 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ | |
2244 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) | |
2245 # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) | |
2246 #elif \ | |
2247 JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ | |
2248 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
2249 # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) | |
2250 #else | |
2251 # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) | |
2252 #endif | |
2253 | |
2254 #if defined(JSON_HEDLEY_REQUIRE) | |
2255 #undef JSON_HEDLEY_REQUIRE | |
2256 #endif | |
2257 #if defined(JSON_HEDLEY_REQUIRE_MSG) | |
2258 #undef JSON_HEDLEY_REQUIRE_MSG | |
2259 #endif | |
2260 #if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) | |
2261 # if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") | |
2262 # define JSON_HEDLEY_REQUIRE(expr) \ | |
2263 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
2264 _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ | |
2265 __attribute__((diagnose_if(!(expr), #expr, "error"))) \ | |
2266 JSON_HEDLEY_DIAGNOSTIC_POP | |
2267 # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ | |
2268 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
2269 _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ | |
2270 __attribute__((diagnose_if(!(expr), msg, "error"))) \ | |
2271 JSON_HEDLEY_DIAGNOSTIC_POP | |
2272 # else | |
2273 # define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) | |
2274 # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) | |
2275 # endif | |
2276 #else | |
2277 # define JSON_HEDLEY_REQUIRE(expr) | |
2278 # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) | |
2279 #endif | |
2280 | |
2281 #if defined(JSON_HEDLEY_FLAGS) | |
2282 #undef JSON_HEDLEY_FLAGS | |
2283 #endif | |
2284 #if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) | |
2285 #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) | |
2286 #else | |
2287 #define JSON_HEDLEY_FLAGS | |
2288 #endif | |
2289 | |
2290 #if defined(JSON_HEDLEY_FLAGS_CAST) | |
2291 #undef JSON_HEDLEY_FLAGS_CAST | |
2292 #endif | |
2293 #if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) | |
2294 # define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ | |
2295 JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |
2296 _Pragma("warning(disable:188)") \ | |
2297 ((T) (expr)); \ | |
2298 JSON_HEDLEY_DIAGNOSTIC_POP \ | |
2299 })) | |
2300 #else | |
2301 # define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) | |
2302 #endif | |
2303 | |
2304 #if defined(JSON_HEDLEY_EMPTY_BASES) | |
2305 #undef JSON_HEDLEY_EMPTY_BASES | |
2306 #endif | |
2307 #if \ | |
2308 (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ | |
2309 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) | |
2310 #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) | |
2311 #else | |
2312 #define JSON_HEDLEY_EMPTY_BASES | |
2313 #endif | |
2314 | |
2315 /* Remaining macros are deprecated. */ | |
2316 | |
2317 #if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) | |
2318 #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK | |
2319 #endif | |
2320 #if defined(__clang__) | |
2321 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) | |
2322 #else | |
2323 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | |
2324 #endif | |
2325 | |
2326 #if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) | |
2327 #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE | |
2328 #endif | |
2329 #define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) | |
2330 | |
2331 #if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) | |
2332 #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE | |
2333 #endif | |
2334 #define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) | |
2335 | |
2336 #if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) | |
2337 #undef JSON_HEDLEY_CLANG_HAS_BUILTIN | |
2338 #endif | |
2339 #define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) | |
2340 | |
2341 #if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) | |
2342 #undef JSON_HEDLEY_CLANG_HAS_FEATURE | |
2343 #endif | |
2344 #define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) | |
2345 | |
2346 #if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) | |
2347 #undef JSON_HEDLEY_CLANG_HAS_EXTENSION | |
2348 #endif | |
2349 #define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) | |
2350 | |
2351 #if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) | |
2352 #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE | |
2353 #endif | |
2354 #define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) | |
2355 | |
2356 #if defined(JSON_HEDLEY_CLANG_HAS_WARNING) | |
2357 #undef JSON_HEDLEY_CLANG_HAS_WARNING | |
2358 #endif | |
2359 #define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) | |
2360 | |
2361 #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ | |
2362 | |
2363 | |
2364 // This file contains all internal macro definitions (except those affecting ABI) | |
2365 // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them | |
2366 | |
2367 // #include <nlohmann/detail/abi_macros.hpp> | |
2368 | |
2369 | |
2370 // exclude unsupported compilers | |
2371 #if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) | |
2372 #if defined(__clang__) | |
2373 #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 | |
2374 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" | |
2375 #endif | |
2376 #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) | |
2377 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 | |
2378 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" | |
2379 #endif | |
2380 #endif | |
2381 #endif | |
2382 | |
2383 // C++ language standard detection | |
2384 // if the user manually specified the used c++ version this is skipped | |
2385 #if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) | |
2386 #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) | |
2387 #define JSON_HAS_CPP_20 | |
2388 #define JSON_HAS_CPP_17 | |
2389 #define JSON_HAS_CPP_14 | |
2390 #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 | |
2391 #define JSON_HAS_CPP_17 | |
2392 #define JSON_HAS_CPP_14 | |
2393 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) | |
2394 #define JSON_HAS_CPP_14 | |
2395 #endif | |
2396 // the cpp 11 flag is always specified because it is the minimal required version | |
2397 #define JSON_HAS_CPP_11 | |
2398 #endif | |
2399 | |
2400 #ifdef __has_include | |
2401 #if __has_include(<version>) | |
2402 #include <version> | |
2403 #endif | |
2404 #endif | |
2405 | |
2406 #if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) | |
2407 #ifdef JSON_HAS_CPP_17 | |
2408 #if defined(__cpp_lib_filesystem) | |
2409 #define JSON_HAS_FILESYSTEM 1 | |
2410 #elif defined(__cpp_lib_experimental_filesystem) | |
2411 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 | |
2412 #elif !defined(__has_include) | |
2413 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 | |
2414 #elif __has_include(<filesystem>) | |
2415 #define JSON_HAS_FILESYSTEM 1 | |
2416 #elif __has_include(<experimental/filesystem>) | |
2417 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 | |
2418 #endif | |
2419 | |
2420 // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ | |
2421 #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 | |
2422 #undef JSON_HAS_FILESYSTEM | |
2423 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
2424 #endif | |
2425 | |
2426 // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support | |
2427 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 | |
2428 #undef JSON_HAS_FILESYSTEM | |
2429 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
2430 #endif | |
2431 | |
2432 // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support | |
2433 #if defined(__clang_major__) && __clang_major__ < 7 | |
2434 #undef JSON_HAS_FILESYSTEM | |
2435 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
2436 #endif | |
2437 | |
2438 // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support | |
2439 #if defined(_MSC_VER) && _MSC_VER < 1914 | |
2440 #undef JSON_HAS_FILESYSTEM | |
2441 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
2442 #endif | |
2443 | |
2444 // no filesystem support before iOS 13 | |
2445 #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 | |
2446 #undef JSON_HAS_FILESYSTEM | |
2447 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
2448 #endif | |
2449 | |
2450 // no filesystem support before macOS Catalina | |
2451 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 | |
2452 #undef JSON_HAS_FILESYSTEM | |
2453 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
2454 #endif | |
2455 #endif | |
2456 #endif | |
2457 | |
2458 #ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
2459 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 | |
2460 #endif | |
2461 | |
2462 #ifndef JSON_HAS_FILESYSTEM | |
2463 #define JSON_HAS_FILESYSTEM 0 | |
2464 #endif | |
2465 | |
2466 #ifndef JSON_HAS_THREE_WAY_COMPARISON | |
2467 #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ | |
2468 && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L | |
2469 #define JSON_HAS_THREE_WAY_COMPARISON 1 | |
2470 #else | |
2471 #define JSON_HAS_THREE_WAY_COMPARISON 0 | |
2472 #endif | |
2473 #endif | |
2474 | |
2475 #ifndef JSON_HAS_RANGES | |
2476 // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error | |
2477 #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 | |
2478 #define JSON_HAS_RANGES 0 | |
2479 #elif defined(__cpp_lib_ranges) | |
2480 #define JSON_HAS_RANGES 1 | |
2481 #else | |
2482 #define JSON_HAS_RANGES 0 | |
2483 #endif | |
2484 #endif | |
2485 | |
2486 #ifdef JSON_HAS_CPP_17 | |
2487 #define JSON_INLINE_VARIABLE inline | |
2488 #else | |
2489 #define JSON_INLINE_VARIABLE | |
2490 #endif | |
2491 | |
2492 #if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) | |
2493 #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] | |
2494 #else | |
2495 #define JSON_NO_UNIQUE_ADDRESS | |
2496 #endif | |
2497 | |
2498 // disable documentation warnings on clang | |
2499 #if defined(__clang__) | |
2500 #pragma clang diagnostic push | |
2501 #pragma clang diagnostic ignored "-Wdocumentation" | |
2502 #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" | |
2503 #endif | |
2504 | |
2505 // allow disabling exceptions | |
2506 #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) | |
2507 #define JSON_THROW(exception) throw exception | |
2508 #define JSON_TRY try | |
2509 #define JSON_CATCH(exception) catch(exception) | |
2510 #define JSON_INTERNAL_CATCH(exception) catch(exception) | |
2511 #else | |
2512 #include <cstdlib> | |
2513 #define JSON_THROW(exception) std::abort() | |
2514 #define JSON_TRY if(true) | |
2515 #define JSON_CATCH(exception) if(false) | |
2516 #define JSON_INTERNAL_CATCH(exception) if(false) | |
2517 #endif | |
2518 | |
2519 // override exception macros | |
2520 #if defined(JSON_THROW_USER) | |
2521 #undef JSON_THROW | |
2522 #define JSON_THROW JSON_THROW_USER | |
2523 #endif | |
2524 #if defined(JSON_TRY_USER) | |
2525 #undef JSON_TRY | |
2526 #define JSON_TRY JSON_TRY_USER | |
2527 #endif | |
2528 #if defined(JSON_CATCH_USER) | |
2529 #undef JSON_CATCH | |
2530 #define JSON_CATCH JSON_CATCH_USER | |
2531 #undef JSON_INTERNAL_CATCH | |
2532 #define JSON_INTERNAL_CATCH JSON_CATCH_USER | |
2533 #endif | |
2534 #if defined(JSON_INTERNAL_CATCH_USER) | |
2535 #undef JSON_INTERNAL_CATCH | |
2536 #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER | |
2537 #endif | |
2538 | |
2539 // allow overriding assert | |
2540 #if !defined(JSON_ASSERT) | |
2541 #include <cassert> // assert | |
2542 #define JSON_ASSERT(x) assert(x) | |
2543 #endif | |
2544 | |
2545 // allow to access some private functions (needed by the test suite) | |
2546 #if defined(JSON_TESTS_PRIVATE) | |
2547 #define JSON_PRIVATE_UNLESS_TESTED public | |
2548 #else | |
2549 #define JSON_PRIVATE_UNLESS_TESTED private | |
2550 #endif | |
2551 | |
2552 /*! | |
2553 @brief macro to briefly define a mapping between an enum and JSON | |
2554 @def NLOHMANN_JSON_SERIALIZE_ENUM | |
2555 @since version 3.4.0 | |
2556 */ | |
2557 #define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ | |
2558 template<typename BasicJsonType> \ | |
2559 inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ | |
2560 { \ | |
2561 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ | |
2562 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ | |
2563 auto it = std::find_if(std::begin(m), std::end(m), \ | |
2564 [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ | |
2565 { \ | |
2566 return ej_pair.first == e; \ | |
2567 }); \ | |
2568 j = ((it != std::end(m)) ? it : std::begin(m))->second; \ | |
2569 } \ | |
2570 template<typename BasicJsonType> \ | |
2571 inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ | |
2572 { \ | |
2573 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ | |
2574 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ | |
2575 auto it = std::find_if(std::begin(m), std::end(m), \ | |
2576 [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ | |
2577 { \ | |
2578 return ej_pair.second == j; \ | |
2579 }); \ | |
2580 e = ((it != std::end(m)) ? it : std::begin(m))->first; \ | |
2581 } | |
2582 | |
2583 // Ugly macros to avoid uglier copy-paste when specializing basic_json. They | |
2584 // may be removed in the future once the class is split. | |
2585 | |
2586 #define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ | |
2587 template<template<typename, typename, typename...> class ObjectType, \ | |
2588 template<typename, typename...> class ArrayType, \ | |
2589 class StringType, class BooleanType, class NumberIntegerType, \ | |
2590 class NumberUnsignedType, class NumberFloatType, \ | |
2591 template<typename> class AllocatorType, \ | |
2592 template<typename, typename = void> class JSONSerializer, \ | |
2593 class BinaryType> | |
2594 | |
2595 #define NLOHMANN_BASIC_JSON_TPL \ | |
2596 basic_json<ObjectType, ArrayType, StringType, BooleanType, \ | |
2597 NumberIntegerType, NumberUnsignedType, NumberFloatType, \ | |
2598 AllocatorType, JSONSerializer, BinaryType> | |
2599 | |
2600 // Macros to simplify conversion from/to types | |
2601 | |
2602 #define NLOHMANN_JSON_EXPAND( x ) x | |
2603 #define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME | |
2604 #define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ | |
2605 NLOHMANN_JSON_PASTE64, \ | |
2606 NLOHMANN_JSON_PASTE63, \ | |
2607 NLOHMANN_JSON_PASTE62, \ | |
2608 NLOHMANN_JSON_PASTE61, \ | |
2609 NLOHMANN_JSON_PASTE60, \ | |
2610 NLOHMANN_JSON_PASTE59, \ | |
2611 NLOHMANN_JSON_PASTE58, \ | |
2612 NLOHMANN_JSON_PASTE57, \ | |
2613 NLOHMANN_JSON_PASTE56, \ | |
2614 NLOHMANN_JSON_PASTE55, \ | |
2615 NLOHMANN_JSON_PASTE54, \ | |
2616 NLOHMANN_JSON_PASTE53, \ | |
2617 NLOHMANN_JSON_PASTE52, \ | |
2618 NLOHMANN_JSON_PASTE51, \ | |
2619 NLOHMANN_JSON_PASTE50, \ | |
2620 NLOHMANN_JSON_PASTE49, \ | |
2621 NLOHMANN_JSON_PASTE48, \ | |
2622 NLOHMANN_JSON_PASTE47, \ | |
2623 NLOHMANN_JSON_PASTE46, \ | |
2624 NLOHMANN_JSON_PASTE45, \ | |
2625 NLOHMANN_JSON_PASTE44, \ | |
2626 NLOHMANN_JSON_PASTE43, \ | |
2627 NLOHMANN_JSON_PASTE42, \ | |
2628 NLOHMANN_JSON_PASTE41, \ | |
2629 NLOHMANN_JSON_PASTE40, \ | |
2630 NLOHMANN_JSON_PASTE39, \ | |
2631 NLOHMANN_JSON_PASTE38, \ | |
2632 NLOHMANN_JSON_PASTE37, \ | |
2633 NLOHMANN_JSON_PASTE36, \ | |
2634 NLOHMANN_JSON_PASTE35, \ | |
2635 NLOHMANN_JSON_PASTE34, \ | |
2636 NLOHMANN_JSON_PASTE33, \ | |
2637 NLOHMANN_JSON_PASTE32, \ | |
2638 NLOHMANN_JSON_PASTE31, \ | |
2639 NLOHMANN_JSON_PASTE30, \ | |
2640 NLOHMANN_JSON_PASTE29, \ | |
2641 NLOHMANN_JSON_PASTE28, \ | |
2642 NLOHMANN_JSON_PASTE27, \ | |
2643 NLOHMANN_JSON_PASTE26, \ | |
2644 NLOHMANN_JSON_PASTE25, \ | |
2645 NLOHMANN_JSON_PASTE24, \ | |
2646 NLOHMANN_JSON_PASTE23, \ | |
2647 NLOHMANN_JSON_PASTE22, \ | |
2648 NLOHMANN_JSON_PASTE21, \ | |
2649 NLOHMANN_JSON_PASTE20, \ | |
2650 NLOHMANN_JSON_PASTE19, \ | |
2651 NLOHMANN_JSON_PASTE18, \ | |
2652 NLOHMANN_JSON_PASTE17, \ | |
2653 NLOHMANN_JSON_PASTE16, \ | |
2654 NLOHMANN_JSON_PASTE15, \ | |
2655 NLOHMANN_JSON_PASTE14, \ | |
2656 NLOHMANN_JSON_PASTE13, \ | |
2657 NLOHMANN_JSON_PASTE12, \ | |
2658 NLOHMANN_JSON_PASTE11, \ | |
2659 NLOHMANN_JSON_PASTE10, \ | |
2660 NLOHMANN_JSON_PASTE9, \ | |
2661 NLOHMANN_JSON_PASTE8, \ | |
2662 NLOHMANN_JSON_PASTE7, \ | |
2663 NLOHMANN_JSON_PASTE6, \ | |
2664 NLOHMANN_JSON_PASTE5, \ | |
2665 NLOHMANN_JSON_PASTE4, \ | |
2666 NLOHMANN_JSON_PASTE3, \ | |
2667 NLOHMANN_JSON_PASTE2, \ | |
2668 NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) | |
2669 #define NLOHMANN_JSON_PASTE2(func, v1) func(v1) | |
2670 #define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) | |
2671 #define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) | |
2672 #define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) | |
2673 #define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) | |
2674 #define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) | |
2675 #define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) | |
2676 #define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) | |
2677 #define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) | |
2678 #define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) | |
2679 #define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) | |
2680 #define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) | |
2681 #define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) | |
2682 #define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) | |
2683 #define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) | |
2684 #define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) | |
2685 #define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) | |
2686 #define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) | |
2687 #define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) | |
2688 #define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) | |
2689 #define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) | |
2690 #define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) | |
2691 #define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) | |
2692 #define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) | |
2693 #define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) | |
2694 #define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) | |
2695 #define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) | |
2696 #define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) | |
2697 #define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) | |
2698 #define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) | |
2699 #define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) | |
2700 #define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) | |
2701 #define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) | |
2702 #define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) | |
2703 #define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) | |
2704 #define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) | |
2705 #define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) | |
2706 #define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) | |
2707 #define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) | |
2708 #define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) | |
2709 #define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) | |
2710 #define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) | |
2711 #define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) | |
2712 #define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) | |
2713 #define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) | |
2714 #define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) | |
2715 #define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) | |
2716 #define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) | |
2717 #define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) | |
2718 #define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) | |
2719 #define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) | |
2720 #define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) | |
2721 #define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) | |
2722 #define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) | |
2723 #define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) | |
2724 #define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) | |
2725 #define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) | |
2726 #define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) | |
2727 #define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) | |
2728 #define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) | |
2729 #define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) | |
2730 #define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) | |
2731 #define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) | |
2732 | |
2733 #define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; | |
2734 #define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); | |
2735 #define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); | |
2736 | |
2737 /*! | |
2738 @brief macro | |
2739 @def NLOHMANN_DEFINE_TYPE_INTRUSIVE | |
2740 @since version 3.9.0 | |
2741 */ | |
2742 #define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ | |
2743 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |
2744 friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } | |
2745 | |
2746 #define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ | |
2747 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |
2748 friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } | |
2749 | |
2750 /*! | |
2751 @brief macro | |
2752 @def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE | |
2753 @since version 3.9.0 | |
2754 */ | |
2755 #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ | |
2756 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |
2757 inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } | |
2758 | |
2759 #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ | |
2760 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ | |
2761 inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } | |
2762 | |
2763 | |
2764 // inspired from https://stackoverflow.com/a/26745591 | |
2765 // allows to call any std function as if (e.g. with begin): | |
2766 // using std::begin; begin(x); | |
2767 // | |
2768 // it allows using the detected idiom to retrieve the return type | |
2769 // of such an expression | |
2770 #define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ | |
2771 namespace detail { \ | |
2772 using std::std_name; \ | |
2773 \ | |
2774 template<typename... T> \ | |
2775 using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ | |
2776 } \ | |
2777 \ | |
2778 namespace detail2 { \ | |
2779 struct std_name##_tag \ | |
2780 { \ | |
2781 }; \ | |
2782 \ | |
2783 template<typename... T> \ | |
2784 std_name##_tag std_name(T&&...); \ | |
2785 \ | |
2786 template<typename... T> \ | |
2787 using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ | |
2788 \ | |
2789 template<typename... T> \ | |
2790 struct would_call_std_##std_name \ | |
2791 { \ | |
2792 static constexpr auto const value = ::nlohmann::detail:: \ | |
2793 is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \ | |
2794 }; \ | |
2795 } /* namespace detail2 */ \ | |
2796 \ | |
2797 template<typename... T> \ | |
2798 struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \ | |
2799 { \ | |
2800 } | |
2801 | |
2802 #ifndef JSON_USE_IMPLICIT_CONVERSIONS | |
2803 #define JSON_USE_IMPLICIT_CONVERSIONS 1 | |
2804 #endif | |
2805 | |
2806 #if JSON_USE_IMPLICIT_CONVERSIONS | |
2807 #define JSON_EXPLICIT | |
2808 #else | |
2809 #define JSON_EXPLICIT explicit | |
2810 #endif | |
2811 | |
2812 #ifndef JSON_DISABLE_ENUM_SERIALIZATION | |
2813 #define JSON_DISABLE_ENUM_SERIALIZATION 0 | |
2814 #endif | |
2815 | |
2816 #ifndef JSON_USE_GLOBAL_UDLS | |
2817 #define JSON_USE_GLOBAL_UDLS 1 | |
2818 #endif | |
2819 | |
2820 #if JSON_HAS_THREE_WAY_COMPARISON | |
2821 #include <compare> // partial_ordering | |
2822 #endif | |
2823 | |
2824 NLOHMANN_JSON_NAMESPACE_BEGIN | |
2825 namespace detail | |
2826 { | |
2827 | |
2828 /////////////////////////// | |
2829 // JSON type enumeration // | |
2830 /////////////////////////// | |
2831 | |
2832 /*! | |
2833 @brief the JSON type enumeration | |
2834 | |
2835 This enumeration collects the different JSON types. It is internally used to | |
2836 distinguish the stored values, and the functions @ref basic_json::is_null(), | |
2837 @ref basic_json::is_object(), @ref basic_json::is_array(), | |
2838 @ref basic_json::is_string(), @ref basic_json::is_boolean(), | |
2839 @ref basic_json::is_number() (with @ref basic_json::is_number_integer(), | |
2840 @ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), | |
2841 @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and | |
2842 @ref basic_json::is_structured() rely on it. | |
2843 | |
2844 @note There are three enumeration entries (number_integer, number_unsigned, and | |
2845 number_float), because the library distinguishes these three types for numbers: | |
2846 @ref basic_json::number_unsigned_t is used for unsigned integers, | |
2847 @ref basic_json::number_integer_t is used for signed integers, and | |
2848 @ref basic_json::number_float_t is used for floating-point numbers or to | |
2849 approximate integers which do not fit in the limits of their respective type. | |
2850 | |
2851 @sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON | |
2852 value with the default value for a given type | |
2853 | |
2854 @since version 1.0.0 | |
2855 */ | |
2856 enum class value_t : std::uint8_t | |
2857 { | |
2858 null, ///< null value | |
2859 object, ///< object (unordered set of name/value pairs) | |
2860 array, ///< array (ordered collection of values) | |
2861 string, ///< string value | |
2862 boolean, ///< boolean value | |
2863 number_integer, ///< number value (signed integer) | |
2864 number_unsigned, ///< number value (unsigned integer) | |
2865 number_float, ///< number value (floating-point) | |
2866 binary, ///< binary array (ordered collection of bytes) | |
2867 discarded ///< discarded by the parser callback function | |
2868 }; | |
2869 | |
2870 /*! | |
2871 @brief comparison operator for JSON types | |
2872 | |
2873 Returns an ordering that is similar to Python: | |
2874 - order: null < boolean < number < object < array < string < binary | |
2875 - furthermore, each type is not smaller than itself | |
2876 - discarded values are not comparable | |
2877 - binary is represented as a b"" string in python and directly comparable to a | |
2878 string; however, making a binary array directly comparable with a string would | |
2879 be surprising behavior in a JSON file. | |
2880 | |
2881 @since version 1.0.0 | |
2882 */ | |
2883 #if JSON_HAS_THREE_WAY_COMPARISON | |
2884 inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* | |
2885 #else | |
2886 inline bool operator<(const value_t lhs, const value_t rhs) noexcept | |
2887 #endif | |
2888 { | |
2889 static constexpr std::array<std::uint8_t, 9> order = {{ | |
2890 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, | |
2891 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, | |
2892 6 /* binary */ | |
2893 } | |
2894 }; | |
2895 | |
2896 const auto l_index = static_cast<std::size_t>(lhs); | |
2897 const auto r_index = static_cast<std::size_t>(rhs); | |
2898 #if JSON_HAS_THREE_WAY_COMPARISON | |
2899 if (l_index < order.size() && r_index < order.size()) | |
2900 { | |
2901 return order[l_index] <=> order[r_index]; // *NOPAD* | |
2902 } | |
2903 return std::partial_ordering::unordered; | |
2904 #else | |
2905 return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; | |
2906 #endif | |
2907 } | |
2908 | |
2909 // GCC selects the built-in operator< over an operator rewritten from | |
2910 // a user-defined spaceship operator | |
2911 // Clang, MSVC, and ICC select the rewritten candidate | |
2912 // (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) | |
2913 #if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) | |
2914 inline bool operator<(const value_t lhs, const value_t rhs) noexcept | |
2915 { | |
2916 return std::is_lt(lhs <=> rhs); // *NOPAD* | |
2917 } | |
2918 #endif | |
2919 | |
2920 } // namespace detail | |
2921 NLOHMANN_JSON_NAMESPACE_END | |
2922 | |
2923 // #include <nlohmann/detail/string_escape.hpp> | |
2924 // __ _____ _____ _____ | |
2925 // __| | __| | | | JSON for Modern C++ | |
2926 // | | |__ | | | | | | version 3.11.2 | |
2927 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
2928 // | |
2929 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
2930 // SPDX-License-Identifier: MIT | |
2931 | |
2932 | |
2933 | |
2934 // #include <nlohmann/detail/abi_macros.hpp> | |
2935 | |
2936 | |
2937 NLOHMANN_JSON_NAMESPACE_BEGIN | |
2938 namespace detail | |
2939 { | |
2940 | |
2941 /*! | |
2942 @brief replace all occurrences of a substring by another string | |
2943 | |
2944 @param[in,out] s the string to manipulate; changed so that all | |
2945 occurrences of @a f are replaced with @a t | |
2946 @param[in] f the substring to replace with @a t | |
2947 @param[in] t the string to replace @a f | |
2948 | |
2949 @pre The search string @a f must not be empty. **This precondition is | |
2950 enforced with an assertion.** | |
2951 | |
2952 @since version 2.0.0 | |
2953 */ | |
2954 template<typename StringType> | |
2955 inline void replace_substring(StringType& s, const StringType& f, | |
2956 const StringType& t) | |
2957 { | |
2958 JSON_ASSERT(!f.empty()); | |
2959 for (auto pos = s.find(f); // find first occurrence of f | |
2960 pos != StringType::npos; // make sure f was found | |
2961 s.replace(pos, f.size(), t), // replace with t, and | |
2962 pos = s.find(f, pos + t.size())) // find next occurrence of f | |
2963 {} | |
2964 } | |
2965 | |
2966 /*! | |
2967 * @brief string escaping as described in RFC 6901 (Sect. 4) | |
2968 * @param[in] s string to escape | |
2969 * @return escaped string | |
2970 * | |
2971 * Note the order of escaping "~" to "~0" and "/" to "~1" is important. | |
2972 */ | |
2973 template<typename StringType> | |
2974 inline StringType escape(StringType s) | |
2975 { | |
2976 replace_substring(s, StringType{"~"}, StringType{"~0"}); | |
2977 replace_substring(s, StringType{"/"}, StringType{"~1"}); | |
2978 return s; | |
2979 } | |
2980 | |
2981 /*! | |
2982 * @brief string unescaping as described in RFC 6901 (Sect. 4) | |
2983 * @param[in] s string to unescape | |
2984 * @return unescaped string | |
2985 * | |
2986 * Note the order of escaping "~1" to "/" and "~0" to "~" is important. | |
2987 */ | |
2988 template<typename StringType> | |
2989 static void unescape(StringType& s) | |
2990 { | |
2991 replace_substring(s, StringType{"~1"}, StringType{"/"}); | |
2992 replace_substring(s, StringType{"~0"}, StringType{"~"}); | |
2993 } | |
2994 | |
2995 } // namespace detail | |
2996 NLOHMANN_JSON_NAMESPACE_END | |
2997 | |
2998 // #include <nlohmann/detail/input/position_t.hpp> | |
2999 // __ _____ _____ _____ | |
3000 // __| | __| | | | JSON for Modern C++ | |
3001 // | | |__ | | | | | | version 3.11.2 | |
3002 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
3003 // | |
3004 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
3005 // SPDX-License-Identifier: MIT | |
3006 | |
3007 | |
3008 | |
3009 #include <cstddef> // size_t | |
3010 | |
3011 // #include <nlohmann/detail/abi_macros.hpp> | |
3012 | |
3013 | |
3014 NLOHMANN_JSON_NAMESPACE_BEGIN | |
3015 namespace detail | |
3016 { | |
3017 | |
3018 /// struct to capture the start position of the current token | |
3019 struct position_t | |
3020 { | |
3021 /// the total number of characters read | |
3022 std::size_t chars_read_total = 0; | |
3023 /// the number of characters read in the current line | |
3024 std::size_t chars_read_current_line = 0; | |
3025 /// the number of lines read | |
3026 std::size_t lines_read = 0; | |
3027 | |
3028 /// conversion to size_t to preserve SAX interface | |
3029 constexpr operator size_t() const | |
3030 { | |
3031 return chars_read_total; | |
3032 } | |
3033 }; | |
3034 | |
3035 } // namespace detail | |
3036 NLOHMANN_JSON_NAMESPACE_END | |
3037 | |
3038 // #include <nlohmann/detail/macro_scope.hpp> | |
3039 | |
3040 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
3041 // __ _____ _____ _____ | |
3042 // __| | __| | | | JSON for Modern C++ | |
3043 // | | |__ | | | | | | version 3.11.2 | |
3044 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
3045 // | |
3046 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
3047 // SPDX-FileCopyrightText: 2018 The Abseil Authors | |
3048 // SPDX-License-Identifier: MIT | |
3049 | |
3050 | |
3051 | |
3052 #include <array> // array | |
3053 #include <cstddef> // size_t | |
3054 #include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type | |
3055 #include <utility> // index_sequence, make_index_sequence, index_sequence_for | |
3056 | |
3057 // #include <nlohmann/detail/macro_scope.hpp> | |
3058 | |
3059 | |
3060 NLOHMANN_JSON_NAMESPACE_BEGIN | |
3061 namespace detail | |
3062 { | |
3063 | |
3064 template<typename T> | |
3065 using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; | |
3066 | |
3067 #ifdef JSON_HAS_CPP_14 | |
3068 | |
3069 // the following utilities are natively available in C++14 | |
3070 using std::enable_if_t; | |
3071 using std::index_sequence; | |
3072 using std::make_index_sequence; | |
3073 using std::index_sequence_for; | |
3074 | |
3075 #else | |
3076 | |
3077 // alias templates to reduce boilerplate | |
3078 template<bool B, typename T = void> | |
3079 using enable_if_t = typename std::enable_if<B, T>::type; | |
3080 | |
3081 // The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h | |
3082 // which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. | |
3083 | |
3084 //// START OF CODE FROM GOOGLE ABSEIL | |
3085 | |
3086 // integer_sequence | |
3087 // | |
3088 // Class template representing a compile-time integer sequence. An instantiation | |
3089 // of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its | |
3090 // type through its template arguments (which is a common need when | |
3091 // working with C++11 variadic templates). `absl::integer_sequence` is designed | |
3092 // to be a drop-in replacement for C++14's `std::integer_sequence`. | |
3093 // | |
3094 // Example: | |
3095 // | |
3096 // template< class T, T... Ints > | |
3097 // void user_function(integer_sequence<T, Ints...>); | |
3098 // | |
3099 // int main() | |
3100 // { | |
3101 // // user_function's `T` will be deduced to `int` and `Ints...` | |
3102 // // will be deduced to `0, 1, 2, 3, 4`. | |
3103 // user_function(make_integer_sequence<int, 5>()); | |
3104 // } | |
3105 template <typename T, T... Ints> | |
3106 struct integer_sequence | |
3107 { | |
3108 using value_type = T; | |
3109 static constexpr std::size_t size() noexcept | |
3110 { | |
3111 return sizeof...(Ints); | |
3112 } | |
3113 }; | |
3114 | |
3115 // index_sequence | |
3116 // | |
3117 // A helper template for an `integer_sequence` of `size_t`, | |
3118 // `absl::index_sequence` is designed to be a drop-in replacement for C++14's | |
3119 // `std::index_sequence`. | |
3120 template <size_t... Ints> | |
3121 using index_sequence = integer_sequence<size_t, Ints...>; | |
3122 | |
3123 namespace utility_internal | |
3124 { | |
3125 | |
3126 template <typename Seq, size_t SeqSize, size_t Rem> | |
3127 struct Extend; | |
3128 | |
3129 // Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. | |
3130 template <typename T, T... Ints, size_t SeqSize> | |
3131 struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> | |
3132 { | |
3133 using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; | |
3134 }; | |
3135 | |
3136 template <typename T, T... Ints, size_t SeqSize> | |
3137 struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> | |
3138 { | |
3139 using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; | |
3140 }; | |
3141 | |
3142 // Recursion helper for 'make_integer_sequence<T, N>'. | |
3143 // 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'. | |
3144 template <typename T, size_t N> | |
3145 struct Gen | |
3146 { | |
3147 using type = | |
3148 typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; | |
3149 }; | |
3150 | |
3151 template <typename T> | |
3152 struct Gen<T, 0> | |
3153 { | |
3154 using type = integer_sequence<T>; | |
3155 }; | |
3156 | |
3157 } // namespace utility_internal | |
3158 | |
3159 // Compile-time sequences of integers | |
3160 | |
3161 // make_integer_sequence | |
3162 // | |
3163 // This template alias is equivalent to | |
3164 // `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in | |
3165 // replacement for C++14's `std::make_integer_sequence`. | |
3166 template <typename T, T N> | |
3167 using make_integer_sequence = typename utility_internal::Gen<T, N>::type; | |
3168 | |
3169 // make_index_sequence | |
3170 // | |
3171 // This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, | |
3172 // and is designed to be a drop-in replacement for C++14's | |
3173 // `std::make_index_sequence`. | |
3174 template <size_t N> | |
3175 using make_index_sequence = make_integer_sequence<size_t, N>; | |
3176 | |
3177 // index_sequence_for | |
3178 // | |
3179 // Converts a typename pack into an index sequence of the same length, and | |
3180 // is designed to be a drop-in replacement for C++14's | |
3181 // `std::index_sequence_for()` | |
3182 template <typename... Ts> | |
3183 using index_sequence_for = make_index_sequence<sizeof...(Ts)>; | |
3184 | |
3185 //// END OF CODE FROM GOOGLE ABSEIL | |
3186 | |
3187 #endif | |
3188 | |
3189 // dispatch utility (taken from ranges-v3) | |
3190 template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; | |
3191 template<> struct priority_tag<0> {}; | |
3192 | |
3193 // taken from ranges-v3 | |
3194 template<typename T> | |
3195 struct static_const | |
3196 { | |
3197 static JSON_INLINE_VARIABLE constexpr T value{}; | |
3198 }; | |
3199 | |
3200 #ifndef JSON_HAS_CPP_17 | |
3201 template<typename T> | |
3202 constexpr T static_const<T>::value; | |
3203 #endif | |
3204 | |
3205 template<typename T, typename... Args> | |
3206 inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args) | |
3207 { | |
3208 return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}}; | |
3209 } | |
3210 | |
3211 } // namespace detail | |
3212 NLOHMANN_JSON_NAMESPACE_END | |
3213 | |
3214 // #include <nlohmann/detail/meta/type_traits.hpp> | |
3215 // __ _____ _____ _____ | |
3216 // __| | __| | | | JSON for Modern C++ | |
3217 // | | |__ | | | | | | version 3.11.2 | |
3218 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
3219 // | |
3220 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
3221 // SPDX-License-Identifier: MIT | |
3222 | |
3223 | |
3224 | |
3225 #include <limits> // numeric_limits | |
3226 #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type | |
3227 #include <utility> // declval | |
3228 #include <tuple> // tuple | |
3229 | |
3230 // #include <nlohmann/detail/iterators/iterator_traits.hpp> | |
3231 // __ _____ _____ _____ | |
3232 // __| | __| | | | JSON for Modern C++ | |
3233 // | | |__ | | | | | | version 3.11.2 | |
3234 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
3235 // | |
3236 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
3237 // SPDX-License-Identifier: MIT | |
3238 | |
3239 | |
3240 | |
3241 #include <iterator> // random_access_iterator_tag | |
3242 | |
3243 // #include <nlohmann/detail/abi_macros.hpp> | |
3244 | |
3245 // #include <nlohmann/detail/meta/void_t.hpp> | |
3246 | |
3247 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
3248 | |
3249 | |
3250 NLOHMANN_JSON_NAMESPACE_BEGIN | |
3251 namespace detail | |
3252 { | |
3253 | |
3254 template<typename It, typename = void> | |
3255 struct iterator_types {}; | |
3256 | |
3257 template<typename It> | |
3258 struct iterator_types < | |
3259 It, | |
3260 void_t<typename It::difference_type, typename It::value_type, typename It::pointer, | |
3261 typename It::reference, typename It::iterator_category >> | |
3262 { | |
3263 using difference_type = typename It::difference_type; | |
3264 using value_type = typename It::value_type; | |
3265 using pointer = typename It::pointer; | |
3266 using reference = typename It::reference; | |
3267 using iterator_category = typename It::iterator_category; | |
3268 }; | |
3269 | |
3270 // This is required as some compilers implement std::iterator_traits in a way that | |
3271 // doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. | |
3272 template<typename T, typename = void> | |
3273 struct iterator_traits | |
3274 { | |
3275 }; | |
3276 | |
3277 template<typename T> | |
3278 struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >> | |
3279 : iterator_types<T> | |
3280 { | |
3281 }; | |
3282 | |
3283 template<typename T> | |
3284 struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> | |
3285 { | |
3286 using iterator_category = std::random_access_iterator_tag; | |
3287 using value_type = T; | |
3288 using difference_type = ptrdiff_t; | |
3289 using pointer = T*; | |
3290 using reference = T&; | |
3291 }; | |
3292 | |
3293 } // namespace detail | |
3294 NLOHMANN_JSON_NAMESPACE_END | |
3295 | |
3296 // #include <nlohmann/detail/macro_scope.hpp> | |
3297 | |
3298 // #include <nlohmann/detail/meta/call_std/begin.hpp> | |
3299 // __ _____ _____ _____ | |
3300 // __| | __| | | | JSON for Modern C++ | |
3301 // | | |__ | | | | | | version 3.11.2 | |
3302 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
3303 // | |
3304 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
3305 // SPDX-License-Identifier: MIT | |
3306 | |
3307 | |
3308 | |
3309 // #include <nlohmann/detail/macro_scope.hpp> | |
3310 | |
3311 | |
3312 NLOHMANN_JSON_NAMESPACE_BEGIN | |
3313 | |
3314 NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); | |
3315 | |
3316 NLOHMANN_JSON_NAMESPACE_END | |
3317 | |
3318 // #include <nlohmann/detail/meta/call_std/end.hpp> | |
3319 // __ _____ _____ _____ | |
3320 // __| | __| | | | JSON for Modern C++ | |
3321 // | | |__ | | | | | | version 3.11.2 | |
3322 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
3323 // | |
3324 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
3325 // SPDX-License-Identifier: MIT | |
3326 | |
3327 | |
3328 | |
3329 // #include <nlohmann/detail/macro_scope.hpp> | |
3330 | |
3331 | |
3332 NLOHMANN_JSON_NAMESPACE_BEGIN | |
3333 | |
3334 NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); | |
3335 | |
3336 NLOHMANN_JSON_NAMESPACE_END | |
3337 | |
3338 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
3339 | |
3340 // #include <nlohmann/detail/meta/detected.hpp> | |
3341 | |
3342 // #include <nlohmann/json_fwd.hpp> | |
3343 // __ _____ _____ _____ | |
3344 // __| | __| | | | JSON for Modern C++ | |
3345 // | | |__ | | | | | | version 3.11.2 | |
3346 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
3347 // | |
3348 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
3349 // SPDX-License-Identifier: MIT | |
3350 | |
3351 #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ | |
3352 #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ | |
3353 | |
3354 #include <cstdint> // int64_t, uint64_t | |
3355 #include <map> // map | |
3356 #include <memory> // allocator | |
3357 #include <string> // string | |
3358 #include <vector> // vector | |
3359 | |
3360 // #include <nlohmann/detail/abi_macros.hpp> | |
3361 | |
3362 | |
3363 /*! | |
3364 @brief namespace for Niels Lohmann | |
3365 @see https://github.com/nlohmann | |
3366 @since version 1.0.0 | |
3367 */ | |
3368 NLOHMANN_JSON_NAMESPACE_BEGIN | |
3369 | |
3370 /*! | |
3371 @brief default JSONSerializer template argument | |
3372 | |
3373 This serializer ignores the template arguments and uses ADL | |
3374 ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) | |
3375 for serialization. | |
3376 */ | |
3377 template<typename T = void, typename SFINAE = void> | |
3378 struct adl_serializer; | |
3379 | |
3380 /// a class to store JSON values | |
3381 /// @sa https://json.nlohmann.me/api/basic_json/ | |
3382 template<template<typename U, typename V, typename... Args> class ObjectType = | |
3383 std::map, | |
3384 template<typename U, typename... Args> class ArrayType = std::vector, | |
3385 class StringType = std::string, class BooleanType = bool, | |
3386 class NumberIntegerType = std::int64_t, | |
3387 class NumberUnsignedType = std::uint64_t, | |
3388 class NumberFloatType = double, | |
3389 template<typename U> class AllocatorType = std::allocator, | |
3390 template<typename T, typename SFINAE = void> class JSONSerializer = | |
3391 adl_serializer, | |
3392 class BinaryType = std::vector<std::uint8_t>> | |
3393 class basic_json; | |
3394 | |
3395 /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document | |
3396 /// @sa https://json.nlohmann.me/api/json_pointer/ | |
3397 template<typename RefStringType> | |
3398 class json_pointer; | |
3399 | |
3400 /*! | |
3401 @brief default specialization | |
3402 @sa https://json.nlohmann.me/api/json/ | |
3403 */ | |
3404 using json = basic_json<>; | |
3405 | |
3406 /// @brief a minimal map-like container that preserves insertion order | |
3407 /// @sa https://json.nlohmann.me/api/ordered_map/ | |
3408 template<class Key, class T, class IgnoredLess, class Allocator> | |
3409 struct ordered_map; | |
3410 | |
3411 /// @brief specialization that maintains the insertion order of object keys | |
3412 /// @sa https://json.nlohmann.me/api/ordered_json/ | |
3413 using ordered_json = basic_json<nlohmann::ordered_map>; | |
3414 | |
3415 NLOHMANN_JSON_NAMESPACE_END | |
3416 | |
3417 #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ | |
3418 | |
3419 | |
3420 NLOHMANN_JSON_NAMESPACE_BEGIN | |
3421 /*! | |
3422 @brief detail namespace with internal helper functions | |
3423 | |
3424 This namespace collects functions that should not be exposed, | |
3425 implementations of some @ref basic_json methods, and meta-programming helpers. | |
3426 | |
3427 @since version 2.1.0 | |
3428 */ | |
3429 namespace detail | |
3430 { | |
3431 | |
3432 ///////////// | |
3433 // helpers // | |
3434 ///////////// | |
3435 | |
3436 // Note to maintainers: | |
3437 // | |
3438 // Every trait in this file expects a non CV-qualified type. | |
3439 // The only exceptions are in the 'aliases for detected' section | |
3440 // (i.e. those of the form: decltype(T::member_function(std::declval<T>()))) | |
3441 // | |
3442 // In this case, T has to be properly CV-qualified to constraint the function arguments | |
3443 // (e.g. to_json(BasicJsonType&, const T&)) | |
3444 | |
3445 template<typename> struct is_basic_json : std::false_type {}; | |
3446 | |
3447 NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
3448 struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; | |
3449 | |
3450 // used by exceptions create() member functions | |
3451 // true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t | |
3452 // false_type otherwise | |
3453 template<typename BasicJsonContext> | |
3454 struct is_basic_json_context : | |
3455 std::integral_constant < bool, | |
3456 is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value | |
3457 || std::is_same<BasicJsonContext, std::nullptr_t>::value > | |
3458 {}; | |
3459 | |
3460 ////////////////////// | |
3461 // json_ref helpers // | |
3462 ////////////////////// | |
3463 | |
3464 template<typename> | |
3465 class json_ref; | |
3466 | |
3467 template<typename> | |
3468 struct is_json_ref : std::false_type {}; | |
3469 | |
3470 template<typename T> | |
3471 struct is_json_ref<json_ref<T>> : std::true_type {}; | |
3472 | |
3473 ////////////////////////// | |
3474 // aliases for detected // | |
3475 ////////////////////////// | |
3476 | |
3477 template<typename T> | |
3478 using mapped_type_t = typename T::mapped_type; | |
3479 | |
3480 template<typename T> | |
3481 using key_type_t = typename T::key_type; | |
3482 | |
3483 template<typename T> | |
3484 using value_type_t = typename T::value_type; | |
3485 | |
3486 template<typename T> | |
3487 using difference_type_t = typename T::difference_type; | |
3488 | |
3489 template<typename T> | |
3490 using pointer_t = typename T::pointer; | |
3491 | |
3492 template<typename T> | |
3493 using reference_t = typename T::reference; | |
3494 | |
3495 template<typename T> | |
3496 using iterator_category_t = typename T::iterator_category; | |
3497 | |
3498 template<typename T, typename... Args> | |
3499 using to_json_function = decltype(T::to_json(std::declval<Args>()...)); | |
3500 | |
3501 template<typename T, typename... Args> | |
3502 using from_json_function = decltype(T::from_json(std::declval<Args>()...)); | |
3503 | |
3504 template<typename T, typename U> | |
3505 using get_template_function = decltype(std::declval<T>().template get<U>()); | |
3506 | |
3507 // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists | |
3508 template<typename BasicJsonType, typename T, typename = void> | |
3509 struct has_from_json : std::false_type {}; | |
3510 | |
3511 // trait checking if j.get<T> is valid | |
3512 // use this trait instead of std::is_constructible or std::is_convertible, | |
3513 // both rely on, or make use of implicit conversions, and thus fail when T | |
3514 // has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) | |
3515 template <typename BasicJsonType, typename T> | |
3516 struct is_getable | |
3517 { | |
3518 static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value; | |
3519 }; | |
3520 | |
3521 template<typename BasicJsonType, typename T> | |
3522 struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> | |
3523 { | |
3524 using serializer = typename BasicJsonType::template json_serializer<T, void>; | |
3525 | |
3526 static constexpr bool value = | |
3527 is_detected_exact<void, from_json_function, serializer, | |
3528 const BasicJsonType&, T&>::value; | |
3529 }; | |
3530 | |
3531 // This trait checks if JSONSerializer<T>::from_json(json const&) exists | |
3532 // this overload is used for non-default-constructible user-defined-types | |
3533 template<typename BasicJsonType, typename T, typename = void> | |
3534 struct has_non_default_from_json : std::false_type {}; | |
3535 | |
3536 template<typename BasicJsonType, typename T> | |
3537 struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> | |
3538 { | |
3539 using serializer = typename BasicJsonType::template json_serializer<T, void>; | |
3540 | |
3541 static constexpr bool value = | |
3542 is_detected_exact<T, from_json_function, serializer, | |
3543 const BasicJsonType&>::value; | |
3544 }; | |
3545 | |
3546 // This trait checks if BasicJsonType::json_serializer<T>::to_json exists | |
3547 // Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. | |
3548 template<typename BasicJsonType, typename T, typename = void> | |
3549 struct has_to_json : std::false_type {}; | |
3550 | |
3551 template<typename BasicJsonType, typename T> | |
3552 struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> | |
3553 { | |
3554 using serializer = typename BasicJsonType::template json_serializer<T, void>; | |
3555 | |
3556 static constexpr bool value = | |
3557 is_detected_exact<void, to_json_function, serializer, BasicJsonType&, | |
3558 T>::value; | |
3559 }; | |
3560 | |
3561 template<typename T> | |
3562 using detect_key_compare = typename T::key_compare; | |
3563 | |
3564 template<typename T> | |
3565 struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {}; | |
3566 | |
3567 // obtains the actual object key comparator | |
3568 template<typename BasicJsonType> | |
3569 struct actual_object_comparator | |
3570 { | |
3571 using object_t = typename BasicJsonType::object_t; | |
3572 using object_comparator_t = typename BasicJsonType::default_object_comparator_t; | |
3573 using type = typename std::conditional < has_key_compare<object_t>::value, | |
3574 typename object_t::key_compare, object_comparator_t>::type; | |
3575 }; | |
3576 | |
3577 template<typename BasicJsonType> | |
3578 using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type; | |
3579 | |
3580 /////////////////// | |
3581 // is_ functions // | |
3582 /////////////////// | |
3583 | |
3584 // https://en.cppreference.com/w/cpp/types/conjunction | |
3585 template<class...> struct conjunction : std::true_type { }; | |
3586 template<class B> struct conjunction<B> : B { }; | |
3587 template<class B, class... Bn> | |
3588 struct conjunction<B, Bn...> | |
3589 : std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {}; | |
3590 | |
3591 // https://en.cppreference.com/w/cpp/types/negation | |
3592 template<class B> struct negation : std::integral_constant < bool, !B::value > { }; | |
3593 | |
3594 // Reimplementation of is_constructible and is_default_constructible, due to them being broken for | |
3595 // std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). | |
3596 // This causes compile errors in e.g. clang 3.5 or gcc 4.9. | |
3597 template <typename T> | |
3598 struct is_default_constructible : std::is_default_constructible<T> {}; | |
3599 | |
3600 template <typename T1, typename T2> | |
3601 struct is_default_constructible<std::pair<T1, T2>> | |
3602 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; | |
3603 | |
3604 template <typename T1, typename T2> | |
3605 struct is_default_constructible<const std::pair<T1, T2>> | |
3606 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; | |
3607 | |
3608 template <typename... Ts> | |
3609 struct is_default_constructible<std::tuple<Ts...>> | |
3610 : conjunction<is_default_constructible<Ts>...> {}; | |
3611 | |
3612 template <typename... Ts> | |
3613 struct is_default_constructible<const std::tuple<Ts...>> | |
3614 : conjunction<is_default_constructible<Ts>...> {}; | |
3615 | |
3616 | |
3617 template <typename T, typename... Args> | |
3618 struct is_constructible : std::is_constructible<T, Args...> {}; | |
3619 | |
3620 template <typename T1, typename T2> | |
3621 struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {}; | |
3622 | |
3623 template <typename T1, typename T2> | |
3624 struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {}; | |
3625 | |
3626 template <typename... Ts> | |
3627 struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {}; | |
3628 | |
3629 template <typename... Ts> | |
3630 struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {}; | |
3631 | |
3632 | |
3633 template<typename T, typename = void> | |
3634 struct is_iterator_traits : std::false_type {}; | |
3635 | |
3636 template<typename T> | |
3637 struct is_iterator_traits<iterator_traits<T>> | |
3638 { | |
3639 private: | |
3640 using traits = iterator_traits<T>; | |
3641 | |
3642 public: | |
3643 static constexpr auto value = | |
3644 is_detected<value_type_t, traits>::value && | |
3645 is_detected<difference_type_t, traits>::value && | |
3646 is_detected<pointer_t, traits>::value && | |
3647 is_detected<iterator_category_t, traits>::value && | |
3648 is_detected<reference_t, traits>::value; | |
3649 }; | |
3650 | |
3651 template<typename T> | |
3652 struct is_range | |
3653 { | |
3654 private: | |
3655 using t_ref = typename std::add_lvalue_reference<T>::type; | |
3656 | |
3657 using iterator = detected_t<result_of_begin, t_ref>; | |
3658 using sentinel = detected_t<result_of_end, t_ref>; | |
3659 | |
3660 // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator | |
3661 // and https://en.cppreference.com/w/cpp/iterator/sentinel_for | |
3662 // but reimplementing these would be too much work, as a lot of other concepts are used underneath | |
3663 static constexpr auto is_iterator_begin = | |
3664 is_iterator_traits<iterator_traits<iterator>>::value; | |
3665 | |
3666 public: | |
3667 static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin; | |
3668 }; | |
3669 | |
3670 template<typename R> | |
3671 using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>; | |
3672 | |
3673 template<typename T> | |
3674 using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>; | |
3675 | |
3676 // The following implementation of is_complete_type is taken from | |
3677 // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ | |
3678 // and is written by Xiang Fan who agreed to using it in this library. | |
3679 | |
3680 template<typename T, typename = void> | |
3681 struct is_complete_type : std::false_type {}; | |
3682 | |
3683 template<typename T> | |
3684 struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; | |
3685 | |
3686 template<typename BasicJsonType, typename CompatibleObjectType, | |
3687 typename = void> | |
3688 struct is_compatible_object_type_impl : std::false_type {}; | |
3689 | |
3690 template<typename BasicJsonType, typename CompatibleObjectType> | |
3691 struct is_compatible_object_type_impl < | |
3692 BasicJsonType, CompatibleObjectType, | |
3693 enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&& | |
3694 is_detected<key_type_t, CompatibleObjectType>::value >> | |
3695 { | |
3696 using object_t = typename BasicJsonType::object_t; | |
3697 | |
3698 // macOS's is_constructible does not play well with nonesuch... | |
3699 static constexpr bool value = | |
3700 is_constructible<typename object_t::key_type, | |
3701 typename CompatibleObjectType::key_type>::value && | |
3702 is_constructible<typename object_t::mapped_type, | |
3703 typename CompatibleObjectType::mapped_type>::value; | |
3704 }; | |
3705 | |
3706 template<typename BasicJsonType, typename CompatibleObjectType> | |
3707 struct is_compatible_object_type | |
3708 : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; | |
3709 | |
3710 template<typename BasicJsonType, typename ConstructibleObjectType, | |
3711 typename = void> | |
3712 struct is_constructible_object_type_impl : std::false_type {}; | |
3713 | |
3714 template<typename BasicJsonType, typename ConstructibleObjectType> | |
3715 struct is_constructible_object_type_impl < | |
3716 BasicJsonType, ConstructibleObjectType, | |
3717 enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&& | |
3718 is_detected<key_type_t, ConstructibleObjectType>::value >> | |
3719 { | |
3720 using object_t = typename BasicJsonType::object_t; | |
3721 | |
3722 static constexpr bool value = | |
3723 (is_default_constructible<ConstructibleObjectType>::value && | |
3724 (std::is_move_assignable<ConstructibleObjectType>::value || | |
3725 std::is_copy_assignable<ConstructibleObjectType>::value) && | |
3726 (is_constructible<typename ConstructibleObjectType::key_type, | |
3727 typename object_t::key_type>::value && | |
3728 std::is_same < | |
3729 typename object_t::mapped_type, | |
3730 typename ConstructibleObjectType::mapped_type >::value)) || | |
3731 (has_from_json<BasicJsonType, | |
3732 typename ConstructibleObjectType::mapped_type>::value || | |
3733 has_non_default_from_json < | |
3734 BasicJsonType, | |
3735 typename ConstructibleObjectType::mapped_type >::value); | |
3736 }; | |
3737 | |
3738 template<typename BasicJsonType, typename ConstructibleObjectType> | |
3739 struct is_constructible_object_type | |
3740 : is_constructible_object_type_impl<BasicJsonType, | |
3741 ConstructibleObjectType> {}; | |
3742 | |
3743 template<typename BasicJsonType, typename CompatibleStringType> | |
3744 struct is_compatible_string_type | |
3745 { | |
3746 static constexpr auto value = | |
3747 is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; | |
3748 }; | |
3749 | |
3750 template<typename BasicJsonType, typename ConstructibleStringType> | |
3751 struct is_constructible_string_type | |
3752 { | |
3753 // launder type through decltype() to fix compilation failure on ICPC | |
3754 #ifdef __INTEL_COMPILER | |
3755 using laundered_type = decltype(std::declval<ConstructibleStringType>()); | |
3756 #else | |
3757 using laundered_type = ConstructibleStringType; | |
3758 #endif | |
3759 | |
3760 static constexpr auto value = | |
3761 conjunction < | |
3762 is_constructible<laundered_type, typename BasicJsonType::string_t>, | |
3763 is_detected_exact<typename BasicJsonType::string_t::value_type, | |
3764 value_type_t, laundered_type >>::value; | |
3765 }; | |
3766 | |
3767 template<typename BasicJsonType, typename CompatibleArrayType, typename = void> | |
3768 struct is_compatible_array_type_impl : std::false_type {}; | |
3769 | |
3770 template<typename BasicJsonType, typename CompatibleArrayType> | |
3771 struct is_compatible_array_type_impl < | |
3772 BasicJsonType, CompatibleArrayType, | |
3773 enable_if_t < | |
3774 is_detected<iterator_t, CompatibleArrayType>::value&& | |
3775 is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&& | |
3776 // special case for types like std::filesystem::path whose iterator's value_type are themselves | |
3777 // c.f. https://github.com/nlohmann/json/pull/3073 | |
3778 !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >> | |
3779 { | |
3780 static constexpr bool value = | |
3781 is_constructible<BasicJsonType, | |
3782 range_value_t<CompatibleArrayType>>::value; | |
3783 }; | |
3784 | |
3785 template<typename BasicJsonType, typename CompatibleArrayType> | |
3786 struct is_compatible_array_type | |
3787 : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; | |
3788 | |
3789 template<typename BasicJsonType, typename ConstructibleArrayType, typename = void> | |
3790 struct is_constructible_array_type_impl : std::false_type {}; | |
3791 | |
3792 template<typename BasicJsonType, typename ConstructibleArrayType> | |
3793 struct is_constructible_array_type_impl < | |
3794 BasicJsonType, ConstructibleArrayType, | |
3795 enable_if_t<std::is_same<ConstructibleArrayType, | |
3796 typename BasicJsonType::value_type>::value >> | |
3797 : std::true_type {}; | |
3798 | |
3799 template<typename BasicJsonType, typename ConstructibleArrayType> | |
3800 struct is_constructible_array_type_impl < | |
3801 BasicJsonType, ConstructibleArrayType, | |
3802 enable_if_t < !std::is_same<ConstructibleArrayType, | |
3803 typename BasicJsonType::value_type>::value&& | |
3804 !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&& | |
3805 is_default_constructible<ConstructibleArrayType>::value&& | |
3806 (std::is_move_assignable<ConstructibleArrayType>::value || | |
3807 std::is_copy_assignable<ConstructibleArrayType>::value)&& | |
3808 is_detected<iterator_t, ConstructibleArrayType>::value&& | |
3809 is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& | |
3810 is_detected<range_value_t, ConstructibleArrayType>::value&& | |
3811 // special case for types like std::filesystem::path whose iterator's value_type are themselves | |
3812 // c.f. https://github.com/nlohmann/json/pull/3073 | |
3813 !std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&& | |
3814 is_complete_type < | |
3815 detected_t<range_value_t, ConstructibleArrayType >>::value >> | |
3816 { | |
3817 using value_type = range_value_t<ConstructibleArrayType>; | |
3818 | |
3819 static constexpr bool value = | |
3820 std::is_same<value_type, | |
3821 typename BasicJsonType::array_t::value_type>::value || | |
3822 has_from_json<BasicJsonType, | |
3823 value_type>::value || | |
3824 has_non_default_from_json < | |
3825 BasicJsonType, | |
3826 value_type >::value; | |
3827 }; | |
3828 | |
3829 template<typename BasicJsonType, typename ConstructibleArrayType> | |
3830 struct is_constructible_array_type | |
3831 : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {}; | |
3832 | |
3833 template<typename RealIntegerType, typename CompatibleNumberIntegerType, | |
3834 typename = void> | |
3835 struct is_compatible_integer_type_impl : std::false_type {}; | |
3836 | |
3837 template<typename RealIntegerType, typename CompatibleNumberIntegerType> | |
3838 struct is_compatible_integer_type_impl < | |
3839 RealIntegerType, CompatibleNumberIntegerType, | |
3840 enable_if_t < std::is_integral<RealIntegerType>::value&& | |
3841 std::is_integral<CompatibleNumberIntegerType>::value&& | |
3842 !std::is_same<bool, CompatibleNumberIntegerType>::value >> | |
3843 { | |
3844 // is there an assert somewhere on overflows? | |
3845 using RealLimits = std::numeric_limits<RealIntegerType>; | |
3846 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; | |
3847 | |
3848 static constexpr auto value = | |
3849 is_constructible<RealIntegerType, | |
3850 CompatibleNumberIntegerType>::value && | |
3851 CompatibleLimits::is_integer && | |
3852 RealLimits::is_signed == CompatibleLimits::is_signed; | |
3853 }; | |
3854 | |
3855 template<typename RealIntegerType, typename CompatibleNumberIntegerType> | |
3856 struct is_compatible_integer_type | |
3857 : is_compatible_integer_type_impl<RealIntegerType, | |
3858 CompatibleNumberIntegerType> {}; | |
3859 | |
3860 template<typename BasicJsonType, typename CompatibleType, typename = void> | |
3861 struct is_compatible_type_impl: std::false_type {}; | |
3862 | |
3863 template<typename BasicJsonType, typename CompatibleType> | |
3864 struct is_compatible_type_impl < | |
3865 BasicJsonType, CompatibleType, | |
3866 enable_if_t<is_complete_type<CompatibleType>::value >> | |
3867 { | |
3868 static constexpr bool value = | |
3869 has_to_json<BasicJsonType, CompatibleType>::value; | |
3870 }; | |
3871 | |
3872 template<typename BasicJsonType, typename CompatibleType> | |
3873 struct is_compatible_type | |
3874 : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; | |
3875 | |
3876 template<typename T1, typename T2> | |
3877 struct is_constructible_tuple : std::false_type {}; | |
3878 | |
3879 template<typename T1, typename... Args> | |
3880 struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {}; | |
3881 | |
3882 template<typename BasicJsonType, typename T> | |
3883 struct is_json_iterator_of : std::false_type {}; | |
3884 | |
3885 template<typename BasicJsonType> | |
3886 struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {}; | |
3887 | |
3888 template<typename BasicJsonType> | |
3889 struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type | |
3890 {}; | |
3891 | |
3892 // checks if a given type T is a template specialization of Primary | |
3893 template<template <typename...> class Primary, typename T> | |
3894 struct is_specialization_of : std::false_type {}; | |
3895 | |
3896 template<template <typename...> class Primary, typename... Args> | |
3897 struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {}; | |
3898 | |
3899 template<typename T> | |
3900 using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>; | |
3901 | |
3902 // checks if A and B are comparable using Compare functor | |
3903 template<typename Compare, typename A, typename B, typename = void> | |
3904 struct is_comparable : std::false_type {}; | |
3905 | |
3906 template<typename Compare, typename A, typename B> | |
3907 struct is_comparable<Compare, A, B, void_t< | |
3908 decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())), | |
3909 decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>())) | |
3910 >> : std::true_type {}; | |
3911 | |
3912 template<typename T> | |
3913 using detect_is_transparent = typename T::is_transparent; | |
3914 | |
3915 // type trait to check if KeyType can be used as object key (without a BasicJsonType) | |
3916 // see is_usable_as_basic_json_key_type below | |
3917 template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, | |
3918 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> | |
3919 using is_usable_as_key_type = typename std::conditional < | |
3920 is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value | |
3921 && !(ExcludeObjectKeyType && std::is_same<KeyType, | |
3922 ObjectKeyType>::value) | |
3923 && (!RequireTransparentComparator | |
3924 || is_detected <detect_is_transparent, Comparator>::value) | |
3925 && !is_json_pointer<KeyType>::value, | |
3926 std::true_type, | |
3927 std::false_type >::type; | |
3928 | |
3929 // type trait to check if KeyType can be used as object key | |
3930 // true if: | |
3931 // - KeyType is comparable with BasicJsonType::object_t::key_type | |
3932 // - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type | |
3933 // - the comparator is transparent or RequireTransparentComparator is false | |
3934 // - KeyType is not a JSON iterator or json_pointer | |
3935 template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, | |
3936 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> | |
3937 using is_usable_as_basic_json_key_type = typename std::conditional < | |
3938 is_usable_as_key_type<typename BasicJsonType::object_comparator_t, | |
3939 typename BasicJsonType::object_t::key_type, KeyTypeCVRef, | |
3940 RequireTransparentComparator, ExcludeObjectKeyType>::value | |
3941 && !is_json_iterator_of<BasicJsonType, KeyType>::value, | |
3942 std::true_type, | |
3943 std::false_type >::type; | |
3944 | |
3945 template<typename ObjectType, typename KeyType> | |
3946 using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>())); | |
3947 | |
3948 // type trait to check if object_t has an erase() member functions accepting KeyType | |
3949 template<typename BasicJsonType, typename KeyType> | |
3950 using has_erase_with_key_type = typename std::conditional < | |
3951 is_detected < | |
3952 detect_erase_with_key_type, | |
3953 typename BasicJsonType::object_t, KeyType >::value, | |
3954 std::true_type, | |
3955 std::false_type >::type; | |
3956 | |
3957 // a naive helper to check if a type is an ordered_map (exploits the fact that | |
3958 // ordered_map inherits capacity() from std::vector) | |
3959 template <typename T> | |
3960 struct is_ordered_map | |
3961 { | |
3962 using one = char; | |
3963 | |
3964 struct two | |
3965 { | |
3966 char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) | |
3967 }; | |
3968 | |
3969 template <typename C> static one test( decltype(&C::capacity) ) ; | |
3970 template <typename C> static two test(...); | |
3971 | |
3972 enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
3973 }; | |
3974 | |
3975 // to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) | |
3976 template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 > | |
3977 T conditional_static_cast(U value) | |
3978 { | |
3979 return static_cast<T>(value); | |
3980 } | |
3981 | |
3982 template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0> | |
3983 T conditional_static_cast(U value) | |
3984 { | |
3985 return value; | |
3986 } | |
3987 | |
3988 template<typename... Types> | |
3989 using all_integral = conjunction<std::is_integral<Types>...>; | |
3990 | |
3991 template<typename... Types> | |
3992 using all_signed = conjunction<std::is_signed<Types>...>; | |
3993 | |
3994 template<typename... Types> | |
3995 using all_unsigned = conjunction<std::is_unsigned<Types>...>; | |
3996 | |
3997 // there's a disjunction trait in another PR; replace when merged | |
3998 template<typename... Types> | |
3999 using same_sign = std::integral_constant < bool, | |
4000 all_signed<Types...>::value || all_unsigned<Types...>::value >; | |
4001 | |
4002 template<typename OfType, typename T> | |
4003 using never_out_of_range = std::integral_constant < bool, | |
4004 (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType))) | |
4005 || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >; | |
4006 | |
4007 template<typename OfType, typename T, | |
4008 bool OfTypeSigned = std::is_signed<OfType>::value, | |
4009 bool TSigned = std::is_signed<T>::value> | |
4010 struct value_in_range_of_impl2; | |
4011 | |
4012 template<typename OfType, typename T> | |
4013 struct value_in_range_of_impl2<OfType, T, false, false> | |
4014 { | |
4015 static constexpr bool test(T val) | |
4016 { | |
4017 using CommonType = typename std::common_type<OfType, T>::type; | |
4018 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); | |
4019 } | |
4020 }; | |
4021 | |
4022 template<typename OfType, typename T> | |
4023 struct value_in_range_of_impl2<OfType, T, true, false> | |
4024 { | |
4025 static constexpr bool test(T val) | |
4026 { | |
4027 using CommonType = typename std::common_type<OfType, T>::type; | |
4028 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); | |
4029 } | |
4030 }; | |
4031 | |
4032 template<typename OfType, typename T> | |
4033 struct value_in_range_of_impl2<OfType, T, false, true> | |
4034 { | |
4035 static constexpr bool test(T val) | |
4036 { | |
4037 using CommonType = typename std::common_type<OfType, T>::type; | |
4038 return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); | |
4039 } | |
4040 }; | |
4041 | |
4042 | |
4043 template<typename OfType, typename T> | |
4044 struct value_in_range_of_impl2<OfType, T, true, true> | |
4045 { | |
4046 static constexpr bool test(T val) | |
4047 { | |
4048 using CommonType = typename std::common_type<OfType, T>::type; | |
4049 return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)()) | |
4050 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); | |
4051 } | |
4052 }; | |
4053 | |
4054 template<typename OfType, typename T, | |
4055 bool NeverOutOfRange = never_out_of_range<OfType, T>::value, | |
4056 typename = detail::enable_if_t<all_integral<OfType, T>::value>> | |
4057 struct value_in_range_of_impl1; | |
4058 | |
4059 template<typename OfType, typename T> | |
4060 struct value_in_range_of_impl1<OfType, T, false> | |
4061 { | |
4062 static constexpr bool test(T val) | |
4063 { | |
4064 return value_in_range_of_impl2<OfType, T>::test(val); | |
4065 } | |
4066 }; | |
4067 | |
4068 template<typename OfType, typename T> | |
4069 struct value_in_range_of_impl1<OfType, T, true> | |
4070 { | |
4071 static constexpr bool test(T /*val*/) | |
4072 { | |
4073 return true; | |
4074 } | |
4075 }; | |
4076 | |
4077 template<typename OfType, typename T> | |
4078 inline constexpr bool value_in_range_of(T val) | |
4079 { | |
4080 return value_in_range_of_impl1<OfType, T>::test(val); | |
4081 } | |
4082 | |
4083 template<bool Value> | |
4084 using bool_constant = std::integral_constant<bool, Value>; | |
4085 | |
4086 /////////////////////////////////////////////////////////////////////////////// | |
4087 // is_c_string | |
4088 /////////////////////////////////////////////////////////////////////////////// | |
4089 | |
4090 namespace impl | |
4091 { | |
4092 | |
4093 template<typename T> | |
4094 inline constexpr bool is_c_string() | |
4095 { | |
4096 using TUnExt = typename std::remove_extent<T>::type; | |
4097 using TUnCVExt = typename std::remove_cv<TUnExt>::type; | |
4098 using TUnPtr = typename std::remove_pointer<T>::type; | |
4099 using TUnCVPtr = typename std::remove_cv<TUnPtr>::type; | |
4100 return | |
4101 (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value) | |
4102 || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value); | |
4103 } | |
4104 | |
4105 } // namespace impl | |
4106 | |
4107 // checks whether T is a [cv] char */[cv] char[] C string | |
4108 template<typename T> | |
4109 struct is_c_string : bool_constant<impl::is_c_string<T>()> {}; | |
4110 | |
4111 template<typename T> | |
4112 using is_c_string_uncvref = is_c_string<uncvref_t<T>>; | |
4113 | |
4114 /////////////////////////////////////////////////////////////////////////////// | |
4115 // is_transparent | |
4116 /////////////////////////////////////////////////////////////////////////////// | |
4117 | |
4118 namespace impl | |
4119 { | |
4120 | |
4121 template<typename T> | |
4122 inline constexpr bool is_transparent() | |
4123 { | |
4124 return is_detected<detect_is_transparent, T>::value; | |
4125 } | |
4126 | |
4127 } // namespace impl | |
4128 | |
4129 // checks whether T has a member named is_transparent | |
4130 template<typename T> | |
4131 struct is_transparent : bool_constant<impl::is_transparent<T>()> {}; | |
4132 | |
4133 /////////////////////////////////////////////////////////////////////////////// | |
4134 | |
4135 } // namespace detail | |
4136 NLOHMANN_JSON_NAMESPACE_END | |
4137 | |
4138 // #include <nlohmann/detail/string_concat.hpp> | |
4139 // __ _____ _____ _____ | |
4140 // __| | __| | | | JSON for Modern C++ | |
4141 // | | |__ | | | | | | version 3.11.2 | |
4142 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
4143 // | |
4144 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
4145 // SPDX-License-Identifier: MIT | |
4146 | |
4147 | |
4148 | |
4149 #include <cstring> // strlen | |
4150 #include <string> // string | |
4151 #include <utility> // forward | |
4152 | |
4153 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
4154 | |
4155 // #include <nlohmann/detail/meta/detected.hpp> | |
4156 | |
4157 | |
4158 NLOHMANN_JSON_NAMESPACE_BEGIN | |
4159 namespace detail | |
4160 { | |
4161 | |
4162 inline std::size_t concat_length() | |
4163 { | |
4164 return 0; | |
4165 } | |
4166 | |
4167 template<typename... Args> | |
4168 inline std::size_t concat_length(const char* cstr, Args&& ... rest); | |
4169 | |
4170 template<typename StringType, typename... Args> | |
4171 inline std::size_t concat_length(const StringType& str, Args&& ... rest); | |
4172 | |
4173 template<typename... Args> | |
4174 inline std::size_t concat_length(const char /*c*/, Args&& ... rest) | |
4175 { | |
4176 return 1 + concat_length(std::forward<Args>(rest)...); | |
4177 } | |
4178 | |
4179 template<typename... Args> | |
4180 inline std::size_t concat_length(const char* cstr, Args&& ... rest) | |
4181 { | |
4182 // cppcheck-suppress ignoredReturnValue | |
4183 return ::strlen(cstr) + concat_length(std::forward<Args>(rest)...); | |
4184 } | |
4185 | |
4186 template<typename StringType, typename... Args> | |
4187 inline std::size_t concat_length(const StringType& str, Args&& ... rest) | |
4188 { | |
4189 return str.size() + concat_length(std::forward<Args>(rest)...); | |
4190 } | |
4191 | |
4192 template<typename OutStringType> | |
4193 inline void concat_into(OutStringType& /*out*/) | |
4194 {} | |
4195 | |
4196 template<typename StringType, typename Arg> | |
4197 using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ())); | |
4198 | |
4199 template<typename StringType, typename Arg> | |
4200 using detect_string_can_append = is_detected<string_can_append, StringType, Arg>; | |
4201 | |
4202 template<typename StringType, typename Arg> | |
4203 using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ()); | |
4204 | |
4205 template<typename StringType, typename Arg> | |
4206 using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>; | |
4207 | |
4208 template<typename StringType, typename Arg> | |
4209 using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end())); | |
4210 | |
4211 template<typename StringType, typename Arg> | |
4212 using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>; | |
4213 | |
4214 template<typename StringType, typename Arg> | |
4215 using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size())); | |
4216 | |
4217 template<typename StringType, typename Arg> | |
4218 using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>; | |
4219 | |
4220 template < typename OutStringType, typename Arg, typename... Args, | |
4221 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value | |
4222 && detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 > | |
4223 inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest); | |
4224 | |
4225 template < typename OutStringType, typename Arg, typename... Args, | |
4226 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value | |
4227 && !detect_string_can_append_op<OutStringType, Arg>::value | |
4228 && detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 > | |
4229 inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest); | |
4230 | |
4231 template < typename OutStringType, typename Arg, typename... Args, | |
4232 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value | |
4233 && !detect_string_can_append_op<OutStringType, Arg>::value | |
4234 && !detect_string_can_append_iter<OutStringType, Arg>::value | |
4235 && detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 > | |
4236 inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest); | |
4237 | |
4238 template<typename OutStringType, typename Arg, typename... Args, | |
4239 enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0> | |
4240 inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest) | |
4241 { | |
4242 out.append(std::forward<Arg>(arg)); | |
4243 concat_into(out, std::forward<Args>(rest)...); | |
4244 } | |
4245 | |
4246 template < typename OutStringType, typename Arg, typename... Args, | |
4247 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value | |
4248 && detect_string_can_append_op<OutStringType, Arg>::value, int > > | |
4249 inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest) | |
4250 { | |
4251 out += std::forward<Arg>(arg); | |
4252 concat_into(out, std::forward<Args>(rest)...); | |
4253 } | |
4254 | |
4255 template < typename OutStringType, typename Arg, typename... Args, | |
4256 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value | |
4257 && !detect_string_can_append_op<OutStringType, Arg>::value | |
4258 && detect_string_can_append_iter<OutStringType, Arg>::value, int > > | |
4259 inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest) | |
4260 { | |
4261 out.append(arg.begin(), arg.end()); | |
4262 concat_into(out, std::forward<Args>(rest)...); | |
4263 } | |
4264 | |
4265 template < typename OutStringType, typename Arg, typename... Args, | |
4266 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value | |
4267 && !detect_string_can_append_op<OutStringType, Arg>::value | |
4268 && !detect_string_can_append_iter<OutStringType, Arg>::value | |
4269 && detect_string_can_append_data<OutStringType, Arg>::value, int > > | |
4270 inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest) | |
4271 { | |
4272 out.append(arg.data(), arg.size()); | |
4273 concat_into(out, std::forward<Args>(rest)...); | |
4274 } | |
4275 | |
4276 template<typename OutStringType = std::string, typename... Args> | |
4277 inline OutStringType concat(Args && ... args) | |
4278 { | |
4279 OutStringType str; | |
4280 str.reserve(concat_length(std::forward<Args>(args)...)); | |
4281 concat_into(str, std::forward<Args>(args)...); | |
4282 return str; | |
4283 } | |
4284 | |
4285 } // namespace detail | |
4286 NLOHMANN_JSON_NAMESPACE_END | |
4287 | |
4288 | |
4289 | |
4290 NLOHMANN_JSON_NAMESPACE_BEGIN | |
4291 namespace detail | |
4292 { | |
4293 | |
4294 //////////////// | |
4295 // exceptions // | |
4296 //////////////// | |
4297 | |
4298 /// @brief general exception of the @ref basic_json class | |
4299 /// @sa https://json.nlohmann.me/api/basic_json/exception/ | |
4300 class exception : public std::exception | |
4301 { | |
4302 public: | |
4303 /// returns the explanatory string | |
4304 const char* what() const noexcept override | |
4305 { | |
4306 return m.what(); | |
4307 } | |
4308 | |
4309 /// the id of the exception | |
4310 const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) | |
4311 | |
4312 protected: | |
4313 JSON_HEDLEY_NON_NULL(3) | |
4314 exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) | |
4315 | |
4316 static std::string name(const std::string& ename, int id_) | |
4317 { | |
4318 return concat("[json.exception.", ename, '.', std::to_string(id_), "] "); | |
4319 } | |
4320 | |
4321 static std::string diagnostics(std::nullptr_t /*leaf_element*/) | |
4322 { | |
4323 return ""; | |
4324 } | |
4325 | |
4326 template<typename BasicJsonType> | |
4327 static std::string diagnostics(const BasicJsonType* leaf_element) | |
4328 { | |
4329 #if JSON_DIAGNOSTICS | |
4330 std::vector<std::string> tokens; | |
4331 for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent) | |
4332 { | |
4333 switch (current->m_parent->type()) | |
4334 { | |
4335 case value_t::array: | |
4336 { | |
4337 for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) | |
4338 { | |
4339 if (¤t->m_parent->m_value.array->operator[](i) == current) | |
4340 { | |
4341 tokens.emplace_back(std::to_string(i)); | |
4342 break; | |
4343 } | |
4344 } | |
4345 break; | |
4346 } | |
4347 | |
4348 case value_t::object: | |
4349 { | |
4350 for (const auto& element : *current->m_parent->m_value.object) | |
4351 { | |
4352 if (&element.second == current) | |
4353 { | |
4354 tokens.emplace_back(element.first.c_str()); | |
4355 break; | |
4356 } | |
4357 } | |
4358 break; | |
4359 } | |
4360 | |
4361 case value_t::null: // LCOV_EXCL_LINE | |
4362 case value_t::string: // LCOV_EXCL_LINE | |
4363 case value_t::boolean: // LCOV_EXCL_LINE | |
4364 case value_t::number_integer: // LCOV_EXCL_LINE | |
4365 case value_t::number_unsigned: // LCOV_EXCL_LINE | |
4366 case value_t::number_float: // LCOV_EXCL_LINE | |
4367 case value_t::binary: // LCOV_EXCL_LINE | |
4368 case value_t::discarded: // LCOV_EXCL_LINE | |
4369 default: // LCOV_EXCL_LINE | |
4370 break; // LCOV_EXCL_LINE | |
4371 } | |
4372 } | |
4373 | |
4374 if (tokens.empty()) | |
4375 { | |
4376 return ""; | |
4377 } | |
4378 | |
4379 auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, | |
4380 [](const std::string & a, const std::string & b) | |
4381 { | |
4382 return concat(a, '/', detail::escape(b)); | |
4383 }); | |
4384 return concat('(', str, ") "); | |
4385 #else | |
4386 static_cast<void>(leaf_element); | |
4387 return ""; | |
4388 #endif | |
4389 } | |
4390 | |
4391 private: | |
4392 /// an exception object as storage for error messages | |
4393 std::runtime_error m; | |
4394 }; | |
4395 | |
4396 /// @brief exception indicating a parse error | |
4397 /// @sa https://json.nlohmann.me/api/basic_json/parse_error/ | |
4398 class parse_error : public exception | |
4399 { | |
4400 public: | |
4401 /*! | |
4402 @brief create a parse error exception | |
4403 @param[in] id_ the id of the exception | |
4404 @param[in] pos the position where the error occurred (or with | |
4405 chars_read_total=0 if the position cannot be | |
4406 determined) | |
4407 @param[in] what_arg the explanatory string | |
4408 @return parse_error object | |
4409 */ | |
4410 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> | |
4411 static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) | |
4412 { | |
4413 std::string w = concat(exception::name("parse_error", id_), "parse error", | |
4414 position_string(pos), ": ", exception::diagnostics(context), what_arg); | |
4415 return {id_, pos.chars_read_total, w.c_str()}; | |
4416 } | |
4417 | |
4418 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> | |
4419 static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) | |
4420 { | |
4421 std::string w = concat(exception::name("parse_error", id_), "parse error", | |
4422 (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""), | |
4423 ": ", exception::diagnostics(context), what_arg); | |
4424 return {id_, byte_, w.c_str()}; | |
4425 } | |
4426 | |
4427 /*! | |
4428 @brief byte index of the parse error | |
4429 | |
4430 The byte index of the last read character in the input file. | |
4431 | |
4432 @note For an input with n bytes, 1 is the index of the first character and | |
4433 n+1 is the index of the terminating null byte or the end of file. | |
4434 This also holds true when reading a byte vector (CBOR or MessagePack). | |
4435 */ | |
4436 const std::size_t byte; | |
4437 | |
4438 private: | |
4439 parse_error(int id_, std::size_t byte_, const char* what_arg) | |
4440 : exception(id_, what_arg), byte(byte_) {} | |
4441 | |
4442 static std::string position_string(const position_t& pos) | |
4443 { | |
4444 return concat(" at line ", std::to_string(pos.lines_read + 1), | |
4445 ", column ", std::to_string(pos.chars_read_current_line)); | |
4446 } | |
4447 }; | |
4448 | |
4449 /// @brief exception indicating errors with iterators | |
4450 /// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/ | |
4451 class invalid_iterator : public exception | |
4452 { | |
4453 public: | |
4454 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> | |
4455 static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context) | |
4456 { | |
4457 std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg); | |
4458 return {id_, w.c_str()}; | |
4459 } | |
4460 | |
4461 private: | |
4462 JSON_HEDLEY_NON_NULL(3) | |
4463 invalid_iterator(int id_, const char* what_arg) | |
4464 : exception(id_, what_arg) {} | |
4465 }; | |
4466 | |
4467 /// @brief exception indicating executing a member function with a wrong type | |
4468 /// @sa https://json.nlohmann.me/api/basic_json/type_error/ | |
4469 class type_error : public exception | |
4470 { | |
4471 public: | |
4472 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> | |
4473 static type_error create(int id_, const std::string& what_arg, BasicJsonContext context) | |
4474 { | |
4475 std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg); | |
4476 return {id_, w.c_str()}; | |
4477 } | |
4478 | |
4479 private: | |
4480 JSON_HEDLEY_NON_NULL(3) | |
4481 type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} | |
4482 }; | |
4483 | |
4484 /// @brief exception indicating access out of the defined range | |
4485 /// @sa https://json.nlohmann.me/api/basic_json/out_of_range/ | |
4486 class out_of_range : public exception | |
4487 { | |
4488 public: | |
4489 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> | |
4490 static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context) | |
4491 { | |
4492 std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg); | |
4493 return {id_, w.c_str()}; | |
4494 } | |
4495 | |
4496 private: | |
4497 JSON_HEDLEY_NON_NULL(3) | |
4498 out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} | |
4499 }; | |
4500 | |
4501 /// @brief exception indicating other library errors | |
4502 /// @sa https://json.nlohmann.me/api/basic_json/other_error/ | |
4503 class other_error : public exception | |
4504 { | |
4505 public: | |
4506 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> | |
4507 static other_error create(int id_, const std::string& what_arg, BasicJsonContext context) | |
4508 { | |
4509 std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg); | |
4510 return {id_, w.c_str()}; | |
4511 } | |
4512 | |
4513 private: | |
4514 JSON_HEDLEY_NON_NULL(3) | |
4515 other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} | |
4516 }; | |
4517 | |
4518 } // namespace detail | |
4519 NLOHMANN_JSON_NAMESPACE_END | |
4520 | |
4521 // #include <nlohmann/detail/macro_scope.hpp> | |
4522 | |
4523 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
4524 | |
4525 // #include <nlohmann/detail/meta/identity_tag.hpp> | |
4526 // __ _____ _____ _____ | |
4527 // __| | __| | | | JSON for Modern C++ | |
4528 // | | |__ | | | | | | version 3.11.2 | |
4529 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
4530 // | |
4531 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
4532 // SPDX-License-Identifier: MIT | |
4533 | |
4534 | |
4535 | |
4536 // #include <nlohmann/detail/abi_macros.hpp> | |
4537 | |
4538 | |
4539 NLOHMANN_JSON_NAMESPACE_BEGIN | |
4540 namespace detail | |
4541 { | |
4542 | |
4543 // dispatching helper struct | |
4544 template <class T> struct identity_tag {}; | |
4545 | |
4546 } // namespace detail | |
4547 NLOHMANN_JSON_NAMESPACE_END | |
4548 | |
4549 // #include <nlohmann/detail/meta/std_fs.hpp> | |
4550 // __ _____ _____ _____ | |
4551 // __| | __| | | | JSON for Modern C++ | |
4552 // | | |__ | | | | | | version 3.11.2 | |
4553 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
4554 // | |
4555 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
4556 // SPDX-License-Identifier: MIT | |
4557 | |
4558 | |
4559 | |
4560 // #include <nlohmann/detail/macro_scope.hpp> | |
4561 | |
4562 | |
4563 #if JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
4564 #include <experimental/filesystem> | |
4565 NLOHMANN_JSON_NAMESPACE_BEGIN | |
4566 namespace detail | |
4567 { | |
4568 namespace std_fs = std::experimental::filesystem; | |
4569 } // namespace detail | |
4570 NLOHMANN_JSON_NAMESPACE_END | |
4571 #elif JSON_HAS_FILESYSTEM | |
4572 #include <filesystem> | |
4573 NLOHMANN_JSON_NAMESPACE_BEGIN | |
4574 namespace detail | |
4575 { | |
4576 namespace std_fs = std::filesystem; | |
4577 } // namespace detail | |
4578 NLOHMANN_JSON_NAMESPACE_END | |
4579 #endif | |
4580 | |
4581 // #include <nlohmann/detail/meta/type_traits.hpp> | |
4582 | |
4583 // #include <nlohmann/detail/string_concat.hpp> | |
4584 | |
4585 // #include <nlohmann/detail/value_t.hpp> | |
4586 | |
4587 | |
4588 NLOHMANN_JSON_NAMESPACE_BEGIN | |
4589 namespace detail | |
4590 { | |
4591 | |
4592 template<typename BasicJsonType> | |
4593 inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) | |
4594 { | |
4595 if (JSON_HEDLEY_UNLIKELY(!j.is_null())) | |
4596 { | |
4597 JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j)); | |
4598 } | |
4599 n = nullptr; | |
4600 } | |
4601 | |
4602 // overloads for basic_json template parameters | |
4603 template < typename BasicJsonType, typename ArithmeticType, | |
4604 enable_if_t < std::is_arithmetic<ArithmeticType>::value&& | |
4605 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, | |
4606 int > = 0 > | |
4607 void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) | |
4608 { | |
4609 switch (static_cast<value_t>(j)) | |
4610 { | |
4611 case value_t::number_unsigned: | |
4612 { | |
4613 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>()); | |
4614 break; | |
4615 } | |
4616 case value_t::number_integer: | |
4617 { | |
4618 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>()); | |
4619 break; | |
4620 } | |
4621 case value_t::number_float: | |
4622 { | |
4623 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>()); | |
4624 break; | |
4625 } | |
4626 | |
4627 case value_t::null: | |
4628 case value_t::object: | |
4629 case value_t::array: | |
4630 case value_t::string: | |
4631 case value_t::boolean: | |
4632 case value_t::binary: | |
4633 case value_t::discarded: | |
4634 default: | |
4635 JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); | |
4636 } | |
4637 } | |
4638 | |
4639 template<typename BasicJsonType> | |
4640 inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) | |
4641 { | |
4642 if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) | |
4643 { | |
4644 JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j)); | |
4645 } | |
4646 b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>(); | |
4647 } | |
4648 | |
4649 template<typename BasicJsonType> | |
4650 inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) | |
4651 { | |
4652 if (JSON_HEDLEY_UNLIKELY(!j.is_string())) | |
4653 { | |
4654 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); | |
4655 } | |
4656 s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); | |
4657 } | |
4658 | |
4659 template < | |
4660 typename BasicJsonType, typename StringType, | |
4661 enable_if_t < | |
4662 std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value | |
4663 && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value | |
4664 && !std::is_same<typename BasicJsonType::string_t, StringType>::value | |
4665 && !is_json_ref<StringType>::value, int > = 0 > | |
4666 inline void from_json(const BasicJsonType& j, StringType& s) | |
4667 { | |
4668 if (JSON_HEDLEY_UNLIKELY(!j.is_string())) | |
4669 { | |
4670 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); | |
4671 } | |
4672 | |
4673 s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); | |
4674 } | |
4675 | |
4676 template<typename BasicJsonType> | |
4677 inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) | |
4678 { | |
4679 get_arithmetic_value(j, val); | |
4680 } | |
4681 | |
4682 template<typename BasicJsonType> | |
4683 inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) | |
4684 { | |
4685 get_arithmetic_value(j, val); | |
4686 } | |
4687 | |
4688 template<typename BasicJsonType> | |
4689 inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) | |
4690 { | |
4691 get_arithmetic_value(j, val); | |
4692 } | |
4693 | |
4694 #if !JSON_DISABLE_ENUM_SERIALIZATION | |
4695 template<typename BasicJsonType, typename EnumType, | |
4696 enable_if_t<std::is_enum<EnumType>::value, int> = 0> | |
4697 inline void from_json(const BasicJsonType& j, EnumType& e) | |
4698 { | |
4699 typename std::underlying_type<EnumType>::type val; | |
4700 get_arithmetic_value(j, val); | |
4701 e = static_cast<EnumType>(val); | |
4702 } | |
4703 #endif // JSON_DISABLE_ENUM_SERIALIZATION | |
4704 | |
4705 // forward_list doesn't have an insert method | |
4706 template<typename BasicJsonType, typename T, typename Allocator, | |
4707 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0> | |
4708 inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) | |
4709 { | |
4710 if (JSON_HEDLEY_UNLIKELY(!j.is_array())) | |
4711 { | |
4712 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); | |
4713 } | |
4714 l.clear(); | |
4715 std::transform(j.rbegin(), j.rend(), | |
4716 std::front_inserter(l), [](const BasicJsonType & i) | |
4717 { | |
4718 return i.template get<T>(); | |
4719 }); | |
4720 } | |
4721 | |
4722 // valarray doesn't have an insert method | |
4723 template<typename BasicJsonType, typename T, | |
4724 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0> | |
4725 inline void from_json(const BasicJsonType& j, std::valarray<T>& l) | |
4726 { | |
4727 if (JSON_HEDLEY_UNLIKELY(!j.is_array())) | |
4728 { | |
4729 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); | |
4730 } | |
4731 l.resize(j.size()); | |
4732 std::transform(j.begin(), j.end(), std::begin(l), | |
4733 [](const BasicJsonType & elem) | |
4734 { | |
4735 return elem.template get<T>(); | |
4736 }); | |
4737 } | |
4738 | |
4739 template<typename BasicJsonType, typename T, std::size_t N> | |
4740 auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) | |
4741 -> decltype(j.template get<T>(), void()) | |
4742 { | |
4743 for (std::size_t i = 0; i < N; ++i) | |
4744 { | |
4745 arr[i] = j.at(i).template get<T>(); | |
4746 } | |
4747 } | |
4748 | |
4749 template<typename BasicJsonType> | |
4750 inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) | |
4751 { | |
4752 arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); | |
4753 } | |
4754 | |
4755 template<typename BasicJsonType, typename T, std::size_t N> | |
4756 auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, | |
4757 priority_tag<2> /*unused*/) | |
4758 -> decltype(j.template get<T>(), void()) | |
4759 { | |
4760 for (std::size_t i = 0; i < N; ++i) | |
4761 { | |
4762 arr[i] = j.at(i).template get<T>(); | |
4763 } | |
4764 } | |
4765 | |
4766 template<typename BasicJsonType, typename ConstructibleArrayType, | |
4767 enable_if_t< | |
4768 std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value, | |
4769 int> = 0> | |
4770 auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) | |
4771 -> decltype( | |
4772 arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()), | |
4773 j.template get<typename ConstructibleArrayType::value_type>(), | |
4774 void()) | |
4775 { | |
4776 using std::end; | |
4777 | |
4778 ConstructibleArrayType ret; | |
4779 ret.reserve(j.size()); | |
4780 std::transform(j.begin(), j.end(), | |
4781 std::inserter(ret, end(ret)), [](const BasicJsonType & i) | |
4782 { | |
4783 // get<BasicJsonType>() returns *this, this won't call a from_json | |
4784 // method when value_type is BasicJsonType | |
4785 return i.template get<typename ConstructibleArrayType::value_type>(); | |
4786 }); | |
4787 arr = std::move(ret); | |
4788 } | |
4789 | |
4790 template<typename BasicJsonType, typename ConstructibleArrayType, | |
4791 enable_if_t< | |
4792 std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value, | |
4793 int> = 0> | |
4794 inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, | |
4795 priority_tag<0> /*unused*/) | |
4796 { | |
4797 using std::end; | |
4798 | |
4799 ConstructibleArrayType ret; | |
4800 std::transform( | |
4801 j.begin(), j.end(), std::inserter(ret, end(ret)), | |
4802 [](const BasicJsonType & i) | |
4803 { | |
4804 // get<BasicJsonType>() returns *this, this won't call a from_json | |
4805 // method when value_type is BasicJsonType | |
4806 return i.template get<typename ConstructibleArrayType::value_type>(); | |
4807 }); | |
4808 arr = std::move(ret); | |
4809 } | |
4810 | |
4811 template < typename BasicJsonType, typename ConstructibleArrayType, | |
4812 enable_if_t < | |
4813 is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&& | |
4814 !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&& | |
4815 !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&& | |
4816 !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&& | |
4817 !is_basic_json<ConstructibleArrayType>::value, | |
4818 int > = 0 > | |
4819 auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) | |
4820 -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), | |
4821 j.template get<typename ConstructibleArrayType::value_type>(), | |
4822 void()) | |
4823 { | |
4824 if (JSON_HEDLEY_UNLIKELY(!j.is_array())) | |
4825 { | |
4826 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); | |
4827 } | |
4828 | |
4829 from_json_array_impl(j, arr, priority_tag<3> {}); | |
4830 } | |
4831 | |
4832 template < typename BasicJsonType, typename T, std::size_t... Idx > | |
4833 std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j, | |
4834 identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/) | |
4835 { | |
4836 return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } }; | |
4837 } | |
4838 | |
4839 template < typename BasicJsonType, typename T, std::size_t N > | |
4840 auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag) | |
4841 -> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {})) | |
4842 { | |
4843 if (JSON_HEDLEY_UNLIKELY(!j.is_array())) | |
4844 { | |
4845 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); | |
4846 } | |
4847 | |
4848 return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}); | |
4849 } | |
4850 | |
4851 template<typename BasicJsonType> | |
4852 inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) | |
4853 { | |
4854 if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) | |
4855 { | |
4856 JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j)); | |
4857 } | |
4858 | |
4859 bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>(); | |
4860 } | |
4861 | |
4862 template<typename BasicJsonType, typename ConstructibleObjectType, | |
4863 enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0> | |
4864 inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) | |
4865 { | |
4866 if (JSON_HEDLEY_UNLIKELY(!j.is_object())) | |
4867 { | |
4868 JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j)); | |
4869 } | |
4870 | |
4871 ConstructibleObjectType ret; | |
4872 const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>(); | |
4873 using value_type = typename ConstructibleObjectType::value_type; | |
4874 std::transform( | |
4875 inner_object->begin(), inner_object->end(), | |
4876 std::inserter(ret, ret.begin()), | |
4877 [](typename BasicJsonType::object_t::value_type const & p) | |
4878 { | |
4879 return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>()); | |
4880 }); | |
4881 obj = std::move(ret); | |
4882 } | |
4883 | |
4884 // overload for arithmetic types, not chosen for basic_json template arguments | |
4885 // (BooleanType, etc..); note: Is it really necessary to provide explicit | |
4886 // overloads for boolean_t etc. in case of a custom BooleanType which is not | |
4887 // an arithmetic type? | |
4888 template < typename BasicJsonType, typename ArithmeticType, | |
4889 enable_if_t < | |
4890 std::is_arithmetic<ArithmeticType>::value&& | |
4891 !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&& | |
4892 !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&& | |
4893 !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&& | |
4894 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, | |
4895 int > = 0 > | |
4896 inline void from_json(const BasicJsonType& j, ArithmeticType& val) | |
4897 { | |
4898 switch (static_cast<value_t>(j)) | |
4899 { | |
4900 case value_t::number_unsigned: | |
4901 { | |
4902 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>()); | |
4903 break; | |
4904 } | |
4905 case value_t::number_integer: | |
4906 { | |
4907 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>()); | |
4908 break; | |
4909 } | |
4910 case value_t::number_float: | |
4911 { | |
4912 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>()); | |
4913 break; | |
4914 } | |
4915 case value_t::boolean: | |
4916 { | |
4917 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>()); | |
4918 break; | |
4919 } | |
4920 | |
4921 case value_t::null: | |
4922 case value_t::object: | |
4923 case value_t::array: | |
4924 case value_t::string: | |
4925 case value_t::binary: | |
4926 case value_t::discarded: | |
4927 default: | |
4928 JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); | |
4929 } | |
4930 } | |
4931 | |
4932 template<typename BasicJsonType, typename... Args, std::size_t... Idx> | |
4933 std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/) | |
4934 { | |
4935 return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...); | |
4936 } | |
4937 | |
4938 template < typename BasicJsonType, class A1, class A2 > | |
4939 std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/) | |
4940 { | |
4941 return {std::forward<BasicJsonType>(j).at(0).template get<A1>(), | |
4942 std::forward<BasicJsonType>(j).at(1).template get<A2>()}; | |
4943 } | |
4944 | |
4945 template<typename BasicJsonType, typename A1, typename A2> | |
4946 inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/) | |
4947 { | |
4948 p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {}); | |
4949 } | |
4950 | |
4951 template<typename BasicJsonType, typename... Args> | |
4952 std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/) | |
4953 { | |
4954 return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {}); | |
4955 } | |
4956 | |
4957 template<typename BasicJsonType, typename... Args> | |
4958 inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/) | |
4959 { | |
4960 t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {}); | |
4961 } | |
4962 | |
4963 template<typename BasicJsonType, typename TupleRelated> | |
4964 auto from_json(BasicJsonType&& j, TupleRelated&& t) | |
4965 -> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {})) | |
4966 { | |
4967 if (JSON_HEDLEY_UNLIKELY(!j.is_array())) | |
4968 { | |
4969 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); | |
4970 } | |
4971 | |
4972 return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}); | |
4973 } | |
4974 | |
4975 template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, | |
4976 typename = enable_if_t < !std::is_constructible < | |
4977 typename BasicJsonType::string_t, Key >::value >> | |
4978 inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m) | |
4979 { | |
4980 if (JSON_HEDLEY_UNLIKELY(!j.is_array())) | |
4981 { | |
4982 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); | |
4983 } | |
4984 m.clear(); | |
4985 for (const auto& p : j) | |
4986 { | |
4987 if (JSON_HEDLEY_UNLIKELY(!p.is_array())) | |
4988 { | |
4989 JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); | |
4990 } | |
4991 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>()); | |
4992 } | |
4993 } | |
4994 | |
4995 template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, | |
4996 typename = enable_if_t < !std::is_constructible < | |
4997 typename BasicJsonType::string_t, Key >::value >> | |
4998 inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m) | |
4999 { | |
5000 if (JSON_HEDLEY_UNLIKELY(!j.is_array())) | |
5001 { | |
5002 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); | |
5003 } | |
5004 m.clear(); | |
5005 for (const auto& p : j) | |
5006 { | |
5007 if (JSON_HEDLEY_UNLIKELY(!p.is_array())) | |
5008 { | |
5009 JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); | |
5010 } | |
5011 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>()); | |
5012 } | |
5013 } | |
5014 | |
5015 #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
5016 template<typename BasicJsonType> | |
5017 inline void from_json(const BasicJsonType& j, std_fs::path& p) | |
5018 { | |
5019 if (JSON_HEDLEY_UNLIKELY(!j.is_string())) | |
5020 { | |
5021 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); | |
5022 } | |
5023 p = *j.template get_ptr<const typename BasicJsonType::string_t*>(); | |
5024 } | |
5025 #endif | |
5026 | |
5027 struct from_json_fn | |
5028 { | |
5029 template<typename BasicJsonType, typename T> | |
5030 auto operator()(const BasicJsonType& j, T&& val) const | |
5031 noexcept(noexcept(from_json(j, std::forward<T>(val)))) | |
5032 -> decltype(from_json(j, std::forward<T>(val))) | |
5033 { | |
5034 return from_json(j, std::forward<T>(val)); | |
5035 } | |
5036 }; | |
5037 | |
5038 } // namespace detail | |
5039 | |
5040 #ifndef JSON_HAS_CPP_17 | |
5041 /// namespace to hold default `from_json` function | |
5042 /// to see why this is required: | |
5043 /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html | |
5044 namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) | |
5045 { | |
5046 #endif | |
5047 JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers) | |
5048 detail::static_const<detail::from_json_fn>::value; | |
5049 #ifndef JSON_HAS_CPP_17 | |
5050 } // namespace | |
5051 #endif | |
5052 | |
5053 NLOHMANN_JSON_NAMESPACE_END | |
5054 | |
5055 // #include <nlohmann/detail/conversions/to_json.hpp> | |
5056 // __ _____ _____ _____ | |
5057 // __| | __| | | | JSON for Modern C++ | |
5058 // | | |__ | | | | | | version 3.11.2 | |
5059 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
5060 // | |
5061 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
5062 // SPDX-License-Identifier: MIT | |
5063 | |
5064 | |
5065 | |
5066 #include <algorithm> // copy | |
5067 #include <iterator> // begin, end | |
5068 #include <string> // string | |
5069 #include <tuple> // tuple, get | |
5070 #include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type | |
5071 #include <utility> // move, forward, declval, pair | |
5072 #include <valarray> // valarray | |
5073 #include <vector> // vector | |
5074 | |
5075 // #include <nlohmann/detail/iterators/iteration_proxy.hpp> | |
5076 // __ _____ _____ _____ | |
5077 // __| | __| | | | JSON for Modern C++ | |
5078 // | | |__ | | | | | | version 3.11.2 | |
5079 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
5080 // | |
5081 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
5082 // SPDX-License-Identifier: MIT | |
5083 | |
5084 | |
5085 | |
5086 #include <cstddef> // size_t | |
5087 #include <iterator> // input_iterator_tag | |
5088 #include <string> // string, to_string | |
5089 #include <tuple> // tuple_size, get, tuple_element | |
5090 #include <utility> // move | |
5091 | |
5092 #if JSON_HAS_RANGES | |
5093 #include <ranges> // enable_borrowed_range | |
5094 #endif | |
5095 | |
5096 // #include <nlohmann/detail/abi_macros.hpp> | |
5097 | |
5098 // #include <nlohmann/detail/meta/type_traits.hpp> | |
5099 | |
5100 // #include <nlohmann/detail/value_t.hpp> | |
5101 | |
5102 | |
5103 NLOHMANN_JSON_NAMESPACE_BEGIN | |
5104 namespace detail | |
5105 { | |
5106 | |
5107 template<typename string_type> | |
5108 void int_to_string( string_type& target, std::size_t value ) | |
5109 { | |
5110 // For ADL | |
5111 using std::to_string; | |
5112 target = to_string(value); | |
5113 } | |
5114 template<typename IteratorType> class iteration_proxy_value | |
5115 { | |
5116 public: | |
5117 using difference_type = std::ptrdiff_t; | |
5118 using value_type = iteration_proxy_value; | |
5119 using pointer = value_type *; | |
5120 using reference = value_type &; | |
5121 using iterator_category = std::input_iterator_tag; | |
5122 using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type; | |
5123 | |
5124 private: | |
5125 /// the iterator | |
5126 IteratorType anchor{}; | |
5127 /// an index for arrays (used to create key names) | |
5128 std::size_t array_index = 0; | |
5129 /// last stringified array index | |
5130 mutable std::size_t array_index_last = 0; | |
5131 /// a string representation of the array index | |
5132 mutable string_type array_index_str = "0"; | |
5133 /// an empty string (to return a reference for primitive values) | |
5134 string_type empty_str{}; | |
5135 | |
5136 public: | |
5137 explicit iteration_proxy_value() = default; | |
5138 explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0) | |
5139 noexcept(std::is_nothrow_move_constructible<IteratorType>::value | |
5140 && std::is_nothrow_default_constructible<string_type>::value) | |
5141 : anchor(std::move(it)) | |
5142 , array_index(array_index_) | |
5143 {} | |
5144 | |
5145 iteration_proxy_value(iteration_proxy_value const&) = default; | |
5146 iteration_proxy_value& operator=(iteration_proxy_value const&) = default; | |
5147 // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions | |
5148 iteration_proxy_value(iteration_proxy_value&&) | |
5149 noexcept(std::is_nothrow_move_constructible<IteratorType>::value | |
5150 && std::is_nothrow_move_constructible<string_type>::value) = default; | |
5151 iteration_proxy_value& operator=(iteration_proxy_value&&) | |
5152 noexcept(std::is_nothrow_move_assignable<IteratorType>::value | |
5153 && std::is_nothrow_move_assignable<string_type>::value) = default; | |
5154 ~iteration_proxy_value() = default; | |
5155 | |
5156 /// dereference operator (needed for range-based for) | |
5157 const iteration_proxy_value& operator*() const | |
5158 { | |
5159 return *this; | |
5160 } | |
5161 | |
5162 /// increment operator (needed for range-based for) | |
5163 iteration_proxy_value& operator++() | |
5164 { | |
5165 ++anchor; | |
5166 ++array_index; | |
5167 | |
5168 return *this; | |
5169 } | |
5170 | |
5171 iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp) | |
5172 { | |
5173 auto tmp = iteration_proxy_value(anchor, array_index); | |
5174 ++anchor; | |
5175 ++array_index; | |
5176 return tmp; | |
5177 } | |
5178 | |
5179 /// equality operator (needed for InputIterator) | |
5180 bool operator==(const iteration_proxy_value& o) const | |
5181 { | |
5182 return anchor == o.anchor; | |
5183 } | |
5184 | |
5185 /// inequality operator (needed for range-based for) | |
5186 bool operator!=(const iteration_proxy_value& o) const | |
5187 { | |
5188 return anchor != o.anchor; | |
5189 } | |
5190 | |
5191 /// return key of the iterator | |
5192 const string_type& key() const | |
5193 { | |
5194 JSON_ASSERT(anchor.m_object != nullptr); | |
5195 | |
5196 switch (anchor.m_object->type()) | |
5197 { | |
5198 // use integer array index as key | |
5199 case value_t::array: | |
5200 { | |
5201 if (array_index != array_index_last) | |
5202 { | |
5203 int_to_string( array_index_str, array_index ); | |
5204 array_index_last = array_index; | |
5205 } | |
5206 return array_index_str; | |
5207 } | |
5208 | |
5209 // use key from the object | |
5210 case value_t::object: | |
5211 return anchor.key(); | |
5212 | |
5213 // use an empty key for all primitive types | |
5214 case value_t::null: | |
5215 case value_t::string: | |
5216 case value_t::boolean: | |
5217 case value_t::number_integer: | |
5218 case value_t::number_unsigned: | |
5219 case value_t::number_float: | |
5220 case value_t::binary: | |
5221 case value_t::discarded: | |
5222 default: | |
5223 return empty_str; | |
5224 } | |
5225 } | |
5226 | |
5227 /// return value of the iterator | |
5228 typename IteratorType::reference value() const | |
5229 { | |
5230 return anchor.value(); | |
5231 } | |
5232 }; | |
5233 | |
5234 /// proxy class for the items() function | |
5235 template<typename IteratorType> class iteration_proxy | |
5236 { | |
5237 private: | |
5238 /// the container to iterate | |
5239 typename IteratorType::pointer container = nullptr; | |
5240 | |
5241 public: | |
5242 explicit iteration_proxy() = default; | |
5243 | |
5244 /// construct iteration proxy from a container | |
5245 explicit iteration_proxy(typename IteratorType::reference cont) noexcept | |
5246 : container(&cont) {} | |
5247 | |
5248 iteration_proxy(iteration_proxy const&) = default; | |
5249 iteration_proxy& operator=(iteration_proxy const&) = default; | |
5250 iteration_proxy(iteration_proxy&&) noexcept = default; | |
5251 iteration_proxy& operator=(iteration_proxy&&) noexcept = default; | |
5252 ~iteration_proxy() = default; | |
5253 | |
5254 /// return iterator begin (needed for range-based for) | |
5255 iteration_proxy_value<IteratorType> begin() const noexcept | |
5256 { | |
5257 return iteration_proxy_value<IteratorType>(container->begin()); | |
5258 } | |
5259 | |
5260 /// return iterator end (needed for range-based for) | |
5261 iteration_proxy_value<IteratorType> end() const noexcept | |
5262 { | |
5263 return iteration_proxy_value<IteratorType>(container->end()); | |
5264 } | |
5265 }; | |
5266 | |
5267 // Structured Bindings Support | |
5268 // For further reference see https://blog.tartanllama.xyz/structured-bindings/ | |
5269 // And see https://github.com/nlohmann/json/pull/1391 | |
5270 template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0> | |
5271 auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key()) | |
5272 { | |
5273 return i.key(); | |
5274 } | |
5275 // Structured Bindings Support | |
5276 // For further reference see https://blog.tartanllama.xyz/structured-bindings/ | |
5277 // And see https://github.com/nlohmann/json/pull/1391 | |
5278 template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0> | |
5279 auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value()) | |
5280 { | |
5281 return i.value(); | |
5282 } | |
5283 | |
5284 } // namespace detail | |
5285 NLOHMANN_JSON_NAMESPACE_END | |
5286 | |
5287 // The Addition to the STD Namespace is required to add | |
5288 // Structured Bindings Support to the iteration_proxy_value class | |
5289 // For further reference see https://blog.tartanllama.xyz/structured-bindings/ | |
5290 // And see https://github.com/nlohmann/json/pull/1391 | |
5291 namespace std | |
5292 { | |
5293 | |
5294 #if defined(__clang__) | |
5295 // Fix: https://github.com/nlohmann/json/issues/1401 | |
5296 #pragma clang diagnostic push | |
5297 #pragma clang diagnostic ignored "-Wmismatched-tags" | |
5298 #endif | |
5299 template<typename IteratorType> | |
5300 class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> | |
5301 : public std::integral_constant<std::size_t, 2> {}; | |
5302 | |
5303 template<std::size_t N, typename IteratorType> | |
5304 class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> | |
5305 { | |
5306 public: | |
5307 using type = decltype( | |
5308 get<N>(std::declval < | |
5309 ::nlohmann::detail::iteration_proxy_value<IteratorType >> ())); | |
5310 }; | |
5311 #if defined(__clang__) | |
5312 #pragma clang diagnostic pop | |
5313 #endif | |
5314 | |
5315 } // namespace std | |
5316 | |
5317 #if JSON_HAS_RANGES | |
5318 template <typename IteratorType> | |
5319 inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true; | |
5320 #endif | |
5321 | |
5322 // #include <nlohmann/detail/macro_scope.hpp> | |
5323 | |
5324 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
5325 | |
5326 // #include <nlohmann/detail/meta/std_fs.hpp> | |
5327 | |
5328 // #include <nlohmann/detail/meta/type_traits.hpp> | |
5329 | |
5330 // #include <nlohmann/detail/value_t.hpp> | |
5331 | |
5332 | |
5333 NLOHMANN_JSON_NAMESPACE_BEGIN | |
5334 namespace detail | |
5335 { | |
5336 | |
5337 ////////////////// | |
5338 // constructors // | |
5339 ////////////////// | |
5340 | |
5341 /* | |
5342 * Note all external_constructor<>::construct functions need to call | |
5343 * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an | |
5344 * allocated value (e.g., a string). See bug issue | |
5345 * https://github.com/nlohmann/json/issues/2865 for more information. | |
5346 */ | |
5347 | |
5348 template<value_t> struct external_constructor; | |
5349 | |
5350 template<> | |
5351 struct external_constructor<value_t::boolean> | |
5352 { | |
5353 template<typename BasicJsonType> | |
5354 static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept | |
5355 { | |
5356 j.m_value.destroy(j.m_type); | |
5357 j.m_type = value_t::boolean; | |
5358 j.m_value = b; | |
5359 j.assert_invariant(); | |
5360 } | |
5361 }; | |
5362 | |
5363 template<> | |
5364 struct external_constructor<value_t::string> | |
5365 { | |
5366 template<typename BasicJsonType> | |
5367 static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) | |
5368 { | |
5369 j.m_value.destroy(j.m_type); | |
5370 j.m_type = value_t::string; | |
5371 j.m_value = s; | |
5372 j.assert_invariant(); | |
5373 } | |
5374 | |
5375 template<typename BasicJsonType> | |
5376 static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) | |
5377 { | |
5378 j.m_value.destroy(j.m_type); | |
5379 j.m_type = value_t::string; | |
5380 j.m_value = std::move(s); | |
5381 j.assert_invariant(); | |
5382 } | |
5383 | |
5384 template < typename BasicJsonType, typename CompatibleStringType, | |
5385 enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value, | |
5386 int > = 0 > | |
5387 static void construct(BasicJsonType& j, const CompatibleStringType& str) | |
5388 { | |
5389 j.m_value.destroy(j.m_type); | |
5390 j.m_type = value_t::string; | |
5391 j.m_value.string = j.template create<typename BasicJsonType::string_t>(str); | |
5392 j.assert_invariant(); | |
5393 } | |
5394 }; | |
5395 | |
5396 template<> | |
5397 struct external_constructor<value_t::binary> | |
5398 { | |
5399 template<typename BasicJsonType> | |
5400 static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) | |
5401 { | |
5402 j.m_value.destroy(j.m_type); | |
5403 j.m_type = value_t::binary; | |
5404 j.m_value = typename BasicJsonType::binary_t(b); | |
5405 j.assert_invariant(); | |
5406 } | |
5407 | |
5408 template<typename BasicJsonType> | |
5409 static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) | |
5410 { | |
5411 j.m_value.destroy(j.m_type); | |
5412 j.m_type = value_t::binary; | |
5413 j.m_value = typename BasicJsonType::binary_t(std::move(b)); | |
5414 j.assert_invariant(); | |
5415 } | |
5416 }; | |
5417 | |
5418 template<> | |
5419 struct external_constructor<value_t::number_float> | |
5420 { | |
5421 template<typename BasicJsonType> | |
5422 static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept | |
5423 { | |
5424 j.m_value.destroy(j.m_type); | |
5425 j.m_type = value_t::number_float; | |
5426 j.m_value = val; | |
5427 j.assert_invariant(); | |
5428 } | |
5429 }; | |
5430 | |
5431 template<> | |
5432 struct external_constructor<value_t::number_unsigned> | |
5433 { | |
5434 template<typename BasicJsonType> | |
5435 static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept | |
5436 { | |
5437 j.m_value.destroy(j.m_type); | |
5438 j.m_type = value_t::number_unsigned; | |
5439 j.m_value = val; | |
5440 j.assert_invariant(); | |
5441 } | |
5442 }; | |
5443 | |
5444 template<> | |
5445 struct external_constructor<value_t::number_integer> | |
5446 { | |
5447 template<typename BasicJsonType> | |
5448 static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept | |
5449 { | |
5450 j.m_value.destroy(j.m_type); | |
5451 j.m_type = value_t::number_integer; | |
5452 j.m_value = val; | |
5453 j.assert_invariant(); | |
5454 } | |
5455 }; | |
5456 | |
5457 template<> | |
5458 struct external_constructor<value_t::array> | |
5459 { | |
5460 template<typename BasicJsonType> | |
5461 static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) | |
5462 { | |
5463 j.m_value.destroy(j.m_type); | |
5464 j.m_type = value_t::array; | |
5465 j.m_value = arr; | |
5466 j.set_parents(); | |
5467 j.assert_invariant(); | |
5468 } | |
5469 | |
5470 template<typename BasicJsonType> | |
5471 static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) | |
5472 { | |
5473 j.m_value.destroy(j.m_type); | |
5474 j.m_type = value_t::array; | |
5475 j.m_value = std::move(arr); | |
5476 j.set_parents(); | |
5477 j.assert_invariant(); | |
5478 } | |
5479 | |
5480 template < typename BasicJsonType, typename CompatibleArrayType, | |
5481 enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value, | |
5482 int > = 0 > | |
5483 static void construct(BasicJsonType& j, const CompatibleArrayType& arr) | |
5484 { | |
5485 using std::begin; | |
5486 using std::end; | |
5487 | |
5488 j.m_value.destroy(j.m_type); | |
5489 j.m_type = value_t::array; | |
5490 j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr)); | |
5491 j.set_parents(); | |
5492 j.assert_invariant(); | |
5493 } | |
5494 | |
5495 template<typename BasicJsonType> | |
5496 static void construct(BasicJsonType& j, const std::vector<bool>& arr) | |
5497 { | |
5498 j.m_value.destroy(j.m_type); | |
5499 j.m_type = value_t::array; | |
5500 j.m_value = value_t::array; | |
5501 j.m_value.array->reserve(arr.size()); | |
5502 for (const bool x : arr) | |
5503 { | |
5504 j.m_value.array->push_back(x); | |
5505 j.set_parent(j.m_value.array->back()); | |
5506 } | |
5507 j.assert_invariant(); | |
5508 } | |
5509 | |
5510 template<typename BasicJsonType, typename T, | |
5511 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> | |
5512 static void construct(BasicJsonType& j, const std::valarray<T>& arr) | |
5513 { | |
5514 j.m_value.destroy(j.m_type); | |
5515 j.m_type = value_t::array; | |
5516 j.m_value = value_t::array; | |
5517 j.m_value.array->resize(arr.size()); | |
5518 if (arr.size() > 0) | |
5519 { | |
5520 std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); | |
5521 } | |
5522 j.set_parents(); | |
5523 j.assert_invariant(); | |
5524 } | |
5525 }; | |
5526 | |
5527 template<> | |
5528 struct external_constructor<value_t::object> | |
5529 { | |
5530 template<typename BasicJsonType> | |
5531 static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) | |
5532 { | |
5533 j.m_value.destroy(j.m_type); | |
5534 j.m_type = value_t::object; | |
5535 j.m_value = obj; | |
5536 j.set_parents(); | |
5537 j.assert_invariant(); | |
5538 } | |
5539 | |
5540 template<typename BasicJsonType> | |
5541 static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) | |
5542 { | |
5543 j.m_value.destroy(j.m_type); | |
5544 j.m_type = value_t::object; | |
5545 j.m_value = std::move(obj); | |
5546 j.set_parents(); | |
5547 j.assert_invariant(); | |
5548 } | |
5549 | |
5550 template < typename BasicJsonType, typename CompatibleObjectType, | |
5551 enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 > | |
5552 static void construct(BasicJsonType& j, const CompatibleObjectType& obj) | |
5553 { | |
5554 using std::begin; | |
5555 using std::end; | |
5556 | |
5557 j.m_value.destroy(j.m_type); | |
5558 j.m_type = value_t::object; | |
5559 j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj)); | |
5560 j.set_parents(); | |
5561 j.assert_invariant(); | |
5562 } | |
5563 }; | |
5564 | |
5565 ///////////// | |
5566 // to_json // | |
5567 ///////////// | |
5568 | |
5569 template<typename BasicJsonType, typename T, | |
5570 enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0> | |
5571 inline void to_json(BasicJsonType& j, T b) noexcept | |
5572 { | |
5573 external_constructor<value_t::boolean>::construct(j, b); | |
5574 } | |
5575 | |
5576 template < typename BasicJsonType, typename BoolRef, | |
5577 enable_if_t < | |
5578 ((std::is_same<std::vector<bool>::reference, BoolRef>::value | |
5579 && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value) | |
5580 || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value | |
5581 && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>, | |
5582 typename BasicJsonType::boolean_t >::value)) | |
5583 && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 > | |
5584 inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept | |
5585 { | |
5586 external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b)); | |
5587 } | |
5588 | |
5589 template<typename BasicJsonType, typename CompatibleString, | |
5590 enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0> | |
5591 inline void to_json(BasicJsonType& j, const CompatibleString& s) | |
5592 { | |
5593 external_constructor<value_t::string>::construct(j, s); | |
5594 } | |
5595 | |
5596 template<typename BasicJsonType> | |
5597 inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) | |
5598 { | |
5599 external_constructor<value_t::string>::construct(j, std::move(s)); | |
5600 } | |
5601 | |
5602 template<typename BasicJsonType, typename FloatType, | |
5603 enable_if_t<std::is_floating_point<FloatType>::value, int> = 0> | |
5604 inline void to_json(BasicJsonType& j, FloatType val) noexcept | |
5605 { | |
5606 external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val)); | |
5607 } | |
5608 | |
5609 template<typename BasicJsonType, typename CompatibleNumberUnsignedType, | |
5610 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0> | |
5611 inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept | |
5612 { | |
5613 external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val)); | |
5614 } | |
5615 | |
5616 template<typename BasicJsonType, typename CompatibleNumberIntegerType, | |
5617 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0> | |
5618 inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept | |
5619 { | |
5620 external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val)); | |
5621 } | |
5622 | |
5623 #if !JSON_DISABLE_ENUM_SERIALIZATION | |
5624 template<typename BasicJsonType, typename EnumType, | |
5625 enable_if_t<std::is_enum<EnumType>::value, int> = 0> | |
5626 inline void to_json(BasicJsonType& j, EnumType e) noexcept | |
5627 { | |
5628 using underlying_type = typename std::underlying_type<EnumType>::type; | |
5629 external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e)); | |
5630 } | |
5631 #endif // JSON_DISABLE_ENUM_SERIALIZATION | |
5632 | |
5633 template<typename BasicJsonType> | |
5634 inline void to_json(BasicJsonType& j, const std::vector<bool>& e) | |
5635 { | |
5636 external_constructor<value_t::array>::construct(j, e); | |
5637 } | |
5638 | |
5639 template < typename BasicJsonType, typename CompatibleArrayType, | |
5640 enable_if_t < is_compatible_array_type<BasicJsonType, | |
5641 CompatibleArrayType>::value&& | |
5642 !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&& | |
5643 !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&& | |
5644 !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&& | |
5645 !is_basic_json<CompatibleArrayType>::value, | |
5646 int > = 0 > | |
5647 inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) | |
5648 { | |
5649 external_constructor<value_t::array>::construct(j, arr); | |
5650 } | |
5651 | |
5652 template<typename BasicJsonType> | |
5653 inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) | |
5654 { | |
5655 external_constructor<value_t::binary>::construct(j, bin); | |
5656 } | |
5657 | |
5658 template<typename BasicJsonType, typename T, | |
5659 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> | |
5660 inline void to_json(BasicJsonType& j, const std::valarray<T>& arr) | |
5661 { | |
5662 external_constructor<value_t::array>::construct(j, std::move(arr)); | |
5663 } | |
5664 | |
5665 template<typename BasicJsonType> | |
5666 inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) | |
5667 { | |
5668 external_constructor<value_t::array>::construct(j, std::move(arr)); | |
5669 } | |
5670 | |
5671 template < typename BasicJsonType, typename CompatibleObjectType, | |
5672 enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 > | |
5673 inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) | |
5674 { | |
5675 external_constructor<value_t::object>::construct(j, obj); | |
5676 } | |
5677 | |
5678 template<typename BasicJsonType> | |
5679 inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) | |
5680 { | |
5681 external_constructor<value_t::object>::construct(j, std::move(obj)); | |
5682 } | |
5683 | |
5684 template < | |
5685 typename BasicJsonType, typename T, std::size_t N, | |
5686 enable_if_t < !std::is_constructible<typename BasicJsonType::string_t, | |
5687 const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) | |
5688 int > = 0 > | |
5689 inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) | |
5690 { | |
5691 external_constructor<value_t::array>::construct(j, arr); | |
5692 } | |
5693 | |
5694 template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 > | |
5695 inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p) | |
5696 { | |
5697 j = { p.first, p.second }; | |
5698 } | |
5699 | |
5700 // for https://github.com/nlohmann/json/pull/1134 | |
5701 template<typename BasicJsonType, typename T, | |
5702 enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0> | |
5703 inline void to_json(BasicJsonType& j, const T& b) | |
5704 { | |
5705 j = { {b.key(), b.value()} }; | |
5706 } | |
5707 | |
5708 template<typename BasicJsonType, typename Tuple, std::size_t... Idx> | |
5709 inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/) | |
5710 { | |
5711 j = { std::get<Idx>(t)... }; | |
5712 } | |
5713 | |
5714 template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0> | |
5715 inline void to_json(BasicJsonType& j, const T& t) | |
5716 { | |
5717 to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); | |
5718 } | |
5719 | |
5720 #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
5721 template<typename BasicJsonType> | |
5722 inline void to_json(BasicJsonType& j, const std_fs::path& p) | |
5723 { | |
5724 j = p.string(); | |
5725 } | |
5726 #endif | |
5727 | |
5728 struct to_json_fn | |
5729 { | |
5730 template<typename BasicJsonType, typename T> | |
5731 auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) | |
5732 -> decltype(to_json(j, std::forward<T>(val)), void()) | |
5733 { | |
5734 return to_json(j, std::forward<T>(val)); | |
5735 } | |
5736 }; | |
5737 } // namespace detail | |
5738 | |
5739 #ifndef JSON_HAS_CPP_17 | |
5740 /// namespace to hold default `to_json` function | |
5741 /// to see why this is required: | |
5742 /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html | |
5743 namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) | |
5744 { | |
5745 #endif | |
5746 JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers) | |
5747 detail::static_const<detail::to_json_fn>::value; | |
5748 #ifndef JSON_HAS_CPP_17 | |
5749 } // namespace | |
5750 #endif | |
5751 | |
5752 NLOHMANN_JSON_NAMESPACE_END | |
5753 | |
5754 // #include <nlohmann/detail/meta/identity_tag.hpp> | |
5755 | |
5756 | |
5757 NLOHMANN_JSON_NAMESPACE_BEGIN | |
5758 | |
5759 /// @sa https://json.nlohmann.me/api/adl_serializer/ | |
5760 template<typename ValueType, typename> | |
5761 struct adl_serializer | |
5762 { | |
5763 /// @brief convert a JSON value to any value type | |
5764 /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ | |
5765 template<typename BasicJsonType, typename TargetType = ValueType> | |
5766 static auto from_json(BasicJsonType && j, TargetType& val) noexcept( | |
5767 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) | |
5768 -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()) | |
5769 { | |
5770 ::nlohmann::from_json(std::forward<BasicJsonType>(j), val); | |
5771 } | |
5772 | |
5773 /// @brief convert a JSON value to any value type | |
5774 /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ | |
5775 template<typename BasicJsonType, typename TargetType = ValueType> | |
5776 static auto from_json(BasicJsonType && j) noexcept( | |
5777 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))) | |
5778 -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})) | |
5779 { | |
5780 return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}); | |
5781 } | |
5782 | |
5783 /// @brief convert any value type to a JSON value | |
5784 /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ | |
5785 template<typename BasicJsonType, typename TargetType = ValueType> | |
5786 static auto to_json(BasicJsonType& j, TargetType && val) noexcept( | |
5787 noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val)))) | |
5788 -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void()) | |
5789 { | |
5790 ::nlohmann::to_json(j, std::forward<TargetType>(val)); | |
5791 } | |
5792 }; | |
5793 | |
5794 NLOHMANN_JSON_NAMESPACE_END | |
5795 | |
5796 // #include <nlohmann/byte_container_with_subtype.hpp> | |
5797 // __ _____ _____ _____ | |
5798 // __| | __| | | | JSON for Modern C++ | |
5799 // | | |__ | | | | | | version 3.11.2 | |
5800 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
5801 // | |
5802 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
5803 // SPDX-License-Identifier: MIT | |
5804 | |
5805 | |
5806 | |
5807 #include <cstdint> // uint8_t, uint64_t | |
5808 #include <tuple> // tie | |
5809 #include <utility> // move | |
5810 | |
5811 // #include <nlohmann/detail/abi_macros.hpp> | |
5812 | |
5813 | |
5814 NLOHMANN_JSON_NAMESPACE_BEGIN | |
5815 | |
5816 /// @brief an internal type for a backed binary type | |
5817 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ | |
5818 template<typename BinaryType> | |
5819 class byte_container_with_subtype : public BinaryType | |
5820 { | |
5821 public: | |
5822 using container_type = BinaryType; | |
5823 using subtype_type = std::uint64_t; | |
5824 | |
5825 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ | |
5826 byte_container_with_subtype() noexcept(noexcept(container_type())) | |
5827 : container_type() | |
5828 {} | |
5829 | |
5830 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ | |
5831 byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) | |
5832 : container_type(b) | |
5833 {} | |
5834 | |
5835 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ | |
5836 byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) | |
5837 : container_type(std::move(b)) | |
5838 {} | |
5839 | |
5840 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ | |
5841 byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) | |
5842 : container_type(b) | |
5843 , m_subtype(subtype_) | |
5844 , m_has_subtype(true) | |
5845 {} | |
5846 | |
5847 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ | |
5848 byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) | |
5849 : container_type(std::move(b)) | |
5850 , m_subtype(subtype_) | |
5851 , m_has_subtype(true) | |
5852 {} | |
5853 | |
5854 bool operator==(const byte_container_with_subtype& rhs) const | |
5855 { | |
5856 return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) == | |
5857 std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype); | |
5858 } | |
5859 | |
5860 bool operator!=(const byte_container_with_subtype& rhs) const | |
5861 { | |
5862 return !(rhs == *this); | |
5863 } | |
5864 | |
5865 /// @brief sets the binary subtype | |
5866 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ | |
5867 void set_subtype(subtype_type subtype_) noexcept | |
5868 { | |
5869 m_subtype = subtype_; | |
5870 m_has_subtype = true; | |
5871 } | |
5872 | |
5873 /// @brief return the binary subtype | |
5874 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ | |
5875 constexpr subtype_type subtype() const noexcept | |
5876 { | |
5877 return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1); | |
5878 } | |
5879 | |
5880 /// @brief return whether the value has a subtype | |
5881 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ | |
5882 constexpr bool has_subtype() const noexcept | |
5883 { | |
5884 return m_has_subtype; | |
5885 } | |
5886 | |
5887 /// @brief clears the binary subtype | |
5888 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ | |
5889 void clear_subtype() noexcept | |
5890 { | |
5891 m_subtype = 0; | |
5892 m_has_subtype = false; | |
5893 } | |
5894 | |
5895 private: | |
5896 subtype_type m_subtype = 0; | |
5897 bool m_has_subtype = false; | |
5898 }; | |
5899 | |
5900 NLOHMANN_JSON_NAMESPACE_END | |
5901 | |
5902 // #include <nlohmann/detail/conversions/from_json.hpp> | |
5903 | |
5904 // #include <nlohmann/detail/conversions/to_json.hpp> | |
5905 | |
5906 // #include <nlohmann/detail/exceptions.hpp> | |
5907 | |
5908 // #include <nlohmann/detail/hash.hpp> | |
5909 // __ _____ _____ _____ | |
5910 // __| | __| | | | JSON for Modern C++ | |
5911 // | | |__ | | | | | | version 3.11.2 | |
5912 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
5913 // | |
5914 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
5915 // SPDX-License-Identifier: MIT | |
5916 | |
5917 | |
5918 | |
5919 #include <cstdint> // uint8_t | |
5920 #include <cstddef> // size_t | |
5921 #include <functional> // hash | |
5922 | |
5923 // #include <nlohmann/detail/abi_macros.hpp> | |
5924 | |
5925 // #include <nlohmann/detail/value_t.hpp> | |
5926 | |
5927 | |
5928 NLOHMANN_JSON_NAMESPACE_BEGIN | |
5929 namespace detail | |
5930 { | |
5931 | |
5932 // boost::hash_combine | |
5933 inline std::size_t combine(std::size_t seed, std::size_t h) noexcept | |
5934 { | |
5935 seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); | |
5936 return seed; | |
5937 } | |
5938 | |
5939 /*! | |
5940 @brief hash a JSON value | |
5941 | |
5942 The hash function tries to rely on std::hash where possible. Furthermore, the | |
5943 type of the JSON value is taken into account to have different hash values for | |
5944 null, 0, 0U, and false, etc. | |
5945 | |
5946 @tparam BasicJsonType basic_json specialization | |
5947 @param j JSON value to hash | |
5948 @return hash value of j | |
5949 */ | |
5950 template<typename BasicJsonType> | |
5951 std::size_t hash(const BasicJsonType& j) | |
5952 { | |
5953 using string_t = typename BasicJsonType::string_t; | |
5954 using number_integer_t = typename BasicJsonType::number_integer_t; | |
5955 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
5956 using number_float_t = typename BasicJsonType::number_float_t; | |
5957 | |
5958 const auto type = static_cast<std::size_t>(j.type()); | |
5959 switch (j.type()) | |
5960 { | |
5961 case BasicJsonType::value_t::null: | |
5962 case BasicJsonType::value_t::discarded: | |
5963 { | |
5964 return combine(type, 0); | |
5965 } | |
5966 | |
5967 case BasicJsonType::value_t::object: | |
5968 { | |
5969 auto seed = combine(type, j.size()); | |
5970 for (const auto& element : j.items()) | |
5971 { | |
5972 const auto h = std::hash<string_t> {}(element.key()); | |
5973 seed = combine(seed, h); | |
5974 seed = combine(seed, hash(element.value())); | |
5975 } | |
5976 return seed; | |
5977 } | |
5978 | |
5979 case BasicJsonType::value_t::array: | |
5980 { | |
5981 auto seed = combine(type, j.size()); | |
5982 for (const auto& element : j) | |
5983 { | |
5984 seed = combine(seed, hash(element)); | |
5985 } | |
5986 return seed; | |
5987 } | |
5988 | |
5989 case BasicJsonType::value_t::string: | |
5990 { | |
5991 const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>()); | |
5992 return combine(type, h); | |
5993 } | |
5994 | |
5995 case BasicJsonType::value_t::boolean: | |
5996 { | |
5997 const auto h = std::hash<bool> {}(j.template get<bool>()); | |
5998 return combine(type, h); | |
5999 } | |
6000 | |
6001 case BasicJsonType::value_t::number_integer: | |
6002 { | |
6003 const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>()); | |
6004 return combine(type, h); | |
6005 } | |
6006 | |
6007 case BasicJsonType::value_t::number_unsigned: | |
6008 { | |
6009 const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>()); | |
6010 return combine(type, h); | |
6011 } | |
6012 | |
6013 case BasicJsonType::value_t::number_float: | |
6014 { | |
6015 const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>()); | |
6016 return combine(type, h); | |
6017 } | |
6018 | |
6019 case BasicJsonType::value_t::binary: | |
6020 { | |
6021 auto seed = combine(type, j.get_binary().size()); | |
6022 const auto h = std::hash<bool> {}(j.get_binary().has_subtype()); | |
6023 seed = combine(seed, h); | |
6024 seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype())); | |
6025 for (const auto byte : j.get_binary()) | |
6026 { | |
6027 seed = combine(seed, std::hash<std::uint8_t> {}(byte)); | |
6028 } | |
6029 return seed; | |
6030 } | |
6031 | |
6032 default: // LCOV_EXCL_LINE | |
6033 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
6034 return 0; // LCOV_EXCL_LINE | |
6035 } | |
6036 } | |
6037 | |
6038 } // namespace detail | |
6039 NLOHMANN_JSON_NAMESPACE_END | |
6040 | |
6041 // #include <nlohmann/detail/input/binary_reader.hpp> | |
6042 // __ _____ _____ _____ | |
6043 // __| | __| | | | JSON for Modern C++ | |
6044 // | | |__ | | | | | | version 3.11.2 | |
6045 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
6046 // | |
6047 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
6048 // SPDX-License-Identifier: MIT | |
6049 | |
6050 | |
6051 | |
6052 #include <algorithm> // generate_n | |
6053 #include <array> // array | |
6054 #include <cmath> // ldexp | |
6055 #include <cstddef> // size_t | |
6056 #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t | |
6057 #include <cstdio> // snprintf | |
6058 #include <cstring> // memcpy | |
6059 #include <iterator> // back_inserter | |
6060 #include <limits> // numeric_limits | |
6061 #include <string> // char_traits, string | |
6062 #include <utility> // make_pair, move | |
6063 #include <vector> // vector | |
6064 | |
6065 // #include <nlohmann/detail/exceptions.hpp> | |
6066 | |
6067 // #include <nlohmann/detail/input/input_adapters.hpp> | |
6068 // __ _____ _____ _____ | |
6069 // __| | __| | | | JSON for Modern C++ | |
6070 // | | |__ | | | | | | version 3.11.2 | |
6071 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
6072 // | |
6073 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
6074 // SPDX-License-Identifier: MIT | |
6075 | |
6076 | |
6077 | |
6078 #include <array> // array | |
6079 #include <cstddef> // size_t | |
6080 #include <cstring> // strlen | |
6081 #include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next | |
6082 #include <memory> // shared_ptr, make_shared, addressof | |
6083 #include <numeric> // accumulate | |
6084 #include <string> // string, char_traits | |
6085 #include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer | |
6086 #include <utility> // pair, declval | |
6087 | |
6088 #ifndef JSON_NO_IO | |
6089 #include <cstdio> // FILE * | |
6090 #include <istream> // istream | |
6091 #endif // JSON_NO_IO | |
6092 | |
6093 // #include <nlohmann/detail/iterators/iterator_traits.hpp> | |
6094 | |
6095 // #include <nlohmann/detail/macro_scope.hpp> | |
6096 | |
6097 | |
6098 NLOHMANN_JSON_NAMESPACE_BEGIN | |
6099 namespace detail | |
6100 { | |
6101 | |
6102 /// the supported input formats | |
6103 enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata }; | |
6104 | |
6105 //////////////////// | |
6106 // input adapters // | |
6107 //////////////////// | |
6108 | |
6109 #ifndef JSON_NO_IO | |
6110 /*! | |
6111 Input adapter for stdio file access. This adapter read only 1 byte and do not use any | |
6112 buffer. This adapter is a very low level adapter. | |
6113 */ | |
6114 class file_input_adapter | |
6115 { | |
6116 public: | |
6117 using char_type = char; | |
6118 | |
6119 JSON_HEDLEY_NON_NULL(2) | |
6120 explicit file_input_adapter(std::FILE* f) noexcept | |
6121 : m_file(f) | |
6122 { | |
6123 JSON_ASSERT(m_file != nullptr); | |
6124 } | |
6125 | |
6126 // make class move-only | |
6127 file_input_adapter(const file_input_adapter&) = delete; | |
6128 file_input_adapter(file_input_adapter&&) noexcept = default; | |
6129 file_input_adapter& operator=(const file_input_adapter&) = delete; | |
6130 file_input_adapter& operator=(file_input_adapter&&) = delete; | |
6131 ~file_input_adapter() = default; | |
6132 | |
6133 std::char_traits<char>::int_type get_character() noexcept | |
6134 { | |
6135 return std::fgetc(m_file); | |
6136 } | |
6137 | |
6138 private: | |
6139 /// the file pointer to read from | |
6140 std::FILE* m_file; | |
6141 }; | |
6142 | |
6143 | |
6144 /*! | |
6145 Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at | |
6146 beginning of input. Does not support changing the underlying std::streambuf | |
6147 in mid-input. Maintains underlying std::istream and std::streambuf to support | |
6148 subsequent use of standard std::istream operations to process any input | |
6149 characters following those used in parsing the JSON input. Clears the | |
6150 std::istream flags; any input errors (e.g., EOF) will be detected by the first | |
6151 subsequent call for input from the std::istream. | |
6152 */ | |
6153 class input_stream_adapter | |
6154 { | |
6155 public: | |
6156 using char_type = char; | |
6157 | |
6158 ~input_stream_adapter() | |
6159 { | |
6160 // clear stream flags; we use underlying streambuf I/O, do not | |
6161 // maintain ifstream flags, except eof | |
6162 if (is != nullptr) | |
6163 { | |
6164 is->clear(is->rdstate() & std::ios::eofbit); | |
6165 } | |
6166 } | |
6167 | |
6168 explicit input_stream_adapter(std::istream& i) | |
6169 : is(&i), sb(i.rdbuf()) | |
6170 {} | |
6171 | |
6172 // delete because of pointer members | |
6173 input_stream_adapter(const input_stream_adapter&) = delete; | |
6174 input_stream_adapter& operator=(input_stream_adapter&) = delete; | |
6175 input_stream_adapter& operator=(input_stream_adapter&&) = delete; | |
6176 | |
6177 input_stream_adapter(input_stream_adapter&& rhs) noexcept | |
6178 : is(rhs.is), sb(rhs.sb) | |
6179 { | |
6180 rhs.is = nullptr; | |
6181 rhs.sb = nullptr; | |
6182 } | |
6183 | |
6184 // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to | |
6185 // ensure that std::char_traits<char>::eof() and the character 0xFF do not | |
6186 // end up as the same value, e.g. 0xFFFFFFFF. | |
6187 std::char_traits<char>::int_type get_character() | |
6188 { | |
6189 auto res = sb->sbumpc(); | |
6190 // set eof manually, as we don't use the istream interface. | |
6191 if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof())) | |
6192 { | |
6193 is->clear(is->rdstate() | std::ios::eofbit); | |
6194 } | |
6195 return res; | |
6196 } | |
6197 | |
6198 private: | |
6199 /// the associated input stream | |
6200 std::istream* is = nullptr; | |
6201 std::streambuf* sb = nullptr; | |
6202 }; | |
6203 #endif // JSON_NO_IO | |
6204 | |
6205 // General-purpose iterator-based adapter. It might not be as fast as | |
6206 // theoretically possible for some containers, but it is extremely versatile. | |
6207 template<typename IteratorType> | |
6208 class iterator_input_adapter | |
6209 { | |
6210 public: | |
6211 using char_type = typename std::iterator_traits<IteratorType>::value_type; | |
6212 | |
6213 iterator_input_adapter(IteratorType first, IteratorType last) | |
6214 : current(std::move(first)), end(std::move(last)) | |
6215 {} | |
6216 | |
6217 typename std::char_traits<char_type>::int_type get_character() | |
6218 { | |
6219 if (JSON_HEDLEY_LIKELY(current != end)) | |
6220 { | |
6221 auto result = std::char_traits<char_type>::to_int_type(*current); | |
6222 std::advance(current, 1); | |
6223 return result; | |
6224 } | |
6225 | |
6226 return std::char_traits<char_type>::eof(); | |
6227 } | |
6228 | |
6229 private: | |
6230 IteratorType current; | |
6231 IteratorType end; | |
6232 | |
6233 template<typename BaseInputAdapter, size_t T> | |
6234 friend struct wide_string_input_helper; | |
6235 | |
6236 bool empty() const | |
6237 { | |
6238 return current == end; | |
6239 } | |
6240 }; | |
6241 | |
6242 | |
6243 template<typename BaseInputAdapter, size_t T> | |
6244 struct wide_string_input_helper; | |
6245 | |
6246 template<typename BaseInputAdapter> | |
6247 struct wide_string_input_helper<BaseInputAdapter, 4> | |
6248 { | |
6249 // UTF-32 | |
6250 static void fill_buffer(BaseInputAdapter& input, | |
6251 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, | |
6252 size_t& utf8_bytes_index, | |
6253 size_t& utf8_bytes_filled) | |
6254 { | |
6255 utf8_bytes_index = 0; | |
6256 | |
6257 if (JSON_HEDLEY_UNLIKELY(input.empty())) | |
6258 { | |
6259 utf8_bytes[0] = std::char_traits<char>::eof(); | |
6260 utf8_bytes_filled = 1; | |
6261 } | |
6262 else | |
6263 { | |
6264 // get the current character | |
6265 const auto wc = input.get_character(); | |
6266 | |
6267 // UTF-32 to UTF-8 encoding | |
6268 if (wc < 0x80) | |
6269 { | |
6270 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); | |
6271 utf8_bytes_filled = 1; | |
6272 } | |
6273 else if (wc <= 0x7FF) | |
6274 { | |
6275 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu)); | |
6276 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); | |
6277 utf8_bytes_filled = 2; | |
6278 } | |
6279 else if (wc <= 0xFFFF) | |
6280 { | |
6281 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu)); | |
6282 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); | |
6283 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); | |
6284 utf8_bytes_filled = 3; | |
6285 } | |
6286 else if (wc <= 0x10FFFF) | |
6287 { | |
6288 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u)); | |
6289 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu)); | |
6290 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); | |
6291 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); | |
6292 utf8_bytes_filled = 4; | |
6293 } | |
6294 else | |
6295 { | |
6296 // unknown character | |
6297 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); | |
6298 utf8_bytes_filled = 1; | |
6299 } | |
6300 } | |
6301 } | |
6302 }; | |
6303 | |
6304 template<typename BaseInputAdapter> | |
6305 struct wide_string_input_helper<BaseInputAdapter, 2> | |
6306 { | |
6307 // UTF-16 | |
6308 static void fill_buffer(BaseInputAdapter& input, | |
6309 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, | |
6310 size_t& utf8_bytes_index, | |
6311 size_t& utf8_bytes_filled) | |
6312 { | |
6313 utf8_bytes_index = 0; | |
6314 | |
6315 if (JSON_HEDLEY_UNLIKELY(input.empty())) | |
6316 { | |
6317 utf8_bytes[0] = std::char_traits<char>::eof(); | |
6318 utf8_bytes_filled = 1; | |
6319 } | |
6320 else | |
6321 { | |
6322 // get the current character | |
6323 const auto wc = input.get_character(); | |
6324 | |
6325 // UTF-16 to UTF-8 encoding | |
6326 if (wc < 0x80) | |
6327 { | |
6328 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); | |
6329 utf8_bytes_filled = 1; | |
6330 } | |
6331 else if (wc <= 0x7FF) | |
6332 { | |
6333 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u))); | |
6334 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); | |
6335 utf8_bytes_filled = 2; | |
6336 } | |
6337 else if (0xD800 > wc || wc >= 0xE000) | |
6338 { | |
6339 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u))); | |
6340 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); | |
6341 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); | |
6342 utf8_bytes_filled = 3; | |
6343 } | |
6344 else | |
6345 { | |
6346 if (JSON_HEDLEY_UNLIKELY(!input.empty())) | |
6347 { | |
6348 const auto wc2 = static_cast<unsigned int>(input.get_character()); | |
6349 const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); | |
6350 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u)); | |
6351 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); | |
6352 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); | |
6353 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu)); | |
6354 utf8_bytes_filled = 4; | |
6355 } | |
6356 else | |
6357 { | |
6358 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); | |
6359 utf8_bytes_filled = 1; | |
6360 } | |
6361 } | |
6362 } | |
6363 } | |
6364 }; | |
6365 | |
6366 // Wraps another input apdater to convert wide character types into individual bytes. | |
6367 template<typename BaseInputAdapter, typename WideCharType> | |
6368 class wide_string_input_adapter | |
6369 { | |
6370 public: | |
6371 using char_type = char; | |
6372 | |
6373 wide_string_input_adapter(BaseInputAdapter base) | |
6374 : base_adapter(base) {} | |
6375 | |
6376 typename std::char_traits<char>::int_type get_character() noexcept | |
6377 { | |
6378 // check if buffer needs to be filled | |
6379 if (utf8_bytes_index == utf8_bytes_filled) | |
6380 { | |
6381 fill_buffer<sizeof(WideCharType)>(); | |
6382 | |
6383 JSON_ASSERT(utf8_bytes_filled > 0); | |
6384 JSON_ASSERT(utf8_bytes_index == 0); | |
6385 } | |
6386 | |
6387 // use buffer | |
6388 JSON_ASSERT(utf8_bytes_filled > 0); | |
6389 JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); | |
6390 return utf8_bytes[utf8_bytes_index++]; | |
6391 } | |
6392 | |
6393 private: | |
6394 BaseInputAdapter base_adapter; | |
6395 | |
6396 template<size_t T> | |
6397 void fill_buffer() | |
6398 { | |
6399 wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); | |
6400 } | |
6401 | |
6402 /// a buffer for UTF-8 bytes | |
6403 std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; | |
6404 | |
6405 /// index to the utf8_codes array for the next valid byte | |
6406 std::size_t utf8_bytes_index = 0; | |
6407 /// number of valid bytes in the utf8_codes array | |
6408 std::size_t utf8_bytes_filled = 0; | |
6409 }; | |
6410 | |
6411 | |
6412 template<typename IteratorType, typename Enable = void> | |
6413 struct iterator_input_adapter_factory | |
6414 { | |
6415 using iterator_type = IteratorType; | |
6416 using char_type = typename std::iterator_traits<iterator_type>::value_type; | |
6417 using adapter_type = iterator_input_adapter<iterator_type>; | |
6418 | |
6419 static adapter_type create(IteratorType first, IteratorType last) | |
6420 { | |
6421 return adapter_type(std::move(first), std::move(last)); | |
6422 } | |
6423 }; | |
6424 | |
6425 template<typename T> | |
6426 struct is_iterator_of_multibyte | |
6427 { | |
6428 using value_type = typename std::iterator_traits<T>::value_type; | |
6429 enum | |
6430 { | |
6431 value = sizeof(value_type) > 1 | |
6432 }; | |
6433 }; | |
6434 | |
6435 template<typename IteratorType> | |
6436 struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>> | |
6437 { | |
6438 using iterator_type = IteratorType; | |
6439 using char_type = typename std::iterator_traits<iterator_type>::value_type; | |
6440 using base_adapter_type = iterator_input_adapter<iterator_type>; | |
6441 using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>; | |
6442 | |
6443 static adapter_type create(IteratorType first, IteratorType last) | |
6444 { | |
6445 return adapter_type(base_adapter_type(std::move(first), std::move(last))); | |
6446 } | |
6447 }; | |
6448 | |
6449 // General purpose iterator-based input | |
6450 template<typename IteratorType> | |
6451 typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last) | |
6452 { | |
6453 using factory_type = iterator_input_adapter_factory<IteratorType>; | |
6454 return factory_type::create(first, last); | |
6455 } | |
6456 | |
6457 // Convenience shorthand from container to iterator | |
6458 // Enables ADL on begin(container) and end(container) | |
6459 // Encloses the using declarations in namespace for not to leak them to outside scope | |
6460 | |
6461 namespace container_input_adapter_factory_impl | |
6462 { | |
6463 | |
6464 using std::begin; | |
6465 using std::end; | |
6466 | |
6467 template<typename ContainerType, typename Enable = void> | |
6468 struct container_input_adapter_factory {}; | |
6469 | |
6470 template<typename ContainerType> | |
6471 struct container_input_adapter_factory< ContainerType, | |
6472 void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>> | |
6473 { | |
6474 using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))); | |
6475 | |
6476 static adapter_type create(const ContainerType& container) | |
6477 { | |
6478 return input_adapter(begin(container), end(container)); | |
6479 } | |
6480 }; | |
6481 | |
6482 } // namespace container_input_adapter_factory_impl | |
6483 | |
6484 template<typename ContainerType> | |
6485 typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container) | |
6486 { | |
6487 return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container); | |
6488 } | |
6489 | |
6490 #ifndef JSON_NO_IO | |
6491 // Special cases with fast paths | |
6492 inline file_input_adapter input_adapter(std::FILE* file) | |
6493 { | |
6494 return file_input_adapter(file); | |
6495 } | |
6496 | |
6497 inline input_stream_adapter input_adapter(std::istream& stream) | |
6498 { | |
6499 return input_stream_adapter(stream); | |
6500 } | |
6501 | |
6502 inline input_stream_adapter input_adapter(std::istream&& stream) | |
6503 { | |
6504 return input_stream_adapter(stream); | |
6505 } | |
6506 #endif // JSON_NO_IO | |
6507 | |
6508 using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>())); | |
6509 | |
6510 // Null-delimited strings, and the like. | |
6511 template < typename CharT, | |
6512 typename std::enable_if < | |
6513 std::is_pointer<CharT>::value&& | |
6514 !std::is_array<CharT>::value&& | |
6515 std::is_integral<typename std::remove_pointer<CharT>::type>::value&& | |
6516 sizeof(typename std::remove_pointer<CharT>::type) == 1, | |
6517 int >::type = 0 > | |
6518 contiguous_bytes_input_adapter input_adapter(CharT b) | |
6519 { | |
6520 auto length = std::strlen(reinterpret_cast<const char*>(b)); | |
6521 const auto* ptr = reinterpret_cast<const char*>(b); | |
6522 return input_adapter(ptr, ptr + length); | |
6523 } | |
6524 | |
6525 template<typename T, std::size_t N> | |
6526 auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) | |
6527 { | |
6528 return input_adapter(array, array + N); | |
6529 } | |
6530 | |
6531 // This class only handles inputs of input_buffer_adapter type. | |
6532 // It's required so that expressions like {ptr, len} can be implicitly cast | |
6533 // to the correct adapter. | |
6534 class span_input_adapter | |
6535 { | |
6536 public: | |
6537 template < typename CharT, | |
6538 typename std::enable_if < | |
6539 std::is_pointer<CharT>::value&& | |
6540 std::is_integral<typename std::remove_pointer<CharT>::type>::value&& | |
6541 sizeof(typename std::remove_pointer<CharT>::type) == 1, | |
6542 int >::type = 0 > | |
6543 span_input_adapter(CharT b, std::size_t l) | |
6544 : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {} | |
6545 | |
6546 template<class IteratorType, | |
6547 typename std::enable_if< | |
6548 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, | |
6549 int>::type = 0> | |
6550 span_input_adapter(IteratorType first, IteratorType last) | |
6551 : ia(input_adapter(first, last)) {} | |
6552 | |
6553 contiguous_bytes_input_adapter&& get() | |
6554 { | |
6555 return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) | |
6556 } | |
6557 | |
6558 private: | |
6559 contiguous_bytes_input_adapter ia; | |
6560 }; | |
6561 | |
6562 } // namespace detail | |
6563 NLOHMANN_JSON_NAMESPACE_END | |
6564 | |
6565 // #include <nlohmann/detail/input/json_sax.hpp> | |
6566 // __ _____ _____ _____ | |
6567 // __| | __| | | | JSON for Modern C++ | |
6568 // | | |__ | | | | | | version 3.11.2 | |
6569 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
6570 // | |
6571 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
6572 // SPDX-License-Identifier: MIT | |
6573 | |
6574 | |
6575 | |
6576 #include <cstddef> | |
6577 #include <string> // string | |
6578 #include <utility> // move | |
6579 #include <vector> // vector | |
6580 | |
6581 // #include <nlohmann/detail/exceptions.hpp> | |
6582 | |
6583 // #include <nlohmann/detail/macro_scope.hpp> | |
6584 | |
6585 // #include <nlohmann/detail/string_concat.hpp> | |
6586 | |
6587 | |
6588 NLOHMANN_JSON_NAMESPACE_BEGIN | |
6589 | |
6590 /*! | |
6591 @brief SAX interface | |
6592 | |
6593 This class describes the SAX interface used by @ref nlohmann::json::sax_parse. | |
6594 Each function is called in different situations while the input is parsed. The | |
6595 boolean return value informs the parser whether to continue processing the | |
6596 input. | |
6597 */ | |
6598 template<typename BasicJsonType> | |
6599 struct json_sax | |
6600 { | |
6601 using number_integer_t = typename BasicJsonType::number_integer_t; | |
6602 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
6603 using number_float_t = typename BasicJsonType::number_float_t; | |
6604 using string_t = typename BasicJsonType::string_t; | |
6605 using binary_t = typename BasicJsonType::binary_t; | |
6606 | |
6607 /*! | |
6608 @brief a null value was read | |
6609 @return whether parsing should proceed | |
6610 */ | |
6611 virtual bool null() = 0; | |
6612 | |
6613 /*! | |
6614 @brief a boolean value was read | |
6615 @param[in] val boolean value | |
6616 @return whether parsing should proceed | |
6617 */ | |
6618 virtual bool boolean(bool val) = 0; | |
6619 | |
6620 /*! | |
6621 @brief an integer number was read | |
6622 @param[in] val integer value | |
6623 @return whether parsing should proceed | |
6624 */ | |
6625 virtual bool number_integer(number_integer_t val) = 0; | |
6626 | |
6627 /*! | |
6628 @brief an unsigned integer number was read | |
6629 @param[in] val unsigned integer value | |
6630 @return whether parsing should proceed | |
6631 */ | |
6632 virtual bool number_unsigned(number_unsigned_t val) = 0; | |
6633 | |
6634 /*! | |
6635 @brief a floating-point number was read | |
6636 @param[in] val floating-point value | |
6637 @param[in] s raw token value | |
6638 @return whether parsing should proceed | |
6639 */ | |
6640 virtual bool number_float(number_float_t val, const string_t& s) = 0; | |
6641 | |
6642 /*! | |
6643 @brief a string value was read | |
6644 @param[in] val string value | |
6645 @return whether parsing should proceed | |
6646 @note It is safe to move the passed string value. | |
6647 */ | |
6648 virtual bool string(string_t& val) = 0; | |
6649 | |
6650 /*! | |
6651 @brief a binary value was read | |
6652 @param[in] val binary value | |
6653 @return whether parsing should proceed | |
6654 @note It is safe to move the passed binary value. | |
6655 */ | |
6656 virtual bool binary(binary_t& val) = 0; | |
6657 | |
6658 /*! | |
6659 @brief the beginning of an object was read | |
6660 @param[in] elements number of object elements or -1 if unknown | |
6661 @return whether parsing should proceed | |
6662 @note binary formats may report the number of elements | |
6663 */ | |
6664 virtual bool start_object(std::size_t elements) = 0; | |
6665 | |
6666 /*! | |
6667 @brief an object key was read | |
6668 @param[in] val object key | |
6669 @return whether parsing should proceed | |
6670 @note It is safe to move the passed string. | |
6671 */ | |
6672 virtual bool key(string_t& val) = 0; | |
6673 | |
6674 /*! | |
6675 @brief the end of an object was read | |
6676 @return whether parsing should proceed | |
6677 */ | |
6678 virtual bool end_object() = 0; | |
6679 | |
6680 /*! | |
6681 @brief the beginning of an array was read | |
6682 @param[in] elements number of array elements or -1 if unknown | |
6683 @return whether parsing should proceed | |
6684 @note binary formats may report the number of elements | |
6685 */ | |
6686 virtual bool start_array(std::size_t elements) = 0; | |
6687 | |
6688 /*! | |
6689 @brief the end of an array was read | |
6690 @return whether parsing should proceed | |
6691 */ | |
6692 virtual bool end_array() = 0; | |
6693 | |
6694 /*! | |
6695 @brief a parse error occurred | |
6696 @param[in] position the position in the input where the error occurs | |
6697 @param[in] last_token the last read token | |
6698 @param[in] ex an exception object describing the error | |
6699 @return whether parsing should proceed (must return false) | |
6700 */ | |
6701 virtual bool parse_error(std::size_t position, | |
6702 const std::string& last_token, | |
6703 const detail::exception& ex) = 0; | |
6704 | |
6705 json_sax() = default; | |
6706 json_sax(const json_sax&) = default; | |
6707 json_sax(json_sax&&) noexcept = default; | |
6708 json_sax& operator=(const json_sax&) = default; | |
6709 json_sax& operator=(json_sax&&) noexcept = default; | |
6710 virtual ~json_sax() = default; | |
6711 }; | |
6712 | |
6713 | |
6714 namespace detail | |
6715 { | |
6716 /*! | |
6717 @brief SAX implementation to create a JSON value from SAX events | |
6718 | |
6719 This class implements the @ref json_sax interface and processes the SAX events | |
6720 to create a JSON value which makes it basically a DOM parser. The structure or | |
6721 hierarchy of the JSON value is managed by the stack `ref_stack` which contains | |
6722 a pointer to the respective array or object for each recursion depth. | |
6723 | |
6724 After successful parsing, the value that is passed by reference to the | |
6725 constructor contains the parsed value. | |
6726 | |
6727 @tparam BasicJsonType the JSON type | |
6728 */ | |
6729 template<typename BasicJsonType> | |
6730 class json_sax_dom_parser | |
6731 { | |
6732 public: | |
6733 using number_integer_t = typename BasicJsonType::number_integer_t; | |
6734 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
6735 using number_float_t = typename BasicJsonType::number_float_t; | |
6736 using string_t = typename BasicJsonType::string_t; | |
6737 using binary_t = typename BasicJsonType::binary_t; | |
6738 | |
6739 /*! | |
6740 @param[in,out] r reference to a JSON value that is manipulated while | |
6741 parsing | |
6742 @param[in] allow_exceptions_ whether parse errors yield exceptions | |
6743 */ | |
6744 explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) | |
6745 : root(r), allow_exceptions(allow_exceptions_) | |
6746 {} | |
6747 | |
6748 // make class move-only | |
6749 json_sax_dom_parser(const json_sax_dom_parser&) = delete; | |
6750 json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
6751 json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; | |
6752 json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
6753 ~json_sax_dom_parser() = default; | |
6754 | |
6755 bool null() | |
6756 { | |
6757 handle_value(nullptr); | |
6758 return true; | |
6759 } | |
6760 | |
6761 bool boolean(bool val) | |
6762 { | |
6763 handle_value(val); | |
6764 return true; | |
6765 } | |
6766 | |
6767 bool number_integer(number_integer_t val) | |
6768 { | |
6769 handle_value(val); | |
6770 return true; | |
6771 } | |
6772 | |
6773 bool number_unsigned(number_unsigned_t val) | |
6774 { | |
6775 handle_value(val); | |
6776 return true; | |
6777 } | |
6778 | |
6779 bool number_float(number_float_t val, const string_t& /*unused*/) | |
6780 { | |
6781 handle_value(val); | |
6782 return true; | |
6783 } | |
6784 | |
6785 bool string(string_t& val) | |
6786 { | |
6787 handle_value(val); | |
6788 return true; | |
6789 } | |
6790 | |
6791 bool binary(binary_t& val) | |
6792 { | |
6793 handle_value(std::move(val)); | |
6794 return true; | |
6795 } | |
6796 | |
6797 bool start_object(std::size_t len) | |
6798 { | |
6799 ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); | |
6800 | |
6801 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) | |
6802 { | |
6803 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); | |
6804 } | |
6805 | |
6806 return true; | |
6807 } | |
6808 | |
6809 bool key(string_t& val) | |
6810 { | |
6811 JSON_ASSERT(!ref_stack.empty()); | |
6812 JSON_ASSERT(ref_stack.back()->is_object()); | |
6813 | |
6814 // add null at given key and store the reference for later | |
6815 object_element = &(ref_stack.back()->m_value.object->operator[](val)); | |
6816 return true; | |
6817 } | |
6818 | |
6819 bool end_object() | |
6820 { | |
6821 JSON_ASSERT(!ref_stack.empty()); | |
6822 JSON_ASSERT(ref_stack.back()->is_object()); | |
6823 | |
6824 ref_stack.back()->set_parents(); | |
6825 ref_stack.pop_back(); | |
6826 return true; | |
6827 } | |
6828 | |
6829 bool start_array(std::size_t len) | |
6830 { | |
6831 ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); | |
6832 | |
6833 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) | |
6834 { | |
6835 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); | |
6836 } | |
6837 | |
6838 return true; | |
6839 } | |
6840 | |
6841 bool end_array() | |
6842 { | |
6843 JSON_ASSERT(!ref_stack.empty()); | |
6844 JSON_ASSERT(ref_stack.back()->is_array()); | |
6845 | |
6846 ref_stack.back()->set_parents(); | |
6847 ref_stack.pop_back(); | |
6848 return true; | |
6849 } | |
6850 | |
6851 template<class Exception> | |
6852 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, | |
6853 const Exception& ex) | |
6854 { | |
6855 errored = true; | |
6856 static_cast<void>(ex); | |
6857 if (allow_exceptions) | |
6858 { | |
6859 JSON_THROW(ex); | |
6860 } | |
6861 return false; | |
6862 } | |
6863 | |
6864 constexpr bool is_errored() const | |
6865 { | |
6866 return errored; | |
6867 } | |
6868 | |
6869 private: | |
6870 /*! | |
6871 @invariant If the ref stack is empty, then the passed value will be the new | |
6872 root. | |
6873 @invariant If the ref stack contains a value, then it is an array or an | |
6874 object to which we can add elements | |
6875 */ | |
6876 template<typename Value> | |
6877 JSON_HEDLEY_RETURNS_NON_NULL | |
6878 BasicJsonType* handle_value(Value&& v) | |
6879 { | |
6880 if (ref_stack.empty()) | |
6881 { | |
6882 root = BasicJsonType(std::forward<Value>(v)); | |
6883 return &root; | |
6884 } | |
6885 | |
6886 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); | |
6887 | |
6888 if (ref_stack.back()->is_array()) | |
6889 { | |
6890 ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v)); | |
6891 return &(ref_stack.back()->m_value.array->back()); | |
6892 } | |
6893 | |
6894 JSON_ASSERT(ref_stack.back()->is_object()); | |
6895 JSON_ASSERT(object_element); | |
6896 *object_element = BasicJsonType(std::forward<Value>(v)); | |
6897 return object_element; | |
6898 } | |
6899 | |
6900 /// the parsed JSON value | |
6901 BasicJsonType& root; | |
6902 /// stack to model hierarchy of values | |
6903 std::vector<BasicJsonType*> ref_stack {}; | |
6904 /// helper to hold the reference for the next object element | |
6905 BasicJsonType* object_element = nullptr; | |
6906 /// whether a syntax error occurred | |
6907 bool errored = false; | |
6908 /// whether to throw exceptions in case of errors | |
6909 const bool allow_exceptions = true; | |
6910 }; | |
6911 | |
6912 template<typename BasicJsonType> | |
6913 class json_sax_dom_callback_parser | |
6914 { | |
6915 public: | |
6916 using number_integer_t = typename BasicJsonType::number_integer_t; | |
6917 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
6918 using number_float_t = typename BasicJsonType::number_float_t; | |
6919 using string_t = typename BasicJsonType::string_t; | |
6920 using binary_t = typename BasicJsonType::binary_t; | |
6921 using parser_callback_t = typename BasicJsonType::parser_callback_t; | |
6922 using parse_event_t = typename BasicJsonType::parse_event_t; | |
6923 | |
6924 json_sax_dom_callback_parser(BasicJsonType& r, | |
6925 const parser_callback_t cb, | |
6926 const bool allow_exceptions_ = true) | |
6927 : root(r), callback(cb), allow_exceptions(allow_exceptions_) | |
6928 { | |
6929 keep_stack.push_back(true); | |
6930 } | |
6931 | |
6932 // make class move-only | |
6933 json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; | |
6934 json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
6935 json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; | |
6936 json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
6937 ~json_sax_dom_callback_parser() = default; | |
6938 | |
6939 bool null() | |
6940 { | |
6941 handle_value(nullptr); | |
6942 return true; | |
6943 } | |
6944 | |
6945 bool boolean(bool val) | |
6946 { | |
6947 handle_value(val); | |
6948 return true; | |
6949 } | |
6950 | |
6951 bool number_integer(number_integer_t val) | |
6952 { | |
6953 handle_value(val); | |
6954 return true; | |
6955 } | |
6956 | |
6957 bool number_unsigned(number_unsigned_t val) | |
6958 { | |
6959 handle_value(val); | |
6960 return true; | |
6961 } | |
6962 | |
6963 bool number_float(number_float_t val, const string_t& /*unused*/) | |
6964 { | |
6965 handle_value(val); | |
6966 return true; | |
6967 } | |
6968 | |
6969 bool string(string_t& val) | |
6970 { | |
6971 handle_value(val); | |
6972 return true; | |
6973 } | |
6974 | |
6975 bool binary(binary_t& val) | |
6976 { | |
6977 handle_value(std::move(val)); | |
6978 return true; | |
6979 } | |
6980 | |
6981 bool start_object(std::size_t len) | |
6982 { | |
6983 // check callback for object start | |
6984 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded); | |
6985 keep_stack.push_back(keep); | |
6986 | |
6987 auto val = handle_value(BasicJsonType::value_t::object, true); | |
6988 ref_stack.push_back(val.second); | |
6989 | |
6990 // check object limit | |
6991 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) | |
6992 { | |
6993 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); | |
6994 } | |
6995 | |
6996 return true; | |
6997 } | |
6998 | |
6999 bool key(string_t& val) | |
7000 { | |
7001 BasicJsonType k = BasicJsonType(val); | |
7002 | |
7003 // check callback for key | |
7004 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k); | |
7005 key_keep_stack.push_back(keep); | |
7006 | |
7007 // add discarded value at given key and store the reference for later | |
7008 if (keep && ref_stack.back()) | |
7009 { | |
7010 object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); | |
7011 } | |
7012 | |
7013 return true; | |
7014 } | |
7015 | |
7016 bool end_object() | |
7017 { | |
7018 if (ref_stack.back()) | |
7019 { | |
7020 if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) | |
7021 { | |
7022 // discard object | |
7023 *ref_stack.back() = discarded; | |
7024 } | |
7025 else | |
7026 { | |
7027 ref_stack.back()->set_parents(); | |
7028 } | |
7029 } | |
7030 | |
7031 JSON_ASSERT(!ref_stack.empty()); | |
7032 JSON_ASSERT(!keep_stack.empty()); | |
7033 ref_stack.pop_back(); | |
7034 keep_stack.pop_back(); | |
7035 | |
7036 if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) | |
7037 { | |
7038 // remove discarded value | |
7039 for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) | |
7040 { | |
7041 if (it->is_discarded()) | |
7042 { | |
7043 ref_stack.back()->erase(it); | |
7044 break; | |
7045 } | |
7046 } | |
7047 } | |
7048 | |
7049 return true; | |
7050 } | |
7051 | |
7052 bool start_array(std::size_t len) | |
7053 { | |
7054 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded); | |
7055 keep_stack.push_back(keep); | |
7056 | |
7057 auto val = handle_value(BasicJsonType::value_t::array, true); | |
7058 ref_stack.push_back(val.second); | |
7059 | |
7060 // check array limit | |
7061 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) | |
7062 { | |
7063 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); | |
7064 } | |
7065 | |
7066 return true; | |
7067 } | |
7068 | |
7069 bool end_array() | |
7070 { | |
7071 bool keep = true; | |
7072 | |
7073 if (ref_stack.back()) | |
7074 { | |
7075 keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); | |
7076 if (keep) | |
7077 { | |
7078 ref_stack.back()->set_parents(); | |
7079 } | |
7080 else | |
7081 { | |
7082 // discard array | |
7083 *ref_stack.back() = discarded; | |
7084 } | |
7085 } | |
7086 | |
7087 JSON_ASSERT(!ref_stack.empty()); | |
7088 JSON_ASSERT(!keep_stack.empty()); | |
7089 ref_stack.pop_back(); | |
7090 keep_stack.pop_back(); | |
7091 | |
7092 // remove discarded value | |
7093 if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) | |
7094 { | |
7095 ref_stack.back()->m_value.array->pop_back(); | |
7096 } | |
7097 | |
7098 return true; | |
7099 } | |
7100 | |
7101 template<class Exception> | |
7102 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, | |
7103 const Exception& ex) | |
7104 { | |
7105 errored = true; | |
7106 static_cast<void>(ex); | |
7107 if (allow_exceptions) | |
7108 { | |
7109 JSON_THROW(ex); | |
7110 } | |
7111 return false; | |
7112 } | |
7113 | |
7114 constexpr bool is_errored() const | |
7115 { | |
7116 return errored; | |
7117 } | |
7118 | |
7119 private: | |
7120 /*! | |
7121 @param[in] v value to add to the JSON value we build during parsing | |
7122 @param[in] skip_callback whether we should skip calling the callback | |
7123 function; this is required after start_array() and | |
7124 start_object() SAX events, because otherwise we would call the | |
7125 callback function with an empty array or object, respectively. | |
7126 | |
7127 @invariant If the ref stack is empty, then the passed value will be the new | |
7128 root. | |
7129 @invariant If the ref stack contains a value, then it is an array or an | |
7130 object to which we can add elements | |
7131 | |
7132 @return pair of boolean (whether value should be kept) and pointer (to the | |
7133 passed value in the ref_stack hierarchy; nullptr if not kept) | |
7134 */ | |
7135 template<typename Value> | |
7136 std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false) | |
7137 { | |
7138 JSON_ASSERT(!keep_stack.empty()); | |
7139 | |
7140 // do not handle this value if we know it would be added to a discarded | |
7141 // container | |
7142 if (!keep_stack.back()) | |
7143 { | |
7144 return {false, nullptr}; | |
7145 } | |
7146 | |
7147 // create value | |
7148 auto value = BasicJsonType(std::forward<Value>(v)); | |
7149 | |
7150 // check callback | |
7151 const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value); | |
7152 | |
7153 // do not handle this value if we just learnt it shall be discarded | |
7154 if (!keep) | |
7155 { | |
7156 return {false, nullptr}; | |
7157 } | |
7158 | |
7159 if (ref_stack.empty()) | |
7160 { | |
7161 root = std::move(value); | |
7162 return {true, &root}; | |
7163 } | |
7164 | |
7165 // skip this value if we already decided to skip the parent | |
7166 // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) | |
7167 if (!ref_stack.back()) | |
7168 { | |
7169 return {false, nullptr}; | |
7170 } | |
7171 | |
7172 // we now only expect arrays and objects | |
7173 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); | |
7174 | |
7175 // array | |
7176 if (ref_stack.back()->is_array()) | |
7177 { | |
7178 ref_stack.back()->m_value.array->emplace_back(std::move(value)); | |
7179 return {true, &(ref_stack.back()->m_value.array->back())}; | |
7180 } | |
7181 | |
7182 // object | |
7183 JSON_ASSERT(ref_stack.back()->is_object()); | |
7184 // check if we should store an element for the current key | |
7185 JSON_ASSERT(!key_keep_stack.empty()); | |
7186 const bool store_element = key_keep_stack.back(); | |
7187 key_keep_stack.pop_back(); | |
7188 | |
7189 if (!store_element) | |
7190 { | |
7191 return {false, nullptr}; | |
7192 } | |
7193 | |
7194 JSON_ASSERT(object_element); | |
7195 *object_element = std::move(value); | |
7196 return {true, object_element}; | |
7197 } | |
7198 | |
7199 /// the parsed JSON value | |
7200 BasicJsonType& root; | |
7201 /// stack to model hierarchy of values | |
7202 std::vector<BasicJsonType*> ref_stack {}; | |
7203 /// stack to manage which values to keep | |
7204 std::vector<bool> keep_stack {}; | |
7205 /// stack to manage which object keys to keep | |
7206 std::vector<bool> key_keep_stack {}; | |
7207 /// helper to hold the reference for the next object element | |
7208 BasicJsonType* object_element = nullptr; | |
7209 /// whether a syntax error occurred | |
7210 bool errored = false; | |
7211 /// callback function | |
7212 const parser_callback_t callback = nullptr; | |
7213 /// whether to throw exceptions in case of errors | |
7214 const bool allow_exceptions = true; | |
7215 /// a discarded value for the callback | |
7216 BasicJsonType discarded = BasicJsonType::value_t::discarded; | |
7217 }; | |
7218 | |
7219 template<typename BasicJsonType> | |
7220 class json_sax_acceptor | |
7221 { | |
7222 public: | |
7223 using number_integer_t = typename BasicJsonType::number_integer_t; | |
7224 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
7225 using number_float_t = typename BasicJsonType::number_float_t; | |
7226 using string_t = typename BasicJsonType::string_t; | |
7227 using binary_t = typename BasicJsonType::binary_t; | |
7228 | |
7229 bool null() | |
7230 { | |
7231 return true; | |
7232 } | |
7233 | |
7234 bool boolean(bool /*unused*/) | |
7235 { | |
7236 return true; | |
7237 } | |
7238 | |
7239 bool number_integer(number_integer_t /*unused*/) | |
7240 { | |
7241 return true; | |
7242 } | |
7243 | |
7244 bool number_unsigned(number_unsigned_t /*unused*/) | |
7245 { | |
7246 return true; | |
7247 } | |
7248 | |
7249 bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) | |
7250 { | |
7251 return true; | |
7252 } | |
7253 | |
7254 bool string(string_t& /*unused*/) | |
7255 { | |
7256 return true; | |
7257 } | |
7258 | |
7259 bool binary(binary_t& /*unused*/) | |
7260 { | |
7261 return true; | |
7262 } | |
7263 | |
7264 bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) | |
7265 { | |
7266 return true; | |
7267 } | |
7268 | |
7269 bool key(string_t& /*unused*/) | |
7270 { | |
7271 return true; | |
7272 } | |
7273 | |
7274 bool end_object() | |
7275 { | |
7276 return true; | |
7277 } | |
7278 | |
7279 bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) | |
7280 { | |
7281 return true; | |
7282 } | |
7283 | |
7284 bool end_array() | |
7285 { | |
7286 return true; | |
7287 } | |
7288 | |
7289 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) | |
7290 { | |
7291 return false; | |
7292 } | |
7293 }; | |
7294 | |
7295 } // namespace detail | |
7296 NLOHMANN_JSON_NAMESPACE_END | |
7297 | |
7298 // #include <nlohmann/detail/input/lexer.hpp> | |
7299 // __ _____ _____ _____ | |
7300 // __| | __| | | | JSON for Modern C++ | |
7301 // | | |__ | | | | | | version 3.11.2 | |
7302 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
7303 // | |
7304 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
7305 // SPDX-License-Identifier: MIT | |
7306 | |
7307 | |
7308 | |
7309 #include <array> // array | |
7310 #include <clocale> // localeconv | |
7311 #include <cstddef> // size_t | |
7312 #include <cstdio> // snprintf | |
7313 #include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull | |
7314 #include <initializer_list> // initializer_list | |
7315 #include <string> // char_traits, string | |
7316 #include <utility> // move | |
7317 #include <vector> // vector | |
7318 | |
7319 // #include <nlohmann/detail/input/input_adapters.hpp> | |
7320 | |
7321 // #include <nlohmann/detail/input/position_t.hpp> | |
7322 | |
7323 // #include <nlohmann/detail/macro_scope.hpp> | |
7324 | |
7325 | |
7326 NLOHMANN_JSON_NAMESPACE_BEGIN | |
7327 namespace detail | |
7328 { | |
7329 | |
7330 /////////// | |
7331 // lexer // | |
7332 /////////// | |
7333 | |
7334 template<typename BasicJsonType> | |
7335 class lexer_base | |
7336 { | |
7337 public: | |
7338 /// token types for the parser | |
7339 enum class token_type | |
7340 { | |
7341 uninitialized, ///< indicating the scanner is uninitialized | |
7342 literal_true, ///< the `true` literal | |
7343 literal_false, ///< the `false` literal | |
7344 literal_null, ///< the `null` literal | |
7345 value_string, ///< a string -- use get_string() for actual value | |
7346 value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value | |
7347 value_integer, ///< a signed integer -- use get_number_integer() for actual value | |
7348 value_float, ///< an floating point number -- use get_number_float() for actual value | |
7349 begin_array, ///< the character for array begin `[` | |
7350 begin_object, ///< the character for object begin `{` | |
7351 end_array, ///< the character for array end `]` | |
7352 end_object, ///< the character for object end `}` | |
7353 name_separator, ///< the name separator `:` | |
7354 value_separator, ///< the value separator `,` | |
7355 parse_error, ///< indicating a parse error | |
7356 end_of_input, ///< indicating the end of the input buffer | |
7357 literal_or_value ///< a literal or the begin of a value (only for diagnostics) | |
7358 }; | |
7359 | |
7360 /// return name of values of type token_type (only used for errors) | |
7361 JSON_HEDLEY_RETURNS_NON_NULL | |
7362 JSON_HEDLEY_CONST | |
7363 static const char* token_type_name(const token_type t) noexcept | |
7364 { | |
7365 switch (t) | |
7366 { | |
7367 case token_type::uninitialized: | |
7368 return "<uninitialized>"; | |
7369 case token_type::literal_true: | |
7370 return "true literal"; | |
7371 case token_type::literal_false: | |
7372 return "false literal"; | |
7373 case token_type::literal_null: | |
7374 return "null literal"; | |
7375 case token_type::value_string: | |
7376 return "string literal"; | |
7377 case token_type::value_unsigned: | |
7378 case token_type::value_integer: | |
7379 case token_type::value_float: | |
7380 return "number literal"; | |
7381 case token_type::begin_array: | |
7382 return "'['"; | |
7383 case token_type::begin_object: | |
7384 return "'{'"; | |
7385 case token_type::end_array: | |
7386 return "']'"; | |
7387 case token_type::end_object: | |
7388 return "'}'"; | |
7389 case token_type::name_separator: | |
7390 return "':'"; | |
7391 case token_type::value_separator: | |
7392 return "','"; | |
7393 case token_type::parse_error: | |
7394 return "<parse error>"; | |
7395 case token_type::end_of_input: | |
7396 return "end of input"; | |
7397 case token_type::literal_or_value: | |
7398 return "'[', '{', or a literal"; | |
7399 // LCOV_EXCL_START | |
7400 default: // catch non-enum values | |
7401 return "unknown token"; | |
7402 // LCOV_EXCL_STOP | |
7403 } | |
7404 } | |
7405 }; | |
7406 /*! | |
7407 @brief lexical analysis | |
7408 | |
7409 This class organizes the lexical analysis during JSON deserialization. | |
7410 */ | |
7411 template<typename BasicJsonType, typename InputAdapterType> | |
7412 class lexer : public lexer_base<BasicJsonType> | |
7413 { | |
7414 using number_integer_t = typename BasicJsonType::number_integer_t; | |
7415 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
7416 using number_float_t = typename BasicJsonType::number_float_t; | |
7417 using string_t = typename BasicJsonType::string_t; | |
7418 using char_type = typename InputAdapterType::char_type; | |
7419 using char_int_type = typename std::char_traits<char_type>::int_type; | |
7420 | |
7421 public: | |
7422 using token_type = typename lexer_base<BasicJsonType>::token_type; | |
7423 | |
7424 explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept | |
7425 : ia(std::move(adapter)) | |
7426 , ignore_comments(ignore_comments_) | |
7427 , decimal_point_char(static_cast<char_int_type>(get_decimal_point())) | |
7428 {} | |
7429 | |
7430 // delete because of pointer members | |
7431 lexer(const lexer&) = delete; | |
7432 lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
7433 lexer& operator=(lexer&) = delete; | |
7434 lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
7435 ~lexer() = default; | |
7436 | |
7437 private: | |
7438 ///////////////////// | |
7439 // locales | |
7440 ///////////////////// | |
7441 | |
7442 /// return the locale-dependent decimal point | |
7443 JSON_HEDLEY_PURE | |
7444 static char get_decimal_point() noexcept | |
7445 { | |
7446 const auto* loc = localeconv(); | |
7447 JSON_ASSERT(loc != nullptr); | |
7448 return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); | |
7449 } | |
7450 | |
7451 ///////////////////// | |
7452 // scan functions | |
7453 ///////////////////// | |
7454 | |
7455 /*! | |
7456 @brief get codepoint from 4 hex characters following `\u` | |
7457 | |
7458 For input "\u c1 c2 c3 c4" the codepoint is: | |
7459 (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 | |
7460 = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) | |
7461 | |
7462 Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' | |
7463 must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The | |
7464 conversion is done by subtracting the offset (0x30, 0x37, and 0x57) | |
7465 between the ASCII value of the character and the desired integer value. | |
7466 | |
7467 @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or | |
7468 non-hex character) | |
7469 */ | |
7470 int get_codepoint() | |
7471 { | |
7472 // this function only makes sense after reading `\u` | |
7473 JSON_ASSERT(current == 'u'); | |
7474 int codepoint = 0; | |
7475 | |
7476 const auto factors = { 12u, 8u, 4u, 0u }; | |
7477 for (const auto factor : factors) | |
7478 { | |
7479 get(); | |
7480 | |
7481 if (current >= '0' && current <= '9') | |
7482 { | |
7483 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor); | |
7484 } | |
7485 else if (current >= 'A' && current <= 'F') | |
7486 { | |
7487 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor); | |
7488 } | |
7489 else if (current >= 'a' && current <= 'f') | |
7490 { | |
7491 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor); | |
7492 } | |
7493 else | |
7494 { | |
7495 return -1; | |
7496 } | |
7497 } | |
7498 | |
7499 JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); | |
7500 return codepoint; | |
7501 } | |
7502 | |
7503 /*! | |
7504 @brief check if the next byte(s) are inside a given range | |
7505 | |
7506 Adds the current byte and, for each passed range, reads a new byte and | |
7507 checks if it is inside the range. If a violation was detected, set up an | |
7508 error message and return false. Otherwise, return true. | |
7509 | |
7510 @param[in] ranges list of integers; interpreted as list of pairs of | |
7511 inclusive lower and upper bound, respectively | |
7512 | |
7513 @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, | |
7514 1, 2, or 3 pairs. This precondition is enforced by an assertion. | |
7515 | |
7516 @return true if and only if no range violation was detected | |
7517 */ | |
7518 bool next_byte_in_range(std::initializer_list<char_int_type> ranges) | |
7519 { | |
7520 JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); | |
7521 add(current); | |
7522 | |
7523 for (auto range = ranges.begin(); range != ranges.end(); ++range) | |
7524 { | |
7525 get(); | |
7526 if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) | |
7527 { | |
7528 add(current); | |
7529 } | |
7530 else | |
7531 { | |
7532 error_message = "invalid string: ill-formed UTF-8 byte"; | |
7533 return false; | |
7534 } | |
7535 } | |
7536 | |
7537 return true; | |
7538 } | |
7539 | |
7540 /*! | |
7541 @brief scan a string literal | |
7542 | |
7543 This function scans a string according to Sect. 7 of RFC 8259. While | |
7544 scanning, bytes are escaped and copied into buffer token_buffer. Then the | |
7545 function returns successfully, token_buffer is *not* null-terminated (as it | |
7546 may contain \0 bytes), and token_buffer.size() is the number of bytes in the | |
7547 string. | |
7548 | |
7549 @return token_type::value_string if string could be successfully scanned, | |
7550 token_type::parse_error otherwise | |
7551 | |
7552 @note In case of errors, variable error_message contains a textual | |
7553 description. | |
7554 */ | |
7555 token_type scan_string() | |
7556 { | |
7557 // reset token_buffer (ignore opening quote) | |
7558 reset(); | |
7559 | |
7560 // we entered the function by reading an open quote | |
7561 JSON_ASSERT(current == '\"'); | |
7562 | |
7563 while (true) | |
7564 { | |
7565 // get next character | |
7566 switch (get()) | |
7567 { | |
7568 // end of file while parsing string | |
7569 case std::char_traits<char_type>::eof(): | |
7570 { | |
7571 error_message = "invalid string: missing closing quote"; | |
7572 return token_type::parse_error; | |
7573 } | |
7574 | |
7575 // closing quote | |
7576 case '\"': | |
7577 { | |
7578 return token_type::value_string; | |
7579 } | |
7580 | |
7581 // escapes | |
7582 case '\\': | |
7583 { | |
7584 switch (get()) | |
7585 { | |
7586 // quotation mark | |
7587 case '\"': | |
7588 add('\"'); | |
7589 break; | |
7590 // reverse solidus | |
7591 case '\\': | |
7592 add('\\'); | |
7593 break; | |
7594 // solidus | |
7595 case '/': | |
7596 add('/'); | |
7597 break; | |
7598 // backspace | |
7599 case 'b': | |
7600 add('\b'); | |
7601 break; | |
7602 // form feed | |
7603 case 'f': | |
7604 add('\f'); | |
7605 break; | |
7606 // line feed | |
7607 case 'n': | |
7608 add('\n'); | |
7609 break; | |
7610 // carriage return | |
7611 case 'r': | |
7612 add('\r'); | |
7613 break; | |
7614 // tab | |
7615 case 't': | |
7616 add('\t'); | |
7617 break; | |
7618 | |
7619 // unicode escapes | |
7620 case 'u': | |
7621 { | |
7622 const int codepoint1 = get_codepoint(); | |
7623 int codepoint = codepoint1; // start with codepoint1 | |
7624 | |
7625 if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) | |
7626 { | |
7627 error_message = "invalid string: '\\u' must be followed by 4 hex digits"; | |
7628 return token_type::parse_error; | |
7629 } | |
7630 | |
7631 // check if code point is a high surrogate | |
7632 if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) | |
7633 { | |
7634 // expect next \uxxxx entry | |
7635 if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) | |
7636 { | |
7637 const int codepoint2 = get_codepoint(); | |
7638 | |
7639 if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) | |
7640 { | |
7641 error_message = "invalid string: '\\u' must be followed by 4 hex digits"; | |
7642 return token_type::parse_error; | |
7643 } | |
7644 | |
7645 // check if codepoint2 is a low surrogate | |
7646 if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) | |
7647 { | |
7648 // overwrite codepoint | |
7649 codepoint = static_cast<int>( | |
7650 // high surrogate occupies the most significant 22 bits | |
7651 (static_cast<unsigned int>(codepoint1) << 10u) | |
7652 // low surrogate occupies the least significant 15 bits | |
7653 + static_cast<unsigned int>(codepoint2) | |
7654 // there is still the 0xD800, 0xDC00 and 0x10000 noise | |
7655 // in the result, so we have to subtract with: | |
7656 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 | |
7657 - 0x35FDC00u); | |
7658 } | |
7659 else | |
7660 { | |
7661 error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; | |
7662 return token_type::parse_error; | |
7663 } | |
7664 } | |
7665 else | |
7666 { | |
7667 error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; | |
7668 return token_type::parse_error; | |
7669 } | |
7670 } | |
7671 else | |
7672 { | |
7673 if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) | |
7674 { | |
7675 error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; | |
7676 return token_type::parse_error; | |
7677 } | |
7678 } | |
7679 | |
7680 // result of the above calculation yields a proper codepoint | |
7681 JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); | |
7682 | |
7683 // translate codepoint into bytes | |
7684 if (codepoint < 0x80) | |
7685 { | |
7686 // 1-byte characters: 0xxxxxxx (ASCII) | |
7687 add(static_cast<char_int_type>(codepoint)); | |
7688 } | |
7689 else if (codepoint <= 0x7FF) | |
7690 { | |
7691 // 2-byte characters: 110xxxxx 10xxxxxx | |
7692 add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u))); | |
7693 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); | |
7694 } | |
7695 else if (codepoint <= 0xFFFF) | |
7696 { | |
7697 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx | |
7698 add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u))); | |
7699 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu))); | |
7700 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); | |
7701 } | |
7702 else | |
7703 { | |
7704 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | |
7705 add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u))); | |
7706 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu))); | |
7707 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu))); | |
7708 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); | |
7709 } | |
7710 | |
7711 break; | |
7712 } | |
7713 | |
7714 // other characters after escape | |
7715 default: | |
7716 error_message = "invalid string: forbidden character after backslash"; | |
7717 return token_type::parse_error; | |
7718 } | |
7719 | |
7720 break; | |
7721 } | |
7722 | |
7723 // invalid control characters | |
7724 case 0x00: | |
7725 { | |
7726 error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; | |
7727 return token_type::parse_error; | |
7728 } | |
7729 | |
7730 case 0x01: | |
7731 { | |
7732 error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; | |
7733 return token_type::parse_error; | |
7734 } | |
7735 | |
7736 case 0x02: | |
7737 { | |
7738 error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; | |
7739 return token_type::parse_error; | |
7740 } | |
7741 | |
7742 case 0x03: | |
7743 { | |
7744 error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; | |
7745 return token_type::parse_error; | |
7746 } | |
7747 | |
7748 case 0x04: | |
7749 { | |
7750 error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; | |
7751 return token_type::parse_error; | |
7752 } | |
7753 | |
7754 case 0x05: | |
7755 { | |
7756 error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; | |
7757 return token_type::parse_error; | |
7758 } | |
7759 | |
7760 case 0x06: | |
7761 { | |
7762 error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; | |
7763 return token_type::parse_error; | |
7764 } | |
7765 | |
7766 case 0x07: | |
7767 { | |
7768 error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; | |
7769 return token_type::parse_error; | |
7770 } | |
7771 | |
7772 case 0x08: | |
7773 { | |
7774 error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; | |
7775 return token_type::parse_error; | |
7776 } | |
7777 | |
7778 case 0x09: | |
7779 { | |
7780 error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; | |
7781 return token_type::parse_error; | |
7782 } | |
7783 | |
7784 case 0x0A: | |
7785 { | |
7786 error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; | |
7787 return token_type::parse_error; | |
7788 } | |
7789 | |
7790 case 0x0B: | |
7791 { | |
7792 error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; | |
7793 return token_type::parse_error; | |
7794 } | |
7795 | |
7796 case 0x0C: | |
7797 { | |
7798 error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; | |
7799 return token_type::parse_error; | |
7800 } | |
7801 | |
7802 case 0x0D: | |
7803 { | |
7804 error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; | |
7805 return token_type::parse_error; | |
7806 } | |
7807 | |
7808 case 0x0E: | |
7809 { | |
7810 error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; | |
7811 return token_type::parse_error; | |
7812 } | |
7813 | |
7814 case 0x0F: | |
7815 { | |
7816 error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; | |
7817 return token_type::parse_error; | |
7818 } | |
7819 | |
7820 case 0x10: | |
7821 { | |
7822 error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; | |
7823 return token_type::parse_error; | |
7824 } | |
7825 | |
7826 case 0x11: | |
7827 { | |
7828 error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; | |
7829 return token_type::parse_error; | |
7830 } | |
7831 | |
7832 case 0x12: | |
7833 { | |
7834 error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; | |
7835 return token_type::parse_error; | |
7836 } | |
7837 | |
7838 case 0x13: | |
7839 { | |
7840 error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; | |
7841 return token_type::parse_error; | |
7842 } | |
7843 | |
7844 case 0x14: | |
7845 { | |
7846 error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; | |
7847 return token_type::parse_error; | |
7848 } | |
7849 | |
7850 case 0x15: | |
7851 { | |
7852 error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; | |
7853 return token_type::parse_error; | |
7854 } | |
7855 | |
7856 case 0x16: | |
7857 { | |
7858 error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; | |
7859 return token_type::parse_error; | |
7860 } | |
7861 | |
7862 case 0x17: | |
7863 { | |
7864 error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; | |
7865 return token_type::parse_error; | |
7866 } | |
7867 | |
7868 case 0x18: | |
7869 { | |
7870 error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; | |
7871 return token_type::parse_error; | |
7872 } | |
7873 | |
7874 case 0x19: | |
7875 { | |
7876 error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; | |
7877 return token_type::parse_error; | |
7878 } | |
7879 | |
7880 case 0x1A: | |
7881 { | |
7882 error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; | |
7883 return token_type::parse_error; | |
7884 } | |
7885 | |
7886 case 0x1B: | |
7887 { | |
7888 error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; | |
7889 return token_type::parse_error; | |
7890 } | |
7891 | |
7892 case 0x1C: | |
7893 { | |
7894 error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; | |
7895 return token_type::parse_error; | |
7896 } | |
7897 | |
7898 case 0x1D: | |
7899 { | |
7900 error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; | |
7901 return token_type::parse_error; | |
7902 } | |
7903 | |
7904 case 0x1E: | |
7905 { | |
7906 error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; | |
7907 return token_type::parse_error; | |
7908 } | |
7909 | |
7910 case 0x1F: | |
7911 { | |
7912 error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; | |
7913 return token_type::parse_error; | |
7914 } | |
7915 | |
7916 // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) | |
7917 case 0x20: | |
7918 case 0x21: | |
7919 case 0x23: | |
7920 case 0x24: | |
7921 case 0x25: | |
7922 case 0x26: | |
7923 case 0x27: | |
7924 case 0x28: | |
7925 case 0x29: | |
7926 case 0x2A: | |
7927 case 0x2B: | |
7928 case 0x2C: | |
7929 case 0x2D: | |
7930 case 0x2E: | |
7931 case 0x2F: | |
7932 case 0x30: | |
7933 case 0x31: | |
7934 case 0x32: | |
7935 case 0x33: | |
7936 case 0x34: | |
7937 case 0x35: | |
7938 case 0x36: | |
7939 case 0x37: | |
7940 case 0x38: | |
7941 case 0x39: | |
7942 case 0x3A: | |
7943 case 0x3B: | |
7944 case 0x3C: | |
7945 case 0x3D: | |
7946 case 0x3E: | |
7947 case 0x3F: | |
7948 case 0x40: | |
7949 case 0x41: | |
7950 case 0x42: | |
7951 case 0x43: | |
7952 case 0x44: | |
7953 case 0x45: | |
7954 case 0x46: | |
7955 case 0x47: | |
7956 case 0x48: | |
7957 case 0x49: | |
7958 case 0x4A: | |
7959 case 0x4B: | |
7960 case 0x4C: | |
7961 case 0x4D: | |
7962 case 0x4E: | |
7963 case 0x4F: | |
7964 case 0x50: | |
7965 case 0x51: | |
7966 case 0x52: | |
7967 case 0x53: | |
7968 case 0x54: | |
7969 case 0x55: | |
7970 case 0x56: | |
7971 case 0x57: | |
7972 case 0x58: | |
7973 case 0x59: | |
7974 case 0x5A: | |
7975 case 0x5B: | |
7976 case 0x5D: | |
7977 case 0x5E: | |
7978 case 0x5F: | |
7979 case 0x60: | |
7980 case 0x61: | |
7981 case 0x62: | |
7982 case 0x63: | |
7983 case 0x64: | |
7984 case 0x65: | |
7985 case 0x66: | |
7986 case 0x67: | |
7987 case 0x68: | |
7988 case 0x69: | |
7989 case 0x6A: | |
7990 case 0x6B: | |
7991 case 0x6C: | |
7992 case 0x6D: | |
7993 case 0x6E: | |
7994 case 0x6F: | |
7995 case 0x70: | |
7996 case 0x71: | |
7997 case 0x72: | |
7998 case 0x73: | |
7999 case 0x74: | |
8000 case 0x75: | |
8001 case 0x76: | |
8002 case 0x77: | |
8003 case 0x78: | |
8004 case 0x79: | |
8005 case 0x7A: | |
8006 case 0x7B: | |
8007 case 0x7C: | |
8008 case 0x7D: | |
8009 case 0x7E: | |
8010 case 0x7F: | |
8011 { | |
8012 add(current); | |
8013 break; | |
8014 } | |
8015 | |
8016 // U+0080..U+07FF: bytes C2..DF 80..BF | |
8017 case 0xC2: | |
8018 case 0xC3: | |
8019 case 0xC4: | |
8020 case 0xC5: | |
8021 case 0xC6: | |
8022 case 0xC7: | |
8023 case 0xC8: | |
8024 case 0xC9: | |
8025 case 0xCA: | |
8026 case 0xCB: | |
8027 case 0xCC: | |
8028 case 0xCD: | |
8029 case 0xCE: | |
8030 case 0xCF: | |
8031 case 0xD0: | |
8032 case 0xD1: | |
8033 case 0xD2: | |
8034 case 0xD3: | |
8035 case 0xD4: | |
8036 case 0xD5: | |
8037 case 0xD6: | |
8038 case 0xD7: | |
8039 case 0xD8: | |
8040 case 0xD9: | |
8041 case 0xDA: | |
8042 case 0xDB: | |
8043 case 0xDC: | |
8044 case 0xDD: | |
8045 case 0xDE: | |
8046 case 0xDF: | |
8047 { | |
8048 if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) | |
8049 { | |
8050 return token_type::parse_error; | |
8051 } | |
8052 break; | |
8053 } | |
8054 | |
8055 // U+0800..U+0FFF: bytes E0 A0..BF 80..BF | |
8056 case 0xE0: | |
8057 { | |
8058 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) | |
8059 { | |
8060 return token_type::parse_error; | |
8061 } | |
8062 break; | |
8063 } | |
8064 | |
8065 // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF | |
8066 // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF | |
8067 case 0xE1: | |
8068 case 0xE2: | |
8069 case 0xE3: | |
8070 case 0xE4: | |
8071 case 0xE5: | |
8072 case 0xE6: | |
8073 case 0xE7: | |
8074 case 0xE8: | |
8075 case 0xE9: | |
8076 case 0xEA: | |
8077 case 0xEB: | |
8078 case 0xEC: | |
8079 case 0xEE: | |
8080 case 0xEF: | |
8081 { | |
8082 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) | |
8083 { | |
8084 return token_type::parse_error; | |
8085 } | |
8086 break; | |
8087 } | |
8088 | |
8089 // U+D000..U+D7FF: bytes ED 80..9F 80..BF | |
8090 case 0xED: | |
8091 { | |
8092 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) | |
8093 { | |
8094 return token_type::parse_error; | |
8095 } | |
8096 break; | |
8097 } | |
8098 | |
8099 // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF | |
8100 case 0xF0: | |
8101 { | |
8102 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) | |
8103 { | |
8104 return token_type::parse_error; | |
8105 } | |
8106 break; | |
8107 } | |
8108 | |
8109 // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF | |
8110 case 0xF1: | |
8111 case 0xF2: | |
8112 case 0xF3: | |
8113 { | |
8114 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) | |
8115 { | |
8116 return token_type::parse_error; | |
8117 } | |
8118 break; | |
8119 } | |
8120 | |
8121 // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF | |
8122 case 0xF4: | |
8123 { | |
8124 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) | |
8125 { | |
8126 return token_type::parse_error; | |
8127 } | |
8128 break; | |
8129 } | |
8130 | |
8131 // remaining bytes (80..C1 and F5..FF) are ill-formed | |
8132 default: | |
8133 { | |
8134 error_message = "invalid string: ill-formed UTF-8 byte"; | |
8135 return token_type::parse_error; | |
8136 } | |
8137 } | |
8138 } | |
8139 } | |
8140 | |
8141 /*! | |
8142 * @brief scan a comment | |
8143 * @return whether comment could be scanned successfully | |
8144 */ | |
8145 bool scan_comment() | |
8146 { | |
8147 switch (get()) | |
8148 { | |
8149 // single-line comments skip input until a newline or EOF is read | |
8150 case '/': | |
8151 { | |
8152 while (true) | |
8153 { | |
8154 switch (get()) | |
8155 { | |
8156 case '\n': | |
8157 case '\r': | |
8158 case std::char_traits<char_type>::eof(): | |
8159 case '\0': | |
8160 return true; | |
8161 | |
8162 default: | |
8163 break; | |
8164 } | |
8165 } | |
8166 } | |
8167 | |
8168 // multi-line comments skip input until */ is read | |
8169 case '*': | |
8170 { | |
8171 while (true) | |
8172 { | |
8173 switch (get()) | |
8174 { | |
8175 case std::char_traits<char_type>::eof(): | |
8176 case '\0': | |
8177 { | |
8178 error_message = "invalid comment; missing closing '*/'"; | |
8179 return false; | |
8180 } | |
8181 | |
8182 case '*': | |
8183 { | |
8184 switch (get()) | |
8185 { | |
8186 case '/': | |
8187 return true; | |
8188 | |
8189 default: | |
8190 { | |
8191 unget(); | |
8192 continue; | |
8193 } | |
8194 } | |
8195 } | |
8196 | |
8197 default: | |
8198 continue; | |
8199 } | |
8200 } | |
8201 } | |
8202 | |
8203 // unexpected character after reading '/' | |
8204 default: | |
8205 { | |
8206 error_message = "invalid comment; expecting '/' or '*' after '/'"; | |
8207 return false; | |
8208 } | |
8209 } | |
8210 } | |
8211 | |
8212 JSON_HEDLEY_NON_NULL(2) | |
8213 static void strtof(float& f, const char* str, char** endptr) noexcept | |
8214 { | |
8215 f = std::strtof(str, endptr); | |
8216 } | |
8217 | |
8218 JSON_HEDLEY_NON_NULL(2) | |
8219 static void strtof(double& f, const char* str, char** endptr) noexcept | |
8220 { | |
8221 f = std::strtod(str, endptr); | |
8222 } | |
8223 | |
8224 JSON_HEDLEY_NON_NULL(2) | |
8225 static void strtof(long double& f, const char* str, char** endptr) noexcept | |
8226 { | |
8227 f = std::strtold(str, endptr); | |
8228 } | |
8229 | |
8230 /*! | |
8231 @brief scan a number literal | |
8232 | |
8233 This function scans a string according to Sect. 6 of RFC 8259. | |
8234 | |
8235 The function is realized with a deterministic finite state machine derived | |
8236 from the grammar described in RFC 8259. Starting in state "init", the | |
8237 input is read and used to determined the next state. Only state "done" | |
8238 accepts the number. State "error" is a trap state to model errors. In the | |
8239 table below, "anything" means any character but the ones listed before. | |
8240 | |
8241 state | 0 | 1-9 | e E | + | - | . | anything | |
8242 ---------|----------|----------|----------|---------|---------|----------|----------- | |
8243 init | zero | any1 | [error] | [error] | minus | [error] | [error] | |
8244 minus | zero | any1 | [error] | [error] | [error] | [error] | [error] | |
8245 zero | done | done | exponent | done | done | decimal1 | done | |
8246 any1 | any1 | any1 | exponent | done | done | decimal1 | done | |
8247 decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] | |
8248 decimal2 | decimal2 | decimal2 | exponent | done | done | done | done | |
8249 exponent | any2 | any2 | [error] | sign | sign | [error] | [error] | |
8250 sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] | |
8251 any2 | any2 | any2 | done | done | done | done | done | |
8252 | |
8253 The state machine is realized with one label per state (prefixed with | |
8254 "scan_number_") and `goto` statements between them. The state machine | |
8255 contains cycles, but any cycle can be left when EOF is read. Therefore, | |
8256 the function is guaranteed to terminate. | |
8257 | |
8258 During scanning, the read bytes are stored in token_buffer. This string is | |
8259 then converted to a signed integer, an unsigned integer, or a | |
8260 floating-point number. | |
8261 | |
8262 @return token_type::value_unsigned, token_type::value_integer, or | |
8263 token_type::value_float if number could be successfully scanned, | |
8264 token_type::parse_error otherwise | |
8265 | |
8266 @note The scanner is independent of the current locale. Internally, the | |
8267 locale's decimal point is used instead of `.` to work with the | |
8268 locale-dependent converters. | |
8269 */ | |
8270 token_type scan_number() // lgtm [cpp/use-of-goto] | |
8271 { | |
8272 // reset token_buffer to store the number's bytes | |
8273 reset(); | |
8274 | |
8275 // the type of the parsed number; initially set to unsigned; will be | |
8276 // changed if minus sign, decimal point or exponent is read | |
8277 token_type number_type = token_type::value_unsigned; | |
8278 | |
8279 // state (init): we just found out we need to scan a number | |
8280 switch (current) | |
8281 { | |
8282 case '-': | |
8283 { | |
8284 add(current); | |
8285 goto scan_number_minus; | |
8286 } | |
8287 | |
8288 case '0': | |
8289 { | |
8290 add(current); | |
8291 goto scan_number_zero; | |
8292 } | |
8293 | |
8294 case '1': | |
8295 case '2': | |
8296 case '3': | |
8297 case '4': | |
8298 case '5': | |
8299 case '6': | |
8300 case '7': | |
8301 case '8': | |
8302 case '9': | |
8303 { | |
8304 add(current); | |
8305 goto scan_number_any1; | |
8306 } | |
8307 | |
8308 // all other characters are rejected outside scan_number() | |
8309 default: // LCOV_EXCL_LINE | |
8310 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
8311 } | |
8312 | |
8313 scan_number_minus: | |
8314 // state: we just parsed a leading minus sign | |
8315 number_type = token_type::value_integer; | |
8316 switch (get()) | |
8317 { | |
8318 case '0': | |
8319 { | |
8320 add(current); | |
8321 goto scan_number_zero; | |
8322 } | |
8323 | |
8324 case '1': | |
8325 case '2': | |
8326 case '3': | |
8327 case '4': | |
8328 case '5': | |
8329 case '6': | |
8330 case '7': | |
8331 case '8': | |
8332 case '9': | |
8333 { | |
8334 add(current); | |
8335 goto scan_number_any1; | |
8336 } | |
8337 | |
8338 default: | |
8339 { | |
8340 error_message = "invalid number; expected digit after '-'"; | |
8341 return token_type::parse_error; | |
8342 } | |
8343 } | |
8344 | |
8345 scan_number_zero: | |
8346 // state: we just parse a zero (maybe with a leading minus sign) | |
8347 switch (get()) | |
8348 { | |
8349 case '.': | |
8350 { | |
8351 add(decimal_point_char); | |
8352 goto scan_number_decimal1; | |
8353 } | |
8354 | |
8355 case 'e': | |
8356 case 'E': | |
8357 { | |
8358 add(current); | |
8359 goto scan_number_exponent; | |
8360 } | |
8361 | |
8362 default: | |
8363 goto scan_number_done; | |
8364 } | |
8365 | |
8366 scan_number_any1: | |
8367 // state: we just parsed a number 0-9 (maybe with a leading minus sign) | |
8368 switch (get()) | |
8369 { | |
8370 case '0': | |
8371 case '1': | |
8372 case '2': | |
8373 case '3': | |
8374 case '4': | |
8375 case '5': | |
8376 case '6': | |
8377 case '7': | |
8378 case '8': | |
8379 case '9': | |
8380 { | |
8381 add(current); | |
8382 goto scan_number_any1; | |
8383 } | |
8384 | |
8385 case '.': | |
8386 { | |
8387 add(decimal_point_char); | |
8388 goto scan_number_decimal1; | |
8389 } | |
8390 | |
8391 case 'e': | |
8392 case 'E': | |
8393 { | |
8394 add(current); | |
8395 goto scan_number_exponent; | |
8396 } | |
8397 | |
8398 default: | |
8399 goto scan_number_done; | |
8400 } | |
8401 | |
8402 scan_number_decimal1: | |
8403 // state: we just parsed a decimal point | |
8404 number_type = token_type::value_float; | |
8405 switch (get()) | |
8406 { | |
8407 case '0': | |
8408 case '1': | |
8409 case '2': | |
8410 case '3': | |
8411 case '4': | |
8412 case '5': | |
8413 case '6': | |
8414 case '7': | |
8415 case '8': | |
8416 case '9': | |
8417 { | |
8418 add(current); | |
8419 goto scan_number_decimal2; | |
8420 } | |
8421 | |
8422 default: | |
8423 { | |
8424 error_message = "invalid number; expected digit after '.'"; | |
8425 return token_type::parse_error; | |
8426 } | |
8427 } | |
8428 | |
8429 scan_number_decimal2: | |
8430 // we just parsed at least one number after a decimal point | |
8431 switch (get()) | |
8432 { | |
8433 case '0': | |
8434 case '1': | |
8435 case '2': | |
8436 case '3': | |
8437 case '4': | |
8438 case '5': | |
8439 case '6': | |
8440 case '7': | |
8441 case '8': | |
8442 case '9': | |
8443 { | |
8444 add(current); | |
8445 goto scan_number_decimal2; | |
8446 } | |
8447 | |
8448 case 'e': | |
8449 case 'E': | |
8450 { | |
8451 add(current); | |
8452 goto scan_number_exponent; | |
8453 } | |
8454 | |
8455 default: | |
8456 goto scan_number_done; | |
8457 } | |
8458 | |
8459 scan_number_exponent: | |
8460 // we just parsed an exponent | |
8461 number_type = token_type::value_float; | |
8462 switch (get()) | |
8463 { | |
8464 case '+': | |
8465 case '-': | |
8466 { | |
8467 add(current); | |
8468 goto scan_number_sign; | |
8469 } | |
8470 | |
8471 case '0': | |
8472 case '1': | |
8473 case '2': | |
8474 case '3': | |
8475 case '4': | |
8476 case '5': | |
8477 case '6': | |
8478 case '7': | |
8479 case '8': | |
8480 case '9': | |
8481 { | |
8482 add(current); | |
8483 goto scan_number_any2; | |
8484 } | |
8485 | |
8486 default: | |
8487 { | |
8488 error_message = | |
8489 "invalid number; expected '+', '-', or digit after exponent"; | |
8490 return token_type::parse_error; | |
8491 } | |
8492 } | |
8493 | |
8494 scan_number_sign: | |
8495 // we just parsed an exponent sign | |
8496 switch (get()) | |
8497 { | |
8498 case '0': | |
8499 case '1': | |
8500 case '2': | |
8501 case '3': | |
8502 case '4': | |
8503 case '5': | |
8504 case '6': | |
8505 case '7': | |
8506 case '8': | |
8507 case '9': | |
8508 { | |
8509 add(current); | |
8510 goto scan_number_any2; | |
8511 } | |
8512 | |
8513 default: | |
8514 { | |
8515 error_message = "invalid number; expected digit after exponent sign"; | |
8516 return token_type::parse_error; | |
8517 } | |
8518 } | |
8519 | |
8520 scan_number_any2: | |
8521 // we just parsed a number after the exponent or exponent sign | |
8522 switch (get()) | |
8523 { | |
8524 case '0': | |
8525 case '1': | |
8526 case '2': | |
8527 case '3': | |
8528 case '4': | |
8529 case '5': | |
8530 case '6': | |
8531 case '7': | |
8532 case '8': | |
8533 case '9': | |
8534 { | |
8535 add(current); | |
8536 goto scan_number_any2; | |
8537 } | |
8538 | |
8539 default: | |
8540 goto scan_number_done; | |
8541 } | |
8542 | |
8543 scan_number_done: | |
8544 // unget the character after the number (we only read it to know that | |
8545 // we are done scanning a number) | |
8546 unget(); | |
8547 | |
8548 char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
8549 errno = 0; | |
8550 | |
8551 // try to parse integers first and fall back to floats | |
8552 if (number_type == token_type::value_unsigned) | |
8553 { | |
8554 const auto x = std::strtoull(token_buffer.data(), &endptr, 10); | |
8555 | |
8556 // we checked the number format before | |
8557 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); | |
8558 | |
8559 if (errno == 0) | |
8560 { | |
8561 value_unsigned = static_cast<number_unsigned_t>(x); | |
8562 if (value_unsigned == x) | |
8563 { | |
8564 return token_type::value_unsigned; | |
8565 } | |
8566 } | |
8567 } | |
8568 else if (number_type == token_type::value_integer) | |
8569 { | |
8570 const auto x = std::strtoll(token_buffer.data(), &endptr, 10); | |
8571 | |
8572 // we checked the number format before | |
8573 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); | |
8574 | |
8575 if (errno == 0) | |
8576 { | |
8577 value_integer = static_cast<number_integer_t>(x); | |
8578 if (value_integer == x) | |
8579 { | |
8580 return token_type::value_integer; | |
8581 } | |
8582 } | |
8583 } | |
8584 | |
8585 // this code is reached if we parse a floating-point number or if an | |
8586 // integer conversion above failed | |
8587 strtof(value_float, token_buffer.data(), &endptr); | |
8588 | |
8589 // we checked the number format before | |
8590 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); | |
8591 | |
8592 return token_type::value_float; | |
8593 } | |
8594 | |
8595 /*! | |
8596 @param[in] literal_text the literal text to expect | |
8597 @param[in] length the length of the passed literal text | |
8598 @param[in] return_type the token type to return on success | |
8599 */ | |
8600 JSON_HEDLEY_NON_NULL(2) | |
8601 token_type scan_literal(const char_type* literal_text, const std::size_t length, | |
8602 token_type return_type) | |
8603 { | |
8604 JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]); | |
8605 for (std::size_t i = 1; i < length; ++i) | |
8606 { | |
8607 if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i])) | |
8608 { | |
8609 error_message = "invalid literal"; | |
8610 return token_type::parse_error; | |
8611 } | |
8612 } | |
8613 return return_type; | |
8614 } | |
8615 | |
8616 ///////////////////// | |
8617 // input management | |
8618 ///////////////////// | |
8619 | |
8620 /// reset token_buffer; current character is beginning of token | |
8621 void reset() noexcept | |
8622 { | |
8623 token_buffer.clear(); | |
8624 token_string.clear(); | |
8625 token_string.push_back(std::char_traits<char_type>::to_char_type(current)); | |
8626 } | |
8627 | |
8628 /* | |
8629 @brief get next character from the input | |
8630 | |
8631 This function provides the interface to the used input adapter. It does | |
8632 not throw in case the input reached EOF, but returns a | |
8633 `std::char_traits<char>::eof()` in that case. Stores the scanned characters | |
8634 for use in error messages. | |
8635 | |
8636 @return character read from the input | |
8637 */ | |
8638 char_int_type get() | |
8639 { | |
8640 ++position.chars_read_total; | |
8641 ++position.chars_read_current_line; | |
8642 | |
8643 if (next_unget) | |
8644 { | |
8645 // just reset the next_unget variable and work with current | |
8646 next_unget = false; | |
8647 } | |
8648 else | |
8649 { | |
8650 current = ia.get_character(); | |
8651 } | |
8652 | |
8653 if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof())) | |
8654 { | |
8655 token_string.push_back(std::char_traits<char_type>::to_char_type(current)); | |
8656 } | |
8657 | |
8658 if (current == '\n') | |
8659 { | |
8660 ++position.lines_read; | |
8661 position.chars_read_current_line = 0; | |
8662 } | |
8663 | |
8664 return current; | |
8665 } | |
8666 | |
8667 /*! | |
8668 @brief unget current character (read it again on next get) | |
8669 | |
8670 We implement unget by setting variable next_unget to true. The input is not | |
8671 changed - we just simulate ungetting by modifying chars_read_total, | |
8672 chars_read_current_line, and token_string. The next call to get() will | |
8673 behave as if the unget character is read again. | |
8674 */ | |
8675 void unget() | |
8676 { | |
8677 next_unget = true; | |
8678 | |
8679 --position.chars_read_total; | |
8680 | |
8681 // in case we "unget" a newline, we have to also decrement the lines_read | |
8682 if (position.chars_read_current_line == 0) | |
8683 { | |
8684 if (position.lines_read > 0) | |
8685 { | |
8686 --position.lines_read; | |
8687 } | |
8688 } | |
8689 else | |
8690 { | |
8691 --position.chars_read_current_line; | |
8692 } | |
8693 | |
8694 if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof())) | |
8695 { | |
8696 JSON_ASSERT(!token_string.empty()); | |
8697 token_string.pop_back(); | |
8698 } | |
8699 } | |
8700 | |
8701 /// add a character to token_buffer | |
8702 void add(char_int_type c) | |
8703 { | |
8704 token_buffer.push_back(static_cast<typename string_t::value_type>(c)); | |
8705 } | |
8706 | |
8707 public: | |
8708 ///////////////////// | |
8709 // value getters | |
8710 ///////////////////// | |
8711 | |
8712 /// return integer value | |
8713 constexpr number_integer_t get_number_integer() const noexcept | |
8714 { | |
8715 return value_integer; | |
8716 } | |
8717 | |
8718 /// return unsigned integer value | |
8719 constexpr number_unsigned_t get_number_unsigned() const noexcept | |
8720 { | |
8721 return value_unsigned; | |
8722 } | |
8723 | |
8724 /// return floating-point value | |
8725 constexpr number_float_t get_number_float() const noexcept | |
8726 { | |
8727 return value_float; | |
8728 } | |
8729 | |
8730 /// return current string value (implicitly resets the token; useful only once) | |
8731 string_t& get_string() | |
8732 { | |
8733 return token_buffer; | |
8734 } | |
8735 | |
8736 ///////////////////// | |
8737 // diagnostics | |
8738 ///////////////////// | |
8739 | |
8740 /// return position of last read token | |
8741 constexpr position_t get_position() const noexcept | |
8742 { | |
8743 return position; | |
8744 } | |
8745 | |
8746 /// return the last read token (for errors only). Will never contain EOF | |
8747 /// (an arbitrary value that is not a valid char value, often -1), because | |
8748 /// 255 may legitimately occur. May contain NUL, which should be escaped. | |
8749 std::string get_token_string() const | |
8750 { | |
8751 // escape control characters | |
8752 std::string result; | |
8753 for (const auto c : token_string) | |
8754 { | |
8755 if (static_cast<unsigned char>(c) <= '\x1F') | |
8756 { | |
8757 // escape control characters | |
8758 std::array<char, 9> cs{{}}; | |
8759 static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
8760 result += cs.data(); | |
8761 } | |
8762 else | |
8763 { | |
8764 // add character as is | |
8765 result.push_back(static_cast<std::string::value_type>(c)); | |
8766 } | |
8767 } | |
8768 | |
8769 return result; | |
8770 } | |
8771 | |
8772 /// return syntax error message | |
8773 JSON_HEDLEY_RETURNS_NON_NULL | |
8774 constexpr const char* get_error_message() const noexcept | |
8775 { | |
8776 return error_message; | |
8777 } | |
8778 | |
8779 ///////////////////// | |
8780 // actual scanner | |
8781 ///////////////////// | |
8782 | |
8783 /*! | |
8784 @brief skip the UTF-8 byte order mark | |
8785 @return true iff there is no BOM or the correct BOM has been skipped | |
8786 */ | |
8787 bool skip_bom() | |
8788 { | |
8789 if (get() == 0xEF) | |
8790 { | |
8791 // check if we completely parse the BOM | |
8792 return get() == 0xBB && get() == 0xBF; | |
8793 } | |
8794 | |
8795 // the first character is not the beginning of the BOM; unget it to | |
8796 // process is later | |
8797 unget(); | |
8798 return true; | |
8799 } | |
8800 | |
8801 void skip_whitespace() | |
8802 { | |
8803 do | |
8804 { | |
8805 get(); | |
8806 } | |
8807 while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); | |
8808 } | |
8809 | |
8810 token_type scan() | |
8811 { | |
8812 // initially, skip the BOM | |
8813 if (position.chars_read_total == 0 && !skip_bom()) | |
8814 { | |
8815 error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; | |
8816 return token_type::parse_error; | |
8817 } | |
8818 | |
8819 // read next character and ignore whitespace | |
8820 skip_whitespace(); | |
8821 | |
8822 // ignore comments | |
8823 while (ignore_comments && current == '/') | |
8824 { | |
8825 if (!scan_comment()) | |
8826 { | |
8827 return token_type::parse_error; | |
8828 } | |
8829 | |
8830 // skip following whitespace | |
8831 skip_whitespace(); | |
8832 } | |
8833 | |
8834 switch (current) | |
8835 { | |
8836 // structural characters | |
8837 case '[': | |
8838 return token_type::begin_array; | |
8839 case ']': | |
8840 return token_type::end_array; | |
8841 case '{': | |
8842 return token_type::begin_object; | |
8843 case '}': | |
8844 return token_type::end_object; | |
8845 case ':': | |
8846 return token_type::name_separator; | |
8847 case ',': | |
8848 return token_type::value_separator; | |
8849 | |
8850 // literals | |
8851 case 't': | |
8852 { | |
8853 std::array<char_type, 4> true_literal = {{static_cast<char_type>('t'), static_cast<char_type>('r'), static_cast<char_type>('u'), static_cast<char_type>('e')}}; | |
8854 return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); | |
8855 } | |
8856 case 'f': | |
8857 { | |
8858 std::array<char_type, 5> false_literal = {{static_cast<char_type>('f'), static_cast<char_type>('a'), static_cast<char_type>('l'), static_cast<char_type>('s'), static_cast<char_type>('e')}}; | |
8859 return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); | |
8860 } | |
8861 case 'n': | |
8862 { | |
8863 std::array<char_type, 4> null_literal = {{static_cast<char_type>('n'), static_cast<char_type>('u'), static_cast<char_type>('l'), static_cast<char_type>('l')}}; | |
8864 return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); | |
8865 } | |
8866 | |
8867 // string | |
8868 case '\"': | |
8869 return scan_string(); | |
8870 | |
8871 // number | |
8872 case '-': | |
8873 case '0': | |
8874 case '1': | |
8875 case '2': | |
8876 case '3': | |
8877 case '4': | |
8878 case '5': | |
8879 case '6': | |
8880 case '7': | |
8881 case '8': | |
8882 case '9': | |
8883 return scan_number(); | |
8884 | |
8885 // end of input (the null byte is needed when parsing from | |
8886 // string literals) | |
8887 case '\0': | |
8888 case std::char_traits<char_type>::eof(): | |
8889 return token_type::end_of_input; | |
8890 | |
8891 // error | |
8892 default: | |
8893 error_message = "invalid literal"; | |
8894 return token_type::parse_error; | |
8895 } | |
8896 } | |
8897 | |
8898 private: | |
8899 /// input adapter | |
8900 InputAdapterType ia; | |
8901 | |
8902 /// whether comments should be ignored (true) or signaled as errors (false) | |
8903 const bool ignore_comments = false; | |
8904 | |
8905 /// the current character | |
8906 char_int_type current = std::char_traits<char_type>::eof(); | |
8907 | |
8908 /// whether the next get() call should just return current | |
8909 bool next_unget = false; | |
8910 | |
8911 /// the start position of the current token | |
8912 position_t position {}; | |
8913 | |
8914 /// raw input token string (for error messages) | |
8915 std::vector<char_type> token_string {}; | |
8916 | |
8917 /// buffer for variable-length tokens (numbers, strings) | |
8918 string_t token_buffer {}; | |
8919 | |
8920 /// a description of occurred lexer errors | |
8921 const char* error_message = ""; | |
8922 | |
8923 // number values | |
8924 number_integer_t value_integer = 0; | |
8925 number_unsigned_t value_unsigned = 0; | |
8926 number_float_t value_float = 0; | |
8927 | |
8928 /// the decimal point | |
8929 const char_int_type decimal_point_char = '.'; | |
8930 }; | |
8931 | |
8932 } // namespace detail | |
8933 NLOHMANN_JSON_NAMESPACE_END | |
8934 | |
8935 // #include <nlohmann/detail/macro_scope.hpp> | |
8936 | |
8937 // #include <nlohmann/detail/meta/is_sax.hpp> | |
8938 // __ _____ _____ _____ | |
8939 // __| | __| | | | JSON for Modern C++ | |
8940 // | | |__ | | | | | | version 3.11.2 | |
8941 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
8942 // | |
8943 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
8944 // SPDX-License-Identifier: MIT | |
8945 | |
8946 | |
8947 | |
8948 #include <cstdint> // size_t | |
8949 #include <utility> // declval | |
8950 #include <string> // string | |
8951 | |
8952 // #include <nlohmann/detail/abi_macros.hpp> | |
8953 | |
8954 // #include <nlohmann/detail/meta/detected.hpp> | |
8955 | |
8956 // #include <nlohmann/detail/meta/type_traits.hpp> | |
8957 | |
8958 | |
8959 NLOHMANN_JSON_NAMESPACE_BEGIN | |
8960 namespace detail | |
8961 { | |
8962 | |
8963 template<typename T> | |
8964 using null_function_t = decltype(std::declval<T&>().null()); | |
8965 | |
8966 template<typename T> | |
8967 using boolean_function_t = | |
8968 decltype(std::declval<T&>().boolean(std::declval<bool>())); | |
8969 | |
8970 template<typename T, typename Integer> | |
8971 using number_integer_function_t = | |
8972 decltype(std::declval<T&>().number_integer(std::declval<Integer>())); | |
8973 | |
8974 template<typename T, typename Unsigned> | |
8975 using number_unsigned_function_t = | |
8976 decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>())); | |
8977 | |
8978 template<typename T, typename Float, typename String> | |
8979 using number_float_function_t = decltype(std::declval<T&>().number_float( | |
8980 std::declval<Float>(), std::declval<const String&>())); | |
8981 | |
8982 template<typename T, typename String> | |
8983 using string_function_t = | |
8984 decltype(std::declval<T&>().string(std::declval<String&>())); | |
8985 | |
8986 template<typename T, typename Binary> | |
8987 using binary_function_t = | |
8988 decltype(std::declval<T&>().binary(std::declval<Binary&>())); | |
8989 | |
8990 template<typename T> | |
8991 using start_object_function_t = | |
8992 decltype(std::declval<T&>().start_object(std::declval<std::size_t>())); | |
8993 | |
8994 template<typename T, typename String> | |
8995 using key_function_t = | |
8996 decltype(std::declval<T&>().key(std::declval<String&>())); | |
8997 | |
8998 template<typename T> | |
8999 using end_object_function_t = decltype(std::declval<T&>().end_object()); | |
9000 | |
9001 template<typename T> | |
9002 using start_array_function_t = | |
9003 decltype(std::declval<T&>().start_array(std::declval<std::size_t>())); | |
9004 | |
9005 template<typename T> | |
9006 using end_array_function_t = decltype(std::declval<T&>().end_array()); | |
9007 | |
9008 template<typename T, typename Exception> | |
9009 using parse_error_function_t = decltype(std::declval<T&>().parse_error( | |
9010 std::declval<std::size_t>(), std::declval<const std::string&>(), | |
9011 std::declval<const Exception&>())); | |
9012 | |
9013 template<typename SAX, typename BasicJsonType> | |
9014 struct is_sax | |
9015 { | |
9016 private: | |
9017 static_assert(is_basic_json<BasicJsonType>::value, | |
9018 "BasicJsonType must be of type basic_json<...>"); | |
9019 | |
9020 using number_integer_t = typename BasicJsonType::number_integer_t; | |
9021 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
9022 using number_float_t = typename BasicJsonType::number_float_t; | |
9023 using string_t = typename BasicJsonType::string_t; | |
9024 using binary_t = typename BasicJsonType::binary_t; | |
9025 using exception_t = typename BasicJsonType::exception; | |
9026 | |
9027 public: | |
9028 static constexpr bool value = | |
9029 is_detected_exact<bool, null_function_t, SAX>::value && | |
9030 is_detected_exact<bool, boolean_function_t, SAX>::value && | |
9031 is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value && | |
9032 is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value && | |
9033 is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value && | |
9034 is_detected_exact<bool, string_function_t, SAX, string_t>::value && | |
9035 is_detected_exact<bool, binary_function_t, SAX, binary_t>::value && | |
9036 is_detected_exact<bool, start_object_function_t, SAX>::value && | |
9037 is_detected_exact<bool, key_function_t, SAX, string_t>::value && | |
9038 is_detected_exact<bool, end_object_function_t, SAX>::value && | |
9039 is_detected_exact<bool, start_array_function_t, SAX>::value && | |
9040 is_detected_exact<bool, end_array_function_t, SAX>::value && | |
9041 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value; | |
9042 }; | |
9043 | |
9044 template<typename SAX, typename BasicJsonType> | |
9045 struct is_sax_static_asserts | |
9046 { | |
9047 private: | |
9048 static_assert(is_basic_json<BasicJsonType>::value, | |
9049 "BasicJsonType must be of type basic_json<...>"); | |
9050 | |
9051 using number_integer_t = typename BasicJsonType::number_integer_t; | |
9052 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
9053 using number_float_t = typename BasicJsonType::number_float_t; | |
9054 using string_t = typename BasicJsonType::string_t; | |
9055 using binary_t = typename BasicJsonType::binary_t; | |
9056 using exception_t = typename BasicJsonType::exception; | |
9057 | |
9058 public: | |
9059 static_assert(is_detected_exact<bool, null_function_t, SAX>::value, | |
9060 "Missing/invalid function: bool null()"); | |
9061 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value, | |
9062 "Missing/invalid function: bool boolean(bool)"); | |
9063 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value, | |
9064 "Missing/invalid function: bool boolean(bool)"); | |
9065 static_assert( | |
9066 is_detected_exact<bool, number_integer_function_t, SAX, | |
9067 number_integer_t>::value, | |
9068 "Missing/invalid function: bool number_integer(number_integer_t)"); | |
9069 static_assert( | |
9070 is_detected_exact<bool, number_unsigned_function_t, SAX, | |
9071 number_unsigned_t>::value, | |
9072 "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); | |
9073 static_assert(is_detected_exact<bool, number_float_function_t, SAX, | |
9074 number_float_t, string_t>::value, | |
9075 "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); | |
9076 static_assert( | |
9077 is_detected_exact<bool, string_function_t, SAX, string_t>::value, | |
9078 "Missing/invalid function: bool string(string_t&)"); | |
9079 static_assert( | |
9080 is_detected_exact<bool, binary_function_t, SAX, binary_t>::value, | |
9081 "Missing/invalid function: bool binary(binary_t&)"); | |
9082 static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value, | |
9083 "Missing/invalid function: bool start_object(std::size_t)"); | |
9084 static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value, | |
9085 "Missing/invalid function: bool key(string_t&)"); | |
9086 static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value, | |
9087 "Missing/invalid function: bool end_object()"); | |
9088 static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value, | |
9089 "Missing/invalid function: bool start_array(std::size_t)"); | |
9090 static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value, | |
9091 "Missing/invalid function: bool end_array()"); | |
9092 static_assert( | |
9093 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value, | |
9094 "Missing/invalid function: bool parse_error(std::size_t, const " | |
9095 "std::string&, const exception&)"); | |
9096 }; | |
9097 | |
9098 } // namespace detail | |
9099 NLOHMANN_JSON_NAMESPACE_END | |
9100 | |
9101 // #include <nlohmann/detail/meta/type_traits.hpp> | |
9102 | |
9103 // #include <nlohmann/detail/string_concat.hpp> | |
9104 | |
9105 // #include <nlohmann/detail/value_t.hpp> | |
9106 | |
9107 | |
9108 NLOHMANN_JSON_NAMESPACE_BEGIN | |
9109 namespace detail | |
9110 { | |
9111 | |
9112 /// how to treat CBOR tags | |
9113 enum class cbor_tag_handler_t | |
9114 { | |
9115 error, ///< throw a parse_error exception in case of a tag | |
9116 ignore, ///< ignore tags | |
9117 store ///< store tags as binary type | |
9118 }; | |
9119 | |
9120 /*! | |
9121 @brief determine system byte order | |
9122 | |
9123 @return true if and only if system's byte order is little endian | |
9124 | |
9125 @note from https://stackoverflow.com/a/1001328/266378 | |
9126 */ | |
9127 static inline bool little_endianness(int num = 1) noexcept | |
9128 { | |
9129 return *reinterpret_cast<char*>(&num) == 1; | |
9130 } | |
9131 | |
9132 | |
9133 /////////////////// | |
9134 // binary reader // | |
9135 /////////////////// | |
9136 | |
9137 /*! | |
9138 @brief deserialization of CBOR, MessagePack, and UBJSON values | |
9139 */ | |
9140 template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>> | |
9141 class binary_reader | |
9142 { | |
9143 using number_integer_t = typename BasicJsonType::number_integer_t; | |
9144 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
9145 using number_float_t = typename BasicJsonType::number_float_t; | |
9146 using string_t = typename BasicJsonType::string_t; | |
9147 using binary_t = typename BasicJsonType::binary_t; | |
9148 using json_sax_t = SAX; | |
9149 using char_type = typename InputAdapterType::char_type; | |
9150 using char_int_type = typename std::char_traits<char_type>::int_type; | |
9151 | |
9152 public: | |
9153 /*! | |
9154 @brief create a binary reader | |
9155 | |
9156 @param[in] adapter input adapter to read from | |
9157 */ | |
9158 explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format) | |
9159 { | |
9160 (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; | |
9161 } | |
9162 | |
9163 // make class move-only | |
9164 binary_reader(const binary_reader&) = delete; | |
9165 binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
9166 binary_reader& operator=(const binary_reader&) = delete; | |
9167 binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) | |
9168 ~binary_reader() = default; | |
9169 | |
9170 /*! | |
9171 @param[in] format the binary format to parse | |
9172 @param[in] sax_ a SAX event processor | |
9173 @param[in] strict whether to expect the input to be consumed completed | |
9174 @param[in] tag_handler how to treat CBOR tags | |
9175 | |
9176 @return whether parsing was successful | |
9177 */ | |
9178 JSON_HEDLEY_NON_NULL(3) | |
9179 bool sax_parse(const input_format_t format, | |
9180 json_sax_t* sax_, | |
9181 const bool strict = true, | |
9182 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) | |
9183 { | |
9184 sax = sax_; | |
9185 bool result = false; | |
9186 | |
9187 switch (format) | |
9188 { | |
9189 case input_format_t::bson: | |
9190 result = parse_bson_internal(); | |
9191 break; | |
9192 | |
9193 case input_format_t::cbor: | |
9194 result = parse_cbor_internal(true, tag_handler); | |
9195 break; | |
9196 | |
9197 case input_format_t::msgpack: | |
9198 result = parse_msgpack_internal(); | |
9199 break; | |
9200 | |
9201 case input_format_t::ubjson: | |
9202 case input_format_t::bjdata: | |
9203 result = parse_ubjson_internal(); | |
9204 break; | |
9205 | |
9206 case input_format_t::json: // LCOV_EXCL_LINE | |
9207 default: // LCOV_EXCL_LINE | |
9208 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
9209 } | |
9210 | |
9211 // strict mode: next byte must be EOF | |
9212 if (result && strict) | |
9213 { | |
9214 if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata) | |
9215 { | |
9216 get_ignore_noop(); | |
9217 } | |
9218 else | |
9219 { | |
9220 get(); | |
9221 } | |
9222 | |
9223 if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof())) | |
9224 { | |
9225 return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, | |
9226 exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); | |
9227 } | |
9228 } | |
9229 | |
9230 return result; | |
9231 } | |
9232 | |
9233 private: | |
9234 ////////// | |
9235 // BSON // | |
9236 ////////// | |
9237 | |
9238 /*! | |
9239 @brief Reads in a BSON-object and passes it to the SAX-parser. | |
9240 @return whether a valid BSON-value was passed to the SAX parser | |
9241 */ | |
9242 bool parse_bson_internal() | |
9243 { | |
9244 std::int32_t document_size{}; | |
9245 get_number<std::int32_t, true>(input_format_t::bson, document_size); | |
9246 | |
9247 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) | |
9248 { | |
9249 return false; | |
9250 } | |
9251 | |
9252 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) | |
9253 { | |
9254 return false; | |
9255 } | |
9256 | |
9257 return sax->end_object(); | |
9258 } | |
9259 | |
9260 /*! | |
9261 @brief Parses a C-style string from the BSON input. | |
9262 @param[in,out] result A reference to the string variable where the read | |
9263 string is to be stored. | |
9264 @return `true` if the \x00-byte indicating the end of the string was | |
9265 encountered before the EOF; false` indicates an unexpected EOF. | |
9266 */ | |
9267 bool get_bson_cstr(string_t& result) | |
9268 { | |
9269 auto out = std::back_inserter(result); | |
9270 while (true) | |
9271 { | |
9272 get(); | |
9273 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) | |
9274 { | |
9275 return false; | |
9276 } | |
9277 if (current == 0x00) | |
9278 { | |
9279 return true; | |
9280 } | |
9281 *out++ = static_cast<typename string_t::value_type>(current); | |
9282 } | |
9283 } | |
9284 | |
9285 /*! | |
9286 @brief Parses a zero-terminated string of length @a len from the BSON | |
9287 input. | |
9288 @param[in] len The length (including the zero-byte at the end) of the | |
9289 string to be read. | |
9290 @param[in,out] result A reference to the string variable where the read | |
9291 string is to be stored. | |
9292 @tparam NumberType The type of the length @a len | |
9293 @pre len >= 1 | |
9294 @return `true` if the string was successfully parsed | |
9295 */ | |
9296 template<typename NumberType> | |
9297 bool get_bson_string(const NumberType len, string_t& result) | |
9298 { | |
9299 if (JSON_HEDLEY_UNLIKELY(len < 1)) | |
9300 { | |
9301 auto last_token = get_token_string(); | |
9302 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
9303 exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); | |
9304 } | |
9305 | |
9306 return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof(); | |
9307 } | |
9308 | |
9309 /*! | |
9310 @brief Parses a byte array input of length @a len from the BSON input. | |
9311 @param[in] len The length of the byte array to be read. | |
9312 @param[in,out] result A reference to the binary variable where the read | |
9313 array is to be stored. | |
9314 @tparam NumberType The type of the length @a len | |
9315 @pre len >= 0 | |
9316 @return `true` if the byte array was successfully parsed | |
9317 */ | |
9318 template<typename NumberType> | |
9319 bool get_bson_binary(const NumberType len, binary_t& result) | |
9320 { | |
9321 if (JSON_HEDLEY_UNLIKELY(len < 0)) | |
9322 { | |
9323 auto last_token = get_token_string(); | |
9324 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
9325 exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); | |
9326 } | |
9327 | |
9328 // All BSON binary values have a subtype | |
9329 std::uint8_t subtype{}; | |
9330 get_number<std::uint8_t>(input_format_t::bson, subtype); | |
9331 result.set_subtype(subtype); | |
9332 | |
9333 return get_binary(input_format_t::bson, len, result); | |
9334 } | |
9335 | |
9336 /*! | |
9337 @brief Read a BSON document element of the given @a element_type. | |
9338 @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html | |
9339 @param[in] element_type_parse_position The position in the input stream, | |
9340 where the `element_type` was read. | |
9341 @warning Not all BSON element types are supported yet. An unsupported | |
9342 @a element_type will give rise to a parse_error.114: | |
9343 Unsupported BSON record type 0x... | |
9344 @return whether a valid BSON-object/array was passed to the SAX parser | |
9345 */ | |
9346 bool parse_bson_element_internal(const char_int_type element_type, | |
9347 const std::size_t element_type_parse_position) | |
9348 { | |
9349 switch (element_type) | |
9350 { | |
9351 case 0x01: // double | |
9352 { | |
9353 double number{}; | |
9354 return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), ""); | |
9355 } | |
9356 | |
9357 case 0x02: // string | |
9358 { | |
9359 std::int32_t len{}; | |
9360 string_t value; | |
9361 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); | |
9362 } | |
9363 | |
9364 case 0x03: // object | |
9365 { | |
9366 return parse_bson_internal(); | |
9367 } | |
9368 | |
9369 case 0x04: // array | |
9370 { | |
9371 return parse_bson_array(); | |
9372 } | |
9373 | |
9374 case 0x05: // binary | |
9375 { | |
9376 std::int32_t len{}; | |
9377 binary_t value; | |
9378 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); | |
9379 } | |
9380 | |
9381 case 0x08: // boolean | |
9382 { | |
9383 return sax->boolean(get() != 0); | |
9384 } | |
9385 | |
9386 case 0x0A: // null | |
9387 { | |
9388 return sax->null(); | |
9389 } | |
9390 | |
9391 case 0x10: // int32 | |
9392 { | |
9393 std::int32_t value{}; | |
9394 return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value); | |
9395 } | |
9396 | |
9397 case 0x12: // int64 | |
9398 { | |
9399 std::int64_t value{}; | |
9400 return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value); | |
9401 } | |
9402 | |
9403 default: // anything else not supported (yet) | |
9404 { | |
9405 std::array<char, 3> cr{{}}; | |
9406 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
9407 std::string cr_str{cr.data()}; | |
9408 return sax->parse_error(element_type_parse_position, cr_str, | |
9409 parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); | |
9410 } | |
9411 } | |
9412 } | |
9413 | |
9414 /*! | |
9415 @brief Read a BSON element list (as specified in the BSON-spec) | |
9416 | |
9417 The same binary layout is used for objects and arrays, hence it must be | |
9418 indicated with the argument @a is_array which one is expected | |
9419 (true --> array, false --> object). | |
9420 | |
9421 @param[in] is_array Determines if the element list being read is to be | |
9422 treated as an object (@a is_array == false), or as an | |
9423 array (@a is_array == true). | |
9424 @return whether a valid BSON-object/array was passed to the SAX parser | |
9425 */ | |
9426 bool parse_bson_element_list(const bool is_array) | |
9427 { | |
9428 string_t key; | |
9429 | |
9430 while (auto element_type = get()) | |
9431 { | |
9432 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) | |
9433 { | |
9434 return false; | |
9435 } | |
9436 | |
9437 const std::size_t element_type_parse_position = chars_read; | |
9438 if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) | |
9439 { | |
9440 return false; | |
9441 } | |
9442 | |
9443 if (!is_array && !sax->key(key)) | |
9444 { | |
9445 return false; | |
9446 } | |
9447 | |
9448 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) | |
9449 { | |
9450 return false; | |
9451 } | |
9452 | |
9453 // get_bson_cstr only appends | |
9454 key.clear(); | |
9455 } | |
9456 | |
9457 return true; | |
9458 } | |
9459 | |
9460 /*! | |
9461 @brief Reads an array from the BSON input and passes it to the SAX-parser. | |
9462 @return whether a valid BSON-array was passed to the SAX parser | |
9463 */ | |
9464 bool parse_bson_array() | |
9465 { | |
9466 std::int32_t document_size{}; | |
9467 get_number<std::int32_t, true>(input_format_t::bson, document_size); | |
9468 | |
9469 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) | |
9470 { | |
9471 return false; | |
9472 } | |
9473 | |
9474 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) | |
9475 { | |
9476 return false; | |
9477 } | |
9478 | |
9479 return sax->end_array(); | |
9480 } | |
9481 | |
9482 ////////// | |
9483 // CBOR // | |
9484 ////////// | |
9485 | |
9486 /*! | |
9487 @param[in] get_char whether a new character should be retrieved from the | |
9488 input (true) or whether the last read character should | |
9489 be considered instead (false) | |
9490 @param[in] tag_handler how CBOR tags should be treated | |
9491 | |
9492 @return whether a valid CBOR value was passed to the SAX parser | |
9493 */ | |
9494 bool parse_cbor_internal(const bool get_char, | |
9495 const cbor_tag_handler_t tag_handler) | |
9496 { | |
9497 switch (get_char ? get() : current) | |
9498 { | |
9499 // EOF | |
9500 case std::char_traits<char_type>::eof(): | |
9501 return unexpect_eof(input_format_t::cbor, "value"); | |
9502 | |
9503 // Integer 0x00..0x17 (0..23) | |
9504 case 0x00: | |
9505 case 0x01: | |
9506 case 0x02: | |
9507 case 0x03: | |
9508 case 0x04: | |
9509 case 0x05: | |
9510 case 0x06: | |
9511 case 0x07: | |
9512 case 0x08: | |
9513 case 0x09: | |
9514 case 0x0A: | |
9515 case 0x0B: | |
9516 case 0x0C: | |
9517 case 0x0D: | |
9518 case 0x0E: | |
9519 case 0x0F: | |
9520 case 0x10: | |
9521 case 0x11: | |
9522 case 0x12: | |
9523 case 0x13: | |
9524 case 0x14: | |
9525 case 0x15: | |
9526 case 0x16: | |
9527 case 0x17: | |
9528 return sax->number_unsigned(static_cast<number_unsigned_t>(current)); | |
9529 | |
9530 case 0x18: // Unsigned integer (one-byte uint8_t follows) | |
9531 { | |
9532 std::uint8_t number{}; | |
9533 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); | |
9534 } | |
9535 | |
9536 case 0x19: // Unsigned integer (two-byte uint16_t follows) | |
9537 { | |
9538 std::uint16_t number{}; | |
9539 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); | |
9540 } | |
9541 | |
9542 case 0x1A: // Unsigned integer (four-byte uint32_t follows) | |
9543 { | |
9544 std::uint32_t number{}; | |
9545 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); | |
9546 } | |
9547 | |
9548 case 0x1B: // Unsigned integer (eight-byte uint64_t follows) | |
9549 { | |
9550 std::uint64_t number{}; | |
9551 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); | |
9552 } | |
9553 | |
9554 // Negative integer -1-0x00..-1-0x17 (-1..-24) | |
9555 case 0x20: | |
9556 case 0x21: | |
9557 case 0x22: | |
9558 case 0x23: | |
9559 case 0x24: | |
9560 case 0x25: | |
9561 case 0x26: | |
9562 case 0x27: | |
9563 case 0x28: | |
9564 case 0x29: | |
9565 case 0x2A: | |
9566 case 0x2B: | |
9567 case 0x2C: | |
9568 case 0x2D: | |
9569 case 0x2E: | |
9570 case 0x2F: | |
9571 case 0x30: | |
9572 case 0x31: | |
9573 case 0x32: | |
9574 case 0x33: | |
9575 case 0x34: | |
9576 case 0x35: | |
9577 case 0x36: | |
9578 case 0x37: | |
9579 return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current)); | |
9580 | |
9581 case 0x38: // Negative integer (one-byte uint8_t follows) | |
9582 { | |
9583 std::uint8_t number{}; | |
9584 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number); | |
9585 } | |
9586 | |
9587 case 0x39: // Negative integer -1-n (two-byte uint16_t follows) | |
9588 { | |
9589 std::uint16_t number{}; | |
9590 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number); | |
9591 } | |
9592 | |
9593 case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) | |
9594 { | |
9595 std::uint32_t number{}; | |
9596 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number); | |
9597 } | |
9598 | |
9599 case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) | |
9600 { | |
9601 std::uint64_t number{}; | |
9602 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) | |
9603 - static_cast<number_integer_t>(number)); | |
9604 } | |
9605 | |
9606 // Binary data (0x00..0x17 bytes follow) | |
9607 case 0x40: | |
9608 case 0x41: | |
9609 case 0x42: | |
9610 case 0x43: | |
9611 case 0x44: | |
9612 case 0x45: | |
9613 case 0x46: | |
9614 case 0x47: | |
9615 case 0x48: | |
9616 case 0x49: | |
9617 case 0x4A: | |
9618 case 0x4B: | |
9619 case 0x4C: | |
9620 case 0x4D: | |
9621 case 0x4E: | |
9622 case 0x4F: | |
9623 case 0x50: | |
9624 case 0x51: | |
9625 case 0x52: | |
9626 case 0x53: | |
9627 case 0x54: | |
9628 case 0x55: | |
9629 case 0x56: | |
9630 case 0x57: | |
9631 case 0x58: // Binary data (one-byte uint8_t for n follows) | |
9632 case 0x59: // Binary data (two-byte uint16_t for n follow) | |
9633 case 0x5A: // Binary data (four-byte uint32_t for n follow) | |
9634 case 0x5B: // Binary data (eight-byte uint64_t for n follow) | |
9635 case 0x5F: // Binary data (indefinite length) | |
9636 { | |
9637 binary_t b; | |
9638 return get_cbor_binary(b) && sax->binary(b); | |
9639 } | |
9640 | |
9641 // UTF-8 string (0x00..0x17 bytes follow) | |
9642 case 0x60: | |
9643 case 0x61: | |
9644 case 0x62: | |
9645 case 0x63: | |
9646 case 0x64: | |
9647 case 0x65: | |
9648 case 0x66: | |
9649 case 0x67: | |
9650 case 0x68: | |
9651 case 0x69: | |
9652 case 0x6A: | |
9653 case 0x6B: | |
9654 case 0x6C: | |
9655 case 0x6D: | |
9656 case 0x6E: | |
9657 case 0x6F: | |
9658 case 0x70: | |
9659 case 0x71: | |
9660 case 0x72: | |
9661 case 0x73: | |
9662 case 0x74: | |
9663 case 0x75: | |
9664 case 0x76: | |
9665 case 0x77: | |
9666 case 0x78: // UTF-8 string (one-byte uint8_t for n follows) | |
9667 case 0x79: // UTF-8 string (two-byte uint16_t for n follow) | |
9668 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) | |
9669 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) | |
9670 case 0x7F: // UTF-8 string (indefinite length) | |
9671 { | |
9672 string_t s; | |
9673 return get_cbor_string(s) && sax->string(s); | |
9674 } | |
9675 | |
9676 // array (0x00..0x17 data items follow) | |
9677 case 0x80: | |
9678 case 0x81: | |
9679 case 0x82: | |
9680 case 0x83: | |
9681 case 0x84: | |
9682 case 0x85: | |
9683 case 0x86: | |
9684 case 0x87: | |
9685 case 0x88: | |
9686 case 0x89: | |
9687 case 0x8A: | |
9688 case 0x8B: | |
9689 case 0x8C: | |
9690 case 0x8D: | |
9691 case 0x8E: | |
9692 case 0x8F: | |
9693 case 0x90: | |
9694 case 0x91: | |
9695 case 0x92: | |
9696 case 0x93: | |
9697 case 0x94: | |
9698 case 0x95: | |
9699 case 0x96: | |
9700 case 0x97: | |
9701 return get_cbor_array( | |
9702 conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler); | |
9703 | |
9704 case 0x98: // array (one-byte uint8_t for n follows) | |
9705 { | |
9706 std::uint8_t len{}; | |
9707 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler); | |
9708 } | |
9709 | |
9710 case 0x99: // array (two-byte uint16_t for n follow) | |
9711 { | |
9712 std::uint16_t len{}; | |
9713 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler); | |
9714 } | |
9715 | |
9716 case 0x9A: // array (four-byte uint32_t for n follow) | |
9717 { | |
9718 std::uint32_t len{}; | |
9719 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler); | |
9720 } | |
9721 | |
9722 case 0x9B: // array (eight-byte uint64_t for n follow) | |
9723 { | |
9724 std::uint64_t len{}; | |
9725 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler); | |
9726 } | |
9727 | |
9728 case 0x9F: // array (indefinite length) | |
9729 return get_cbor_array(static_cast<std::size_t>(-1), tag_handler); | |
9730 | |
9731 // map (0x00..0x17 pairs of data items follow) | |
9732 case 0xA0: | |
9733 case 0xA1: | |
9734 case 0xA2: | |
9735 case 0xA3: | |
9736 case 0xA4: | |
9737 case 0xA5: | |
9738 case 0xA6: | |
9739 case 0xA7: | |
9740 case 0xA8: | |
9741 case 0xA9: | |
9742 case 0xAA: | |
9743 case 0xAB: | |
9744 case 0xAC: | |
9745 case 0xAD: | |
9746 case 0xAE: | |
9747 case 0xAF: | |
9748 case 0xB0: | |
9749 case 0xB1: | |
9750 case 0xB2: | |
9751 case 0xB3: | |
9752 case 0xB4: | |
9753 case 0xB5: | |
9754 case 0xB6: | |
9755 case 0xB7: | |
9756 return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler); | |
9757 | |
9758 case 0xB8: // map (one-byte uint8_t for n follows) | |
9759 { | |
9760 std::uint8_t len{}; | |
9761 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler); | |
9762 } | |
9763 | |
9764 case 0xB9: // map (two-byte uint16_t for n follow) | |
9765 { | |
9766 std::uint16_t len{}; | |
9767 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler); | |
9768 } | |
9769 | |
9770 case 0xBA: // map (four-byte uint32_t for n follow) | |
9771 { | |
9772 std::uint32_t len{}; | |
9773 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler); | |
9774 } | |
9775 | |
9776 case 0xBB: // map (eight-byte uint64_t for n follow) | |
9777 { | |
9778 std::uint64_t len{}; | |
9779 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler); | |
9780 } | |
9781 | |
9782 case 0xBF: // map (indefinite length) | |
9783 return get_cbor_object(static_cast<std::size_t>(-1), tag_handler); | |
9784 | |
9785 case 0xC6: // tagged item | |
9786 case 0xC7: | |
9787 case 0xC8: | |
9788 case 0xC9: | |
9789 case 0xCA: | |
9790 case 0xCB: | |
9791 case 0xCC: | |
9792 case 0xCD: | |
9793 case 0xCE: | |
9794 case 0xCF: | |
9795 case 0xD0: | |
9796 case 0xD1: | |
9797 case 0xD2: | |
9798 case 0xD3: | |
9799 case 0xD4: | |
9800 case 0xD8: // tagged item (1 bytes follow) | |
9801 case 0xD9: // tagged item (2 bytes follow) | |
9802 case 0xDA: // tagged item (4 bytes follow) | |
9803 case 0xDB: // tagged item (8 bytes follow) | |
9804 { | |
9805 switch (tag_handler) | |
9806 { | |
9807 case cbor_tag_handler_t::error: | |
9808 { | |
9809 auto last_token = get_token_string(); | |
9810 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
9811 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); | |
9812 } | |
9813 | |
9814 case cbor_tag_handler_t::ignore: | |
9815 { | |
9816 // ignore binary subtype | |
9817 switch (current) | |
9818 { | |
9819 case 0xD8: | |
9820 { | |
9821 std::uint8_t subtype_to_ignore{}; | |
9822 get_number(input_format_t::cbor, subtype_to_ignore); | |
9823 break; | |
9824 } | |
9825 case 0xD9: | |
9826 { | |
9827 std::uint16_t subtype_to_ignore{}; | |
9828 get_number(input_format_t::cbor, subtype_to_ignore); | |
9829 break; | |
9830 } | |
9831 case 0xDA: | |
9832 { | |
9833 std::uint32_t subtype_to_ignore{}; | |
9834 get_number(input_format_t::cbor, subtype_to_ignore); | |
9835 break; | |
9836 } | |
9837 case 0xDB: | |
9838 { | |
9839 std::uint64_t subtype_to_ignore{}; | |
9840 get_number(input_format_t::cbor, subtype_to_ignore); | |
9841 break; | |
9842 } | |
9843 default: | |
9844 break; | |
9845 } | |
9846 return parse_cbor_internal(true, tag_handler); | |
9847 } | |
9848 | |
9849 case cbor_tag_handler_t::store: | |
9850 { | |
9851 binary_t b; | |
9852 // use binary subtype and store in binary container | |
9853 switch (current) | |
9854 { | |
9855 case 0xD8: | |
9856 { | |
9857 std::uint8_t subtype{}; | |
9858 get_number(input_format_t::cbor, subtype); | |
9859 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); | |
9860 break; | |
9861 } | |
9862 case 0xD9: | |
9863 { | |
9864 std::uint16_t subtype{}; | |
9865 get_number(input_format_t::cbor, subtype); | |
9866 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); | |
9867 break; | |
9868 } | |
9869 case 0xDA: | |
9870 { | |
9871 std::uint32_t subtype{}; | |
9872 get_number(input_format_t::cbor, subtype); | |
9873 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); | |
9874 break; | |
9875 } | |
9876 case 0xDB: | |
9877 { | |
9878 std::uint64_t subtype{}; | |
9879 get_number(input_format_t::cbor, subtype); | |
9880 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); | |
9881 break; | |
9882 } | |
9883 default: | |
9884 return parse_cbor_internal(true, tag_handler); | |
9885 } | |
9886 get(); | |
9887 return get_cbor_binary(b) && sax->binary(b); | |
9888 } | |
9889 | |
9890 default: // LCOV_EXCL_LINE | |
9891 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
9892 return false; // LCOV_EXCL_LINE | |
9893 } | |
9894 } | |
9895 | |
9896 case 0xF4: // false | |
9897 return sax->boolean(false); | |
9898 | |
9899 case 0xF5: // true | |
9900 return sax->boolean(true); | |
9901 | |
9902 case 0xF6: // null | |
9903 return sax->null(); | |
9904 | |
9905 case 0xF9: // Half-Precision Float (two-byte IEEE 754) | |
9906 { | |
9907 const auto byte1_raw = get(); | |
9908 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) | |
9909 { | |
9910 return false; | |
9911 } | |
9912 const auto byte2_raw = get(); | |
9913 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) | |
9914 { | |
9915 return false; | |
9916 } | |
9917 | |
9918 const auto byte1 = static_cast<unsigned char>(byte1_raw); | |
9919 const auto byte2 = static_cast<unsigned char>(byte2_raw); | |
9920 | |
9921 // code from RFC 7049, Appendix D, Figure 3: | |
9922 // As half-precision floating-point numbers were only added | |
9923 // to IEEE 754 in 2008, today's programming platforms often | |
9924 // still only have limited support for them. It is very | |
9925 // easy to include at least decoding support for them even | |
9926 // without such support. An example of a small decoder for | |
9927 // half-precision floating-point numbers in the C language | |
9928 // is shown in Fig. 3. | |
9929 const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2); | |
9930 const double val = [&half] | |
9931 { | |
9932 const int exp = (half >> 10u) & 0x1Fu; | |
9933 const unsigned int mant = half & 0x3FFu; | |
9934 JSON_ASSERT(0 <= exp&& exp <= 32); | |
9935 JSON_ASSERT(mant <= 1024); | |
9936 switch (exp) | |
9937 { | |
9938 case 0: | |
9939 return std::ldexp(mant, -24); | |
9940 case 31: | |
9941 return (mant == 0) | |
9942 ? std::numeric_limits<double>::infinity() | |
9943 : std::numeric_limits<double>::quiet_NaN(); | |
9944 default: | |
9945 return std::ldexp(mant + 1024, exp - 25); | |
9946 } | |
9947 }(); | |
9948 return sax->number_float((half & 0x8000u) != 0 | |
9949 ? static_cast<number_float_t>(-val) | |
9950 : static_cast<number_float_t>(val), ""); | |
9951 } | |
9952 | |
9953 case 0xFA: // Single-Precision Float (four-byte IEEE 754) | |
9954 { | |
9955 float number{}; | |
9956 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), ""); | |
9957 } | |
9958 | |
9959 case 0xFB: // Double-Precision Float (eight-byte IEEE 754) | |
9960 { | |
9961 double number{}; | |
9962 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), ""); | |
9963 } | |
9964 | |
9965 default: // anything else (0xFF is handled inside the other types) | |
9966 { | |
9967 auto last_token = get_token_string(); | |
9968 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
9969 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); | |
9970 } | |
9971 } | |
9972 } | |
9973 | |
9974 /*! | |
9975 @brief reads a CBOR string | |
9976 | |
9977 This function first reads starting bytes to determine the expected | |
9978 string length and then copies this number of bytes into a string. | |
9979 Additionally, CBOR's strings with indefinite lengths are supported. | |
9980 | |
9981 @param[out] result created string | |
9982 | |
9983 @return whether string creation completed | |
9984 */ | |
9985 bool get_cbor_string(string_t& result) | |
9986 { | |
9987 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) | |
9988 { | |
9989 return false; | |
9990 } | |
9991 | |
9992 switch (current) | |
9993 { | |
9994 // UTF-8 string (0x00..0x17 bytes follow) | |
9995 case 0x60: | |
9996 case 0x61: | |
9997 case 0x62: | |
9998 case 0x63: | |
9999 case 0x64: | |
10000 case 0x65: | |
10001 case 0x66: | |
10002 case 0x67: | |
10003 case 0x68: | |
10004 case 0x69: | |
10005 case 0x6A: | |
10006 case 0x6B: | |
10007 case 0x6C: | |
10008 case 0x6D: | |
10009 case 0x6E: | |
10010 case 0x6F: | |
10011 case 0x70: | |
10012 case 0x71: | |
10013 case 0x72: | |
10014 case 0x73: | |
10015 case 0x74: | |
10016 case 0x75: | |
10017 case 0x76: | |
10018 case 0x77: | |
10019 { | |
10020 return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result); | |
10021 } | |
10022 | |
10023 case 0x78: // UTF-8 string (one-byte uint8_t for n follows) | |
10024 { | |
10025 std::uint8_t len{}; | |
10026 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); | |
10027 } | |
10028 | |
10029 case 0x79: // UTF-8 string (two-byte uint16_t for n follow) | |
10030 { | |
10031 std::uint16_t len{}; | |
10032 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); | |
10033 } | |
10034 | |
10035 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) | |
10036 { | |
10037 std::uint32_t len{}; | |
10038 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); | |
10039 } | |
10040 | |
10041 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) | |
10042 { | |
10043 std::uint64_t len{}; | |
10044 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); | |
10045 } | |
10046 | |
10047 case 0x7F: // UTF-8 string (indefinite length) | |
10048 { | |
10049 while (get() != 0xFF) | |
10050 { | |
10051 string_t chunk; | |
10052 if (!get_cbor_string(chunk)) | |
10053 { | |
10054 return false; | |
10055 } | |
10056 result.append(chunk); | |
10057 } | |
10058 return true; | |
10059 } | |
10060 | |
10061 default: | |
10062 { | |
10063 auto last_token = get_token_string(); | |
10064 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, | |
10065 exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr)); | |
10066 } | |
10067 } | |
10068 } | |
10069 | |
10070 /*! | |
10071 @brief reads a CBOR byte array | |
10072 | |
10073 This function first reads starting bytes to determine the expected | |
10074 byte array length and then copies this number of bytes into the byte array. | |
10075 Additionally, CBOR's byte arrays with indefinite lengths are supported. | |
10076 | |
10077 @param[out] result created byte array | |
10078 | |
10079 @return whether byte array creation completed | |
10080 */ | |
10081 bool get_cbor_binary(binary_t& result) | |
10082 { | |
10083 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) | |
10084 { | |
10085 return false; | |
10086 } | |
10087 | |
10088 switch (current) | |
10089 { | |
10090 // Binary data (0x00..0x17 bytes follow) | |
10091 case 0x40: | |
10092 case 0x41: | |
10093 case 0x42: | |
10094 case 0x43: | |
10095 case 0x44: | |
10096 case 0x45: | |
10097 case 0x46: | |
10098 case 0x47: | |
10099 case 0x48: | |
10100 case 0x49: | |
10101 case 0x4A: | |
10102 case 0x4B: | |
10103 case 0x4C: | |
10104 case 0x4D: | |
10105 case 0x4E: | |
10106 case 0x4F: | |
10107 case 0x50: | |
10108 case 0x51: | |
10109 case 0x52: | |
10110 case 0x53: | |
10111 case 0x54: | |
10112 case 0x55: | |
10113 case 0x56: | |
10114 case 0x57: | |
10115 { | |
10116 return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result); | |
10117 } | |
10118 | |
10119 case 0x58: // Binary data (one-byte uint8_t for n follows) | |
10120 { | |
10121 std::uint8_t len{}; | |
10122 return get_number(input_format_t::cbor, len) && | |
10123 get_binary(input_format_t::cbor, len, result); | |
10124 } | |
10125 | |
10126 case 0x59: // Binary data (two-byte uint16_t for n follow) | |
10127 { | |
10128 std::uint16_t len{}; | |
10129 return get_number(input_format_t::cbor, len) && | |
10130 get_binary(input_format_t::cbor, len, result); | |
10131 } | |
10132 | |
10133 case 0x5A: // Binary data (four-byte uint32_t for n follow) | |
10134 { | |
10135 std::uint32_t len{}; | |
10136 return get_number(input_format_t::cbor, len) && | |
10137 get_binary(input_format_t::cbor, len, result); | |
10138 } | |
10139 | |
10140 case 0x5B: // Binary data (eight-byte uint64_t for n follow) | |
10141 { | |
10142 std::uint64_t len{}; | |
10143 return get_number(input_format_t::cbor, len) && | |
10144 get_binary(input_format_t::cbor, len, result); | |
10145 } | |
10146 | |
10147 case 0x5F: // Binary data (indefinite length) | |
10148 { | |
10149 while (get() != 0xFF) | |
10150 { | |
10151 binary_t chunk; | |
10152 if (!get_cbor_binary(chunk)) | |
10153 { | |
10154 return false; | |
10155 } | |
10156 result.insert(result.end(), chunk.begin(), chunk.end()); | |
10157 } | |
10158 return true; | |
10159 } | |
10160 | |
10161 default: | |
10162 { | |
10163 auto last_token = get_token_string(); | |
10164 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, | |
10165 exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr)); | |
10166 } | |
10167 } | |
10168 } | |
10169 | |
10170 /*! | |
10171 @param[in] len the length of the array or static_cast<std::size_t>(-1) for an | |
10172 array of indefinite size | |
10173 @param[in] tag_handler how CBOR tags should be treated | |
10174 @return whether array creation completed | |
10175 */ | |
10176 bool get_cbor_array(const std::size_t len, | |
10177 const cbor_tag_handler_t tag_handler) | |
10178 { | |
10179 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) | |
10180 { | |
10181 return false; | |
10182 } | |
10183 | |
10184 if (len != static_cast<std::size_t>(-1)) | |
10185 { | |
10186 for (std::size_t i = 0; i < len; ++i) | |
10187 { | |
10188 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) | |
10189 { | |
10190 return false; | |
10191 } | |
10192 } | |
10193 } | |
10194 else | |
10195 { | |
10196 while (get() != 0xFF) | |
10197 { | |
10198 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) | |
10199 { | |
10200 return false; | |
10201 } | |
10202 } | |
10203 } | |
10204 | |
10205 return sax->end_array(); | |
10206 } | |
10207 | |
10208 /*! | |
10209 @param[in] len the length of the object or static_cast<std::size_t>(-1) for an | |
10210 object of indefinite size | |
10211 @param[in] tag_handler how CBOR tags should be treated | |
10212 @return whether object creation completed | |
10213 */ | |
10214 bool get_cbor_object(const std::size_t len, | |
10215 const cbor_tag_handler_t tag_handler) | |
10216 { | |
10217 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) | |
10218 { | |
10219 return false; | |
10220 } | |
10221 | |
10222 if (len != 0) | |
10223 { | |
10224 string_t key; | |
10225 if (len != static_cast<std::size_t>(-1)) | |
10226 { | |
10227 for (std::size_t i = 0; i < len; ++i) | |
10228 { | |
10229 get(); | |
10230 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) | |
10231 { | |
10232 return false; | |
10233 } | |
10234 | |
10235 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) | |
10236 { | |
10237 return false; | |
10238 } | |
10239 key.clear(); | |
10240 } | |
10241 } | |
10242 else | |
10243 { | |
10244 while (get() != 0xFF) | |
10245 { | |
10246 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) | |
10247 { | |
10248 return false; | |
10249 } | |
10250 | |
10251 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) | |
10252 { | |
10253 return false; | |
10254 } | |
10255 key.clear(); | |
10256 } | |
10257 } | |
10258 } | |
10259 | |
10260 return sax->end_object(); | |
10261 } | |
10262 | |
10263 ///////////// | |
10264 // MsgPack // | |
10265 ///////////// | |
10266 | |
10267 /*! | |
10268 @return whether a valid MessagePack value was passed to the SAX parser | |
10269 */ | |
10270 bool parse_msgpack_internal() | |
10271 { | |
10272 switch (get()) | |
10273 { | |
10274 // EOF | |
10275 case std::char_traits<char_type>::eof(): | |
10276 return unexpect_eof(input_format_t::msgpack, "value"); | |
10277 | |
10278 // positive fixint | |
10279 case 0x00: | |
10280 case 0x01: | |
10281 case 0x02: | |
10282 case 0x03: | |
10283 case 0x04: | |
10284 case 0x05: | |
10285 case 0x06: | |
10286 case 0x07: | |
10287 case 0x08: | |
10288 case 0x09: | |
10289 case 0x0A: | |
10290 case 0x0B: | |
10291 case 0x0C: | |
10292 case 0x0D: | |
10293 case 0x0E: | |
10294 case 0x0F: | |
10295 case 0x10: | |
10296 case 0x11: | |
10297 case 0x12: | |
10298 case 0x13: | |
10299 case 0x14: | |
10300 case 0x15: | |
10301 case 0x16: | |
10302 case 0x17: | |
10303 case 0x18: | |
10304 case 0x19: | |
10305 case 0x1A: | |
10306 case 0x1B: | |
10307 case 0x1C: | |
10308 case 0x1D: | |
10309 case 0x1E: | |
10310 case 0x1F: | |
10311 case 0x20: | |
10312 case 0x21: | |
10313 case 0x22: | |
10314 case 0x23: | |
10315 case 0x24: | |
10316 case 0x25: | |
10317 case 0x26: | |
10318 case 0x27: | |
10319 case 0x28: | |
10320 case 0x29: | |
10321 case 0x2A: | |
10322 case 0x2B: | |
10323 case 0x2C: | |
10324 case 0x2D: | |
10325 case 0x2E: | |
10326 case 0x2F: | |
10327 case 0x30: | |
10328 case 0x31: | |
10329 case 0x32: | |
10330 case 0x33: | |
10331 case 0x34: | |
10332 case 0x35: | |
10333 case 0x36: | |
10334 case 0x37: | |
10335 case 0x38: | |
10336 case 0x39: | |
10337 case 0x3A: | |
10338 case 0x3B: | |
10339 case 0x3C: | |
10340 case 0x3D: | |
10341 case 0x3E: | |
10342 case 0x3F: | |
10343 case 0x40: | |
10344 case 0x41: | |
10345 case 0x42: | |
10346 case 0x43: | |
10347 case 0x44: | |
10348 case 0x45: | |
10349 case 0x46: | |
10350 case 0x47: | |
10351 case 0x48: | |
10352 case 0x49: | |
10353 case 0x4A: | |
10354 case 0x4B: | |
10355 case 0x4C: | |
10356 case 0x4D: | |
10357 case 0x4E: | |
10358 case 0x4F: | |
10359 case 0x50: | |
10360 case 0x51: | |
10361 case 0x52: | |
10362 case 0x53: | |
10363 case 0x54: | |
10364 case 0x55: | |
10365 case 0x56: | |
10366 case 0x57: | |
10367 case 0x58: | |
10368 case 0x59: | |
10369 case 0x5A: | |
10370 case 0x5B: | |
10371 case 0x5C: | |
10372 case 0x5D: | |
10373 case 0x5E: | |
10374 case 0x5F: | |
10375 case 0x60: | |
10376 case 0x61: | |
10377 case 0x62: | |
10378 case 0x63: | |
10379 case 0x64: | |
10380 case 0x65: | |
10381 case 0x66: | |
10382 case 0x67: | |
10383 case 0x68: | |
10384 case 0x69: | |
10385 case 0x6A: | |
10386 case 0x6B: | |
10387 case 0x6C: | |
10388 case 0x6D: | |
10389 case 0x6E: | |
10390 case 0x6F: | |
10391 case 0x70: | |
10392 case 0x71: | |
10393 case 0x72: | |
10394 case 0x73: | |
10395 case 0x74: | |
10396 case 0x75: | |
10397 case 0x76: | |
10398 case 0x77: | |
10399 case 0x78: | |
10400 case 0x79: | |
10401 case 0x7A: | |
10402 case 0x7B: | |
10403 case 0x7C: | |
10404 case 0x7D: | |
10405 case 0x7E: | |
10406 case 0x7F: | |
10407 return sax->number_unsigned(static_cast<number_unsigned_t>(current)); | |
10408 | |
10409 // fixmap | |
10410 case 0x80: | |
10411 case 0x81: | |
10412 case 0x82: | |
10413 case 0x83: | |
10414 case 0x84: | |
10415 case 0x85: | |
10416 case 0x86: | |
10417 case 0x87: | |
10418 case 0x88: | |
10419 case 0x89: | |
10420 case 0x8A: | |
10421 case 0x8B: | |
10422 case 0x8C: | |
10423 case 0x8D: | |
10424 case 0x8E: | |
10425 case 0x8F: | |
10426 return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu)); | |
10427 | |
10428 // fixarray | |
10429 case 0x90: | |
10430 case 0x91: | |
10431 case 0x92: | |
10432 case 0x93: | |
10433 case 0x94: | |
10434 case 0x95: | |
10435 case 0x96: | |
10436 case 0x97: | |
10437 case 0x98: | |
10438 case 0x99: | |
10439 case 0x9A: | |
10440 case 0x9B: | |
10441 case 0x9C: | |
10442 case 0x9D: | |
10443 case 0x9E: | |
10444 case 0x9F: | |
10445 return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu)); | |
10446 | |
10447 // fixstr | |
10448 case 0xA0: | |
10449 case 0xA1: | |
10450 case 0xA2: | |
10451 case 0xA3: | |
10452 case 0xA4: | |
10453 case 0xA5: | |
10454 case 0xA6: | |
10455 case 0xA7: | |
10456 case 0xA8: | |
10457 case 0xA9: | |
10458 case 0xAA: | |
10459 case 0xAB: | |
10460 case 0xAC: | |
10461 case 0xAD: | |
10462 case 0xAE: | |
10463 case 0xAF: | |
10464 case 0xB0: | |
10465 case 0xB1: | |
10466 case 0xB2: | |
10467 case 0xB3: | |
10468 case 0xB4: | |
10469 case 0xB5: | |
10470 case 0xB6: | |
10471 case 0xB7: | |
10472 case 0xB8: | |
10473 case 0xB9: | |
10474 case 0xBA: | |
10475 case 0xBB: | |
10476 case 0xBC: | |
10477 case 0xBD: | |
10478 case 0xBE: | |
10479 case 0xBF: | |
10480 case 0xD9: // str 8 | |
10481 case 0xDA: // str 16 | |
10482 case 0xDB: // str 32 | |
10483 { | |
10484 string_t s; | |
10485 return get_msgpack_string(s) && sax->string(s); | |
10486 } | |
10487 | |
10488 case 0xC0: // nil | |
10489 return sax->null(); | |
10490 | |
10491 case 0xC2: // false | |
10492 return sax->boolean(false); | |
10493 | |
10494 case 0xC3: // true | |
10495 return sax->boolean(true); | |
10496 | |
10497 case 0xC4: // bin 8 | |
10498 case 0xC5: // bin 16 | |
10499 case 0xC6: // bin 32 | |
10500 case 0xC7: // ext 8 | |
10501 case 0xC8: // ext 16 | |
10502 case 0xC9: // ext 32 | |
10503 case 0xD4: // fixext 1 | |
10504 case 0xD5: // fixext 2 | |
10505 case 0xD6: // fixext 4 | |
10506 case 0xD7: // fixext 8 | |
10507 case 0xD8: // fixext 16 | |
10508 { | |
10509 binary_t b; | |
10510 return get_msgpack_binary(b) && sax->binary(b); | |
10511 } | |
10512 | |
10513 case 0xCA: // float 32 | |
10514 { | |
10515 float number{}; | |
10516 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), ""); | |
10517 } | |
10518 | |
10519 case 0xCB: // float 64 | |
10520 { | |
10521 double number{}; | |
10522 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), ""); | |
10523 } | |
10524 | |
10525 case 0xCC: // uint 8 | |
10526 { | |
10527 std::uint8_t number{}; | |
10528 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); | |
10529 } | |
10530 | |
10531 case 0xCD: // uint 16 | |
10532 { | |
10533 std::uint16_t number{}; | |
10534 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); | |
10535 } | |
10536 | |
10537 case 0xCE: // uint 32 | |
10538 { | |
10539 std::uint32_t number{}; | |
10540 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); | |
10541 } | |
10542 | |
10543 case 0xCF: // uint 64 | |
10544 { | |
10545 std::uint64_t number{}; | |
10546 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); | |
10547 } | |
10548 | |
10549 case 0xD0: // int 8 | |
10550 { | |
10551 std::int8_t number{}; | |
10552 return get_number(input_format_t::msgpack, number) && sax->number_integer(number); | |
10553 } | |
10554 | |
10555 case 0xD1: // int 16 | |
10556 { | |
10557 std::int16_t number{}; | |
10558 return get_number(input_format_t::msgpack, number) && sax->number_integer(number); | |
10559 } | |
10560 | |
10561 case 0xD2: // int 32 | |
10562 { | |
10563 std::int32_t number{}; | |
10564 return get_number(input_format_t::msgpack, number) && sax->number_integer(number); | |
10565 } | |
10566 | |
10567 case 0xD3: // int 64 | |
10568 { | |
10569 std::int64_t number{}; | |
10570 return get_number(input_format_t::msgpack, number) && sax->number_integer(number); | |
10571 } | |
10572 | |
10573 case 0xDC: // array 16 | |
10574 { | |
10575 std::uint16_t len{}; | |
10576 return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len)); | |
10577 } | |
10578 | |
10579 case 0xDD: // array 32 | |
10580 { | |
10581 std::uint32_t len{}; | |
10582 return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len)); | |
10583 } | |
10584 | |
10585 case 0xDE: // map 16 | |
10586 { | |
10587 std::uint16_t len{}; | |
10588 return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len)); | |
10589 } | |
10590 | |
10591 case 0xDF: // map 32 | |
10592 { | |
10593 std::uint32_t len{}; | |
10594 return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len)); | |
10595 } | |
10596 | |
10597 // negative fixint | |
10598 case 0xE0: | |
10599 case 0xE1: | |
10600 case 0xE2: | |
10601 case 0xE3: | |
10602 case 0xE4: | |
10603 case 0xE5: | |
10604 case 0xE6: | |
10605 case 0xE7: | |
10606 case 0xE8: | |
10607 case 0xE9: | |
10608 case 0xEA: | |
10609 case 0xEB: | |
10610 case 0xEC: | |
10611 case 0xED: | |
10612 case 0xEE: | |
10613 case 0xEF: | |
10614 case 0xF0: | |
10615 case 0xF1: | |
10616 case 0xF2: | |
10617 case 0xF3: | |
10618 case 0xF4: | |
10619 case 0xF5: | |
10620 case 0xF6: | |
10621 case 0xF7: | |
10622 case 0xF8: | |
10623 case 0xF9: | |
10624 case 0xFA: | |
10625 case 0xFB: | |
10626 case 0xFC: | |
10627 case 0xFD: | |
10628 case 0xFE: | |
10629 case 0xFF: | |
10630 return sax->number_integer(static_cast<std::int8_t>(current)); | |
10631 | |
10632 default: // anything else | |
10633 { | |
10634 auto last_token = get_token_string(); | |
10635 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
10636 exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr)); | |
10637 } | |
10638 } | |
10639 } | |
10640 | |
10641 /*! | |
10642 @brief reads a MessagePack string | |
10643 | |
10644 This function first reads starting bytes to determine the expected | |
10645 string length and then copies this number of bytes into a string. | |
10646 | |
10647 @param[out] result created string | |
10648 | |
10649 @return whether string creation completed | |
10650 */ | |
10651 bool get_msgpack_string(string_t& result) | |
10652 { | |
10653 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) | |
10654 { | |
10655 return false; | |
10656 } | |
10657 | |
10658 switch (current) | |
10659 { | |
10660 // fixstr | |
10661 case 0xA0: | |
10662 case 0xA1: | |
10663 case 0xA2: | |
10664 case 0xA3: | |
10665 case 0xA4: | |
10666 case 0xA5: | |
10667 case 0xA6: | |
10668 case 0xA7: | |
10669 case 0xA8: | |
10670 case 0xA9: | |
10671 case 0xAA: | |
10672 case 0xAB: | |
10673 case 0xAC: | |
10674 case 0xAD: | |
10675 case 0xAE: | |
10676 case 0xAF: | |
10677 case 0xB0: | |
10678 case 0xB1: | |
10679 case 0xB2: | |
10680 case 0xB3: | |
10681 case 0xB4: | |
10682 case 0xB5: | |
10683 case 0xB6: | |
10684 case 0xB7: | |
10685 case 0xB8: | |
10686 case 0xB9: | |
10687 case 0xBA: | |
10688 case 0xBB: | |
10689 case 0xBC: | |
10690 case 0xBD: | |
10691 case 0xBE: | |
10692 case 0xBF: | |
10693 { | |
10694 return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result); | |
10695 } | |
10696 | |
10697 case 0xD9: // str 8 | |
10698 { | |
10699 std::uint8_t len{}; | |
10700 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); | |
10701 } | |
10702 | |
10703 case 0xDA: // str 16 | |
10704 { | |
10705 std::uint16_t len{}; | |
10706 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); | |
10707 } | |
10708 | |
10709 case 0xDB: // str 32 | |
10710 { | |
10711 std::uint32_t len{}; | |
10712 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); | |
10713 } | |
10714 | |
10715 default: | |
10716 { | |
10717 auto last_token = get_token_string(); | |
10718 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, | |
10719 exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); | |
10720 } | |
10721 } | |
10722 } | |
10723 | |
10724 /*! | |
10725 @brief reads a MessagePack byte array | |
10726 | |
10727 This function first reads starting bytes to determine the expected | |
10728 byte array length and then copies this number of bytes into a byte array. | |
10729 | |
10730 @param[out] result created byte array | |
10731 | |
10732 @return whether byte array creation completed | |
10733 */ | |
10734 bool get_msgpack_binary(binary_t& result) | |
10735 { | |
10736 // helper function to set the subtype | |
10737 auto assign_and_return_true = [&result](std::int8_t subtype) | |
10738 { | |
10739 result.set_subtype(static_cast<std::uint8_t>(subtype)); | |
10740 return true; | |
10741 }; | |
10742 | |
10743 switch (current) | |
10744 { | |
10745 case 0xC4: // bin 8 | |
10746 { | |
10747 std::uint8_t len{}; | |
10748 return get_number(input_format_t::msgpack, len) && | |
10749 get_binary(input_format_t::msgpack, len, result); | |
10750 } | |
10751 | |
10752 case 0xC5: // bin 16 | |
10753 { | |
10754 std::uint16_t len{}; | |
10755 return get_number(input_format_t::msgpack, len) && | |
10756 get_binary(input_format_t::msgpack, len, result); | |
10757 } | |
10758 | |
10759 case 0xC6: // bin 32 | |
10760 { | |
10761 std::uint32_t len{}; | |
10762 return get_number(input_format_t::msgpack, len) && | |
10763 get_binary(input_format_t::msgpack, len, result); | |
10764 } | |
10765 | |
10766 case 0xC7: // ext 8 | |
10767 { | |
10768 std::uint8_t len{}; | |
10769 std::int8_t subtype{}; | |
10770 return get_number(input_format_t::msgpack, len) && | |
10771 get_number(input_format_t::msgpack, subtype) && | |
10772 get_binary(input_format_t::msgpack, len, result) && | |
10773 assign_and_return_true(subtype); | |
10774 } | |
10775 | |
10776 case 0xC8: // ext 16 | |
10777 { | |
10778 std::uint16_t len{}; | |
10779 std::int8_t subtype{}; | |
10780 return get_number(input_format_t::msgpack, len) && | |
10781 get_number(input_format_t::msgpack, subtype) && | |
10782 get_binary(input_format_t::msgpack, len, result) && | |
10783 assign_and_return_true(subtype); | |
10784 } | |
10785 | |
10786 case 0xC9: // ext 32 | |
10787 { | |
10788 std::uint32_t len{}; | |
10789 std::int8_t subtype{}; | |
10790 return get_number(input_format_t::msgpack, len) && | |
10791 get_number(input_format_t::msgpack, subtype) && | |
10792 get_binary(input_format_t::msgpack, len, result) && | |
10793 assign_and_return_true(subtype); | |
10794 } | |
10795 | |
10796 case 0xD4: // fixext 1 | |
10797 { | |
10798 std::int8_t subtype{}; | |
10799 return get_number(input_format_t::msgpack, subtype) && | |
10800 get_binary(input_format_t::msgpack, 1, result) && | |
10801 assign_and_return_true(subtype); | |
10802 } | |
10803 | |
10804 case 0xD5: // fixext 2 | |
10805 { | |
10806 std::int8_t subtype{}; | |
10807 return get_number(input_format_t::msgpack, subtype) && | |
10808 get_binary(input_format_t::msgpack, 2, result) && | |
10809 assign_and_return_true(subtype); | |
10810 } | |
10811 | |
10812 case 0xD6: // fixext 4 | |
10813 { | |
10814 std::int8_t subtype{}; | |
10815 return get_number(input_format_t::msgpack, subtype) && | |
10816 get_binary(input_format_t::msgpack, 4, result) && | |
10817 assign_and_return_true(subtype); | |
10818 } | |
10819 | |
10820 case 0xD7: // fixext 8 | |
10821 { | |
10822 std::int8_t subtype{}; | |
10823 return get_number(input_format_t::msgpack, subtype) && | |
10824 get_binary(input_format_t::msgpack, 8, result) && | |
10825 assign_and_return_true(subtype); | |
10826 } | |
10827 | |
10828 case 0xD8: // fixext 16 | |
10829 { | |
10830 std::int8_t subtype{}; | |
10831 return get_number(input_format_t::msgpack, subtype) && | |
10832 get_binary(input_format_t::msgpack, 16, result) && | |
10833 assign_and_return_true(subtype); | |
10834 } | |
10835 | |
10836 default: // LCOV_EXCL_LINE | |
10837 return false; // LCOV_EXCL_LINE | |
10838 } | |
10839 } | |
10840 | |
10841 /*! | |
10842 @param[in] len the length of the array | |
10843 @return whether array creation completed | |
10844 */ | |
10845 bool get_msgpack_array(const std::size_t len) | |
10846 { | |
10847 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) | |
10848 { | |
10849 return false; | |
10850 } | |
10851 | |
10852 for (std::size_t i = 0; i < len; ++i) | |
10853 { | |
10854 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) | |
10855 { | |
10856 return false; | |
10857 } | |
10858 } | |
10859 | |
10860 return sax->end_array(); | |
10861 } | |
10862 | |
10863 /*! | |
10864 @param[in] len the length of the object | |
10865 @return whether object creation completed | |
10866 */ | |
10867 bool get_msgpack_object(const std::size_t len) | |
10868 { | |
10869 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) | |
10870 { | |
10871 return false; | |
10872 } | |
10873 | |
10874 string_t key; | |
10875 for (std::size_t i = 0; i < len; ++i) | |
10876 { | |
10877 get(); | |
10878 if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) | |
10879 { | |
10880 return false; | |
10881 } | |
10882 | |
10883 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) | |
10884 { | |
10885 return false; | |
10886 } | |
10887 key.clear(); | |
10888 } | |
10889 | |
10890 return sax->end_object(); | |
10891 } | |
10892 | |
10893 //////////// | |
10894 // UBJSON // | |
10895 //////////// | |
10896 | |
10897 /*! | |
10898 @param[in] get_char whether a new character should be retrieved from the | |
10899 input (true, default) or whether the last read | |
10900 character should be considered instead | |
10901 | |
10902 @return whether a valid UBJSON value was passed to the SAX parser | |
10903 */ | |
10904 bool parse_ubjson_internal(const bool get_char = true) | |
10905 { | |
10906 return get_ubjson_value(get_char ? get_ignore_noop() : current); | |
10907 } | |
10908 | |
10909 /*! | |
10910 @brief reads a UBJSON string | |
10911 | |
10912 This function is either called after reading the 'S' byte explicitly | |
10913 indicating a string, or in case of an object key where the 'S' byte can be | |
10914 left out. | |
10915 | |
10916 @param[out] result created string | |
10917 @param[in] get_char whether a new character should be retrieved from the | |
10918 input (true, default) or whether the last read | |
10919 character should be considered instead | |
10920 | |
10921 @return whether string creation completed | |
10922 */ | |
10923 bool get_ubjson_string(string_t& result, const bool get_char = true) | |
10924 { | |
10925 if (get_char) | |
10926 { | |
10927 get(); // TODO(niels): may we ignore N here? | |
10928 } | |
10929 | |
10930 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) | |
10931 { | |
10932 return false; | |
10933 } | |
10934 | |
10935 switch (current) | |
10936 { | |
10937 case 'U': | |
10938 { | |
10939 std::uint8_t len{}; | |
10940 return get_number(input_format, len) && get_string(input_format, len, result); | |
10941 } | |
10942 | |
10943 case 'i': | |
10944 { | |
10945 std::int8_t len{}; | |
10946 return get_number(input_format, len) && get_string(input_format, len, result); | |
10947 } | |
10948 | |
10949 case 'I': | |
10950 { | |
10951 std::int16_t len{}; | |
10952 return get_number(input_format, len) && get_string(input_format, len, result); | |
10953 } | |
10954 | |
10955 case 'l': | |
10956 { | |
10957 std::int32_t len{}; | |
10958 return get_number(input_format, len) && get_string(input_format, len, result); | |
10959 } | |
10960 | |
10961 case 'L': | |
10962 { | |
10963 std::int64_t len{}; | |
10964 return get_number(input_format, len) && get_string(input_format, len, result); | |
10965 } | |
10966 | |
10967 case 'u': | |
10968 { | |
10969 if (input_format != input_format_t::bjdata) | |
10970 { | |
10971 break; | |
10972 } | |
10973 std::uint16_t len{}; | |
10974 return get_number(input_format, len) && get_string(input_format, len, result); | |
10975 } | |
10976 | |
10977 case 'm': | |
10978 { | |
10979 if (input_format != input_format_t::bjdata) | |
10980 { | |
10981 break; | |
10982 } | |
10983 std::uint32_t len{}; | |
10984 return get_number(input_format, len) && get_string(input_format, len, result); | |
10985 } | |
10986 | |
10987 case 'M': | |
10988 { | |
10989 if (input_format != input_format_t::bjdata) | |
10990 { | |
10991 break; | |
10992 } | |
10993 std::uint64_t len{}; | |
10994 return get_number(input_format, len) && get_string(input_format, len, result); | |
10995 } | |
10996 | |
10997 default: | |
10998 break; | |
10999 } | |
11000 auto last_token = get_token_string(); | |
11001 std::string message; | |
11002 | |
11003 if (input_format != input_format_t::bjdata) | |
11004 { | |
11005 message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token; | |
11006 } | |
11007 else | |
11008 { | |
11009 message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token; | |
11010 } | |
11011 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr)); | |
11012 } | |
11013 | |
11014 /*! | |
11015 @param[out] dim an integer vector storing the ND array dimensions | |
11016 @return whether reading ND array size vector is successful | |
11017 */ | |
11018 bool get_ubjson_ndarray_size(std::vector<size_t>& dim) | |
11019 { | |
11020 std::pair<std::size_t, char_int_type> size_and_type; | |
11021 size_t dimlen = 0; | |
11022 bool no_ndarray = true; | |
11023 | |
11024 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray))) | |
11025 { | |
11026 return false; | |
11027 } | |
11028 | |
11029 if (size_and_type.first != npos) | |
11030 { | |
11031 if (size_and_type.second != 0) | |
11032 { | |
11033 if (size_and_type.second != 'N') | |
11034 { | |
11035 for (std::size_t i = 0; i < size_and_type.first; ++i) | |
11036 { | |
11037 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second))) | |
11038 { | |
11039 return false; | |
11040 } | |
11041 dim.push_back(dimlen); | |
11042 } | |
11043 } | |
11044 } | |
11045 else | |
11046 { | |
11047 for (std::size_t i = 0; i < size_and_type.first; ++i) | |
11048 { | |
11049 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray))) | |
11050 { | |
11051 return false; | |
11052 } | |
11053 dim.push_back(dimlen); | |
11054 } | |
11055 } | |
11056 } | |
11057 else | |
11058 { | |
11059 while (current != ']') | |
11060 { | |
11061 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current))) | |
11062 { | |
11063 return false; | |
11064 } | |
11065 dim.push_back(dimlen); | |
11066 get_ignore_noop(); | |
11067 } | |
11068 } | |
11069 return true; | |
11070 } | |
11071 | |
11072 /*! | |
11073 @param[out] result determined size | |
11074 @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector | |
11075 or ndarray dimension is not allowed; `false` means ndarray | |
11076 is allowed; for output, `true` means an ndarray is found; | |
11077 is_ndarray can only return `true` when its initial value | |
11078 is `false` | |
11079 @param[in] prefix type marker if already read, otherwise set to 0 | |
11080 | |
11081 @return whether size determination completed | |
11082 */ | |
11083 bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) | |
11084 { | |
11085 if (prefix == 0) | |
11086 { | |
11087 prefix = get_ignore_noop(); | |
11088 } | |
11089 | |
11090 switch (prefix) | |
11091 { | |
11092 case 'U': | |
11093 { | |
11094 std::uint8_t number{}; | |
11095 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11096 { | |
11097 return false; | |
11098 } | |
11099 result = static_cast<std::size_t>(number); | |
11100 return true; | |
11101 } | |
11102 | |
11103 case 'i': | |
11104 { | |
11105 std::int8_t number{}; | |
11106 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11107 { | |
11108 return false; | |
11109 } | |
11110 if (number < 0) | |
11111 { | |
11112 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, | |
11113 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); | |
11114 } | |
11115 result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char | |
11116 return true; | |
11117 } | |
11118 | |
11119 case 'I': | |
11120 { | |
11121 std::int16_t number{}; | |
11122 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11123 { | |
11124 return false; | |
11125 } | |
11126 if (number < 0) | |
11127 { | |
11128 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, | |
11129 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); | |
11130 } | |
11131 result = static_cast<std::size_t>(number); | |
11132 return true; | |
11133 } | |
11134 | |
11135 case 'l': | |
11136 { | |
11137 std::int32_t number{}; | |
11138 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11139 { | |
11140 return false; | |
11141 } | |
11142 if (number < 0) | |
11143 { | |
11144 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, | |
11145 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); | |
11146 } | |
11147 result = static_cast<std::size_t>(number); | |
11148 return true; | |
11149 } | |
11150 | |
11151 case 'L': | |
11152 { | |
11153 std::int64_t number{}; | |
11154 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11155 { | |
11156 return false; | |
11157 } | |
11158 if (number < 0) | |
11159 { | |
11160 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, | |
11161 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); | |
11162 } | |
11163 if (!value_in_range_of<std::size_t>(number)) | |
11164 { | |
11165 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, | |
11166 exception_message(input_format, "integer value overflow", "size"), nullptr)); | |
11167 } | |
11168 result = static_cast<std::size_t>(number); | |
11169 return true; | |
11170 } | |
11171 | |
11172 case 'u': | |
11173 { | |
11174 if (input_format != input_format_t::bjdata) | |
11175 { | |
11176 break; | |
11177 } | |
11178 std::uint16_t number{}; | |
11179 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11180 { | |
11181 return false; | |
11182 } | |
11183 result = static_cast<std::size_t>(number); | |
11184 return true; | |
11185 } | |
11186 | |
11187 case 'm': | |
11188 { | |
11189 if (input_format != input_format_t::bjdata) | |
11190 { | |
11191 break; | |
11192 } | |
11193 std::uint32_t number{}; | |
11194 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11195 { | |
11196 return false; | |
11197 } | |
11198 result = conditional_static_cast<std::size_t>(number); | |
11199 return true; | |
11200 } | |
11201 | |
11202 case 'M': | |
11203 { | |
11204 if (input_format != input_format_t::bjdata) | |
11205 { | |
11206 break; | |
11207 } | |
11208 std::uint64_t number{}; | |
11209 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) | |
11210 { | |
11211 return false; | |
11212 } | |
11213 if (!value_in_range_of<std::size_t>(number)) | |
11214 { | |
11215 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, | |
11216 exception_message(input_format, "integer value overflow", "size"), nullptr)); | |
11217 } | |
11218 result = detail::conditional_static_cast<std::size_t>(number); | |
11219 return true; | |
11220 } | |
11221 | |
11222 case '[': | |
11223 { | |
11224 if (input_format != input_format_t::bjdata) | |
11225 { | |
11226 break; | |
11227 } | |
11228 if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array | |
11229 { | |
11230 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimentional vector is not allowed", "size"), nullptr)); | |
11231 } | |
11232 std::vector<size_t> dim; | |
11233 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) | |
11234 { | |
11235 return false; | |
11236 } | |
11237 if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector | |
11238 { | |
11239 result = dim.at(dim.size() - 1); | |
11240 return true; | |
11241 } | |
11242 if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format | |
11243 { | |
11244 for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container | |
11245 { | |
11246 if ( i == 0 ) | |
11247 { | |
11248 result = 0; | |
11249 return true; | |
11250 } | |
11251 } | |
11252 | |
11253 string_t key = "_ArraySize_"; | |
11254 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size()))) | |
11255 { | |
11256 return false; | |
11257 } | |
11258 result = 1; | |
11259 for (auto i : dim) | |
11260 { | |
11261 result *= i; | |
11262 if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type() | |
11263 { | |
11264 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); | |
11265 } | |
11266 if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i)))) | |
11267 { | |
11268 return false; | |
11269 } | |
11270 } | |
11271 is_ndarray = true; | |
11272 return sax->end_array(); | |
11273 } | |
11274 result = 0; | |
11275 return true; | |
11276 } | |
11277 | |
11278 default: | |
11279 break; | |
11280 } | |
11281 auto last_token = get_token_string(); | |
11282 std::string message; | |
11283 | |
11284 if (input_format != input_format_t::bjdata) | |
11285 { | |
11286 message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token; | |
11287 } | |
11288 else | |
11289 { | |
11290 message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token; | |
11291 } | |
11292 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr)); | |
11293 } | |
11294 | |
11295 /*! | |
11296 @brief determine the type and size for a container | |
11297 | |
11298 In the optimized UBJSON format, a type and a size can be provided to allow | |
11299 for a more compact representation. | |
11300 | |
11301 @param[out] result pair of the size and the type | |
11302 @param[in] inside_ndarray whether the parser is parsing an ND array dimensional vector | |
11303 | |
11304 @return whether pair creation completed | |
11305 */ | |
11306 bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false) | |
11307 { | |
11308 result.first = npos; // size | |
11309 result.second = 0; // type | |
11310 bool is_ndarray = false; | |
11311 | |
11312 get_ignore_noop(); | |
11313 | |
11314 if (current == '$') | |
11315 { | |
11316 result.second = get(); // must not ignore 'N', because 'N' maybe the type | |
11317 if (input_format == input_format_t::bjdata | |
11318 && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second))) | |
11319 { | |
11320 auto last_token = get_token_string(); | |
11321 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
11322 exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); | |
11323 } | |
11324 | |
11325 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type"))) | |
11326 { | |
11327 return false; | |
11328 } | |
11329 | |
11330 get_ignore_noop(); | |
11331 if (JSON_HEDLEY_UNLIKELY(current != '#')) | |
11332 { | |
11333 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) | |
11334 { | |
11335 return false; | |
11336 } | |
11337 auto last_token = get_token_string(); | |
11338 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
11339 exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); | |
11340 } | |
11341 | |
11342 bool is_error = get_ubjson_size_value(result.first, is_ndarray); | |
11343 if (input_format == input_format_t::bjdata && is_ndarray) | |
11344 { | |
11345 if (inside_ndarray) | |
11346 { | |
11347 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, | |
11348 exception_message(input_format, "ndarray can not be recursive", "size"), nullptr)); | |
11349 } | |
11350 result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters | |
11351 } | |
11352 return is_error; | |
11353 } | |
11354 | |
11355 if (current == '#') | |
11356 { | |
11357 bool is_error = get_ubjson_size_value(result.first, is_ndarray); | |
11358 if (input_format == input_format_t::bjdata && is_ndarray) | |
11359 { | |
11360 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, | |
11361 exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); | |
11362 } | |
11363 return is_error; | |
11364 } | |
11365 | |
11366 return true; | |
11367 } | |
11368 | |
11369 /*! | |
11370 @param prefix the previously read or set type prefix | |
11371 @return whether value creation completed | |
11372 */ | |
11373 bool get_ubjson_value(const char_int_type prefix) | |
11374 { | |
11375 switch (prefix) | |
11376 { | |
11377 case std::char_traits<char_type>::eof(): // EOF | |
11378 return unexpect_eof(input_format, "value"); | |
11379 | |
11380 case 'T': // true | |
11381 return sax->boolean(true); | |
11382 case 'F': // false | |
11383 return sax->boolean(false); | |
11384 | |
11385 case 'Z': // null | |
11386 return sax->null(); | |
11387 | |
11388 case 'U': | |
11389 { | |
11390 std::uint8_t number{}; | |
11391 return get_number(input_format, number) && sax->number_unsigned(number); | |
11392 } | |
11393 | |
11394 case 'i': | |
11395 { | |
11396 std::int8_t number{}; | |
11397 return get_number(input_format, number) && sax->number_integer(number); | |
11398 } | |
11399 | |
11400 case 'I': | |
11401 { | |
11402 std::int16_t number{}; | |
11403 return get_number(input_format, number) && sax->number_integer(number); | |
11404 } | |
11405 | |
11406 case 'l': | |
11407 { | |
11408 std::int32_t number{}; | |
11409 return get_number(input_format, number) && sax->number_integer(number); | |
11410 } | |
11411 | |
11412 case 'L': | |
11413 { | |
11414 std::int64_t number{}; | |
11415 return get_number(input_format, number) && sax->number_integer(number); | |
11416 } | |
11417 | |
11418 case 'u': | |
11419 { | |
11420 if (input_format != input_format_t::bjdata) | |
11421 { | |
11422 break; | |
11423 } | |
11424 std::uint16_t number{}; | |
11425 return get_number(input_format, number) && sax->number_unsigned(number); | |
11426 } | |
11427 | |
11428 case 'm': | |
11429 { | |
11430 if (input_format != input_format_t::bjdata) | |
11431 { | |
11432 break; | |
11433 } | |
11434 std::uint32_t number{}; | |
11435 return get_number(input_format, number) && sax->number_unsigned(number); | |
11436 } | |
11437 | |
11438 case 'M': | |
11439 { | |
11440 if (input_format != input_format_t::bjdata) | |
11441 { | |
11442 break; | |
11443 } | |
11444 std::uint64_t number{}; | |
11445 return get_number(input_format, number) && sax->number_unsigned(number); | |
11446 } | |
11447 | |
11448 case 'h': | |
11449 { | |
11450 if (input_format != input_format_t::bjdata) | |
11451 { | |
11452 break; | |
11453 } | |
11454 const auto byte1_raw = get(); | |
11455 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) | |
11456 { | |
11457 return false; | |
11458 } | |
11459 const auto byte2_raw = get(); | |
11460 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) | |
11461 { | |
11462 return false; | |
11463 } | |
11464 | |
11465 const auto byte1 = static_cast<unsigned char>(byte1_raw); | |
11466 const auto byte2 = static_cast<unsigned char>(byte2_raw); | |
11467 | |
11468 // code from RFC 7049, Appendix D, Figure 3: | |
11469 // As half-precision floating-point numbers were only added | |
11470 // to IEEE 754 in 2008, today's programming platforms often | |
11471 // still only have limited support for them. It is very | |
11472 // easy to include at least decoding support for them even | |
11473 // without such support. An example of a small decoder for | |
11474 // half-precision floating-point numbers in the C language | |
11475 // is shown in Fig. 3. | |
11476 const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1); | |
11477 const double val = [&half] | |
11478 { | |
11479 const int exp = (half >> 10u) & 0x1Fu; | |
11480 const unsigned int mant = half & 0x3FFu; | |
11481 JSON_ASSERT(0 <= exp&& exp <= 32); | |
11482 JSON_ASSERT(mant <= 1024); | |
11483 switch (exp) | |
11484 { | |
11485 case 0: | |
11486 return std::ldexp(mant, -24); | |
11487 case 31: | |
11488 return (mant == 0) | |
11489 ? std::numeric_limits<double>::infinity() | |
11490 : std::numeric_limits<double>::quiet_NaN(); | |
11491 default: | |
11492 return std::ldexp(mant + 1024, exp - 25); | |
11493 } | |
11494 }(); | |
11495 return sax->number_float((half & 0x8000u) != 0 | |
11496 ? static_cast<number_float_t>(-val) | |
11497 : static_cast<number_float_t>(val), ""); | |
11498 } | |
11499 | |
11500 case 'd': | |
11501 { | |
11502 float number{}; | |
11503 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), ""); | |
11504 } | |
11505 | |
11506 case 'D': | |
11507 { | |
11508 double number{}; | |
11509 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), ""); | |
11510 } | |
11511 | |
11512 case 'H': | |
11513 { | |
11514 return get_ubjson_high_precision_number(); | |
11515 } | |
11516 | |
11517 case 'C': // char | |
11518 { | |
11519 get(); | |
11520 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char"))) | |
11521 { | |
11522 return false; | |
11523 } | |
11524 if (JSON_HEDLEY_UNLIKELY(current > 127)) | |
11525 { | |
11526 auto last_token = get_token_string(); | |
11527 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, | |
11528 exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); | |
11529 } | |
11530 string_t s(1, static_cast<typename string_t::value_type>(current)); | |
11531 return sax->string(s); | |
11532 } | |
11533 | |
11534 case 'S': // string | |
11535 { | |
11536 string_t s; | |
11537 return get_ubjson_string(s) && sax->string(s); | |
11538 } | |
11539 | |
11540 case '[': // array | |
11541 return get_ubjson_array(); | |
11542 | |
11543 case '{': // object | |
11544 return get_ubjson_object(); | |
11545 | |
11546 default: // anything else | |
11547 break; | |
11548 } | |
11549 auto last_token = get_token_string(); | |
11550 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr)); | |
11551 } | |
11552 | |
11553 /*! | |
11554 @return whether array creation completed | |
11555 */ | |
11556 bool get_ubjson_array() | |
11557 { | |
11558 std::pair<std::size_t, char_int_type> size_and_type; | |
11559 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) | |
11560 { | |
11561 return false; | |
11562 } | |
11563 | |
11564 // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata): | |
11565 // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]} | |
11566 | |
11567 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) | |
11568 { | |
11569 size_and_type.second &= ~(static_cast<char_int_type>(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker | |
11570 auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t) | |
11571 { | |
11572 return p.first < t; | |
11573 }); | |
11574 string_t key = "_ArrayType_"; | |
11575 if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second)) | |
11576 { | |
11577 auto last_token = get_token_string(); | |
11578 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
11579 exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr)); | |
11580 } | |
11581 | |
11582 string_t type = it->second; // sax->string() takes a reference | |
11583 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type))) | |
11584 { | |
11585 return false; | |
11586 } | |
11587 | |
11588 if (size_and_type.second == 'C') | |
11589 { | |
11590 size_and_type.second = 'U'; | |
11591 } | |
11592 | |
11593 key = "_ArrayData_"; | |
11594 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) )) | |
11595 { | |
11596 return false; | |
11597 } | |
11598 | |
11599 for (std::size_t i = 0; i < size_and_type.first; ++i) | |
11600 { | |
11601 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) | |
11602 { | |
11603 return false; | |
11604 } | |
11605 } | |
11606 | |
11607 return (sax->end_array() && sax->end_object()); | |
11608 } | |
11609 | |
11610 if (size_and_type.first != npos) | |
11611 { | |
11612 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) | |
11613 { | |
11614 return false; | |
11615 } | |
11616 | |
11617 if (size_and_type.second != 0) | |
11618 { | |
11619 if (size_and_type.second != 'N') | |
11620 { | |
11621 for (std::size_t i = 0; i < size_and_type.first; ++i) | |
11622 { | |
11623 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) | |
11624 { | |
11625 return false; | |
11626 } | |
11627 } | |
11628 } | |
11629 } | |
11630 else | |
11631 { | |
11632 for (std::size_t i = 0; i < size_and_type.first; ++i) | |
11633 { | |
11634 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) | |
11635 { | |
11636 return false; | |
11637 } | |
11638 } | |
11639 } | |
11640 } | |
11641 else | |
11642 { | |
11643 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) | |
11644 { | |
11645 return false; | |
11646 } | |
11647 | |
11648 while (current != ']') | |
11649 { | |
11650 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) | |
11651 { | |
11652 return false; | |
11653 } | |
11654 get_ignore_noop(); | |
11655 } | |
11656 } | |
11657 | |
11658 return sax->end_array(); | |
11659 } | |
11660 | |
11661 /*! | |
11662 @return whether object creation completed | |
11663 */ | |
11664 bool get_ubjson_object() | |
11665 { | |
11666 std::pair<std::size_t, char_int_type> size_and_type; | |
11667 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) | |
11668 { | |
11669 return false; | |
11670 } | |
11671 | |
11672 // do not accept ND-array size in objects in BJData | |
11673 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) | |
11674 { | |
11675 auto last_token = get_token_string(); | |
11676 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, | |
11677 exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr)); | |
11678 } | |
11679 | |
11680 string_t key; | |
11681 if (size_and_type.first != npos) | |
11682 { | |
11683 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) | |
11684 { | |
11685 return false; | |
11686 } | |
11687 | |
11688 if (size_and_type.second != 0) | |
11689 { | |
11690 for (std::size_t i = 0; i < size_and_type.first; ++i) | |
11691 { | |
11692 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) | |
11693 { | |
11694 return false; | |
11695 } | |
11696 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) | |
11697 { | |
11698 return false; | |
11699 } | |
11700 key.clear(); | |
11701 } | |
11702 } | |
11703 else | |
11704 { | |
11705 for (std::size_t i = 0; i < size_and_type.first; ++i) | |
11706 { | |
11707 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) | |
11708 { | |
11709 return false; | |
11710 } | |
11711 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) | |
11712 { | |
11713 return false; | |
11714 } | |
11715 key.clear(); | |
11716 } | |
11717 } | |
11718 } | |
11719 else | |
11720 { | |
11721 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) | |
11722 { | |
11723 return false; | |
11724 } | |
11725 | |
11726 while (current != '}') | |
11727 { | |
11728 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) | |
11729 { | |
11730 return false; | |
11731 } | |
11732 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) | |
11733 { | |
11734 return false; | |
11735 } | |
11736 get_ignore_noop(); | |
11737 key.clear(); | |
11738 } | |
11739 } | |
11740 | |
11741 return sax->end_object(); | |
11742 } | |
11743 | |
11744 // Note, no reader for UBJSON binary types is implemented because they do | |
11745 // not exist | |
11746 | |
11747 bool get_ubjson_high_precision_number() | |
11748 { | |
11749 // get size of following number string | |
11750 std::size_t size{}; | |
11751 bool no_ndarray = true; | |
11752 auto res = get_ubjson_size_value(size, no_ndarray); | |
11753 if (JSON_HEDLEY_UNLIKELY(!res)) | |
11754 { | |
11755 return res; | |
11756 } | |
11757 | |
11758 // get number string | |
11759 std::vector<char> number_vector; | |
11760 for (std::size_t i = 0; i < size; ++i) | |
11761 { | |
11762 get(); | |
11763 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) | |
11764 { | |
11765 return false; | |
11766 } | |
11767 number_vector.push_back(static_cast<char>(current)); | |
11768 } | |
11769 | |
11770 // parse number string | |
11771 using ia_type = decltype(detail::input_adapter(number_vector)); | |
11772 auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false); | |
11773 const auto result_number = number_lexer.scan(); | |
11774 const auto number_string = number_lexer.get_token_string(); | |
11775 const auto result_remainder = number_lexer.scan(); | |
11776 | |
11777 using token_type = typename detail::lexer_base<BasicJsonType>::token_type; | |
11778 | |
11779 if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) | |
11780 { | |
11781 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, | |
11782 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); | |
11783 } | |
11784 | |
11785 switch (result_number) | |
11786 { | |
11787 case token_type::value_integer: | |
11788 return sax->number_integer(number_lexer.get_number_integer()); | |
11789 case token_type::value_unsigned: | |
11790 return sax->number_unsigned(number_lexer.get_number_unsigned()); | |
11791 case token_type::value_float: | |
11792 return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); | |
11793 case token_type::uninitialized: | |
11794 case token_type::literal_true: | |
11795 case token_type::literal_false: | |
11796 case token_type::literal_null: | |
11797 case token_type::value_string: | |
11798 case token_type::begin_array: | |
11799 case token_type::begin_object: | |
11800 case token_type::end_array: | |
11801 case token_type::end_object: | |
11802 case token_type::name_separator: | |
11803 case token_type::value_separator: | |
11804 case token_type::parse_error: | |
11805 case token_type::end_of_input: | |
11806 case token_type::literal_or_value: | |
11807 default: | |
11808 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, | |
11809 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); | |
11810 } | |
11811 } | |
11812 | |
11813 /////////////////////// | |
11814 // Utility functions // | |
11815 /////////////////////// | |
11816 | |
11817 /*! | |
11818 @brief get next character from the input | |
11819 | |
11820 This function provides the interface to the used input adapter. It does | |
11821 not throw in case the input reached EOF, but returns a -'ve valued | |
11822 `std::char_traits<char_type>::eof()` in that case. | |
11823 | |
11824 @return character read from the input | |
11825 */ | |
11826 char_int_type get() | |
11827 { | |
11828 ++chars_read; | |
11829 return current = ia.get_character(); | |
11830 } | |
11831 | |
11832 /*! | |
11833 @return character read from the input after ignoring all 'N' entries | |
11834 */ | |
11835 char_int_type get_ignore_noop() | |
11836 { | |
11837 do | |
11838 { | |
11839 get(); | |
11840 } | |
11841 while (current == 'N'); | |
11842 | |
11843 return current; | |
11844 } | |
11845 | |
11846 /* | |
11847 @brief read a number from the input | |
11848 | |
11849 @tparam NumberType the type of the number | |
11850 @param[in] format the current format (for diagnostics) | |
11851 @param[out] result number of type @a NumberType | |
11852 | |
11853 @return whether conversion completed | |
11854 | |
11855 @note This function needs to respect the system's endianness, because | |
11856 bytes in CBOR, MessagePack, and UBJSON are stored in network order | |
11857 (big endian) and therefore need reordering on little endian systems. | |
11858 On the other hand, BSON and BJData use little endian and should reorder | |
11859 on big endian systems. | |
11860 */ | |
11861 template<typename NumberType, bool InputIsLittleEndian = false> | |
11862 bool get_number(const input_format_t format, NumberType& result) | |
11863 { | |
11864 // step 1: read input into array with system's byte order | |
11865 std::array<std::uint8_t, sizeof(NumberType)> vec{}; | |
11866 for (std::size_t i = 0; i < sizeof(NumberType); ++i) | |
11867 { | |
11868 get(); | |
11869 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) | |
11870 { | |
11871 return false; | |
11872 } | |
11873 | |
11874 // reverse byte order prior to conversion if necessary | |
11875 if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) | |
11876 { | |
11877 vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current); | |
11878 } | |
11879 else | |
11880 { | |
11881 vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE | |
11882 } | |
11883 } | |
11884 | |
11885 // step 2: convert array into number of type T and return | |
11886 std::memcpy(&result, vec.data(), sizeof(NumberType)); | |
11887 return true; | |
11888 } | |
11889 | |
11890 /*! | |
11891 @brief create a string by reading characters from the input | |
11892 | |
11893 @tparam NumberType the type of the number | |
11894 @param[in] format the current format (for diagnostics) | |
11895 @param[in] len number of characters to read | |
11896 @param[out] result string created by reading @a len bytes | |
11897 | |
11898 @return whether string creation completed | |
11899 | |
11900 @note We can not reserve @a len bytes for the result, because @a len | |
11901 may be too large. Usually, @ref unexpect_eof() detects the end of | |
11902 the input before we run out of string memory. | |
11903 */ | |
11904 template<typename NumberType> | |
11905 bool get_string(const input_format_t format, | |
11906 const NumberType len, | |
11907 string_t& result) | |
11908 { | |
11909 bool success = true; | |
11910 for (NumberType i = 0; i < len; i++) | |
11911 { | |
11912 get(); | |
11913 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) | |
11914 { | |
11915 success = false; | |
11916 break; | |
11917 } | |
11918 result.push_back(static_cast<typename string_t::value_type>(current)); | |
11919 } | |
11920 return success; | |
11921 } | |
11922 | |
11923 /*! | |
11924 @brief create a byte array by reading bytes from the input | |
11925 | |
11926 @tparam NumberType the type of the number | |
11927 @param[in] format the current format (for diagnostics) | |
11928 @param[in] len number of bytes to read | |
11929 @param[out] result byte array created by reading @a len bytes | |
11930 | |
11931 @return whether byte array creation completed | |
11932 | |
11933 @note We can not reserve @a len bytes for the result, because @a len | |
11934 may be too large. Usually, @ref unexpect_eof() detects the end of | |
11935 the input before we run out of memory. | |
11936 */ | |
11937 template<typename NumberType> | |
11938 bool get_binary(const input_format_t format, | |
11939 const NumberType len, | |
11940 binary_t& result) | |
11941 { | |
11942 bool success = true; | |
11943 for (NumberType i = 0; i < len; i++) | |
11944 { | |
11945 get(); | |
11946 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) | |
11947 { | |
11948 success = false; | |
11949 break; | |
11950 } | |
11951 result.push_back(static_cast<std::uint8_t>(current)); | |
11952 } | |
11953 return success; | |
11954 } | |
11955 | |
11956 /*! | |
11957 @param[in] format the current format (for diagnostics) | |
11958 @param[in] context further context information (for diagnostics) | |
11959 @return whether the last read character is not EOF | |
11960 */ | |
11961 JSON_HEDLEY_NON_NULL(3) | |
11962 bool unexpect_eof(const input_format_t format, const char* context) const | |
11963 { | |
11964 if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof())) | |
11965 { | |
11966 return sax->parse_error(chars_read, "<end of file>", | |
11967 parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); | |
11968 } | |
11969 return true; | |
11970 } | |
11971 | |
11972 /*! | |
11973 @return a string representation of the last read byte | |
11974 */ | |
11975 std::string get_token_string() const | |
11976 { | |
11977 std::array<char, 3> cr{{}}; | |
11978 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
11979 return std::string{cr.data()}; | |
11980 } | |
11981 | |
11982 /*! | |
11983 @param[in] format the current format | |
11984 @param[in] detail a detailed error message | |
11985 @param[in] context further context information | |
11986 @return a message string to use in the parse_error exceptions | |
11987 */ | |
11988 std::string exception_message(const input_format_t format, | |
11989 const std::string& detail, | |
11990 const std::string& context) const | |
11991 { | |
11992 std::string error_msg = "syntax error while parsing "; | |
11993 | |
11994 switch (format) | |
11995 { | |
11996 case input_format_t::cbor: | |
11997 error_msg += "CBOR"; | |
11998 break; | |
11999 | |
12000 case input_format_t::msgpack: | |
12001 error_msg += "MessagePack"; | |
12002 break; | |
12003 | |
12004 case input_format_t::ubjson: | |
12005 error_msg += "UBJSON"; | |
12006 break; | |
12007 | |
12008 case input_format_t::bson: | |
12009 error_msg += "BSON"; | |
12010 break; | |
12011 | |
12012 case input_format_t::bjdata: | |
12013 error_msg += "BJData"; | |
12014 break; | |
12015 | |
12016 case input_format_t::json: // LCOV_EXCL_LINE | |
12017 default: // LCOV_EXCL_LINE | |
12018 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
12019 } | |
12020 | |
12021 return concat(error_msg, ' ', context, ": ", detail); | |
12022 } | |
12023 | |
12024 private: | |
12025 static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1); | |
12026 | |
12027 /// input adapter | |
12028 InputAdapterType ia; | |
12029 | |
12030 /// the current character | |
12031 char_int_type current = std::char_traits<char_type>::eof(); | |
12032 | |
12033 /// the number of characters read | |
12034 std::size_t chars_read = 0; | |
12035 | |
12036 /// whether we can assume little endianness | |
12037 const bool is_little_endian = little_endianness(); | |
12038 | |
12039 /// input format | |
12040 const input_format_t input_format = input_format_t::json; | |
12041 | |
12042 /// the SAX parser | |
12043 json_sax_t* sax = nullptr; | |
12044 | |
12045 // excluded markers in bjdata optimized type | |
12046 #define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \ | |
12047 make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{') | |
12048 | |
12049 #define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ | |
12050 make_array<bjd_type>( \ | |
12051 bjd_type{'C', "char"}, \ | |
12052 bjd_type{'D', "double"}, \ | |
12053 bjd_type{'I', "int16"}, \ | |
12054 bjd_type{'L', "int64"}, \ | |
12055 bjd_type{'M', "uint64"}, \ | |
12056 bjd_type{'U', "uint8"}, \ | |
12057 bjd_type{'d', "single"}, \ | |
12058 bjd_type{'i', "int8"}, \ | |
12059 bjd_type{'l', "int32"}, \ | |
12060 bjd_type{'m', "uint32"}, \ | |
12061 bjd_type{'u', "uint16"}) | |
12062 | |
12063 JSON_PRIVATE_UNLESS_TESTED: | |
12064 // lookup tables | |
12065 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) | |
12066 const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers = | |
12067 JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_; | |
12068 | |
12069 using bjd_type = std::pair<char_int_type, string_t>; | |
12070 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) | |
12071 const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map = | |
12072 JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_; | |
12073 | |
12074 #undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ | |
12075 #undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ | |
12076 }; | |
12077 | |
12078 #ifndef JSON_HAS_CPP_17 | |
12079 template<typename BasicJsonType, typename InputAdapterType, typename SAX> | |
12080 constexpr std::size_t binary_reader<BasicJsonType, InputAdapterType, SAX>::npos; | |
12081 #endif | |
12082 | |
12083 } // namespace detail | |
12084 NLOHMANN_JSON_NAMESPACE_END | |
12085 | |
12086 // #include <nlohmann/detail/input/input_adapters.hpp> | |
12087 | |
12088 // #include <nlohmann/detail/input/lexer.hpp> | |
12089 | |
12090 // #include <nlohmann/detail/input/parser.hpp> | |
12091 // __ _____ _____ _____ | |
12092 // __| | __| | | | JSON for Modern C++ | |
12093 // | | |__ | | | | | | version 3.11.2 | |
12094 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
12095 // | |
12096 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
12097 // SPDX-License-Identifier: MIT | |
12098 | |
12099 | |
12100 | |
12101 #include <cmath> // isfinite | |
12102 #include <cstdint> // uint8_t | |
12103 #include <functional> // function | |
12104 #include <string> // string | |
12105 #include <utility> // move | |
12106 #include <vector> // vector | |
12107 | |
12108 // #include <nlohmann/detail/exceptions.hpp> | |
12109 | |
12110 // #include <nlohmann/detail/input/input_adapters.hpp> | |
12111 | |
12112 // #include <nlohmann/detail/input/json_sax.hpp> | |
12113 | |
12114 // #include <nlohmann/detail/input/lexer.hpp> | |
12115 | |
12116 // #include <nlohmann/detail/macro_scope.hpp> | |
12117 | |
12118 // #include <nlohmann/detail/meta/is_sax.hpp> | |
12119 | |
12120 // #include <nlohmann/detail/string_concat.hpp> | |
12121 | |
12122 // #include <nlohmann/detail/value_t.hpp> | |
12123 | |
12124 | |
12125 NLOHMANN_JSON_NAMESPACE_BEGIN | |
12126 namespace detail | |
12127 { | |
12128 //////////// | |
12129 // parser // | |
12130 //////////// | |
12131 | |
12132 enum class parse_event_t : std::uint8_t | |
12133 { | |
12134 /// the parser read `{` and started to process a JSON object | |
12135 object_start, | |
12136 /// the parser read `}` and finished processing a JSON object | |
12137 object_end, | |
12138 /// the parser read `[` and started to process a JSON array | |
12139 array_start, | |
12140 /// the parser read `]` and finished processing a JSON array | |
12141 array_end, | |
12142 /// the parser read a key of a value in an object | |
12143 key, | |
12144 /// the parser finished reading a JSON value | |
12145 value | |
12146 }; | |
12147 | |
12148 template<typename BasicJsonType> | |
12149 using parser_callback_t = | |
12150 std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>; | |
12151 | |
12152 /*! | |
12153 @brief syntax analysis | |
12154 | |
12155 This class implements a recursive descent parser. | |
12156 */ | |
12157 template<typename BasicJsonType, typename InputAdapterType> | |
12158 class parser | |
12159 { | |
12160 using number_integer_t = typename BasicJsonType::number_integer_t; | |
12161 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
12162 using number_float_t = typename BasicJsonType::number_float_t; | |
12163 using string_t = typename BasicJsonType::string_t; | |
12164 using lexer_t = lexer<BasicJsonType, InputAdapterType>; | |
12165 using token_type = typename lexer_t::token_type; | |
12166 | |
12167 public: | |
12168 /// a parser reading from an input adapter | |
12169 explicit parser(InputAdapterType&& adapter, | |
12170 const parser_callback_t<BasicJsonType> cb = nullptr, | |
12171 const bool allow_exceptions_ = true, | |
12172 const bool skip_comments = false) | |
12173 : callback(cb) | |
12174 , m_lexer(std::move(adapter), skip_comments) | |
12175 , allow_exceptions(allow_exceptions_) | |
12176 { | |
12177 // read first token | |
12178 get_token(); | |
12179 } | |
12180 | |
12181 /*! | |
12182 @brief public parser interface | |
12183 | |
12184 @param[in] strict whether to expect the last token to be EOF | |
12185 @param[in,out] result parsed JSON value | |
12186 | |
12187 @throw parse_error.101 in case of an unexpected token | |
12188 @throw parse_error.102 if to_unicode fails or surrogate error | |
12189 @throw parse_error.103 if to_unicode fails | |
12190 */ | |
12191 void parse(const bool strict, BasicJsonType& result) | |
12192 { | |
12193 if (callback) | |
12194 { | |
12195 json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions); | |
12196 sax_parse_internal(&sdp); | |
12197 | |
12198 // in strict mode, input must be completely read | |
12199 if (strict && (get_token() != token_type::end_of_input)) | |
12200 { | |
12201 sdp.parse_error(m_lexer.get_position(), | |
12202 m_lexer.get_token_string(), | |
12203 parse_error::create(101, m_lexer.get_position(), | |
12204 exception_message(token_type::end_of_input, "value"), nullptr)); | |
12205 } | |
12206 | |
12207 // in case of an error, return discarded value | |
12208 if (sdp.is_errored()) | |
12209 { | |
12210 result = value_t::discarded; | |
12211 return; | |
12212 } | |
12213 | |
12214 // set top-level value to null if it was discarded by the callback | |
12215 // function | |
12216 if (result.is_discarded()) | |
12217 { | |
12218 result = nullptr; | |
12219 } | |
12220 } | |
12221 else | |
12222 { | |
12223 json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions); | |
12224 sax_parse_internal(&sdp); | |
12225 | |
12226 // in strict mode, input must be completely read | |
12227 if (strict && (get_token() != token_type::end_of_input)) | |
12228 { | |
12229 sdp.parse_error(m_lexer.get_position(), | |
12230 m_lexer.get_token_string(), | |
12231 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); | |
12232 } | |
12233 | |
12234 // in case of an error, return discarded value | |
12235 if (sdp.is_errored()) | |
12236 { | |
12237 result = value_t::discarded; | |
12238 return; | |
12239 } | |
12240 } | |
12241 | |
12242 result.assert_invariant(); | |
12243 } | |
12244 | |
12245 /*! | |
12246 @brief public accept interface | |
12247 | |
12248 @param[in] strict whether to expect the last token to be EOF | |
12249 @return whether the input is a proper JSON text | |
12250 */ | |
12251 bool accept(const bool strict = true) | |
12252 { | |
12253 json_sax_acceptor<BasicJsonType> sax_acceptor; | |
12254 return sax_parse(&sax_acceptor, strict); | |
12255 } | |
12256 | |
12257 template<typename SAX> | |
12258 JSON_HEDLEY_NON_NULL(2) | |
12259 bool sax_parse(SAX* sax, const bool strict = true) | |
12260 { | |
12261 (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; | |
12262 const bool result = sax_parse_internal(sax); | |
12263 | |
12264 // strict mode: next byte must be EOF | |
12265 if (result && strict && (get_token() != token_type::end_of_input)) | |
12266 { | |
12267 return sax->parse_error(m_lexer.get_position(), | |
12268 m_lexer.get_token_string(), | |
12269 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); | |
12270 } | |
12271 | |
12272 return result; | |
12273 } | |
12274 | |
12275 private: | |
12276 template<typename SAX> | |
12277 JSON_HEDLEY_NON_NULL(2) | |
12278 bool sax_parse_internal(SAX* sax) | |
12279 { | |
12280 // stack to remember the hierarchy of structured values we are parsing | |
12281 // true = array; false = object | |
12282 std::vector<bool> states; | |
12283 // value to avoid a goto (see comment where set to true) | |
12284 bool skip_to_state_evaluation = false; | |
12285 | |
12286 while (true) | |
12287 { | |
12288 if (!skip_to_state_evaluation) | |
12289 { | |
12290 // invariant: get_token() was called before each iteration | |
12291 switch (last_token) | |
12292 { | |
12293 case token_type::begin_object: | |
12294 { | |
12295 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) | |
12296 { | |
12297 return false; | |
12298 } | |
12299 | |
12300 // closing } -> we are done | |
12301 if (get_token() == token_type::end_object) | |
12302 { | |
12303 if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) | |
12304 { | |
12305 return false; | |
12306 } | |
12307 break; | |
12308 } | |
12309 | |
12310 // parse key | |
12311 if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) | |
12312 { | |
12313 return sax->parse_error(m_lexer.get_position(), | |
12314 m_lexer.get_token_string(), | |
12315 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); | |
12316 } | |
12317 if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) | |
12318 { | |
12319 return false; | |
12320 } | |
12321 | |
12322 // parse separator (:) | |
12323 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) | |
12324 { | |
12325 return sax->parse_error(m_lexer.get_position(), | |
12326 m_lexer.get_token_string(), | |
12327 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); | |
12328 } | |
12329 | |
12330 // remember we are now inside an object | |
12331 states.push_back(false); | |
12332 | |
12333 // parse values | |
12334 get_token(); | |
12335 continue; | |
12336 } | |
12337 | |
12338 case token_type::begin_array: | |
12339 { | |
12340 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) | |
12341 { | |
12342 return false; | |
12343 } | |
12344 | |
12345 // closing ] -> we are done | |
12346 if (get_token() == token_type::end_array) | |
12347 { | |
12348 if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) | |
12349 { | |
12350 return false; | |
12351 } | |
12352 break; | |
12353 } | |
12354 | |
12355 // remember we are now inside an array | |
12356 states.push_back(true); | |
12357 | |
12358 // parse values (no need to call get_token) | |
12359 continue; | |
12360 } | |
12361 | |
12362 case token_type::value_float: | |
12363 { | |
12364 const auto res = m_lexer.get_number_float(); | |
12365 | |
12366 if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) | |
12367 { | |
12368 return sax->parse_error(m_lexer.get_position(), | |
12369 m_lexer.get_token_string(), | |
12370 out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); | |
12371 } | |
12372 | |
12373 if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) | |
12374 { | |
12375 return false; | |
12376 } | |
12377 | |
12378 break; | |
12379 } | |
12380 | |
12381 case token_type::literal_false: | |
12382 { | |
12383 if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) | |
12384 { | |
12385 return false; | |
12386 } | |
12387 break; | |
12388 } | |
12389 | |
12390 case token_type::literal_null: | |
12391 { | |
12392 if (JSON_HEDLEY_UNLIKELY(!sax->null())) | |
12393 { | |
12394 return false; | |
12395 } | |
12396 break; | |
12397 } | |
12398 | |
12399 case token_type::literal_true: | |
12400 { | |
12401 if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) | |
12402 { | |
12403 return false; | |
12404 } | |
12405 break; | |
12406 } | |
12407 | |
12408 case token_type::value_integer: | |
12409 { | |
12410 if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) | |
12411 { | |
12412 return false; | |
12413 } | |
12414 break; | |
12415 } | |
12416 | |
12417 case token_type::value_string: | |
12418 { | |
12419 if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) | |
12420 { | |
12421 return false; | |
12422 } | |
12423 break; | |
12424 } | |
12425 | |
12426 case token_type::value_unsigned: | |
12427 { | |
12428 if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) | |
12429 { | |
12430 return false; | |
12431 } | |
12432 break; | |
12433 } | |
12434 | |
12435 case token_type::parse_error: | |
12436 { | |
12437 // using "uninitialized" to avoid "expected" message | |
12438 return sax->parse_error(m_lexer.get_position(), | |
12439 m_lexer.get_token_string(), | |
12440 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr)); | |
12441 } | |
12442 | |
12443 case token_type::uninitialized: | |
12444 case token_type::end_array: | |
12445 case token_type::end_object: | |
12446 case token_type::name_separator: | |
12447 case token_type::value_separator: | |
12448 case token_type::end_of_input: | |
12449 case token_type::literal_or_value: | |
12450 default: // the last token was unexpected | |
12451 { | |
12452 return sax->parse_error(m_lexer.get_position(), | |
12453 m_lexer.get_token_string(), | |
12454 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); | |
12455 } | |
12456 } | |
12457 } | |
12458 else | |
12459 { | |
12460 skip_to_state_evaluation = false; | |
12461 } | |
12462 | |
12463 // we reached this line after we successfully parsed a value | |
12464 if (states.empty()) | |
12465 { | |
12466 // empty stack: we reached the end of the hierarchy: done | |
12467 return true; | |
12468 } | |
12469 | |
12470 if (states.back()) // array | |
12471 { | |
12472 // comma -> next value | |
12473 if (get_token() == token_type::value_separator) | |
12474 { | |
12475 // parse a new value | |
12476 get_token(); | |
12477 continue; | |
12478 } | |
12479 | |
12480 // closing ] | |
12481 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) | |
12482 { | |
12483 if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) | |
12484 { | |
12485 return false; | |
12486 } | |
12487 | |
12488 // We are done with this array. Before we can parse a | |
12489 // new value, we need to evaluate the new state first. | |
12490 // By setting skip_to_state_evaluation to false, we | |
12491 // are effectively jumping to the beginning of this if. | |
12492 JSON_ASSERT(!states.empty()); | |
12493 states.pop_back(); | |
12494 skip_to_state_evaluation = true; | |
12495 continue; | |
12496 } | |
12497 | |
12498 return sax->parse_error(m_lexer.get_position(), | |
12499 m_lexer.get_token_string(), | |
12500 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr)); | |
12501 } | |
12502 | |
12503 // states.back() is false -> object | |
12504 | |
12505 // comma -> next value | |
12506 if (get_token() == token_type::value_separator) | |
12507 { | |
12508 // parse key | |
12509 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) | |
12510 { | |
12511 return sax->parse_error(m_lexer.get_position(), | |
12512 m_lexer.get_token_string(), | |
12513 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); | |
12514 } | |
12515 | |
12516 if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) | |
12517 { | |
12518 return false; | |
12519 } | |
12520 | |
12521 // parse separator (:) | |
12522 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) | |
12523 { | |
12524 return sax->parse_error(m_lexer.get_position(), | |
12525 m_lexer.get_token_string(), | |
12526 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); | |
12527 } | |
12528 | |
12529 // parse values | |
12530 get_token(); | |
12531 continue; | |
12532 } | |
12533 | |
12534 // closing } | |
12535 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) | |
12536 { | |
12537 if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) | |
12538 { | |
12539 return false; | |
12540 } | |
12541 | |
12542 // We are done with this object. Before we can parse a | |
12543 // new value, we need to evaluate the new state first. | |
12544 // By setting skip_to_state_evaluation to false, we | |
12545 // are effectively jumping to the beginning of this if. | |
12546 JSON_ASSERT(!states.empty()); | |
12547 states.pop_back(); | |
12548 skip_to_state_evaluation = true; | |
12549 continue; | |
12550 } | |
12551 | |
12552 return sax->parse_error(m_lexer.get_position(), | |
12553 m_lexer.get_token_string(), | |
12554 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr)); | |
12555 } | |
12556 } | |
12557 | |
12558 /// get next token from lexer | |
12559 token_type get_token() | |
12560 { | |
12561 return last_token = m_lexer.scan(); | |
12562 } | |
12563 | |
12564 std::string exception_message(const token_type expected, const std::string& context) | |
12565 { | |
12566 std::string error_msg = "syntax error "; | |
12567 | |
12568 if (!context.empty()) | |
12569 { | |
12570 error_msg += concat("while parsing ", context, ' '); | |
12571 } | |
12572 | |
12573 error_msg += "- "; | |
12574 | |
12575 if (last_token == token_type::parse_error) | |
12576 { | |
12577 error_msg += concat(m_lexer.get_error_message(), "; last read: '", | |
12578 m_lexer.get_token_string(), '\''); | |
12579 } | |
12580 else | |
12581 { | |
12582 error_msg += concat("unexpected ", lexer_t::token_type_name(last_token)); | |
12583 } | |
12584 | |
12585 if (expected != token_type::uninitialized) | |
12586 { | |
12587 error_msg += concat("; expected ", lexer_t::token_type_name(expected)); | |
12588 } | |
12589 | |
12590 return error_msg; | |
12591 } | |
12592 | |
12593 private: | |
12594 /// callback function | |
12595 const parser_callback_t<BasicJsonType> callback = nullptr; | |
12596 /// the type of the last read token | |
12597 token_type last_token = token_type::uninitialized; | |
12598 /// the lexer | |
12599 lexer_t m_lexer; | |
12600 /// whether to throw exceptions in case of errors | |
12601 const bool allow_exceptions = true; | |
12602 }; | |
12603 | |
12604 } // namespace detail | |
12605 NLOHMANN_JSON_NAMESPACE_END | |
12606 | |
12607 // #include <nlohmann/detail/iterators/internal_iterator.hpp> | |
12608 // __ _____ _____ _____ | |
12609 // __| | __| | | | JSON for Modern C++ | |
12610 // | | |__ | | | | | | version 3.11.2 | |
12611 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
12612 // | |
12613 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
12614 // SPDX-License-Identifier: MIT | |
12615 | |
12616 | |
12617 | |
12618 // #include <nlohmann/detail/abi_macros.hpp> | |
12619 | |
12620 // #include <nlohmann/detail/iterators/primitive_iterator.hpp> | |
12621 // __ _____ _____ _____ | |
12622 // __| | __| | | | JSON for Modern C++ | |
12623 // | | |__ | | | | | | version 3.11.2 | |
12624 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
12625 // | |
12626 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
12627 // SPDX-License-Identifier: MIT | |
12628 | |
12629 | |
12630 | |
12631 #include <cstddef> // ptrdiff_t | |
12632 #include <limits> // numeric_limits | |
12633 | |
12634 // #include <nlohmann/detail/macro_scope.hpp> | |
12635 | |
12636 | |
12637 NLOHMANN_JSON_NAMESPACE_BEGIN | |
12638 namespace detail | |
12639 { | |
12640 | |
12641 /* | |
12642 @brief an iterator for primitive JSON types | |
12643 | |
12644 This class models an iterator for primitive JSON types (boolean, number, | |
12645 string). It's only purpose is to allow the iterator/const_iterator classes | |
12646 to "iterate" over primitive values. Internally, the iterator is modeled by | |
12647 a `difference_type` variable. Value begin_value (`0`) models the begin, | |
12648 end_value (`1`) models past the end. | |
12649 */ | |
12650 class primitive_iterator_t | |
12651 { | |
12652 private: | |
12653 using difference_type = std::ptrdiff_t; | |
12654 static constexpr difference_type begin_value = 0; | |
12655 static constexpr difference_type end_value = begin_value + 1; | |
12656 | |
12657 JSON_PRIVATE_UNLESS_TESTED: | |
12658 /// iterator as signed integer type | |
12659 difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)(); | |
12660 | |
12661 public: | |
12662 constexpr difference_type get_value() const noexcept | |
12663 { | |
12664 return m_it; | |
12665 } | |
12666 | |
12667 /// set iterator to a defined beginning | |
12668 void set_begin() noexcept | |
12669 { | |
12670 m_it = begin_value; | |
12671 } | |
12672 | |
12673 /// set iterator to a defined past the end | |
12674 void set_end() noexcept | |
12675 { | |
12676 m_it = end_value; | |
12677 } | |
12678 | |
12679 /// return whether the iterator can be dereferenced | |
12680 constexpr bool is_begin() const noexcept | |
12681 { | |
12682 return m_it == begin_value; | |
12683 } | |
12684 | |
12685 /// return whether the iterator is at end | |
12686 constexpr bool is_end() const noexcept | |
12687 { | |
12688 return m_it == end_value; | |
12689 } | |
12690 | |
12691 friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept | |
12692 { | |
12693 return lhs.m_it == rhs.m_it; | |
12694 } | |
12695 | |
12696 friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept | |
12697 { | |
12698 return lhs.m_it < rhs.m_it; | |
12699 } | |
12700 | |
12701 primitive_iterator_t operator+(difference_type n) noexcept | |
12702 { | |
12703 auto result = *this; | |
12704 result += n; | |
12705 return result; | |
12706 } | |
12707 | |
12708 friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept | |
12709 { | |
12710 return lhs.m_it - rhs.m_it; | |
12711 } | |
12712 | |
12713 primitive_iterator_t& operator++() noexcept | |
12714 { | |
12715 ++m_it; | |
12716 return *this; | |
12717 } | |
12718 | |
12719 primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) | |
12720 { | |
12721 auto result = *this; | |
12722 ++m_it; | |
12723 return result; | |
12724 } | |
12725 | |
12726 primitive_iterator_t& operator--() noexcept | |
12727 { | |
12728 --m_it; | |
12729 return *this; | |
12730 } | |
12731 | |
12732 primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) | |
12733 { | |
12734 auto result = *this; | |
12735 --m_it; | |
12736 return result; | |
12737 } | |
12738 | |
12739 primitive_iterator_t& operator+=(difference_type n) noexcept | |
12740 { | |
12741 m_it += n; | |
12742 return *this; | |
12743 } | |
12744 | |
12745 primitive_iterator_t& operator-=(difference_type n) noexcept | |
12746 { | |
12747 m_it -= n; | |
12748 return *this; | |
12749 } | |
12750 }; | |
12751 | |
12752 } // namespace detail | |
12753 NLOHMANN_JSON_NAMESPACE_END | |
12754 | |
12755 | |
12756 NLOHMANN_JSON_NAMESPACE_BEGIN | |
12757 namespace detail | |
12758 { | |
12759 | |
12760 /*! | |
12761 @brief an iterator value | |
12762 | |
12763 @note This structure could easily be a union, but MSVC currently does not allow | |
12764 unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. | |
12765 */ | |
12766 template<typename BasicJsonType> struct internal_iterator | |
12767 { | |
12768 /// iterator for JSON objects | |
12769 typename BasicJsonType::object_t::iterator object_iterator {}; | |
12770 /// iterator for JSON arrays | |
12771 typename BasicJsonType::array_t::iterator array_iterator {}; | |
12772 /// generic iterator for all other types | |
12773 primitive_iterator_t primitive_iterator {}; | |
12774 }; | |
12775 | |
12776 } // namespace detail | |
12777 NLOHMANN_JSON_NAMESPACE_END | |
12778 | |
12779 // #include <nlohmann/detail/iterators/iter_impl.hpp> | |
12780 // __ _____ _____ _____ | |
12781 // __| | __| | | | JSON for Modern C++ | |
12782 // | | |__ | | | | | | version 3.11.2 | |
12783 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
12784 // | |
12785 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
12786 // SPDX-License-Identifier: MIT | |
12787 | |
12788 | |
12789 | |
12790 #include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next | |
12791 #include <type_traits> // conditional, is_const, remove_const | |
12792 | |
12793 // #include <nlohmann/detail/exceptions.hpp> | |
12794 | |
12795 // #include <nlohmann/detail/iterators/internal_iterator.hpp> | |
12796 | |
12797 // #include <nlohmann/detail/iterators/primitive_iterator.hpp> | |
12798 | |
12799 // #include <nlohmann/detail/macro_scope.hpp> | |
12800 | |
12801 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
12802 | |
12803 // #include <nlohmann/detail/meta/type_traits.hpp> | |
12804 | |
12805 // #include <nlohmann/detail/value_t.hpp> | |
12806 | |
12807 | |
12808 NLOHMANN_JSON_NAMESPACE_BEGIN | |
12809 namespace detail | |
12810 { | |
12811 | |
12812 // forward declare, to be able to friend it later on | |
12813 template<typename IteratorType> class iteration_proxy; | |
12814 template<typename IteratorType> class iteration_proxy_value; | |
12815 | |
12816 /*! | |
12817 @brief a template for a bidirectional iterator for the @ref basic_json class | |
12818 This class implements a both iterators (iterator and const_iterator) for the | |
12819 @ref basic_json class. | |
12820 @note An iterator is called *initialized* when a pointer to a JSON value has | |
12821 been set (e.g., by a constructor or a copy assignment). If the iterator is | |
12822 default-constructed, it is *uninitialized* and most methods are undefined. | |
12823 **The library uses assertions to detect calls on uninitialized iterators.** | |
12824 @requirement The class satisfies the following concept requirements: | |
12825 - | |
12826 [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): | |
12827 The iterator that can be moved can be moved in both directions (i.e. | |
12828 incremented and decremented). | |
12829 @since version 1.0.0, simplified in version 2.0.9, change to bidirectional | |
12830 iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) | |
12831 */ | |
12832 template<typename BasicJsonType> | |
12833 class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) | |
12834 { | |
12835 /// the iterator with BasicJsonType of different const-ness | |
12836 using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>; | |
12837 /// allow basic_json to access private members | |
12838 friend other_iter_impl; | |
12839 friend BasicJsonType; | |
12840 friend iteration_proxy<iter_impl>; | |
12841 friend iteration_proxy_value<iter_impl>; | |
12842 | |
12843 using object_t = typename BasicJsonType::object_t; | |
12844 using array_t = typename BasicJsonType::array_t; | |
12845 // make sure BasicJsonType is basic_json or const basic_json | |
12846 static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value, | |
12847 "iter_impl only accepts (const) basic_json"); | |
12848 // superficial check for the LegacyBidirectionalIterator named requirement | |
12849 static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value | |
12850 && std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value, | |
12851 "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); | |
12852 | |
12853 public: | |
12854 /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. | |
12855 /// The C++ Standard has never required user-defined iterators to derive from std::iterator. | |
12856 /// A user-defined iterator should provide publicly accessible typedefs named | |
12857 /// iterator_category, value_type, difference_type, pointer, and reference. | |
12858 /// Note that value_type is required to be non-const, even for constant iterators. | |
12859 using iterator_category = std::bidirectional_iterator_tag; | |
12860 | |
12861 /// the type of the values when the iterator is dereferenced | |
12862 using value_type = typename BasicJsonType::value_type; | |
12863 /// a type to represent differences between iterators | |
12864 using difference_type = typename BasicJsonType::difference_type; | |
12865 /// defines a pointer to the type iterated over (value_type) | |
12866 using pointer = typename std::conditional<std::is_const<BasicJsonType>::value, | |
12867 typename BasicJsonType::const_pointer, | |
12868 typename BasicJsonType::pointer>::type; | |
12869 /// defines a reference to the type iterated over (value_type) | |
12870 using reference = | |
12871 typename std::conditional<std::is_const<BasicJsonType>::value, | |
12872 typename BasicJsonType::const_reference, | |
12873 typename BasicJsonType::reference>::type; | |
12874 | |
12875 iter_impl() = default; | |
12876 ~iter_impl() = default; | |
12877 iter_impl(iter_impl&&) noexcept = default; | |
12878 iter_impl& operator=(iter_impl&&) noexcept = default; | |
12879 | |
12880 /*! | |
12881 @brief constructor for a given JSON instance | |
12882 @param[in] object pointer to a JSON object for this iterator | |
12883 @pre object != nullptr | |
12884 @post The iterator is initialized; i.e. `m_object != nullptr`. | |
12885 */ | |
12886 explicit iter_impl(pointer object) noexcept : m_object(object) | |
12887 { | |
12888 JSON_ASSERT(m_object != nullptr); | |
12889 | |
12890 switch (m_object->m_type) | |
12891 { | |
12892 case value_t::object: | |
12893 { | |
12894 m_it.object_iterator = typename object_t::iterator(); | |
12895 break; | |
12896 } | |
12897 | |
12898 case value_t::array: | |
12899 { | |
12900 m_it.array_iterator = typename array_t::iterator(); | |
12901 break; | |
12902 } | |
12903 | |
12904 case value_t::null: | |
12905 case value_t::string: | |
12906 case value_t::boolean: | |
12907 case value_t::number_integer: | |
12908 case value_t::number_unsigned: | |
12909 case value_t::number_float: | |
12910 case value_t::binary: | |
12911 case value_t::discarded: | |
12912 default: | |
12913 { | |
12914 m_it.primitive_iterator = primitive_iterator_t(); | |
12915 break; | |
12916 } | |
12917 } | |
12918 } | |
12919 | |
12920 /*! | |
12921 @note The conventional copy constructor and copy assignment are implicitly | |
12922 defined. Combined with the following converting constructor and | |
12923 assignment, they support: (1) copy from iterator to iterator, (2) | |
12924 copy from const iterator to const iterator, and (3) conversion from | |
12925 iterator to const iterator. However conversion from const iterator | |
12926 to iterator is not defined. | |
12927 */ | |
12928 | |
12929 /*! | |
12930 @brief const copy constructor | |
12931 @param[in] other const iterator to copy from | |
12932 @note This copy constructor had to be defined explicitly to circumvent a bug | |
12933 occurring on msvc v19.0 compiler (VS 2015) debug build. For more | |
12934 information refer to: https://github.com/nlohmann/json/issues/1608 | |
12935 */ | |
12936 iter_impl(const iter_impl<const BasicJsonType>& other) noexcept | |
12937 : m_object(other.m_object), m_it(other.m_it) | |
12938 {} | |
12939 | |
12940 /*! | |
12941 @brief converting assignment | |
12942 @param[in] other const iterator to copy from | |
12943 @return const/non-const iterator | |
12944 @note It is not checked whether @a other is initialized. | |
12945 */ | |
12946 iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept | |
12947 { | |
12948 if (&other != this) | |
12949 { | |
12950 m_object = other.m_object; | |
12951 m_it = other.m_it; | |
12952 } | |
12953 return *this; | |
12954 } | |
12955 | |
12956 /*! | |
12957 @brief converting constructor | |
12958 @param[in] other non-const iterator to copy from | |
12959 @note It is not checked whether @a other is initialized. | |
12960 */ | |
12961 iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept | |
12962 : m_object(other.m_object), m_it(other.m_it) | |
12963 {} | |
12964 | |
12965 /*! | |
12966 @brief converting assignment | |
12967 @param[in] other non-const iterator to copy from | |
12968 @return const/non-const iterator | |
12969 @note It is not checked whether @a other is initialized. | |
12970 */ | |
12971 iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp) | |
12972 { | |
12973 m_object = other.m_object; | |
12974 m_it = other.m_it; | |
12975 return *this; | |
12976 } | |
12977 | |
12978 JSON_PRIVATE_UNLESS_TESTED: | |
12979 /*! | |
12980 @brief set the iterator to the first value | |
12981 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
12982 */ | |
12983 void set_begin() noexcept | |
12984 { | |
12985 JSON_ASSERT(m_object != nullptr); | |
12986 | |
12987 switch (m_object->m_type) | |
12988 { | |
12989 case value_t::object: | |
12990 { | |
12991 m_it.object_iterator = m_object->m_value.object->begin(); | |
12992 break; | |
12993 } | |
12994 | |
12995 case value_t::array: | |
12996 { | |
12997 m_it.array_iterator = m_object->m_value.array->begin(); | |
12998 break; | |
12999 } | |
13000 | |
13001 case value_t::null: | |
13002 { | |
13003 // set to end so begin()==end() is true: null is empty | |
13004 m_it.primitive_iterator.set_end(); | |
13005 break; | |
13006 } | |
13007 | |
13008 case value_t::string: | |
13009 case value_t::boolean: | |
13010 case value_t::number_integer: | |
13011 case value_t::number_unsigned: | |
13012 case value_t::number_float: | |
13013 case value_t::binary: | |
13014 case value_t::discarded: | |
13015 default: | |
13016 { | |
13017 m_it.primitive_iterator.set_begin(); | |
13018 break; | |
13019 } | |
13020 } | |
13021 } | |
13022 | |
13023 /*! | |
13024 @brief set the iterator past the last value | |
13025 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13026 */ | |
13027 void set_end() noexcept | |
13028 { | |
13029 JSON_ASSERT(m_object != nullptr); | |
13030 | |
13031 switch (m_object->m_type) | |
13032 { | |
13033 case value_t::object: | |
13034 { | |
13035 m_it.object_iterator = m_object->m_value.object->end(); | |
13036 break; | |
13037 } | |
13038 | |
13039 case value_t::array: | |
13040 { | |
13041 m_it.array_iterator = m_object->m_value.array->end(); | |
13042 break; | |
13043 } | |
13044 | |
13045 case value_t::null: | |
13046 case value_t::string: | |
13047 case value_t::boolean: | |
13048 case value_t::number_integer: | |
13049 case value_t::number_unsigned: | |
13050 case value_t::number_float: | |
13051 case value_t::binary: | |
13052 case value_t::discarded: | |
13053 default: | |
13054 { | |
13055 m_it.primitive_iterator.set_end(); | |
13056 break; | |
13057 } | |
13058 } | |
13059 } | |
13060 | |
13061 public: | |
13062 /*! | |
13063 @brief return a reference to the value pointed to by the iterator | |
13064 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13065 */ | |
13066 reference operator*() const | |
13067 { | |
13068 JSON_ASSERT(m_object != nullptr); | |
13069 | |
13070 switch (m_object->m_type) | |
13071 { | |
13072 case value_t::object: | |
13073 { | |
13074 JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); | |
13075 return m_it.object_iterator->second; | |
13076 } | |
13077 | |
13078 case value_t::array: | |
13079 { | |
13080 JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); | |
13081 return *m_it.array_iterator; | |
13082 } | |
13083 | |
13084 case value_t::null: | |
13085 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); | |
13086 | |
13087 case value_t::string: | |
13088 case value_t::boolean: | |
13089 case value_t::number_integer: | |
13090 case value_t::number_unsigned: | |
13091 case value_t::number_float: | |
13092 case value_t::binary: | |
13093 case value_t::discarded: | |
13094 default: | |
13095 { | |
13096 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) | |
13097 { | |
13098 return *m_object; | |
13099 } | |
13100 | |
13101 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); | |
13102 } | |
13103 } | |
13104 } | |
13105 | |
13106 /*! | |
13107 @brief dereference the iterator | |
13108 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13109 */ | |
13110 pointer operator->() const | |
13111 { | |
13112 JSON_ASSERT(m_object != nullptr); | |
13113 | |
13114 switch (m_object->m_type) | |
13115 { | |
13116 case value_t::object: | |
13117 { | |
13118 JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); | |
13119 return &(m_it.object_iterator->second); | |
13120 } | |
13121 | |
13122 case value_t::array: | |
13123 { | |
13124 JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); | |
13125 return &*m_it.array_iterator; | |
13126 } | |
13127 | |
13128 case value_t::null: | |
13129 case value_t::string: | |
13130 case value_t::boolean: | |
13131 case value_t::number_integer: | |
13132 case value_t::number_unsigned: | |
13133 case value_t::number_float: | |
13134 case value_t::binary: | |
13135 case value_t::discarded: | |
13136 default: | |
13137 { | |
13138 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) | |
13139 { | |
13140 return m_object; | |
13141 } | |
13142 | |
13143 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); | |
13144 } | |
13145 } | |
13146 } | |
13147 | |
13148 /*! | |
13149 @brief post-increment (it++) | |
13150 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13151 */ | |
13152 iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) | |
13153 { | |
13154 auto result = *this; | |
13155 ++(*this); | |
13156 return result; | |
13157 } | |
13158 | |
13159 /*! | |
13160 @brief pre-increment (++it) | |
13161 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13162 */ | |
13163 iter_impl& operator++() | |
13164 { | |
13165 JSON_ASSERT(m_object != nullptr); | |
13166 | |
13167 switch (m_object->m_type) | |
13168 { | |
13169 case value_t::object: | |
13170 { | |
13171 std::advance(m_it.object_iterator, 1); | |
13172 break; | |
13173 } | |
13174 | |
13175 case value_t::array: | |
13176 { | |
13177 std::advance(m_it.array_iterator, 1); | |
13178 break; | |
13179 } | |
13180 | |
13181 case value_t::null: | |
13182 case value_t::string: | |
13183 case value_t::boolean: | |
13184 case value_t::number_integer: | |
13185 case value_t::number_unsigned: | |
13186 case value_t::number_float: | |
13187 case value_t::binary: | |
13188 case value_t::discarded: | |
13189 default: | |
13190 { | |
13191 ++m_it.primitive_iterator; | |
13192 break; | |
13193 } | |
13194 } | |
13195 | |
13196 return *this; | |
13197 } | |
13198 | |
13199 /*! | |
13200 @brief post-decrement (it--) | |
13201 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13202 */ | |
13203 iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) | |
13204 { | |
13205 auto result = *this; | |
13206 --(*this); | |
13207 return result; | |
13208 } | |
13209 | |
13210 /*! | |
13211 @brief pre-decrement (--it) | |
13212 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13213 */ | |
13214 iter_impl& operator--() | |
13215 { | |
13216 JSON_ASSERT(m_object != nullptr); | |
13217 | |
13218 switch (m_object->m_type) | |
13219 { | |
13220 case value_t::object: | |
13221 { | |
13222 std::advance(m_it.object_iterator, -1); | |
13223 break; | |
13224 } | |
13225 | |
13226 case value_t::array: | |
13227 { | |
13228 std::advance(m_it.array_iterator, -1); | |
13229 break; | |
13230 } | |
13231 | |
13232 case value_t::null: | |
13233 case value_t::string: | |
13234 case value_t::boolean: | |
13235 case value_t::number_integer: | |
13236 case value_t::number_unsigned: | |
13237 case value_t::number_float: | |
13238 case value_t::binary: | |
13239 case value_t::discarded: | |
13240 default: | |
13241 { | |
13242 --m_it.primitive_iterator; | |
13243 break; | |
13244 } | |
13245 } | |
13246 | |
13247 return *this; | |
13248 } | |
13249 | |
13250 /*! | |
13251 @brief comparison: equal | |
13252 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13253 */ | |
13254 template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr > | |
13255 bool operator==(const IterImpl& other) const | |
13256 { | |
13257 // if objects are not the same, the comparison is undefined | |
13258 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) | |
13259 { | |
13260 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); | |
13261 } | |
13262 | |
13263 JSON_ASSERT(m_object != nullptr); | |
13264 | |
13265 switch (m_object->m_type) | |
13266 { | |
13267 case value_t::object: | |
13268 return (m_it.object_iterator == other.m_it.object_iterator); | |
13269 | |
13270 case value_t::array: | |
13271 return (m_it.array_iterator == other.m_it.array_iterator); | |
13272 | |
13273 case value_t::null: | |
13274 case value_t::string: | |
13275 case value_t::boolean: | |
13276 case value_t::number_integer: | |
13277 case value_t::number_unsigned: | |
13278 case value_t::number_float: | |
13279 case value_t::binary: | |
13280 case value_t::discarded: | |
13281 default: | |
13282 return (m_it.primitive_iterator == other.m_it.primitive_iterator); | |
13283 } | |
13284 } | |
13285 | |
13286 /*! | |
13287 @brief comparison: not equal | |
13288 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13289 */ | |
13290 template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr > | |
13291 bool operator!=(const IterImpl& other) const | |
13292 { | |
13293 return !operator==(other); | |
13294 } | |
13295 | |
13296 /*! | |
13297 @brief comparison: smaller | |
13298 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13299 */ | |
13300 bool operator<(const iter_impl& other) const | |
13301 { | |
13302 // if objects are not the same, the comparison is undefined | |
13303 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) | |
13304 { | |
13305 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); | |
13306 } | |
13307 | |
13308 JSON_ASSERT(m_object != nullptr); | |
13309 | |
13310 switch (m_object->m_type) | |
13311 { | |
13312 case value_t::object: | |
13313 JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object)); | |
13314 | |
13315 case value_t::array: | |
13316 return (m_it.array_iterator < other.m_it.array_iterator); | |
13317 | |
13318 case value_t::null: | |
13319 case value_t::string: | |
13320 case value_t::boolean: | |
13321 case value_t::number_integer: | |
13322 case value_t::number_unsigned: | |
13323 case value_t::number_float: | |
13324 case value_t::binary: | |
13325 case value_t::discarded: | |
13326 default: | |
13327 return (m_it.primitive_iterator < other.m_it.primitive_iterator); | |
13328 } | |
13329 } | |
13330 | |
13331 /*! | |
13332 @brief comparison: less than or equal | |
13333 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13334 */ | |
13335 bool operator<=(const iter_impl& other) const | |
13336 { | |
13337 return !other.operator < (*this); | |
13338 } | |
13339 | |
13340 /*! | |
13341 @brief comparison: greater than | |
13342 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13343 */ | |
13344 bool operator>(const iter_impl& other) const | |
13345 { | |
13346 return !operator<=(other); | |
13347 } | |
13348 | |
13349 /*! | |
13350 @brief comparison: greater than or equal | |
13351 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13352 */ | |
13353 bool operator>=(const iter_impl& other) const | |
13354 { | |
13355 return !operator<(other); | |
13356 } | |
13357 | |
13358 /*! | |
13359 @brief add to iterator | |
13360 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13361 */ | |
13362 iter_impl& operator+=(difference_type i) | |
13363 { | |
13364 JSON_ASSERT(m_object != nullptr); | |
13365 | |
13366 switch (m_object->m_type) | |
13367 { | |
13368 case value_t::object: | |
13369 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); | |
13370 | |
13371 case value_t::array: | |
13372 { | |
13373 std::advance(m_it.array_iterator, i); | |
13374 break; | |
13375 } | |
13376 | |
13377 case value_t::null: | |
13378 case value_t::string: | |
13379 case value_t::boolean: | |
13380 case value_t::number_integer: | |
13381 case value_t::number_unsigned: | |
13382 case value_t::number_float: | |
13383 case value_t::binary: | |
13384 case value_t::discarded: | |
13385 default: | |
13386 { | |
13387 m_it.primitive_iterator += i; | |
13388 break; | |
13389 } | |
13390 } | |
13391 | |
13392 return *this; | |
13393 } | |
13394 | |
13395 /*! | |
13396 @brief subtract from iterator | |
13397 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13398 */ | |
13399 iter_impl& operator-=(difference_type i) | |
13400 { | |
13401 return operator+=(-i); | |
13402 } | |
13403 | |
13404 /*! | |
13405 @brief add to iterator | |
13406 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13407 */ | |
13408 iter_impl operator+(difference_type i) const | |
13409 { | |
13410 auto result = *this; | |
13411 result += i; | |
13412 return result; | |
13413 } | |
13414 | |
13415 /*! | |
13416 @brief addition of distance and iterator | |
13417 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13418 */ | |
13419 friend iter_impl operator+(difference_type i, const iter_impl& it) | |
13420 { | |
13421 auto result = it; | |
13422 result += i; | |
13423 return result; | |
13424 } | |
13425 | |
13426 /*! | |
13427 @brief subtract from iterator | |
13428 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13429 */ | |
13430 iter_impl operator-(difference_type i) const | |
13431 { | |
13432 auto result = *this; | |
13433 result -= i; | |
13434 return result; | |
13435 } | |
13436 | |
13437 /*! | |
13438 @brief return difference | |
13439 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13440 */ | |
13441 difference_type operator-(const iter_impl& other) const | |
13442 { | |
13443 JSON_ASSERT(m_object != nullptr); | |
13444 | |
13445 switch (m_object->m_type) | |
13446 { | |
13447 case value_t::object: | |
13448 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); | |
13449 | |
13450 case value_t::array: | |
13451 return m_it.array_iterator - other.m_it.array_iterator; | |
13452 | |
13453 case value_t::null: | |
13454 case value_t::string: | |
13455 case value_t::boolean: | |
13456 case value_t::number_integer: | |
13457 case value_t::number_unsigned: | |
13458 case value_t::number_float: | |
13459 case value_t::binary: | |
13460 case value_t::discarded: | |
13461 default: | |
13462 return m_it.primitive_iterator - other.m_it.primitive_iterator; | |
13463 } | |
13464 } | |
13465 | |
13466 /*! | |
13467 @brief access to successor | |
13468 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13469 */ | |
13470 reference operator[](difference_type n) const | |
13471 { | |
13472 JSON_ASSERT(m_object != nullptr); | |
13473 | |
13474 switch (m_object->m_type) | |
13475 { | |
13476 case value_t::object: | |
13477 JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object)); | |
13478 | |
13479 case value_t::array: | |
13480 return *std::next(m_it.array_iterator, n); | |
13481 | |
13482 case value_t::null: | |
13483 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); | |
13484 | |
13485 case value_t::string: | |
13486 case value_t::boolean: | |
13487 case value_t::number_integer: | |
13488 case value_t::number_unsigned: | |
13489 case value_t::number_float: | |
13490 case value_t::binary: | |
13491 case value_t::discarded: | |
13492 default: | |
13493 { | |
13494 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) | |
13495 { | |
13496 return *m_object; | |
13497 } | |
13498 | |
13499 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); | |
13500 } | |
13501 } | |
13502 } | |
13503 | |
13504 /*! | |
13505 @brief return the key of an object iterator | |
13506 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13507 */ | |
13508 const typename object_t::key_type& key() const | |
13509 { | |
13510 JSON_ASSERT(m_object != nullptr); | |
13511 | |
13512 if (JSON_HEDLEY_LIKELY(m_object->is_object())) | |
13513 { | |
13514 return m_it.object_iterator->first; | |
13515 } | |
13516 | |
13517 JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object)); | |
13518 } | |
13519 | |
13520 /*! | |
13521 @brief return the value of an iterator | |
13522 @pre The iterator is initialized; i.e. `m_object != nullptr`. | |
13523 */ | |
13524 reference value() const | |
13525 { | |
13526 return operator*(); | |
13527 } | |
13528 | |
13529 JSON_PRIVATE_UNLESS_TESTED: | |
13530 /// associated JSON instance | |
13531 pointer m_object = nullptr; | |
13532 /// the actual iterator of the associated instance | |
13533 internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {}; | |
13534 }; | |
13535 | |
13536 } // namespace detail | |
13537 NLOHMANN_JSON_NAMESPACE_END | |
13538 | |
13539 // #include <nlohmann/detail/iterators/iteration_proxy.hpp> | |
13540 | |
13541 // #include <nlohmann/detail/iterators/json_reverse_iterator.hpp> | |
13542 // __ _____ _____ _____ | |
13543 // __| | __| | | | JSON for Modern C++ | |
13544 // | | |__ | | | | | | version 3.11.2 | |
13545 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
13546 // | |
13547 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
13548 // SPDX-License-Identifier: MIT | |
13549 | |
13550 | |
13551 | |
13552 #include <cstddef> // ptrdiff_t | |
13553 #include <iterator> // reverse_iterator | |
13554 #include <utility> // declval | |
13555 | |
13556 // #include <nlohmann/detail/abi_macros.hpp> | |
13557 | |
13558 | |
13559 NLOHMANN_JSON_NAMESPACE_BEGIN | |
13560 namespace detail | |
13561 { | |
13562 | |
13563 ////////////////////// | |
13564 // reverse_iterator // | |
13565 ////////////////////// | |
13566 | |
13567 /*! | |
13568 @brief a template for a reverse iterator class | |
13569 | |
13570 @tparam Base the base iterator type to reverse. Valid types are @ref | |
13571 iterator (to create @ref reverse_iterator) and @ref const_iterator (to | |
13572 create @ref const_reverse_iterator). | |
13573 | |
13574 @requirement The class satisfies the following concept requirements: | |
13575 - | |
13576 [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): | |
13577 The iterator that can be moved can be moved in both directions (i.e. | |
13578 incremented and decremented). | |
13579 - [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): | |
13580 It is possible to write to the pointed-to element (only if @a Base is | |
13581 @ref iterator). | |
13582 | |
13583 @since version 1.0.0 | |
13584 */ | |
13585 template<typename Base> | |
13586 class json_reverse_iterator : public std::reverse_iterator<Base> | |
13587 { | |
13588 public: | |
13589 using difference_type = std::ptrdiff_t; | |
13590 /// shortcut to the reverse iterator adapter | |
13591 using base_iterator = std::reverse_iterator<Base>; | |
13592 /// the reference type for the pointed-to element | |
13593 using reference = typename Base::reference; | |
13594 | |
13595 /// create reverse iterator from iterator | |
13596 explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept | |
13597 : base_iterator(it) {} | |
13598 | |
13599 /// create reverse iterator from base class | |
13600 explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} | |
13601 | |
13602 /// post-increment (it++) | |
13603 json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) | |
13604 { | |
13605 return static_cast<json_reverse_iterator>(base_iterator::operator++(1)); | |
13606 } | |
13607 | |
13608 /// pre-increment (++it) | |
13609 json_reverse_iterator& operator++() | |
13610 { | |
13611 return static_cast<json_reverse_iterator&>(base_iterator::operator++()); | |
13612 } | |
13613 | |
13614 /// post-decrement (it--) | |
13615 json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) | |
13616 { | |
13617 return static_cast<json_reverse_iterator>(base_iterator::operator--(1)); | |
13618 } | |
13619 | |
13620 /// pre-decrement (--it) | |
13621 json_reverse_iterator& operator--() | |
13622 { | |
13623 return static_cast<json_reverse_iterator&>(base_iterator::operator--()); | |
13624 } | |
13625 | |
13626 /// add to iterator | |
13627 json_reverse_iterator& operator+=(difference_type i) | |
13628 { | |
13629 return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i)); | |
13630 } | |
13631 | |
13632 /// add to iterator | |
13633 json_reverse_iterator operator+(difference_type i) const | |
13634 { | |
13635 return static_cast<json_reverse_iterator>(base_iterator::operator+(i)); | |
13636 } | |
13637 | |
13638 /// subtract from iterator | |
13639 json_reverse_iterator operator-(difference_type i) const | |
13640 { | |
13641 return static_cast<json_reverse_iterator>(base_iterator::operator-(i)); | |
13642 } | |
13643 | |
13644 /// return difference | |
13645 difference_type operator-(const json_reverse_iterator& other) const | |
13646 { | |
13647 return base_iterator(*this) - base_iterator(other); | |
13648 } | |
13649 | |
13650 /// access to successor | |
13651 reference operator[](difference_type n) const | |
13652 { | |
13653 return *(this->operator+(n)); | |
13654 } | |
13655 | |
13656 /// return the key of an object iterator | |
13657 auto key() const -> decltype(std::declval<Base>().key()) | |
13658 { | |
13659 auto it = --this->base(); | |
13660 return it.key(); | |
13661 } | |
13662 | |
13663 /// return the value of an iterator | |
13664 reference value() const | |
13665 { | |
13666 auto it = --this->base(); | |
13667 return it.operator * (); | |
13668 } | |
13669 }; | |
13670 | |
13671 } // namespace detail | |
13672 NLOHMANN_JSON_NAMESPACE_END | |
13673 | |
13674 // #include <nlohmann/detail/iterators/primitive_iterator.hpp> | |
13675 | |
13676 // #include <nlohmann/detail/json_pointer.hpp> | |
13677 // __ _____ _____ _____ | |
13678 // __| | __| | | | JSON for Modern C++ | |
13679 // | | |__ | | | | | | version 3.11.2 | |
13680 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
13681 // | |
13682 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
13683 // SPDX-License-Identifier: MIT | |
13684 | |
13685 | |
13686 | |
13687 #include <algorithm> // all_of | |
13688 #include <cctype> // isdigit | |
13689 #include <cerrno> // errno, ERANGE | |
13690 #include <cstdlib> // strtoull | |
13691 #ifndef JSON_NO_IO | |
13692 #include <iosfwd> // ostream | |
13693 #endif // JSON_NO_IO | |
13694 #include <limits> // max | |
13695 #include <numeric> // accumulate | |
13696 #include <string> // string | |
13697 #include <utility> // move | |
13698 #include <vector> // vector | |
13699 | |
13700 // #include <nlohmann/detail/exceptions.hpp> | |
13701 | |
13702 // #include <nlohmann/detail/macro_scope.hpp> | |
13703 | |
13704 // #include <nlohmann/detail/string_concat.hpp> | |
13705 | |
13706 // #include <nlohmann/detail/string_escape.hpp> | |
13707 | |
13708 // #include <nlohmann/detail/value_t.hpp> | |
13709 | |
13710 | |
13711 NLOHMANN_JSON_NAMESPACE_BEGIN | |
13712 | |
13713 /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document | |
13714 /// @sa https://json.nlohmann.me/api/json_pointer/ | |
13715 template<typename RefStringType> | |
13716 class json_pointer | |
13717 { | |
13718 // allow basic_json to access private members | |
13719 NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
13720 friend class basic_json; | |
13721 | |
13722 template<typename> | |
13723 friend class json_pointer; | |
13724 | |
13725 template<typename T> | |
13726 struct string_t_helper | |
13727 { | |
13728 using type = T; | |
13729 }; | |
13730 | |
13731 NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
13732 struct string_t_helper<NLOHMANN_BASIC_JSON_TPL> | |
13733 { | |
13734 using type = StringType; | |
13735 }; | |
13736 | |
13737 public: | |
13738 // for backwards compatibility accept BasicJsonType | |
13739 using string_t = typename string_t_helper<RefStringType>::type; | |
13740 | |
13741 /// @brief create JSON pointer | |
13742 /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ | |
13743 explicit json_pointer(const string_t& s = "") | |
13744 : reference_tokens(split(s)) | |
13745 {} | |
13746 | |
13747 /// @brief return a string representation of the JSON pointer | |
13748 /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ | |
13749 string_t to_string() const | |
13750 { | |
13751 return std::accumulate(reference_tokens.begin(), reference_tokens.end(), | |
13752 string_t{}, | |
13753 [](const string_t& a, const string_t& b) | |
13754 { | |
13755 return detail::concat(a, '/', detail::escape(b)); | |
13756 }); | |
13757 } | |
13758 | |
13759 /// @brief return a string representation of the JSON pointer | |
13760 /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ | |
13761 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) | |
13762 operator string_t() const | |
13763 { | |
13764 return to_string(); | |
13765 } | |
13766 | |
13767 #ifndef JSON_NO_IO | |
13768 /// @brief write string representation of the JSON pointer to stream | |
13769 /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ | |
13770 friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr) | |
13771 { | |
13772 o << ptr.to_string(); | |
13773 return o; | |
13774 } | |
13775 #endif | |
13776 | |
13777 /// @brief append another JSON pointer at the end of this JSON pointer | |
13778 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ | |
13779 json_pointer& operator/=(const json_pointer& ptr) | |
13780 { | |
13781 reference_tokens.insert(reference_tokens.end(), | |
13782 ptr.reference_tokens.begin(), | |
13783 ptr.reference_tokens.end()); | |
13784 return *this; | |
13785 } | |
13786 | |
13787 /// @brief append an unescaped reference token at the end of this JSON pointer | |
13788 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ | |
13789 json_pointer& operator/=(string_t token) | |
13790 { | |
13791 push_back(std::move(token)); | |
13792 return *this; | |
13793 } | |
13794 | |
13795 /// @brief append an array index at the end of this JSON pointer | |
13796 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ | |
13797 json_pointer& operator/=(std::size_t array_idx) | |
13798 { | |
13799 return *this /= std::to_string(array_idx); | |
13800 } | |
13801 | |
13802 /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer | |
13803 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ | |
13804 friend json_pointer operator/(const json_pointer& lhs, | |
13805 const json_pointer& rhs) | |
13806 { | |
13807 return json_pointer(lhs) /= rhs; | |
13808 } | |
13809 | |
13810 /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer | |
13811 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ | |
13812 friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) | |
13813 { | |
13814 return json_pointer(lhs) /= std::move(token); | |
13815 } | |
13816 | |
13817 /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer | |
13818 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ | |
13819 friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) | |
13820 { | |
13821 return json_pointer(lhs) /= array_idx; | |
13822 } | |
13823 | |
13824 /// @brief returns the parent of this JSON pointer | |
13825 /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ | |
13826 json_pointer parent_pointer() const | |
13827 { | |
13828 if (empty()) | |
13829 { | |
13830 return *this; | |
13831 } | |
13832 | |
13833 json_pointer res = *this; | |
13834 res.pop_back(); | |
13835 return res; | |
13836 } | |
13837 | |
13838 /// @brief remove last reference token | |
13839 /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ | |
13840 void pop_back() | |
13841 { | |
13842 if (JSON_HEDLEY_UNLIKELY(empty())) | |
13843 { | |
13844 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); | |
13845 } | |
13846 | |
13847 reference_tokens.pop_back(); | |
13848 } | |
13849 | |
13850 /// @brief return last reference token | |
13851 /// @sa https://json.nlohmann.me/api/json_pointer/back/ | |
13852 const string_t& back() const | |
13853 { | |
13854 if (JSON_HEDLEY_UNLIKELY(empty())) | |
13855 { | |
13856 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); | |
13857 } | |
13858 | |
13859 return reference_tokens.back(); | |
13860 } | |
13861 | |
13862 /// @brief append an unescaped token at the end of the reference pointer | |
13863 /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ | |
13864 void push_back(const string_t& token) | |
13865 { | |
13866 reference_tokens.push_back(token); | |
13867 } | |
13868 | |
13869 /// @brief append an unescaped token at the end of the reference pointer | |
13870 /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ | |
13871 void push_back(string_t&& token) | |
13872 { | |
13873 reference_tokens.push_back(std::move(token)); | |
13874 } | |
13875 | |
13876 /// @brief return whether pointer points to the root document | |
13877 /// @sa https://json.nlohmann.me/api/json_pointer/empty/ | |
13878 bool empty() const noexcept | |
13879 { | |
13880 return reference_tokens.empty(); | |
13881 } | |
13882 | |
13883 private: | |
13884 /*! | |
13885 @param[in] s reference token to be converted into an array index | |
13886 | |
13887 @return integer representation of @a s | |
13888 | |
13889 @throw parse_error.106 if an array index begins with '0' | |
13890 @throw parse_error.109 if an array index begins not with a digit | |
13891 @throw out_of_range.404 if string @a s could not be converted to an integer | |
13892 @throw out_of_range.410 if an array index exceeds size_type | |
13893 */ | |
13894 template<typename BasicJsonType> | |
13895 static typename BasicJsonType::size_type array_index(const string_t& s) | |
13896 { | |
13897 using size_type = typename BasicJsonType::size_type; | |
13898 | |
13899 // error condition (cf. RFC 6901, Sect. 4) | |
13900 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) | |
13901 { | |
13902 JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); | |
13903 } | |
13904 | |
13905 // error condition (cf. RFC 6901, Sect. 4) | |
13906 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) | |
13907 { | |
13908 JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); | |
13909 } | |
13910 | |
13911 const char* p = s.c_str(); | |
13912 char* p_end = nullptr; | |
13913 errno = 0; // strtoull doesn't reset errno | |
13914 unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) | |
13915 if (p == p_end // invalid input or empty string | |
13916 || errno == ERANGE // out of range | |
13917 || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read | |
13918 { | |
13919 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); | |
13920 } | |
13921 | |
13922 // only triggered on special platforms (like 32bit), see also | |
13923 // https://github.com/nlohmann/json/pull/2203 | |
13924 if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int) | |
13925 { | |
13926 JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE | |
13927 } | |
13928 | |
13929 return static_cast<size_type>(res); | |
13930 } | |
13931 | |
13932 JSON_PRIVATE_UNLESS_TESTED: | |
13933 json_pointer top() const | |
13934 { | |
13935 if (JSON_HEDLEY_UNLIKELY(empty())) | |
13936 { | |
13937 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); | |
13938 } | |
13939 | |
13940 json_pointer result = *this; | |
13941 result.reference_tokens = {reference_tokens[0]}; | |
13942 return result; | |
13943 } | |
13944 | |
13945 private: | |
13946 /*! | |
13947 @brief create and return a reference to the pointed to value | |
13948 | |
13949 @complexity Linear in the number of reference tokens. | |
13950 | |
13951 @throw parse_error.109 if array index is not a number | |
13952 @throw type_error.313 if value cannot be unflattened | |
13953 */ | |
13954 template<typename BasicJsonType> | |
13955 BasicJsonType& get_and_create(BasicJsonType& j) const | |
13956 { | |
13957 auto* result = &j; | |
13958 | |
13959 // in case no reference tokens exist, return a reference to the JSON value | |
13960 // j which will be overwritten by a primitive value | |
13961 for (const auto& reference_token : reference_tokens) | |
13962 { | |
13963 switch (result->type()) | |
13964 { | |
13965 case detail::value_t::null: | |
13966 { | |
13967 if (reference_token == "0") | |
13968 { | |
13969 // start a new array if reference token is 0 | |
13970 result = &result->operator[](0); | |
13971 } | |
13972 else | |
13973 { | |
13974 // start a new object otherwise | |
13975 result = &result->operator[](reference_token); | |
13976 } | |
13977 break; | |
13978 } | |
13979 | |
13980 case detail::value_t::object: | |
13981 { | |
13982 // create an entry in the object | |
13983 result = &result->operator[](reference_token); | |
13984 break; | |
13985 } | |
13986 | |
13987 case detail::value_t::array: | |
13988 { | |
13989 // create an entry in the array | |
13990 result = &result->operator[](array_index<BasicJsonType>(reference_token)); | |
13991 break; | |
13992 } | |
13993 | |
13994 /* | |
13995 The following code is only reached if there exists a reference | |
13996 token _and_ the current value is primitive. In this case, we have | |
13997 an error situation, because primitive values may only occur as | |
13998 single value; that is, with an empty list of reference tokens. | |
13999 */ | |
14000 case detail::value_t::string: | |
14001 case detail::value_t::boolean: | |
14002 case detail::value_t::number_integer: | |
14003 case detail::value_t::number_unsigned: | |
14004 case detail::value_t::number_float: | |
14005 case detail::value_t::binary: | |
14006 case detail::value_t::discarded: | |
14007 default: | |
14008 JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); | |
14009 } | |
14010 } | |
14011 | |
14012 return *result; | |
14013 } | |
14014 | |
14015 /*! | |
14016 @brief return a reference to the pointed to value | |
14017 | |
14018 @note This version does not throw if a value is not present, but tries to | |
14019 create nested values instead. For instance, calling this function | |
14020 with pointer `"/this/that"` on a null value is equivalent to calling | |
14021 `operator[]("this").operator[]("that")` on that value, effectively | |
14022 changing the null value to an object. | |
14023 | |
14024 @param[in] ptr a JSON value | |
14025 | |
14026 @return reference to the JSON value pointed to by the JSON pointer | |
14027 | |
14028 @complexity Linear in the length of the JSON pointer. | |
14029 | |
14030 @throw parse_error.106 if an array index begins with '0' | |
14031 @throw parse_error.109 if an array index was not a number | |
14032 @throw out_of_range.404 if the JSON pointer can not be resolved | |
14033 */ | |
14034 template<typename BasicJsonType> | |
14035 BasicJsonType& get_unchecked(BasicJsonType* ptr) const | |
14036 { | |
14037 for (const auto& reference_token : reference_tokens) | |
14038 { | |
14039 // convert null values to arrays or objects before continuing | |
14040 if (ptr->is_null()) | |
14041 { | |
14042 // check if reference token is a number | |
14043 const bool nums = | |
14044 std::all_of(reference_token.begin(), reference_token.end(), | |
14045 [](const unsigned char x) | |
14046 { | |
14047 return std::isdigit(x); | |
14048 }); | |
14049 | |
14050 // change value to array for numbers or "-" or to object otherwise | |
14051 *ptr = (nums || reference_token == "-") | |
14052 ? detail::value_t::array | |
14053 : detail::value_t::object; | |
14054 } | |
14055 | |
14056 switch (ptr->type()) | |
14057 { | |
14058 case detail::value_t::object: | |
14059 { | |
14060 // use unchecked object access | |
14061 ptr = &ptr->operator[](reference_token); | |
14062 break; | |
14063 } | |
14064 | |
14065 case detail::value_t::array: | |
14066 { | |
14067 if (reference_token == "-") | |
14068 { | |
14069 // explicitly treat "-" as index beyond the end | |
14070 ptr = &ptr->operator[](ptr->m_value.array->size()); | |
14071 } | |
14072 else | |
14073 { | |
14074 // convert array index to number; unchecked access | |
14075 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token)); | |
14076 } | |
14077 break; | |
14078 } | |
14079 | |
14080 case detail::value_t::null: | |
14081 case detail::value_t::string: | |
14082 case detail::value_t::boolean: | |
14083 case detail::value_t::number_integer: | |
14084 case detail::value_t::number_unsigned: | |
14085 case detail::value_t::number_float: | |
14086 case detail::value_t::binary: | |
14087 case detail::value_t::discarded: | |
14088 default: | |
14089 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); | |
14090 } | |
14091 } | |
14092 | |
14093 return *ptr; | |
14094 } | |
14095 | |
14096 /*! | |
14097 @throw parse_error.106 if an array index begins with '0' | |
14098 @throw parse_error.109 if an array index was not a number | |
14099 @throw out_of_range.402 if the array index '-' is used | |
14100 @throw out_of_range.404 if the JSON pointer can not be resolved | |
14101 */ | |
14102 template<typename BasicJsonType> | |
14103 BasicJsonType& get_checked(BasicJsonType* ptr) const | |
14104 { | |
14105 for (const auto& reference_token : reference_tokens) | |
14106 { | |
14107 switch (ptr->type()) | |
14108 { | |
14109 case detail::value_t::object: | |
14110 { | |
14111 // note: at performs range check | |
14112 ptr = &ptr->at(reference_token); | |
14113 break; | |
14114 } | |
14115 | |
14116 case detail::value_t::array: | |
14117 { | |
14118 if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) | |
14119 { | |
14120 // "-" always fails the range check | |
14121 JSON_THROW(detail::out_of_range::create(402, detail::concat( | |
14122 "array index '-' (", std::to_string(ptr->m_value.array->size()), | |
14123 ") is out of range"), ptr)); | |
14124 } | |
14125 | |
14126 // note: at performs range check | |
14127 ptr = &ptr->at(array_index<BasicJsonType>(reference_token)); | |
14128 break; | |
14129 } | |
14130 | |
14131 case detail::value_t::null: | |
14132 case detail::value_t::string: | |
14133 case detail::value_t::boolean: | |
14134 case detail::value_t::number_integer: | |
14135 case detail::value_t::number_unsigned: | |
14136 case detail::value_t::number_float: | |
14137 case detail::value_t::binary: | |
14138 case detail::value_t::discarded: | |
14139 default: | |
14140 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); | |
14141 } | |
14142 } | |
14143 | |
14144 return *ptr; | |
14145 } | |
14146 | |
14147 /*! | |
14148 @brief return a const reference to the pointed to value | |
14149 | |
14150 @param[in] ptr a JSON value | |
14151 | |
14152 @return const reference to the JSON value pointed to by the JSON | |
14153 pointer | |
14154 | |
14155 @throw parse_error.106 if an array index begins with '0' | |
14156 @throw parse_error.109 if an array index was not a number | |
14157 @throw out_of_range.402 if the array index '-' is used | |
14158 @throw out_of_range.404 if the JSON pointer can not be resolved | |
14159 */ | |
14160 template<typename BasicJsonType> | |
14161 const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const | |
14162 { | |
14163 for (const auto& reference_token : reference_tokens) | |
14164 { | |
14165 switch (ptr->type()) | |
14166 { | |
14167 case detail::value_t::object: | |
14168 { | |
14169 // use unchecked object access | |
14170 ptr = &ptr->operator[](reference_token); | |
14171 break; | |
14172 } | |
14173 | |
14174 case detail::value_t::array: | |
14175 { | |
14176 if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) | |
14177 { | |
14178 // "-" cannot be used for const access | |
14179 JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_value.array->size()), ") is out of range"), ptr)); | |
14180 } | |
14181 | |
14182 // use unchecked array access | |
14183 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token)); | |
14184 break; | |
14185 } | |
14186 | |
14187 case detail::value_t::null: | |
14188 case detail::value_t::string: | |
14189 case detail::value_t::boolean: | |
14190 case detail::value_t::number_integer: | |
14191 case detail::value_t::number_unsigned: | |
14192 case detail::value_t::number_float: | |
14193 case detail::value_t::binary: | |
14194 case detail::value_t::discarded: | |
14195 default: | |
14196 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); | |
14197 } | |
14198 } | |
14199 | |
14200 return *ptr; | |
14201 } | |
14202 | |
14203 /*! | |
14204 @throw parse_error.106 if an array index begins with '0' | |
14205 @throw parse_error.109 if an array index was not a number | |
14206 @throw out_of_range.402 if the array index '-' is used | |
14207 @throw out_of_range.404 if the JSON pointer can not be resolved | |
14208 */ | |
14209 template<typename BasicJsonType> | |
14210 const BasicJsonType& get_checked(const BasicJsonType* ptr) const | |
14211 { | |
14212 for (const auto& reference_token : reference_tokens) | |
14213 { | |
14214 switch (ptr->type()) | |
14215 { | |
14216 case detail::value_t::object: | |
14217 { | |
14218 // note: at performs range check | |
14219 ptr = &ptr->at(reference_token); | |
14220 break; | |
14221 } | |
14222 | |
14223 case detail::value_t::array: | |
14224 { | |
14225 if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) | |
14226 { | |
14227 // "-" always fails the range check | |
14228 JSON_THROW(detail::out_of_range::create(402, detail::concat( | |
14229 "array index '-' (", std::to_string(ptr->m_value.array->size()), | |
14230 ") is out of range"), ptr)); | |
14231 } | |
14232 | |
14233 // note: at performs range check | |
14234 ptr = &ptr->at(array_index<BasicJsonType>(reference_token)); | |
14235 break; | |
14236 } | |
14237 | |
14238 case detail::value_t::null: | |
14239 case detail::value_t::string: | |
14240 case detail::value_t::boolean: | |
14241 case detail::value_t::number_integer: | |
14242 case detail::value_t::number_unsigned: | |
14243 case detail::value_t::number_float: | |
14244 case detail::value_t::binary: | |
14245 case detail::value_t::discarded: | |
14246 default: | |
14247 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); | |
14248 } | |
14249 } | |
14250 | |
14251 return *ptr; | |
14252 } | |
14253 | |
14254 /*! | |
14255 @throw parse_error.106 if an array index begins with '0' | |
14256 @throw parse_error.109 if an array index was not a number | |
14257 */ | |
14258 template<typename BasicJsonType> | |
14259 bool contains(const BasicJsonType* ptr) const | |
14260 { | |
14261 for (const auto& reference_token : reference_tokens) | |
14262 { | |
14263 switch (ptr->type()) | |
14264 { | |
14265 case detail::value_t::object: | |
14266 { | |
14267 if (!ptr->contains(reference_token)) | |
14268 { | |
14269 // we did not find the key in the object | |
14270 return false; | |
14271 } | |
14272 | |
14273 ptr = &ptr->operator[](reference_token); | |
14274 break; | |
14275 } | |
14276 | |
14277 case detail::value_t::array: | |
14278 { | |
14279 if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) | |
14280 { | |
14281 // "-" always fails the range check | |
14282 return false; | |
14283 } | |
14284 if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) | |
14285 { | |
14286 // invalid char | |
14287 return false; | |
14288 } | |
14289 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) | |
14290 { | |
14291 if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) | |
14292 { | |
14293 // first char should be between '1' and '9' | |
14294 return false; | |
14295 } | |
14296 for (std::size_t i = 1; i < reference_token.size(); i++) | |
14297 { | |
14298 if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) | |
14299 { | |
14300 // other char should be between '0' and '9' | |
14301 return false; | |
14302 } | |
14303 } | |
14304 } | |
14305 | |
14306 const auto idx = array_index<BasicJsonType>(reference_token); | |
14307 if (idx >= ptr->size()) | |
14308 { | |
14309 // index out of range | |
14310 return false; | |
14311 } | |
14312 | |
14313 ptr = &ptr->operator[](idx); | |
14314 break; | |
14315 } | |
14316 | |
14317 case detail::value_t::null: | |
14318 case detail::value_t::string: | |
14319 case detail::value_t::boolean: | |
14320 case detail::value_t::number_integer: | |
14321 case detail::value_t::number_unsigned: | |
14322 case detail::value_t::number_float: | |
14323 case detail::value_t::binary: | |
14324 case detail::value_t::discarded: | |
14325 default: | |
14326 { | |
14327 // we do not expect primitive values if there is still a | |
14328 // reference token to process | |
14329 return false; | |
14330 } | |
14331 } | |
14332 } | |
14333 | |
14334 // no reference token left means we found a primitive value | |
14335 return true; | |
14336 } | |
14337 | |
14338 /*! | |
14339 @brief split the string input to reference tokens | |
14340 | |
14341 @note This function is only called by the json_pointer constructor. | |
14342 All exceptions below are documented there. | |
14343 | |
14344 @throw parse_error.107 if the pointer is not empty or begins with '/' | |
14345 @throw parse_error.108 if character '~' is not followed by '0' or '1' | |
14346 */ | |
14347 static std::vector<string_t> split(const string_t& reference_string) | |
14348 { | |
14349 std::vector<string_t> result; | |
14350 | |
14351 // special case: empty reference string -> no reference tokens | |
14352 if (reference_string.empty()) | |
14353 { | |
14354 return result; | |
14355 } | |
14356 | |
14357 // check if nonempty reference string begins with slash | |
14358 if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) | |
14359 { | |
14360 JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); | |
14361 } | |
14362 | |
14363 // extract the reference tokens: | |
14364 // - slash: position of the last read slash (or end of string) | |
14365 // - start: position after the previous slash | |
14366 for ( | |
14367 // search for the first slash after the first character | |
14368 std::size_t slash = reference_string.find_first_of('/', 1), | |
14369 // set the beginning of the first reference token | |
14370 start = 1; | |
14371 // we can stop if start == 0 (if slash == string_t::npos) | |
14372 start != 0; | |
14373 // set the beginning of the next reference token | |
14374 // (will eventually be 0 if slash == string_t::npos) | |
14375 start = (slash == string_t::npos) ? 0 : slash + 1, | |
14376 // find next slash | |
14377 slash = reference_string.find_first_of('/', start)) | |
14378 { | |
14379 // use the text between the beginning of the reference token | |
14380 // (start) and the last slash (slash). | |
14381 auto reference_token = reference_string.substr(start, slash - start); | |
14382 | |
14383 // check reference tokens are properly escaped | |
14384 for (std::size_t pos = reference_token.find_first_of('~'); | |
14385 pos != string_t::npos; | |
14386 pos = reference_token.find_first_of('~', pos + 1)) | |
14387 { | |
14388 JSON_ASSERT(reference_token[pos] == '~'); | |
14389 | |
14390 // ~ must be followed by 0 or 1 | |
14391 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || | |
14392 (reference_token[pos + 1] != '0' && | |
14393 reference_token[pos + 1] != '1'))) | |
14394 { | |
14395 JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); | |
14396 } | |
14397 } | |
14398 | |
14399 // finally, store the reference token | |
14400 detail::unescape(reference_token); | |
14401 result.push_back(reference_token); | |
14402 } | |
14403 | |
14404 return result; | |
14405 } | |
14406 | |
14407 private: | |
14408 /*! | |
14409 @param[in] reference_string the reference string to the current value | |
14410 @param[in] value the value to consider | |
14411 @param[in,out] result the result object to insert values to | |
14412 | |
14413 @note Empty objects or arrays are flattened to `null`. | |
14414 */ | |
14415 template<typename BasicJsonType> | |
14416 static void flatten(const string_t& reference_string, | |
14417 const BasicJsonType& value, | |
14418 BasicJsonType& result) | |
14419 { | |
14420 switch (value.type()) | |
14421 { | |
14422 case detail::value_t::array: | |
14423 { | |
14424 if (value.m_value.array->empty()) | |
14425 { | |
14426 // flatten empty array as null | |
14427 result[reference_string] = nullptr; | |
14428 } | |
14429 else | |
14430 { | |
14431 // iterate array and use index as reference string | |
14432 for (std::size_t i = 0; i < value.m_value.array->size(); ++i) | |
14433 { | |
14434 flatten(detail::concat(reference_string, '/', std::to_string(i)), | |
14435 value.m_value.array->operator[](i), result); | |
14436 } | |
14437 } | |
14438 break; | |
14439 } | |
14440 | |
14441 case detail::value_t::object: | |
14442 { | |
14443 if (value.m_value.object->empty()) | |
14444 { | |
14445 // flatten empty object as null | |
14446 result[reference_string] = nullptr; | |
14447 } | |
14448 else | |
14449 { | |
14450 // iterate object and use keys as reference string | |
14451 for (const auto& element : *value.m_value.object) | |
14452 { | |
14453 flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); | |
14454 } | |
14455 } | |
14456 break; | |
14457 } | |
14458 | |
14459 case detail::value_t::null: | |
14460 case detail::value_t::string: | |
14461 case detail::value_t::boolean: | |
14462 case detail::value_t::number_integer: | |
14463 case detail::value_t::number_unsigned: | |
14464 case detail::value_t::number_float: | |
14465 case detail::value_t::binary: | |
14466 case detail::value_t::discarded: | |
14467 default: | |
14468 { | |
14469 // add primitive value with its reference string | |
14470 result[reference_string] = value; | |
14471 break; | |
14472 } | |
14473 } | |
14474 } | |
14475 | |
14476 /*! | |
14477 @param[in] value flattened JSON | |
14478 | |
14479 @return unflattened JSON | |
14480 | |
14481 @throw parse_error.109 if array index is not a number | |
14482 @throw type_error.314 if value is not an object | |
14483 @throw type_error.315 if object values are not primitive | |
14484 @throw type_error.313 if value cannot be unflattened | |
14485 */ | |
14486 template<typename BasicJsonType> | |
14487 static BasicJsonType | |
14488 unflatten(const BasicJsonType& value) | |
14489 { | |
14490 if (JSON_HEDLEY_UNLIKELY(!value.is_object())) | |
14491 { | |
14492 JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); | |
14493 } | |
14494 | |
14495 BasicJsonType result; | |
14496 | |
14497 // iterate the JSON object values | |
14498 for (const auto& element : *value.m_value.object) | |
14499 { | |
14500 if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) | |
14501 { | |
14502 JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); | |
14503 } | |
14504 | |
14505 // assign value to reference pointed to by JSON pointer; Note that if | |
14506 // the JSON pointer is "" (i.e., points to the whole value), function | |
14507 // get_and_create returns a reference to result itself. An assignment | |
14508 // will then create a primitive value. | |
14509 json_pointer(element.first).get_and_create(result) = element.second; | |
14510 } | |
14511 | |
14512 return result; | |
14513 } | |
14514 | |
14515 // can't use conversion operator because of ambiguity | |
14516 json_pointer<string_t> convert() const& | |
14517 { | |
14518 json_pointer<string_t> result; | |
14519 result.reference_tokens = reference_tokens; | |
14520 return result; | |
14521 } | |
14522 | |
14523 json_pointer<string_t> convert()&& | |
14524 { | |
14525 json_pointer<string_t> result; | |
14526 result.reference_tokens = std::move(reference_tokens); | |
14527 return result; | |
14528 } | |
14529 | |
14530 public: | |
14531 #if JSON_HAS_THREE_WAY_COMPARISON | |
14532 /// @brief compares two JSON pointers for equality | |
14533 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ | |
14534 template<typename RefStringTypeRhs> | |
14535 bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept | |
14536 { | |
14537 return reference_tokens == rhs.reference_tokens; | |
14538 } | |
14539 | |
14540 /// @brief compares JSON pointer and string for equality | |
14541 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ | |
14542 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) | |
14543 bool operator==(const string_t& rhs) const | |
14544 { | |
14545 return *this == json_pointer(rhs); | |
14546 } | |
14547 | |
14548 /// @brief 3-way compares two JSON pointers | |
14549 template<typename RefStringTypeRhs> | |
14550 std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD* | |
14551 { | |
14552 return reference_tokens <=> rhs.reference_tokens; // *NOPAD* | |
14553 } | |
14554 #else | |
14555 /// @brief compares two JSON pointers for equality | |
14556 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ | |
14557 template<typename RefStringTypeLhs, typename RefStringTypeRhs> | |
14558 // NOLINTNEXTLINE(readability-redundant-declaration) | |
14559 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs, | |
14560 const json_pointer<RefStringTypeRhs>& rhs) noexcept; | |
14561 | |
14562 /// @brief compares JSON pointer and string for equality | |
14563 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ | |
14564 template<typename RefStringTypeLhs, typename StringType> | |
14565 // NOLINTNEXTLINE(readability-redundant-declaration) | |
14566 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs, | |
14567 const StringType& rhs); | |
14568 | |
14569 /// @brief compares string and JSON pointer for equality | |
14570 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ | |
14571 template<typename RefStringTypeRhs, typename StringType> | |
14572 // NOLINTNEXTLINE(readability-redundant-declaration) | |
14573 friend bool operator==(const StringType& lhs, | |
14574 const json_pointer<RefStringTypeRhs>& rhs); | |
14575 | |
14576 /// @brief compares two JSON pointers for inequality | |
14577 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ | |
14578 template<typename RefStringTypeLhs, typename RefStringTypeRhs> | |
14579 // NOLINTNEXTLINE(readability-redundant-declaration) | |
14580 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, | |
14581 const json_pointer<RefStringTypeRhs>& rhs) noexcept; | |
14582 | |
14583 /// @brief compares JSON pointer and string for inequality | |
14584 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ | |
14585 template<typename RefStringTypeLhs, typename StringType> | |
14586 // NOLINTNEXTLINE(readability-redundant-declaration) | |
14587 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, | |
14588 const StringType& rhs); | |
14589 | |
14590 /// @brief compares string and JSON pointer for inequality | |
14591 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ | |
14592 template<typename RefStringTypeRhs, typename StringType> | |
14593 // NOLINTNEXTLINE(readability-redundant-declaration) | |
14594 friend bool operator!=(const StringType& lhs, | |
14595 const json_pointer<RefStringTypeRhs>& rhs); | |
14596 | |
14597 /// @brief compares two JSON pointer for less-than | |
14598 template<typename RefStringTypeLhs, typename RefStringTypeRhs> | |
14599 // NOLINTNEXTLINE(readability-redundant-declaration) | |
14600 friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs, | |
14601 const json_pointer<RefStringTypeRhs>& rhs) noexcept; | |
14602 #endif | |
14603 | |
14604 private: | |
14605 /// the reference tokens | |
14606 std::vector<string_t> reference_tokens; | |
14607 }; | |
14608 | |
14609 #if !JSON_HAS_THREE_WAY_COMPARISON | |
14610 // functions cannot be defined inside class due to ODR violations | |
14611 template<typename RefStringTypeLhs, typename RefStringTypeRhs> | |
14612 inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, | |
14613 const json_pointer<RefStringTypeRhs>& rhs) noexcept | |
14614 { | |
14615 return lhs.reference_tokens == rhs.reference_tokens; | |
14616 } | |
14617 | |
14618 template<typename RefStringTypeLhs, | |
14619 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t> | |
14620 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) | |
14621 inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, | |
14622 const StringType& rhs) | |
14623 { | |
14624 return lhs == json_pointer<RefStringTypeLhs>(rhs); | |
14625 } | |
14626 | |
14627 template<typename RefStringTypeRhs, | |
14628 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> | |
14629 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) | |
14630 inline bool operator==(const StringType& lhs, | |
14631 const json_pointer<RefStringTypeRhs>& rhs) | |
14632 { | |
14633 return json_pointer<RefStringTypeRhs>(lhs) == rhs; | |
14634 } | |
14635 | |
14636 template<typename RefStringTypeLhs, typename RefStringTypeRhs> | |
14637 inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, | |
14638 const json_pointer<RefStringTypeRhs>& rhs) noexcept | |
14639 { | |
14640 return !(lhs == rhs); | |
14641 } | |
14642 | |
14643 template<typename RefStringTypeLhs, | |
14644 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t> | |
14645 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) | |
14646 inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, | |
14647 const StringType& rhs) | |
14648 { | |
14649 return !(lhs == rhs); | |
14650 } | |
14651 | |
14652 template<typename RefStringTypeRhs, | |
14653 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> | |
14654 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) | |
14655 inline bool operator!=(const StringType& lhs, | |
14656 const json_pointer<RefStringTypeRhs>& rhs) | |
14657 { | |
14658 return !(lhs == rhs); | |
14659 } | |
14660 | |
14661 template<typename RefStringTypeLhs, typename RefStringTypeRhs> | |
14662 inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs, | |
14663 const json_pointer<RefStringTypeRhs>& rhs) noexcept | |
14664 { | |
14665 return lhs.reference_tokens < rhs.reference_tokens; | |
14666 } | |
14667 #endif | |
14668 | |
14669 NLOHMANN_JSON_NAMESPACE_END | |
14670 | |
14671 // #include <nlohmann/detail/json_ref.hpp> | |
14672 // __ _____ _____ _____ | |
14673 // __| | __| | | | JSON for Modern C++ | |
14674 // | | |__ | | | | | | version 3.11.2 | |
14675 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
14676 // | |
14677 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
14678 // SPDX-License-Identifier: MIT | |
14679 | |
14680 | |
14681 | |
14682 #include <initializer_list> | |
14683 #include <utility> | |
14684 | |
14685 // #include <nlohmann/detail/abi_macros.hpp> | |
14686 | |
14687 // #include <nlohmann/detail/meta/type_traits.hpp> | |
14688 | |
14689 | |
14690 NLOHMANN_JSON_NAMESPACE_BEGIN | |
14691 namespace detail | |
14692 { | |
14693 | |
14694 template<typename BasicJsonType> | |
14695 class json_ref | |
14696 { | |
14697 public: | |
14698 using value_type = BasicJsonType; | |
14699 | |
14700 json_ref(value_type&& value) | |
14701 : owned_value(std::move(value)) | |
14702 {} | |
14703 | |
14704 json_ref(const value_type& value) | |
14705 : value_ref(&value) | |
14706 {} | |
14707 | |
14708 json_ref(std::initializer_list<json_ref> init) | |
14709 : owned_value(init) | |
14710 {} | |
14711 | |
14712 template < | |
14713 class... Args, | |
14714 enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 > | |
14715 json_ref(Args && ... args) | |
14716 : owned_value(std::forward<Args>(args)...) | |
14717 {} | |
14718 | |
14719 // class should be movable only | |
14720 json_ref(json_ref&&) noexcept = default; | |
14721 json_ref(const json_ref&) = delete; | |
14722 json_ref& operator=(const json_ref&) = delete; | |
14723 json_ref& operator=(json_ref&&) = delete; | |
14724 ~json_ref() = default; | |
14725 | |
14726 value_type moved_or_copied() const | |
14727 { | |
14728 if (value_ref == nullptr) | |
14729 { | |
14730 return std::move(owned_value); | |
14731 } | |
14732 return *value_ref; | |
14733 } | |
14734 | |
14735 value_type const& operator*() const | |
14736 { | |
14737 return value_ref ? *value_ref : owned_value; | |
14738 } | |
14739 | |
14740 value_type const* operator->() const | |
14741 { | |
14742 return &** this; | |
14743 } | |
14744 | |
14745 private: | |
14746 mutable value_type owned_value = nullptr; | |
14747 value_type const* value_ref = nullptr; | |
14748 }; | |
14749 | |
14750 } // namespace detail | |
14751 NLOHMANN_JSON_NAMESPACE_END | |
14752 | |
14753 // #include <nlohmann/detail/macro_scope.hpp> | |
14754 | |
14755 // #include <nlohmann/detail/string_concat.hpp> | |
14756 | |
14757 // #include <nlohmann/detail/string_escape.hpp> | |
14758 | |
14759 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
14760 | |
14761 // #include <nlohmann/detail/meta/type_traits.hpp> | |
14762 | |
14763 // #include <nlohmann/detail/output/binary_writer.hpp> | |
14764 // __ _____ _____ _____ | |
14765 // __| | __| | | | JSON for Modern C++ | |
14766 // | | |__ | | | | | | version 3.11.2 | |
14767 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
14768 // | |
14769 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
14770 // SPDX-License-Identifier: MIT | |
14771 | |
14772 | |
14773 | |
14774 #include <algorithm> // reverse | |
14775 #include <array> // array | |
14776 #include <map> // map | |
14777 #include <cmath> // isnan, isinf | |
14778 #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t | |
14779 #include <cstring> // memcpy | |
14780 #include <limits> // numeric_limits | |
14781 #include <string> // string | |
14782 #include <utility> // move | |
14783 #include <vector> // vector | |
14784 | |
14785 // #include <nlohmann/detail/input/binary_reader.hpp> | |
14786 | |
14787 // #include <nlohmann/detail/macro_scope.hpp> | |
14788 | |
14789 // #include <nlohmann/detail/output/output_adapters.hpp> | |
14790 // __ _____ _____ _____ | |
14791 // __| | __| | | | JSON for Modern C++ | |
14792 // | | |__ | | | | | | version 3.11.2 | |
14793 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
14794 // | |
14795 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
14796 // SPDX-License-Identifier: MIT | |
14797 | |
14798 | |
14799 | |
14800 #include <algorithm> // copy | |
14801 #include <cstddef> // size_t | |
14802 #include <iterator> // back_inserter | |
14803 #include <memory> // shared_ptr, make_shared | |
14804 #include <string> // basic_string | |
14805 #include <vector> // vector | |
14806 | |
14807 #ifndef JSON_NO_IO | |
14808 #include <ios> // streamsize | |
14809 #include <ostream> // basic_ostream | |
14810 #endif // JSON_NO_IO | |
14811 | |
14812 // #include <nlohmann/detail/macro_scope.hpp> | |
14813 | |
14814 | |
14815 NLOHMANN_JSON_NAMESPACE_BEGIN | |
14816 namespace detail | |
14817 { | |
14818 | |
14819 /// abstract output adapter interface | |
14820 template<typename CharType> struct output_adapter_protocol | |
14821 { | |
14822 virtual void write_character(CharType c) = 0; | |
14823 virtual void write_characters(const CharType* s, std::size_t length) = 0; | |
14824 virtual ~output_adapter_protocol() = default; | |
14825 | |
14826 output_adapter_protocol() = default; | |
14827 output_adapter_protocol(const output_adapter_protocol&) = default; | |
14828 output_adapter_protocol(output_adapter_protocol&&) noexcept = default; | |
14829 output_adapter_protocol& operator=(const output_adapter_protocol&) = default; | |
14830 output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; | |
14831 }; | |
14832 | |
14833 /// a type to simplify interfaces | |
14834 template<typename CharType> | |
14835 using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>; | |
14836 | |
14837 /// output adapter for byte vectors | |
14838 template<typename CharType, typename AllocatorType = std::allocator<CharType>> | |
14839 class output_vector_adapter : public output_adapter_protocol<CharType> | |
14840 { | |
14841 public: | |
14842 explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept | |
14843 : v(vec) | |
14844 {} | |
14845 | |
14846 void write_character(CharType c) override | |
14847 { | |
14848 v.push_back(c); | |
14849 } | |
14850 | |
14851 JSON_HEDLEY_NON_NULL(2) | |
14852 void write_characters(const CharType* s, std::size_t length) override | |
14853 { | |
14854 v.insert(v.end(), s, s + length); | |
14855 } | |
14856 | |
14857 private: | |
14858 std::vector<CharType, AllocatorType>& v; | |
14859 }; | |
14860 | |
14861 #ifndef JSON_NO_IO | |
14862 /// output adapter for output streams | |
14863 template<typename CharType> | |
14864 class output_stream_adapter : public output_adapter_protocol<CharType> | |
14865 { | |
14866 public: | |
14867 explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept | |
14868 : stream(s) | |
14869 {} | |
14870 | |
14871 void write_character(CharType c) override | |
14872 { | |
14873 stream.put(c); | |
14874 } | |
14875 | |
14876 JSON_HEDLEY_NON_NULL(2) | |
14877 void write_characters(const CharType* s, std::size_t length) override | |
14878 { | |
14879 stream.write(s, static_cast<std::streamsize>(length)); | |
14880 } | |
14881 | |
14882 private: | |
14883 std::basic_ostream<CharType>& stream; | |
14884 }; | |
14885 #endif // JSON_NO_IO | |
14886 | |
14887 /// output adapter for basic_string | |
14888 template<typename CharType, typename StringType = std::basic_string<CharType>> | |
14889 class output_string_adapter : public output_adapter_protocol<CharType> | |
14890 { | |
14891 public: | |
14892 explicit output_string_adapter(StringType& s) noexcept | |
14893 : str(s) | |
14894 {} | |
14895 | |
14896 void write_character(CharType c) override | |
14897 { | |
14898 str.push_back(c); | |
14899 } | |
14900 | |
14901 JSON_HEDLEY_NON_NULL(2) | |
14902 void write_characters(const CharType* s, std::size_t length) override | |
14903 { | |
14904 str.append(s, length); | |
14905 } | |
14906 | |
14907 private: | |
14908 StringType& str; | |
14909 }; | |
14910 | |
14911 template<typename CharType, typename StringType = std::basic_string<CharType>> | |
14912 class output_adapter | |
14913 { | |
14914 public: | |
14915 template<typename AllocatorType = std::allocator<CharType>> | |
14916 output_adapter(std::vector<CharType, AllocatorType>& vec) | |
14917 : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {} | |
14918 | |
14919 #ifndef JSON_NO_IO | |
14920 output_adapter(std::basic_ostream<CharType>& s) | |
14921 : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {} | |
14922 #endif // JSON_NO_IO | |
14923 | |
14924 output_adapter(StringType& s) | |
14925 : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {} | |
14926 | |
14927 operator output_adapter_t<CharType>() | |
14928 { | |
14929 return oa; | |
14930 } | |
14931 | |
14932 private: | |
14933 output_adapter_t<CharType> oa = nullptr; | |
14934 }; | |
14935 | |
14936 } // namespace detail | |
14937 NLOHMANN_JSON_NAMESPACE_END | |
14938 | |
14939 // #include <nlohmann/detail/string_concat.hpp> | |
14940 | |
14941 | |
14942 NLOHMANN_JSON_NAMESPACE_BEGIN | |
14943 namespace detail | |
14944 { | |
14945 | |
14946 /////////////////// | |
14947 // binary writer // | |
14948 /////////////////// | |
14949 | |
14950 /*! | |
14951 @brief serialization to CBOR and MessagePack values | |
14952 */ | |
14953 template<typename BasicJsonType, typename CharType> | |
14954 class binary_writer | |
14955 { | |
14956 using string_t = typename BasicJsonType::string_t; | |
14957 using binary_t = typename BasicJsonType::binary_t; | |
14958 using number_float_t = typename BasicJsonType::number_float_t; | |
14959 | |
14960 public: | |
14961 /*! | |
14962 @brief create a binary writer | |
14963 | |
14964 @param[in] adapter output adapter to write to | |
14965 */ | |
14966 explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter)) | |
14967 { | |
14968 JSON_ASSERT(oa); | |
14969 } | |
14970 | |
14971 /*! | |
14972 @param[in] j JSON value to serialize | |
14973 @pre j.type() == value_t::object | |
14974 */ | |
14975 void write_bson(const BasicJsonType& j) | |
14976 { | |
14977 switch (j.type()) | |
14978 { | |
14979 case value_t::object: | |
14980 { | |
14981 write_bson_object(*j.m_value.object); | |
14982 break; | |
14983 } | |
14984 | |
14985 case value_t::null: | |
14986 case value_t::array: | |
14987 case value_t::string: | |
14988 case value_t::boolean: | |
14989 case value_t::number_integer: | |
14990 case value_t::number_unsigned: | |
14991 case value_t::number_float: | |
14992 case value_t::binary: | |
14993 case value_t::discarded: | |
14994 default: | |
14995 { | |
14996 JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j)); | |
14997 } | |
14998 } | |
14999 } | |
15000 | |
15001 /*! | |
15002 @param[in] j JSON value to serialize | |
15003 */ | |
15004 void write_cbor(const BasicJsonType& j) | |
15005 { | |
15006 switch (j.type()) | |
15007 { | |
15008 case value_t::null: | |
15009 { | |
15010 oa->write_character(to_char_type(0xF6)); | |
15011 break; | |
15012 } | |
15013 | |
15014 case value_t::boolean: | |
15015 { | |
15016 oa->write_character(j.m_value.boolean | |
15017 ? to_char_type(0xF5) | |
15018 : to_char_type(0xF4)); | |
15019 break; | |
15020 } | |
15021 | |
15022 case value_t::number_integer: | |
15023 { | |
15024 if (j.m_value.number_integer >= 0) | |
15025 { | |
15026 // CBOR does not differentiate between positive signed | |
15027 // integers and unsigned integers. Therefore, we used the | |
15028 // code from the value_t::number_unsigned case here. | |
15029 if (j.m_value.number_integer <= 0x17) | |
15030 { | |
15031 write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); | |
15032 } | |
15033 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) | |
15034 { | |
15035 oa->write_character(to_char_type(0x18)); | |
15036 write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); | |
15037 } | |
15038 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()) | |
15039 { | |
15040 oa->write_character(to_char_type(0x19)); | |
15041 write_number(static_cast<std::uint16_t>(j.m_value.number_integer)); | |
15042 } | |
15043 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()) | |
15044 { | |
15045 oa->write_character(to_char_type(0x1A)); | |
15046 write_number(static_cast<std::uint32_t>(j.m_value.number_integer)); | |
15047 } | |
15048 else | |
15049 { | |
15050 oa->write_character(to_char_type(0x1B)); | |
15051 write_number(static_cast<std::uint64_t>(j.m_value.number_integer)); | |
15052 } | |
15053 } | |
15054 else | |
15055 { | |
15056 // The conversions below encode the sign in the first | |
15057 // byte, and the value is converted to a positive number. | |
15058 const auto positive_number = -1 - j.m_value.number_integer; | |
15059 if (j.m_value.number_integer >= -24) | |
15060 { | |
15061 write_number(static_cast<std::uint8_t>(0x20 + positive_number)); | |
15062 } | |
15063 else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)()) | |
15064 { | |
15065 oa->write_character(to_char_type(0x38)); | |
15066 write_number(static_cast<std::uint8_t>(positive_number)); | |
15067 } | |
15068 else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)()) | |
15069 { | |
15070 oa->write_character(to_char_type(0x39)); | |
15071 write_number(static_cast<std::uint16_t>(positive_number)); | |
15072 } | |
15073 else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)()) | |
15074 { | |
15075 oa->write_character(to_char_type(0x3A)); | |
15076 write_number(static_cast<std::uint32_t>(positive_number)); | |
15077 } | |
15078 else | |
15079 { | |
15080 oa->write_character(to_char_type(0x3B)); | |
15081 write_number(static_cast<std::uint64_t>(positive_number)); | |
15082 } | |
15083 } | |
15084 break; | |
15085 } | |
15086 | |
15087 case value_t::number_unsigned: | |
15088 { | |
15089 if (j.m_value.number_unsigned <= 0x17) | |
15090 { | |
15091 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned)); | |
15092 } | |
15093 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) | |
15094 { | |
15095 oa->write_character(to_char_type(0x18)); | |
15096 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned)); | |
15097 } | |
15098 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) | |
15099 { | |
15100 oa->write_character(to_char_type(0x19)); | |
15101 write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned)); | |
15102 } | |
15103 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) | |
15104 { | |
15105 oa->write_character(to_char_type(0x1A)); | |
15106 write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned)); | |
15107 } | |
15108 else | |
15109 { | |
15110 oa->write_character(to_char_type(0x1B)); | |
15111 write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned)); | |
15112 } | |
15113 break; | |
15114 } | |
15115 | |
15116 case value_t::number_float: | |
15117 { | |
15118 if (std::isnan(j.m_value.number_float)) | |
15119 { | |
15120 // NaN is 0xf97e00 in CBOR | |
15121 oa->write_character(to_char_type(0xF9)); | |
15122 oa->write_character(to_char_type(0x7E)); | |
15123 oa->write_character(to_char_type(0x00)); | |
15124 } | |
15125 else if (std::isinf(j.m_value.number_float)) | |
15126 { | |
15127 // Infinity is 0xf97c00, -Infinity is 0xf9fc00 | |
15128 oa->write_character(to_char_type(0xf9)); | |
15129 oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); | |
15130 oa->write_character(to_char_type(0x00)); | |
15131 } | |
15132 else | |
15133 { | |
15134 write_compact_float(j.m_value.number_float, detail::input_format_t::cbor); | |
15135 } | |
15136 break; | |
15137 } | |
15138 | |
15139 case value_t::string: | |
15140 { | |
15141 // step 1: write control byte and the string length | |
15142 const auto N = j.m_value.string->size(); | |
15143 if (N <= 0x17) | |
15144 { | |
15145 write_number(static_cast<std::uint8_t>(0x60 + N)); | |
15146 } | |
15147 else if (N <= (std::numeric_limits<std::uint8_t>::max)()) | |
15148 { | |
15149 oa->write_character(to_char_type(0x78)); | |
15150 write_number(static_cast<std::uint8_t>(N)); | |
15151 } | |
15152 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15153 { | |
15154 oa->write_character(to_char_type(0x79)); | |
15155 write_number(static_cast<std::uint16_t>(N)); | |
15156 } | |
15157 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15158 { | |
15159 oa->write_character(to_char_type(0x7A)); | |
15160 write_number(static_cast<std::uint32_t>(N)); | |
15161 } | |
15162 // LCOV_EXCL_START | |
15163 else if (N <= (std::numeric_limits<std::uint64_t>::max)()) | |
15164 { | |
15165 oa->write_character(to_char_type(0x7B)); | |
15166 write_number(static_cast<std::uint64_t>(N)); | |
15167 } | |
15168 // LCOV_EXCL_STOP | |
15169 | |
15170 // step 2: write the string | |
15171 oa->write_characters( | |
15172 reinterpret_cast<const CharType*>(j.m_value.string->c_str()), | |
15173 j.m_value.string->size()); | |
15174 break; | |
15175 } | |
15176 | |
15177 case value_t::array: | |
15178 { | |
15179 // step 1: write control byte and the array size | |
15180 const auto N = j.m_value.array->size(); | |
15181 if (N <= 0x17) | |
15182 { | |
15183 write_number(static_cast<std::uint8_t>(0x80 + N)); | |
15184 } | |
15185 else if (N <= (std::numeric_limits<std::uint8_t>::max)()) | |
15186 { | |
15187 oa->write_character(to_char_type(0x98)); | |
15188 write_number(static_cast<std::uint8_t>(N)); | |
15189 } | |
15190 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15191 { | |
15192 oa->write_character(to_char_type(0x99)); | |
15193 write_number(static_cast<std::uint16_t>(N)); | |
15194 } | |
15195 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15196 { | |
15197 oa->write_character(to_char_type(0x9A)); | |
15198 write_number(static_cast<std::uint32_t>(N)); | |
15199 } | |
15200 // LCOV_EXCL_START | |
15201 else if (N <= (std::numeric_limits<std::uint64_t>::max)()) | |
15202 { | |
15203 oa->write_character(to_char_type(0x9B)); | |
15204 write_number(static_cast<std::uint64_t>(N)); | |
15205 } | |
15206 // LCOV_EXCL_STOP | |
15207 | |
15208 // step 2: write each element | |
15209 for (const auto& el : *j.m_value.array) | |
15210 { | |
15211 write_cbor(el); | |
15212 } | |
15213 break; | |
15214 } | |
15215 | |
15216 case value_t::binary: | |
15217 { | |
15218 if (j.m_value.binary->has_subtype()) | |
15219 { | |
15220 if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)()) | |
15221 { | |
15222 write_number(static_cast<std::uint8_t>(0xd8)); | |
15223 write_number(static_cast<std::uint8_t>(j.m_value.binary->subtype())); | |
15224 } | |
15225 else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)()) | |
15226 { | |
15227 write_number(static_cast<std::uint8_t>(0xd9)); | |
15228 write_number(static_cast<std::uint16_t>(j.m_value.binary->subtype())); | |
15229 } | |
15230 else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)()) | |
15231 { | |
15232 write_number(static_cast<std::uint8_t>(0xda)); | |
15233 write_number(static_cast<std::uint32_t>(j.m_value.binary->subtype())); | |
15234 } | |
15235 else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)()) | |
15236 { | |
15237 write_number(static_cast<std::uint8_t>(0xdb)); | |
15238 write_number(static_cast<std::uint64_t>(j.m_value.binary->subtype())); | |
15239 } | |
15240 } | |
15241 | |
15242 // step 1: write control byte and the binary array size | |
15243 const auto N = j.m_value.binary->size(); | |
15244 if (N <= 0x17) | |
15245 { | |
15246 write_number(static_cast<std::uint8_t>(0x40 + N)); | |
15247 } | |
15248 else if (N <= (std::numeric_limits<std::uint8_t>::max)()) | |
15249 { | |
15250 oa->write_character(to_char_type(0x58)); | |
15251 write_number(static_cast<std::uint8_t>(N)); | |
15252 } | |
15253 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15254 { | |
15255 oa->write_character(to_char_type(0x59)); | |
15256 write_number(static_cast<std::uint16_t>(N)); | |
15257 } | |
15258 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15259 { | |
15260 oa->write_character(to_char_type(0x5A)); | |
15261 write_number(static_cast<std::uint32_t>(N)); | |
15262 } | |
15263 // LCOV_EXCL_START | |
15264 else if (N <= (std::numeric_limits<std::uint64_t>::max)()) | |
15265 { | |
15266 oa->write_character(to_char_type(0x5B)); | |
15267 write_number(static_cast<std::uint64_t>(N)); | |
15268 } | |
15269 // LCOV_EXCL_STOP | |
15270 | |
15271 // step 2: write each element | |
15272 oa->write_characters( | |
15273 reinterpret_cast<const CharType*>(j.m_value.binary->data()), | |
15274 N); | |
15275 | |
15276 break; | |
15277 } | |
15278 | |
15279 case value_t::object: | |
15280 { | |
15281 // step 1: write control byte and the object size | |
15282 const auto N = j.m_value.object->size(); | |
15283 if (N <= 0x17) | |
15284 { | |
15285 write_number(static_cast<std::uint8_t>(0xA0 + N)); | |
15286 } | |
15287 else if (N <= (std::numeric_limits<std::uint8_t>::max)()) | |
15288 { | |
15289 oa->write_character(to_char_type(0xB8)); | |
15290 write_number(static_cast<std::uint8_t>(N)); | |
15291 } | |
15292 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15293 { | |
15294 oa->write_character(to_char_type(0xB9)); | |
15295 write_number(static_cast<std::uint16_t>(N)); | |
15296 } | |
15297 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15298 { | |
15299 oa->write_character(to_char_type(0xBA)); | |
15300 write_number(static_cast<std::uint32_t>(N)); | |
15301 } | |
15302 // LCOV_EXCL_START | |
15303 else if (N <= (std::numeric_limits<std::uint64_t>::max)()) | |
15304 { | |
15305 oa->write_character(to_char_type(0xBB)); | |
15306 write_number(static_cast<std::uint64_t>(N)); | |
15307 } | |
15308 // LCOV_EXCL_STOP | |
15309 | |
15310 // step 2: write each element | |
15311 for (const auto& el : *j.m_value.object) | |
15312 { | |
15313 write_cbor(el.first); | |
15314 write_cbor(el.second); | |
15315 } | |
15316 break; | |
15317 } | |
15318 | |
15319 case value_t::discarded: | |
15320 default: | |
15321 break; | |
15322 } | |
15323 } | |
15324 | |
15325 /*! | |
15326 @param[in] j JSON value to serialize | |
15327 */ | |
15328 void write_msgpack(const BasicJsonType& j) | |
15329 { | |
15330 switch (j.type()) | |
15331 { | |
15332 case value_t::null: // nil | |
15333 { | |
15334 oa->write_character(to_char_type(0xC0)); | |
15335 break; | |
15336 } | |
15337 | |
15338 case value_t::boolean: // true and false | |
15339 { | |
15340 oa->write_character(j.m_value.boolean | |
15341 ? to_char_type(0xC3) | |
15342 : to_char_type(0xC2)); | |
15343 break; | |
15344 } | |
15345 | |
15346 case value_t::number_integer: | |
15347 { | |
15348 if (j.m_value.number_integer >= 0) | |
15349 { | |
15350 // MessagePack does not differentiate between positive | |
15351 // signed integers and unsigned integers. Therefore, we used | |
15352 // the code from the value_t::number_unsigned case here. | |
15353 if (j.m_value.number_unsigned < 128) | |
15354 { | |
15355 // positive fixnum | |
15356 write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); | |
15357 } | |
15358 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) | |
15359 { | |
15360 // uint 8 | |
15361 oa->write_character(to_char_type(0xCC)); | |
15362 write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); | |
15363 } | |
15364 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) | |
15365 { | |
15366 // uint 16 | |
15367 oa->write_character(to_char_type(0xCD)); | |
15368 write_number(static_cast<std::uint16_t>(j.m_value.number_integer)); | |
15369 } | |
15370 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) | |
15371 { | |
15372 // uint 32 | |
15373 oa->write_character(to_char_type(0xCE)); | |
15374 write_number(static_cast<std::uint32_t>(j.m_value.number_integer)); | |
15375 } | |
15376 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) | |
15377 { | |
15378 // uint 64 | |
15379 oa->write_character(to_char_type(0xCF)); | |
15380 write_number(static_cast<std::uint64_t>(j.m_value.number_integer)); | |
15381 } | |
15382 } | |
15383 else | |
15384 { | |
15385 if (j.m_value.number_integer >= -32) | |
15386 { | |
15387 // negative fixnum | |
15388 write_number(static_cast<std::int8_t>(j.m_value.number_integer)); | |
15389 } | |
15390 else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() && | |
15391 j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) | |
15392 { | |
15393 // int 8 | |
15394 oa->write_character(to_char_type(0xD0)); | |
15395 write_number(static_cast<std::int8_t>(j.m_value.number_integer)); | |
15396 } | |
15397 else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() && | |
15398 j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) | |
15399 { | |
15400 // int 16 | |
15401 oa->write_character(to_char_type(0xD1)); | |
15402 write_number(static_cast<std::int16_t>(j.m_value.number_integer)); | |
15403 } | |
15404 else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() && | |
15405 j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) | |
15406 { | |
15407 // int 32 | |
15408 oa->write_character(to_char_type(0xD2)); | |
15409 write_number(static_cast<std::int32_t>(j.m_value.number_integer)); | |
15410 } | |
15411 else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() && | |
15412 j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) | |
15413 { | |
15414 // int 64 | |
15415 oa->write_character(to_char_type(0xD3)); | |
15416 write_number(static_cast<std::int64_t>(j.m_value.number_integer)); | |
15417 } | |
15418 } | |
15419 break; | |
15420 } | |
15421 | |
15422 case value_t::number_unsigned: | |
15423 { | |
15424 if (j.m_value.number_unsigned < 128) | |
15425 { | |
15426 // positive fixnum | |
15427 write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); | |
15428 } | |
15429 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) | |
15430 { | |
15431 // uint 8 | |
15432 oa->write_character(to_char_type(0xCC)); | |
15433 write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); | |
15434 } | |
15435 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) | |
15436 { | |
15437 // uint 16 | |
15438 oa->write_character(to_char_type(0xCD)); | |
15439 write_number(static_cast<std::uint16_t>(j.m_value.number_integer)); | |
15440 } | |
15441 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) | |
15442 { | |
15443 // uint 32 | |
15444 oa->write_character(to_char_type(0xCE)); | |
15445 write_number(static_cast<std::uint32_t>(j.m_value.number_integer)); | |
15446 } | |
15447 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) | |
15448 { | |
15449 // uint 64 | |
15450 oa->write_character(to_char_type(0xCF)); | |
15451 write_number(static_cast<std::uint64_t>(j.m_value.number_integer)); | |
15452 } | |
15453 break; | |
15454 } | |
15455 | |
15456 case value_t::number_float: | |
15457 { | |
15458 write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack); | |
15459 break; | |
15460 } | |
15461 | |
15462 case value_t::string: | |
15463 { | |
15464 // step 1: write control byte and the string length | |
15465 const auto N = j.m_value.string->size(); | |
15466 if (N <= 31) | |
15467 { | |
15468 // fixstr | |
15469 write_number(static_cast<std::uint8_t>(0xA0 | N)); | |
15470 } | |
15471 else if (N <= (std::numeric_limits<std::uint8_t>::max)()) | |
15472 { | |
15473 // str 8 | |
15474 oa->write_character(to_char_type(0xD9)); | |
15475 write_number(static_cast<std::uint8_t>(N)); | |
15476 } | |
15477 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15478 { | |
15479 // str 16 | |
15480 oa->write_character(to_char_type(0xDA)); | |
15481 write_number(static_cast<std::uint16_t>(N)); | |
15482 } | |
15483 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15484 { | |
15485 // str 32 | |
15486 oa->write_character(to_char_type(0xDB)); | |
15487 write_number(static_cast<std::uint32_t>(N)); | |
15488 } | |
15489 | |
15490 // step 2: write the string | |
15491 oa->write_characters( | |
15492 reinterpret_cast<const CharType*>(j.m_value.string->c_str()), | |
15493 j.m_value.string->size()); | |
15494 break; | |
15495 } | |
15496 | |
15497 case value_t::array: | |
15498 { | |
15499 // step 1: write control byte and the array size | |
15500 const auto N = j.m_value.array->size(); | |
15501 if (N <= 15) | |
15502 { | |
15503 // fixarray | |
15504 write_number(static_cast<std::uint8_t>(0x90 | N)); | |
15505 } | |
15506 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15507 { | |
15508 // array 16 | |
15509 oa->write_character(to_char_type(0xDC)); | |
15510 write_number(static_cast<std::uint16_t>(N)); | |
15511 } | |
15512 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15513 { | |
15514 // array 32 | |
15515 oa->write_character(to_char_type(0xDD)); | |
15516 write_number(static_cast<std::uint32_t>(N)); | |
15517 } | |
15518 | |
15519 // step 2: write each element | |
15520 for (const auto& el : *j.m_value.array) | |
15521 { | |
15522 write_msgpack(el); | |
15523 } | |
15524 break; | |
15525 } | |
15526 | |
15527 case value_t::binary: | |
15528 { | |
15529 // step 0: determine if the binary type has a set subtype to | |
15530 // determine whether or not to use the ext or fixext types | |
15531 const bool use_ext = j.m_value.binary->has_subtype(); | |
15532 | |
15533 // step 1: write control byte and the byte string length | |
15534 const auto N = j.m_value.binary->size(); | |
15535 if (N <= (std::numeric_limits<std::uint8_t>::max)()) | |
15536 { | |
15537 std::uint8_t output_type{}; | |
15538 bool fixed = true; | |
15539 if (use_ext) | |
15540 { | |
15541 switch (N) | |
15542 { | |
15543 case 1: | |
15544 output_type = 0xD4; // fixext 1 | |
15545 break; | |
15546 case 2: | |
15547 output_type = 0xD5; // fixext 2 | |
15548 break; | |
15549 case 4: | |
15550 output_type = 0xD6; // fixext 4 | |
15551 break; | |
15552 case 8: | |
15553 output_type = 0xD7; // fixext 8 | |
15554 break; | |
15555 case 16: | |
15556 output_type = 0xD8; // fixext 16 | |
15557 break; | |
15558 default: | |
15559 output_type = 0xC7; // ext 8 | |
15560 fixed = false; | |
15561 break; | |
15562 } | |
15563 | |
15564 } | |
15565 else | |
15566 { | |
15567 output_type = 0xC4; // bin 8 | |
15568 fixed = false; | |
15569 } | |
15570 | |
15571 oa->write_character(to_char_type(output_type)); | |
15572 if (!fixed) | |
15573 { | |
15574 write_number(static_cast<std::uint8_t>(N)); | |
15575 } | |
15576 } | |
15577 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15578 { | |
15579 std::uint8_t output_type = use_ext | |
15580 ? 0xC8 // ext 16 | |
15581 : 0xC5; // bin 16 | |
15582 | |
15583 oa->write_character(to_char_type(output_type)); | |
15584 write_number(static_cast<std::uint16_t>(N)); | |
15585 } | |
15586 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15587 { | |
15588 std::uint8_t output_type = use_ext | |
15589 ? 0xC9 // ext 32 | |
15590 : 0xC6; // bin 32 | |
15591 | |
15592 oa->write_character(to_char_type(output_type)); | |
15593 write_number(static_cast<std::uint32_t>(N)); | |
15594 } | |
15595 | |
15596 // step 1.5: if this is an ext type, write the subtype | |
15597 if (use_ext) | |
15598 { | |
15599 write_number(static_cast<std::int8_t>(j.m_value.binary->subtype())); | |
15600 } | |
15601 | |
15602 // step 2: write the byte string | |
15603 oa->write_characters( | |
15604 reinterpret_cast<const CharType*>(j.m_value.binary->data()), | |
15605 N); | |
15606 | |
15607 break; | |
15608 } | |
15609 | |
15610 case value_t::object: | |
15611 { | |
15612 // step 1: write control byte and the object size | |
15613 const auto N = j.m_value.object->size(); | |
15614 if (N <= 15) | |
15615 { | |
15616 // fixmap | |
15617 write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF))); | |
15618 } | |
15619 else if (N <= (std::numeric_limits<std::uint16_t>::max)()) | |
15620 { | |
15621 // map 16 | |
15622 oa->write_character(to_char_type(0xDE)); | |
15623 write_number(static_cast<std::uint16_t>(N)); | |
15624 } | |
15625 else if (N <= (std::numeric_limits<std::uint32_t>::max)()) | |
15626 { | |
15627 // map 32 | |
15628 oa->write_character(to_char_type(0xDF)); | |
15629 write_number(static_cast<std::uint32_t>(N)); | |
15630 } | |
15631 | |
15632 // step 2: write each element | |
15633 for (const auto& el : *j.m_value.object) | |
15634 { | |
15635 write_msgpack(el.first); | |
15636 write_msgpack(el.second); | |
15637 } | |
15638 break; | |
15639 } | |
15640 | |
15641 case value_t::discarded: | |
15642 default: | |
15643 break; | |
15644 } | |
15645 } | |
15646 | |
15647 /*! | |
15648 @param[in] j JSON value to serialize | |
15649 @param[in] use_count whether to use '#' prefixes (optimized format) | |
15650 @param[in] use_type whether to use '$' prefixes (optimized format) | |
15651 @param[in] add_prefix whether prefixes need to be used for this value | |
15652 @param[in] use_bjdata whether write in BJData format, default is false | |
15653 */ | |
15654 void write_ubjson(const BasicJsonType& j, const bool use_count, | |
15655 const bool use_type, const bool add_prefix = true, | |
15656 const bool use_bjdata = false) | |
15657 { | |
15658 switch (j.type()) | |
15659 { | |
15660 case value_t::null: | |
15661 { | |
15662 if (add_prefix) | |
15663 { | |
15664 oa->write_character(to_char_type('Z')); | |
15665 } | |
15666 break; | |
15667 } | |
15668 | |
15669 case value_t::boolean: | |
15670 { | |
15671 if (add_prefix) | |
15672 { | |
15673 oa->write_character(j.m_value.boolean | |
15674 ? to_char_type('T') | |
15675 : to_char_type('F')); | |
15676 } | |
15677 break; | |
15678 } | |
15679 | |
15680 case value_t::number_integer: | |
15681 { | |
15682 write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix, use_bjdata); | |
15683 break; | |
15684 } | |
15685 | |
15686 case value_t::number_unsigned: | |
15687 { | |
15688 write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix, use_bjdata); | |
15689 break; | |
15690 } | |
15691 | |
15692 case value_t::number_float: | |
15693 { | |
15694 write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix, use_bjdata); | |
15695 break; | |
15696 } | |
15697 | |
15698 case value_t::string: | |
15699 { | |
15700 if (add_prefix) | |
15701 { | |
15702 oa->write_character(to_char_type('S')); | |
15703 } | |
15704 write_number_with_ubjson_prefix(j.m_value.string->size(), true, use_bjdata); | |
15705 oa->write_characters( | |
15706 reinterpret_cast<const CharType*>(j.m_value.string->c_str()), | |
15707 j.m_value.string->size()); | |
15708 break; | |
15709 } | |
15710 | |
15711 case value_t::array: | |
15712 { | |
15713 if (add_prefix) | |
15714 { | |
15715 oa->write_character(to_char_type('[')); | |
15716 } | |
15717 | |
15718 bool prefix_required = true; | |
15719 if (use_type && !j.m_value.array->empty()) | |
15720 { | |
15721 JSON_ASSERT(use_count); | |
15722 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); | |
15723 const bool same_prefix = std::all_of(j.begin() + 1, j.end(), | |
15724 [this, first_prefix, use_bjdata](const BasicJsonType & v) | |
15725 { | |
15726 return ubjson_prefix(v, use_bjdata) == first_prefix; | |
15727 }); | |
15728 | |
15729 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type | |
15730 | |
15731 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) | |
15732 { | |
15733 prefix_required = false; | |
15734 oa->write_character(to_char_type('$')); | |
15735 oa->write_character(first_prefix); | |
15736 } | |
15737 } | |
15738 | |
15739 if (use_count) | |
15740 { | |
15741 oa->write_character(to_char_type('#')); | |
15742 write_number_with_ubjson_prefix(j.m_value.array->size(), true, use_bjdata); | |
15743 } | |
15744 | |
15745 for (const auto& el : *j.m_value.array) | |
15746 { | |
15747 write_ubjson(el, use_count, use_type, prefix_required, use_bjdata); | |
15748 } | |
15749 | |
15750 if (!use_count) | |
15751 { | |
15752 oa->write_character(to_char_type(']')); | |
15753 } | |
15754 | |
15755 break; | |
15756 } | |
15757 | |
15758 case value_t::binary: | |
15759 { | |
15760 if (add_prefix) | |
15761 { | |
15762 oa->write_character(to_char_type('[')); | |
15763 } | |
15764 | |
15765 if (use_type && !j.m_value.binary->empty()) | |
15766 { | |
15767 JSON_ASSERT(use_count); | |
15768 oa->write_character(to_char_type('$')); | |
15769 oa->write_character('U'); | |
15770 } | |
15771 | |
15772 if (use_count) | |
15773 { | |
15774 oa->write_character(to_char_type('#')); | |
15775 write_number_with_ubjson_prefix(j.m_value.binary->size(), true, use_bjdata); | |
15776 } | |
15777 | |
15778 if (use_type) | |
15779 { | |
15780 oa->write_characters( | |
15781 reinterpret_cast<const CharType*>(j.m_value.binary->data()), | |
15782 j.m_value.binary->size()); | |
15783 } | |
15784 else | |
15785 { | |
15786 for (size_t i = 0; i < j.m_value.binary->size(); ++i) | |
15787 { | |
15788 oa->write_character(to_char_type('U')); | |
15789 oa->write_character(j.m_value.binary->data()[i]); | |
15790 } | |
15791 } | |
15792 | |
15793 if (!use_count) | |
15794 { | |
15795 oa->write_character(to_char_type(']')); | |
15796 } | |
15797 | |
15798 break; | |
15799 } | |
15800 | |
15801 case value_t::object: | |
15802 { | |
15803 if (use_bjdata && j.m_value.object->size() == 3 && j.m_value.object->find("_ArrayType_") != j.m_value.object->end() && j.m_value.object->find("_ArraySize_") != j.m_value.object->end() && j.m_value.object->find("_ArrayData_") != j.m_value.object->end()) | |
15804 { | |
15805 if (!write_bjdata_ndarray(*j.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) | |
15806 { | |
15807 break; | |
15808 } | |
15809 } | |
15810 | |
15811 if (add_prefix) | |
15812 { | |
15813 oa->write_character(to_char_type('{')); | |
15814 } | |
15815 | |
15816 bool prefix_required = true; | |
15817 if (use_type && !j.m_value.object->empty()) | |
15818 { | |
15819 JSON_ASSERT(use_count); | |
15820 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); | |
15821 const bool same_prefix = std::all_of(j.begin(), j.end(), | |
15822 [this, first_prefix, use_bjdata](const BasicJsonType & v) | |
15823 { | |
15824 return ubjson_prefix(v, use_bjdata) == first_prefix; | |
15825 }); | |
15826 | |
15827 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type | |
15828 | |
15829 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) | |
15830 { | |
15831 prefix_required = false; | |
15832 oa->write_character(to_char_type('$')); | |
15833 oa->write_character(first_prefix); | |
15834 } | |
15835 } | |
15836 | |
15837 if (use_count) | |
15838 { | |
15839 oa->write_character(to_char_type('#')); | |
15840 write_number_with_ubjson_prefix(j.m_value.object->size(), true, use_bjdata); | |
15841 } | |
15842 | |
15843 for (const auto& el : *j.m_value.object) | |
15844 { | |
15845 write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata); | |
15846 oa->write_characters( | |
15847 reinterpret_cast<const CharType*>(el.first.c_str()), | |
15848 el.first.size()); | |
15849 write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata); | |
15850 } | |
15851 | |
15852 if (!use_count) | |
15853 { | |
15854 oa->write_character(to_char_type('}')); | |
15855 } | |
15856 | |
15857 break; | |
15858 } | |
15859 | |
15860 case value_t::discarded: | |
15861 default: | |
15862 break; | |
15863 } | |
15864 } | |
15865 | |
15866 private: | |
15867 ////////// | |
15868 // BSON // | |
15869 ////////// | |
15870 | |
15871 /*! | |
15872 @return The size of a BSON document entry header, including the id marker | |
15873 and the entry name size (and its null-terminator). | |
15874 */ | |
15875 static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j) | |
15876 { | |
15877 const auto it = name.find(static_cast<typename string_t::value_type>(0)); | |
15878 if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) | |
15879 { | |
15880 JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); | |
15881 static_cast<void>(j); | |
15882 } | |
15883 | |
15884 return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; | |
15885 } | |
15886 | |
15887 /*! | |
15888 @brief Writes the given @a element_type and @a name to the output adapter | |
15889 */ | |
15890 void write_bson_entry_header(const string_t& name, | |
15891 const std::uint8_t element_type) | |
15892 { | |
15893 oa->write_character(to_char_type(element_type)); // boolean | |
15894 oa->write_characters( | |
15895 reinterpret_cast<const CharType*>(name.c_str()), | |
15896 name.size() + 1u); | |
15897 } | |
15898 | |
15899 /*! | |
15900 @brief Writes a BSON element with key @a name and boolean value @a value | |
15901 */ | |
15902 void write_bson_boolean(const string_t& name, | |
15903 const bool value) | |
15904 { | |
15905 write_bson_entry_header(name, 0x08); | |
15906 oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); | |
15907 } | |
15908 | |
15909 /*! | |
15910 @brief Writes a BSON element with key @a name and double value @a value | |
15911 */ | |
15912 void write_bson_double(const string_t& name, | |
15913 const double value) | |
15914 { | |
15915 write_bson_entry_header(name, 0x01); | |
15916 write_number<double>(value, true); | |
15917 } | |
15918 | |
15919 /*! | |
15920 @return The size of the BSON-encoded string in @a value | |
15921 */ | |
15922 static std::size_t calc_bson_string_size(const string_t& value) | |
15923 { | |
15924 return sizeof(std::int32_t) + value.size() + 1ul; | |
15925 } | |
15926 | |
15927 /*! | |
15928 @brief Writes a BSON element with key @a name and string value @a value | |
15929 */ | |
15930 void write_bson_string(const string_t& name, | |
15931 const string_t& value) | |
15932 { | |
15933 write_bson_entry_header(name, 0x02); | |
15934 | |
15935 write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true); | |
15936 oa->write_characters( | |
15937 reinterpret_cast<const CharType*>(value.c_str()), | |
15938 value.size() + 1); | |
15939 } | |
15940 | |
15941 /*! | |
15942 @brief Writes a BSON element with key @a name and null value | |
15943 */ | |
15944 void write_bson_null(const string_t& name) | |
15945 { | |
15946 write_bson_entry_header(name, 0x0A); | |
15947 } | |
15948 | |
15949 /*! | |
15950 @return The size of the BSON-encoded integer @a value | |
15951 */ | |
15952 static std::size_t calc_bson_integer_size(const std::int64_t value) | |
15953 { | |
15954 return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)() | |
15955 ? sizeof(std::int32_t) | |
15956 : sizeof(std::int64_t); | |
15957 } | |
15958 | |
15959 /*! | |
15960 @brief Writes a BSON element with key @a name and integer @a value | |
15961 */ | |
15962 void write_bson_integer(const string_t& name, | |
15963 const std::int64_t value) | |
15964 { | |
15965 if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()) | |
15966 { | |
15967 write_bson_entry_header(name, 0x10); // int32 | |
15968 write_number<std::int32_t>(static_cast<std::int32_t>(value), true); | |
15969 } | |
15970 else | |
15971 { | |
15972 write_bson_entry_header(name, 0x12); // int64 | |
15973 write_number<std::int64_t>(static_cast<std::int64_t>(value), true); | |
15974 } | |
15975 } | |
15976 | |
15977 /*! | |
15978 @return The size of the BSON-encoded unsigned integer in @a j | |
15979 */ | |
15980 static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept | |
15981 { | |
15982 return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) | |
15983 ? sizeof(std::int32_t) | |
15984 : sizeof(std::int64_t); | |
15985 } | |
15986 | |
15987 /*! | |
15988 @brief Writes a BSON element with key @a name and unsigned @a value | |
15989 */ | |
15990 void write_bson_unsigned(const string_t& name, | |
15991 const BasicJsonType& j) | |
15992 { | |
15993 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) | |
15994 { | |
15995 write_bson_entry_header(name, 0x10 /* int32 */); | |
15996 write_number<std::int32_t>(static_cast<std::int32_t>(j.m_value.number_unsigned), true); | |
15997 } | |
15998 else if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)())) | |
15999 { | |
16000 write_bson_entry_header(name, 0x12 /* int64 */); | |
16001 write_number<std::int64_t>(static_cast<std::int64_t>(j.m_value.number_unsigned), true); | |
16002 } | |
16003 else | |
16004 { | |
16005 JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j)); | |
16006 } | |
16007 } | |
16008 | |
16009 /*! | |
16010 @brief Writes a BSON element with key @a name and object @a value | |
16011 */ | |
16012 void write_bson_object_entry(const string_t& name, | |
16013 const typename BasicJsonType::object_t& value) | |
16014 { | |
16015 write_bson_entry_header(name, 0x03); // object | |
16016 write_bson_object(value); | |
16017 } | |
16018 | |
16019 /*! | |
16020 @return The size of the BSON-encoded array @a value | |
16021 */ | |
16022 static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) | |
16023 { | |
16024 std::size_t array_index = 0ul; | |
16025 | |
16026 const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) | |
16027 { | |
16028 return result + calc_bson_element_size(std::to_string(array_index++), el); | |
16029 }); | |
16030 | |
16031 return sizeof(std::int32_t) + embedded_document_size + 1ul; | |
16032 } | |
16033 | |
16034 /*! | |
16035 @return The size of the BSON-encoded binary array @a value | |
16036 */ | |
16037 static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) | |
16038 { | |
16039 return sizeof(std::int32_t) + value.size() + 1ul; | |
16040 } | |
16041 | |
16042 /*! | |
16043 @brief Writes a BSON element with key @a name and array @a value | |
16044 */ | |
16045 void write_bson_array(const string_t& name, | |
16046 const typename BasicJsonType::array_t& value) | |
16047 { | |
16048 write_bson_entry_header(name, 0x04); // array | |
16049 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true); | |
16050 | |
16051 std::size_t array_index = 0ul; | |
16052 | |
16053 for (const auto& el : value) | |
16054 { | |
16055 write_bson_element(std::to_string(array_index++), el); | |
16056 } | |
16057 | |
16058 oa->write_character(to_char_type(0x00)); | |
16059 } | |
16060 | |
16061 /*! | |
16062 @brief Writes a BSON element with key @a name and binary value @a value | |
16063 */ | |
16064 void write_bson_binary(const string_t& name, | |
16065 const binary_t& value) | |
16066 { | |
16067 write_bson_entry_header(name, 0x05); | |
16068 | |
16069 write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true); | |
16070 write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00)); | |
16071 | |
16072 oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size()); | |
16073 } | |
16074 | |
16075 /*! | |
16076 @brief Calculates the size necessary to serialize the JSON value @a j with its @a name | |
16077 @return The calculated size for the BSON document entry for @a j with the given @a name. | |
16078 */ | |
16079 static std::size_t calc_bson_element_size(const string_t& name, | |
16080 const BasicJsonType& j) | |
16081 { | |
16082 const auto header_size = calc_bson_entry_header_size(name, j); | |
16083 switch (j.type()) | |
16084 { | |
16085 case value_t::object: | |
16086 return header_size + calc_bson_object_size(*j.m_value.object); | |
16087 | |
16088 case value_t::array: | |
16089 return header_size + calc_bson_array_size(*j.m_value.array); | |
16090 | |
16091 case value_t::binary: | |
16092 return header_size + calc_bson_binary_size(*j.m_value.binary); | |
16093 | |
16094 case value_t::boolean: | |
16095 return header_size + 1ul; | |
16096 | |
16097 case value_t::number_float: | |
16098 return header_size + 8ul; | |
16099 | |
16100 case value_t::number_integer: | |
16101 return header_size + calc_bson_integer_size(j.m_value.number_integer); | |
16102 | |
16103 case value_t::number_unsigned: | |
16104 return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned); | |
16105 | |
16106 case value_t::string: | |
16107 return header_size + calc_bson_string_size(*j.m_value.string); | |
16108 | |
16109 case value_t::null: | |
16110 return header_size + 0ul; | |
16111 | |
16112 // LCOV_EXCL_START | |
16113 case value_t::discarded: | |
16114 default: | |
16115 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) | |
16116 return 0ul; | |
16117 // LCOV_EXCL_STOP | |
16118 } | |
16119 } | |
16120 | |
16121 /*! | |
16122 @brief Serializes the JSON value @a j to BSON and associates it with the | |
16123 key @a name. | |
16124 @param name The name to associate with the JSON entity @a j within the | |
16125 current BSON document | |
16126 */ | |
16127 void write_bson_element(const string_t& name, | |
16128 const BasicJsonType& j) | |
16129 { | |
16130 switch (j.type()) | |
16131 { | |
16132 case value_t::object: | |
16133 return write_bson_object_entry(name, *j.m_value.object); | |
16134 | |
16135 case value_t::array: | |
16136 return write_bson_array(name, *j.m_value.array); | |
16137 | |
16138 case value_t::binary: | |
16139 return write_bson_binary(name, *j.m_value.binary); | |
16140 | |
16141 case value_t::boolean: | |
16142 return write_bson_boolean(name, j.m_value.boolean); | |
16143 | |
16144 case value_t::number_float: | |
16145 return write_bson_double(name, j.m_value.number_float); | |
16146 | |
16147 case value_t::number_integer: | |
16148 return write_bson_integer(name, j.m_value.number_integer); | |
16149 | |
16150 case value_t::number_unsigned: | |
16151 return write_bson_unsigned(name, j); | |
16152 | |
16153 case value_t::string: | |
16154 return write_bson_string(name, *j.m_value.string); | |
16155 | |
16156 case value_t::null: | |
16157 return write_bson_null(name); | |
16158 | |
16159 // LCOV_EXCL_START | |
16160 case value_t::discarded: | |
16161 default: | |
16162 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) | |
16163 return; | |
16164 // LCOV_EXCL_STOP | |
16165 } | |
16166 } | |
16167 | |
16168 /*! | |
16169 @brief Calculates the size of the BSON serialization of the given | |
16170 JSON-object @a j. | |
16171 @param[in] value JSON value to serialize | |
16172 @pre value.type() == value_t::object | |
16173 */ | |
16174 static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) | |
16175 { | |
16176 std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0), | |
16177 [](size_t result, const typename BasicJsonType::object_t::value_type & el) | |
16178 { | |
16179 return result += calc_bson_element_size(el.first, el.second); | |
16180 }); | |
16181 | |
16182 return sizeof(std::int32_t) + document_size + 1ul; | |
16183 } | |
16184 | |
16185 /*! | |
16186 @param[in] value JSON value to serialize | |
16187 @pre value.type() == value_t::object | |
16188 */ | |
16189 void write_bson_object(const typename BasicJsonType::object_t& value) | |
16190 { | |
16191 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true); | |
16192 | |
16193 for (const auto& el : value) | |
16194 { | |
16195 write_bson_element(el.first, el.second); | |
16196 } | |
16197 | |
16198 oa->write_character(to_char_type(0x00)); | |
16199 } | |
16200 | |
16201 ////////// | |
16202 // CBOR // | |
16203 ////////// | |
16204 | |
16205 static constexpr CharType get_cbor_float_prefix(float /*unused*/) | |
16206 { | |
16207 return to_char_type(0xFA); // Single-Precision Float | |
16208 } | |
16209 | |
16210 static constexpr CharType get_cbor_float_prefix(double /*unused*/) | |
16211 { | |
16212 return to_char_type(0xFB); // Double-Precision Float | |
16213 } | |
16214 | |
16215 ///////////// | |
16216 // MsgPack // | |
16217 ///////////// | |
16218 | |
16219 static constexpr CharType get_msgpack_float_prefix(float /*unused*/) | |
16220 { | |
16221 return to_char_type(0xCA); // float 32 | |
16222 } | |
16223 | |
16224 static constexpr CharType get_msgpack_float_prefix(double /*unused*/) | |
16225 { | |
16226 return to_char_type(0xCB); // float 64 | |
16227 } | |
16228 | |
16229 //////////// | |
16230 // UBJSON // | |
16231 //////////// | |
16232 | |
16233 // UBJSON: write number (floating point) | |
16234 template<typename NumberType, typename std::enable_if< | |
16235 std::is_floating_point<NumberType>::value, int>::type = 0> | |
16236 void write_number_with_ubjson_prefix(const NumberType n, | |
16237 const bool add_prefix, | |
16238 const bool use_bjdata) | |
16239 { | |
16240 if (add_prefix) | |
16241 { | |
16242 oa->write_character(get_ubjson_float_prefix(n)); | |
16243 } | |
16244 write_number(n, use_bjdata); | |
16245 } | |
16246 | |
16247 // UBJSON: write number (unsigned integer) | |
16248 template<typename NumberType, typename std::enable_if< | |
16249 std::is_unsigned<NumberType>::value, int>::type = 0> | |
16250 void write_number_with_ubjson_prefix(const NumberType n, | |
16251 const bool add_prefix, | |
16252 const bool use_bjdata) | |
16253 { | |
16254 if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)())) | |
16255 { | |
16256 if (add_prefix) | |
16257 { | |
16258 oa->write_character(to_char_type('i')); // int8 | |
16259 } | |
16260 write_number(static_cast<std::uint8_t>(n), use_bjdata); | |
16261 } | |
16262 else if (n <= (std::numeric_limits<std::uint8_t>::max)()) | |
16263 { | |
16264 if (add_prefix) | |
16265 { | |
16266 oa->write_character(to_char_type('U')); // uint8 | |
16267 } | |
16268 write_number(static_cast<std::uint8_t>(n), use_bjdata); | |
16269 } | |
16270 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)())) | |
16271 { | |
16272 if (add_prefix) | |
16273 { | |
16274 oa->write_character(to_char_type('I')); // int16 | |
16275 } | |
16276 write_number(static_cast<std::int16_t>(n), use_bjdata); | |
16277 } | |
16278 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)())) | |
16279 { | |
16280 if (add_prefix) | |
16281 { | |
16282 oa->write_character(to_char_type('u')); // uint16 - bjdata only | |
16283 } | |
16284 write_number(static_cast<std::uint16_t>(n), use_bjdata); | |
16285 } | |
16286 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) | |
16287 { | |
16288 if (add_prefix) | |
16289 { | |
16290 oa->write_character(to_char_type('l')); // int32 | |
16291 } | |
16292 write_number(static_cast<std::int32_t>(n), use_bjdata); | |
16293 } | |
16294 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)())) | |
16295 { | |
16296 if (add_prefix) | |
16297 { | |
16298 oa->write_character(to_char_type('m')); // uint32 - bjdata only | |
16299 } | |
16300 write_number(static_cast<std::uint32_t>(n), use_bjdata); | |
16301 } | |
16302 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)())) | |
16303 { | |
16304 if (add_prefix) | |
16305 { | |
16306 oa->write_character(to_char_type('L')); // int64 | |
16307 } | |
16308 write_number(static_cast<std::int64_t>(n), use_bjdata); | |
16309 } | |
16310 else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)()) | |
16311 { | |
16312 if (add_prefix) | |
16313 { | |
16314 oa->write_character(to_char_type('M')); // uint64 - bjdata only | |
16315 } | |
16316 write_number(static_cast<std::uint64_t>(n), use_bjdata); | |
16317 } | |
16318 else | |
16319 { | |
16320 if (add_prefix) | |
16321 { | |
16322 oa->write_character(to_char_type('H')); // high-precision number | |
16323 } | |
16324 | |
16325 const auto number = BasicJsonType(n).dump(); | |
16326 write_number_with_ubjson_prefix(number.size(), true, use_bjdata); | |
16327 for (std::size_t i = 0; i < number.size(); ++i) | |
16328 { | |
16329 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i]))); | |
16330 } | |
16331 } | |
16332 } | |
16333 | |
16334 // UBJSON: write number (signed integer) | |
16335 template < typename NumberType, typename std::enable_if < | |
16336 std::is_signed<NumberType>::value&& | |
16337 !std::is_floating_point<NumberType>::value, int >::type = 0 > | |
16338 void write_number_with_ubjson_prefix(const NumberType n, | |
16339 const bool add_prefix, | |
16340 const bool use_bjdata) | |
16341 { | |
16342 if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)()) | |
16343 { | |
16344 if (add_prefix) | |
16345 { | |
16346 oa->write_character(to_char_type('i')); // int8 | |
16347 } | |
16348 write_number(static_cast<std::int8_t>(n), use_bjdata); | |
16349 } | |
16350 else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)())) | |
16351 { | |
16352 if (add_prefix) | |
16353 { | |
16354 oa->write_character(to_char_type('U')); // uint8 | |
16355 } | |
16356 write_number(static_cast<std::uint8_t>(n), use_bjdata); | |
16357 } | |
16358 else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)()) | |
16359 { | |
16360 if (add_prefix) | |
16361 { | |
16362 oa->write_character(to_char_type('I')); // int16 | |
16363 } | |
16364 write_number(static_cast<std::int16_t>(n), use_bjdata); | |
16365 } | |
16366 else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::max)()))) | |
16367 { | |
16368 if (add_prefix) | |
16369 { | |
16370 oa->write_character(to_char_type('u')); // uint16 - bjdata only | |
16371 } | |
16372 write_number(static_cast<uint16_t>(n), use_bjdata); | |
16373 } | |
16374 else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)()) | |
16375 { | |
16376 if (add_prefix) | |
16377 { | |
16378 oa->write_character(to_char_type('l')); // int32 | |
16379 } | |
16380 write_number(static_cast<std::int32_t>(n), use_bjdata); | |
16381 } | |
16382 else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::max)()))) | |
16383 { | |
16384 if (add_prefix) | |
16385 { | |
16386 oa->write_character(to_char_type('m')); // uint32 - bjdata only | |
16387 } | |
16388 write_number(static_cast<uint32_t>(n), use_bjdata); | |
16389 } | |
16390 else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)()) | |
16391 { | |
16392 if (add_prefix) | |
16393 { | |
16394 oa->write_character(to_char_type('L')); // int64 | |
16395 } | |
16396 write_number(static_cast<std::int64_t>(n), use_bjdata); | |
16397 } | |
16398 // LCOV_EXCL_START | |
16399 else | |
16400 { | |
16401 if (add_prefix) | |
16402 { | |
16403 oa->write_character(to_char_type('H')); // high-precision number | |
16404 } | |
16405 | |
16406 const auto number = BasicJsonType(n).dump(); | |
16407 write_number_with_ubjson_prefix(number.size(), true, use_bjdata); | |
16408 for (std::size_t i = 0; i < number.size(); ++i) | |
16409 { | |
16410 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i]))); | |
16411 } | |
16412 } | |
16413 // LCOV_EXCL_STOP | |
16414 } | |
16415 | |
16416 /*! | |
16417 @brief determine the type prefix of container values | |
16418 */ | |
16419 CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept | |
16420 { | |
16421 switch (j.type()) | |
16422 { | |
16423 case value_t::null: | |
16424 return 'Z'; | |
16425 | |
16426 case value_t::boolean: | |
16427 return j.m_value.boolean ? 'T' : 'F'; | |
16428 | |
16429 case value_t::number_integer: | |
16430 { | |
16431 if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) | |
16432 { | |
16433 return 'i'; | |
16434 } | |
16435 if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) | |
16436 { | |
16437 return 'U'; | |
16438 } | |
16439 if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) | |
16440 { | |
16441 return 'I'; | |
16442 } | |
16443 if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())) | |
16444 { | |
16445 return 'u'; | |
16446 } | |
16447 if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) | |
16448 { | |
16449 return 'l'; | |
16450 } | |
16451 if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())) | |
16452 { | |
16453 return 'm'; | |
16454 } | |
16455 if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) | |
16456 { | |
16457 return 'L'; | |
16458 } | |
16459 // anything else is treated as high-precision number | |
16460 return 'H'; // LCOV_EXCL_LINE | |
16461 } | |
16462 | |
16463 case value_t::number_unsigned: | |
16464 { | |
16465 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)())) | |
16466 { | |
16467 return 'i'; | |
16468 } | |
16469 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)())) | |
16470 { | |
16471 return 'U'; | |
16472 } | |
16473 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)())) | |
16474 { | |
16475 return 'I'; | |
16476 } | |
16477 if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)())) | |
16478 { | |
16479 return 'u'; | |
16480 } | |
16481 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) | |
16482 { | |
16483 return 'l'; | |
16484 } | |
16485 if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)())) | |
16486 { | |
16487 return 'm'; | |
16488 } | |
16489 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)())) | |
16490 { | |
16491 return 'L'; | |
16492 } | |
16493 if (use_bjdata && j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) | |
16494 { | |
16495 return 'M'; | |
16496 } | |
16497 // anything else is treated as high-precision number | |
16498 return 'H'; // LCOV_EXCL_LINE | |
16499 } | |
16500 | |
16501 case value_t::number_float: | |
16502 return get_ubjson_float_prefix(j.m_value.number_float); | |
16503 | |
16504 case value_t::string: | |
16505 return 'S'; | |
16506 | |
16507 case value_t::array: // fallthrough | |
16508 case value_t::binary: | |
16509 return '['; | |
16510 | |
16511 case value_t::object: | |
16512 return '{'; | |
16513 | |
16514 case value_t::discarded: | |
16515 default: // discarded values | |
16516 return 'N'; | |
16517 } | |
16518 } | |
16519 | |
16520 static constexpr CharType get_ubjson_float_prefix(float /*unused*/) | |
16521 { | |
16522 return 'd'; // float 32 | |
16523 } | |
16524 | |
16525 static constexpr CharType get_ubjson_float_prefix(double /*unused*/) | |
16526 { | |
16527 return 'D'; // float 64 | |
16528 } | |
16529 | |
16530 /*! | |
16531 @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid | |
16532 */ | |
16533 bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type) | |
16534 { | |
16535 std::map<string_t, CharType> bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'}, | |
16536 {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'} | |
16537 }; | |
16538 | |
16539 string_t key = "_ArrayType_"; | |
16540 auto it = bjdtype.find(static_cast<string_t>(value.at(key))); | |
16541 if (it == bjdtype.end()) | |
16542 { | |
16543 return true; | |
16544 } | |
16545 CharType dtype = it->second; | |
16546 | |
16547 key = "_ArraySize_"; | |
16548 std::size_t len = (value.at(key).empty() ? 0 : 1); | |
16549 for (const auto& el : value.at(key)) | |
16550 { | |
16551 len *= static_cast<std::size_t>(el.m_value.number_unsigned); | |
16552 } | |
16553 | |
16554 key = "_ArrayData_"; | |
16555 if (value.at(key).size() != len) | |
16556 { | |
16557 return true; | |
16558 } | |
16559 | |
16560 oa->write_character('['); | |
16561 oa->write_character('$'); | |
16562 oa->write_character(dtype); | |
16563 oa->write_character('#'); | |
16564 | |
16565 key = "_ArraySize_"; | |
16566 write_ubjson(value.at(key), use_count, use_type, true, true); | |
16567 | |
16568 key = "_ArrayData_"; | |
16569 if (dtype == 'U' || dtype == 'C') | |
16570 { | |
16571 for (const auto& el : value.at(key)) | |
16572 { | |
16573 write_number(static_cast<std::uint8_t>(el.m_value.number_unsigned), true); | |
16574 } | |
16575 } | |
16576 else if (dtype == 'i') | |
16577 { | |
16578 for (const auto& el : value.at(key)) | |
16579 { | |
16580 write_number(static_cast<std::int8_t>(el.m_value.number_integer), true); | |
16581 } | |
16582 } | |
16583 else if (dtype == 'u') | |
16584 { | |
16585 for (const auto& el : value.at(key)) | |
16586 { | |
16587 write_number(static_cast<std::uint16_t>(el.m_value.number_unsigned), true); | |
16588 } | |
16589 } | |
16590 else if (dtype == 'I') | |
16591 { | |
16592 for (const auto& el : value.at(key)) | |
16593 { | |
16594 write_number(static_cast<std::int16_t>(el.m_value.number_integer), true); | |
16595 } | |
16596 } | |
16597 else if (dtype == 'm') | |
16598 { | |
16599 for (const auto& el : value.at(key)) | |
16600 { | |
16601 write_number(static_cast<std::uint32_t>(el.m_value.number_unsigned), true); | |
16602 } | |
16603 } | |
16604 else if (dtype == 'l') | |
16605 { | |
16606 for (const auto& el : value.at(key)) | |
16607 { | |
16608 write_number(static_cast<std::int32_t>(el.m_value.number_integer), true); | |
16609 } | |
16610 } | |
16611 else if (dtype == 'M') | |
16612 { | |
16613 for (const auto& el : value.at(key)) | |
16614 { | |
16615 write_number(static_cast<std::uint64_t>(el.m_value.number_unsigned), true); | |
16616 } | |
16617 } | |
16618 else if (dtype == 'L') | |
16619 { | |
16620 for (const auto& el : value.at(key)) | |
16621 { | |
16622 write_number(static_cast<std::int64_t>(el.m_value.number_integer), true); | |
16623 } | |
16624 } | |
16625 else if (dtype == 'd') | |
16626 { | |
16627 for (const auto& el : value.at(key)) | |
16628 { | |
16629 write_number(static_cast<float>(el.m_value.number_float), true); | |
16630 } | |
16631 } | |
16632 else if (dtype == 'D') | |
16633 { | |
16634 for (const auto& el : value.at(key)) | |
16635 { | |
16636 write_number(static_cast<double>(el.m_value.number_float), true); | |
16637 } | |
16638 } | |
16639 return false; | |
16640 } | |
16641 | |
16642 /////////////////////// | |
16643 // Utility functions // | |
16644 /////////////////////// | |
16645 | |
16646 /* | |
16647 @brief write a number to output input | |
16648 @param[in] n number of type @a NumberType | |
16649 @param[in] OutputIsLittleEndian Set to true if output data is | |
16650 required to be little endian | |
16651 @tparam NumberType the type of the number | |
16652 | |
16653 @note This function needs to respect the system's endianness, because bytes | |
16654 in CBOR, MessagePack, and UBJSON are stored in network order (big | |
16655 endian) and therefore need reordering on little endian systems. | |
16656 On the other hand, BSON and BJData use little endian and should reorder | |
16657 on big endian systems. | |
16658 */ | |
16659 template<typename NumberType> | |
16660 void write_number(const NumberType n, const bool OutputIsLittleEndian = false) | |
16661 { | |
16662 // step 1: write number to array of length NumberType | |
16663 std::array<CharType, sizeof(NumberType)> vec{}; | |
16664 std::memcpy(vec.data(), &n, sizeof(NumberType)); | |
16665 | |
16666 // step 2: write array to output (with possible reordering) | |
16667 if (is_little_endian != OutputIsLittleEndian) | |
16668 { | |
16669 // reverse byte order prior to conversion if necessary | |
16670 std::reverse(vec.begin(), vec.end()); | |
16671 } | |
16672 | |
16673 oa->write_characters(vec.data(), sizeof(NumberType)); | |
16674 } | |
16675 | |
16676 void write_compact_float(const number_float_t n, detail::input_format_t format) | |
16677 { | |
16678 #ifdef __GNUC__ | |
16679 #pragma GCC diagnostic push | |
16680 #pragma GCC diagnostic ignored "-Wfloat-equal" | |
16681 #endif | |
16682 if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) && | |
16683 static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) && | |
16684 static_cast<double>(static_cast<float>(n)) == static_cast<double>(n)) | |
16685 { | |
16686 oa->write_character(format == detail::input_format_t::cbor | |
16687 ? get_cbor_float_prefix(static_cast<float>(n)) | |
16688 : get_msgpack_float_prefix(static_cast<float>(n))); | |
16689 write_number(static_cast<float>(n)); | |
16690 } | |
16691 else | |
16692 { | |
16693 oa->write_character(format == detail::input_format_t::cbor | |
16694 ? get_cbor_float_prefix(n) | |
16695 : get_msgpack_float_prefix(n)); | |
16696 write_number(n); | |
16697 } | |
16698 #ifdef __GNUC__ | |
16699 #pragma GCC diagnostic pop | |
16700 #endif | |
16701 } | |
16702 | |
16703 public: | |
16704 // The following to_char_type functions are implement the conversion | |
16705 // between uint8_t and CharType. In case CharType is not unsigned, | |
16706 // such a conversion is required to allow values greater than 128. | |
16707 // See <https://github.com/nlohmann/json/issues/1286> for a discussion. | |
16708 template < typename C = CharType, | |
16709 enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr > | |
16710 static constexpr CharType to_char_type(std::uint8_t x) noexcept | |
16711 { | |
16712 return *reinterpret_cast<char*>(&x); | |
16713 } | |
16714 | |
16715 template < typename C = CharType, | |
16716 enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr > | |
16717 static CharType to_char_type(std::uint8_t x) noexcept | |
16718 { | |
16719 static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); | |
16720 static_assert(std::is_trivial<CharType>::value, "CharType must be trivial"); | |
16721 CharType result; | |
16722 std::memcpy(&result, &x, sizeof(x)); | |
16723 return result; | |
16724 } | |
16725 | |
16726 template<typename C = CharType, | |
16727 enable_if_t<std::is_unsigned<C>::value>* = nullptr> | |
16728 static constexpr CharType to_char_type(std::uint8_t x) noexcept | |
16729 { | |
16730 return x; | |
16731 } | |
16732 | |
16733 template < typename InputCharType, typename C = CharType, | |
16734 enable_if_t < | |
16735 std::is_signed<C>::value && | |
16736 std::is_signed<char>::value && | |
16737 std::is_same<char, typename std::remove_cv<InputCharType>::type>::value | |
16738 > * = nullptr > | |
16739 static constexpr CharType to_char_type(InputCharType x) noexcept | |
16740 { | |
16741 return x; | |
16742 } | |
16743 | |
16744 private: | |
16745 /// whether we can assume little endianness | |
16746 const bool is_little_endian = little_endianness(); | |
16747 | |
16748 /// the output | |
16749 output_adapter_t<CharType> oa = nullptr; | |
16750 }; | |
16751 | |
16752 } // namespace detail | |
16753 NLOHMANN_JSON_NAMESPACE_END | |
16754 | |
16755 // #include <nlohmann/detail/output/output_adapters.hpp> | |
16756 | |
16757 // #include <nlohmann/detail/output/serializer.hpp> | |
16758 // __ _____ _____ _____ | |
16759 // __| | __| | | | JSON for Modern C++ | |
16760 // | | |__ | | | | | | version 3.11.2 | |
16761 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
16762 // | |
16763 // SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de> | |
16764 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
16765 // SPDX-License-Identifier: MIT | |
16766 | |
16767 | |
16768 | |
16769 #include <algorithm> // reverse, remove, fill, find, none_of | |
16770 #include <array> // array | |
16771 #include <clocale> // localeconv, lconv | |
16772 #include <cmath> // labs, isfinite, isnan, signbit | |
16773 #include <cstddef> // size_t, ptrdiff_t | |
16774 #include <cstdint> // uint8_t | |
16775 #include <cstdio> // snprintf | |
16776 #include <limits> // numeric_limits | |
16777 #include <string> // string, char_traits | |
16778 #include <iomanip> // setfill, setw | |
16779 #include <type_traits> // is_same | |
16780 #include <utility> // move | |
16781 | |
16782 // #include <nlohmann/detail/conversions/to_chars.hpp> | |
16783 // __ _____ _____ _____ | |
16784 // __| | __| | | | JSON for Modern C++ | |
16785 // | | |__ | | | | | | version 3.11.2 | |
16786 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
16787 // | |
16788 // SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/> | |
16789 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
16790 // SPDX-License-Identifier: MIT | |
16791 | |
16792 | |
16793 | |
16794 #include <array> // array | |
16795 #include <cmath> // signbit, isfinite | |
16796 #include <cstdint> // intN_t, uintN_t | |
16797 #include <cstring> // memcpy, memmove | |
16798 #include <limits> // numeric_limits | |
16799 #include <type_traits> // conditional | |
16800 | |
16801 // #include <nlohmann/detail/macro_scope.hpp> | |
16802 | |
16803 | |
16804 NLOHMANN_JSON_NAMESPACE_BEGIN | |
16805 namespace detail | |
16806 { | |
16807 | |
16808 /*! | |
16809 @brief implements the Grisu2 algorithm for binary to decimal floating-point | |
16810 conversion. | |
16811 | |
16812 This implementation is a slightly modified version of the reference | |
16813 implementation which may be obtained from | |
16814 http://florian.loitsch.com/publications (bench.tar.gz). | |
16815 | |
16816 The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. | |
16817 | |
16818 For a detailed description of the algorithm see: | |
16819 | |
16820 [1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with | |
16821 Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming | |
16822 Language Design and Implementation, PLDI 2010 | |
16823 [2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", | |
16824 Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language | |
16825 Design and Implementation, PLDI 1996 | |
16826 */ | |
16827 namespace dtoa_impl | |
16828 { | |
16829 | |
16830 template<typename Target, typename Source> | |
16831 Target reinterpret_bits(const Source source) | |
16832 { | |
16833 static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); | |
16834 | |
16835 Target target; | |
16836 std::memcpy(&target, &source, sizeof(Source)); | |
16837 return target; | |
16838 } | |
16839 | |
16840 struct diyfp // f * 2^e | |
16841 { | |
16842 static constexpr int kPrecision = 64; // = q | |
16843 | |
16844 std::uint64_t f = 0; | |
16845 int e = 0; | |
16846 | |
16847 constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} | |
16848 | |
16849 /*! | |
16850 @brief returns x - y | |
16851 @pre x.e == y.e and x.f >= y.f | |
16852 */ | |
16853 static diyfp sub(const diyfp& x, const diyfp& y) noexcept | |
16854 { | |
16855 JSON_ASSERT(x.e == y.e); | |
16856 JSON_ASSERT(x.f >= y.f); | |
16857 | |
16858 return {x.f - y.f, x.e}; | |
16859 } | |
16860 | |
16861 /*! | |
16862 @brief returns x * y | |
16863 @note The result is rounded. (Only the upper q bits are returned.) | |
16864 */ | |
16865 static diyfp mul(const diyfp& x, const diyfp& y) noexcept | |
16866 { | |
16867 static_assert(kPrecision == 64, "internal error"); | |
16868 | |
16869 // Computes: | |
16870 // f = round((x.f * y.f) / 2^q) | |
16871 // e = x.e + y.e + q | |
16872 | |
16873 // Emulate the 64-bit * 64-bit multiplication: | |
16874 // | |
16875 // p = u * v | |
16876 // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) | |
16877 // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) | |
16878 // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) | |
16879 // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) | |
16880 // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) | |
16881 // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) | |
16882 // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) | |
16883 // | |
16884 // (Since Q might be larger than 2^32 - 1) | |
16885 // | |
16886 // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) | |
16887 // | |
16888 // (Q_hi + H does not overflow a 64-bit int) | |
16889 // | |
16890 // = p_lo + 2^64 p_hi | |
16891 | |
16892 const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; | |
16893 const std::uint64_t u_hi = x.f >> 32u; | |
16894 const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; | |
16895 const std::uint64_t v_hi = y.f >> 32u; | |
16896 | |
16897 const std::uint64_t p0 = u_lo * v_lo; | |
16898 const std::uint64_t p1 = u_lo * v_hi; | |
16899 const std::uint64_t p2 = u_hi * v_lo; | |
16900 const std::uint64_t p3 = u_hi * v_hi; | |
16901 | |
16902 const std::uint64_t p0_hi = p0 >> 32u; | |
16903 const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; | |
16904 const std::uint64_t p1_hi = p1 >> 32u; | |
16905 const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; | |
16906 const std::uint64_t p2_hi = p2 >> 32u; | |
16907 | |
16908 std::uint64_t Q = p0_hi + p1_lo + p2_lo; | |
16909 | |
16910 // The full product might now be computed as | |
16911 // | |
16912 // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) | |
16913 // p_lo = p0_lo + (Q << 32) | |
16914 // | |
16915 // But in this particular case here, the full p_lo is not required. | |
16916 // Effectively we only need to add the highest bit in p_lo to p_hi (and | |
16917 // Q_hi + 1 does not overflow). | |
16918 | |
16919 Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up | |
16920 | |
16921 const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); | |
16922 | |
16923 return {h, x.e + y.e + 64}; | |
16924 } | |
16925 | |
16926 /*! | |
16927 @brief normalize x such that the significand is >= 2^(q-1) | |
16928 @pre x.f != 0 | |
16929 */ | |
16930 static diyfp normalize(diyfp x) noexcept | |
16931 { | |
16932 JSON_ASSERT(x.f != 0); | |
16933 | |
16934 while ((x.f >> 63u) == 0) | |
16935 { | |
16936 x.f <<= 1u; | |
16937 x.e--; | |
16938 } | |
16939 | |
16940 return x; | |
16941 } | |
16942 | |
16943 /*! | |
16944 @brief normalize x such that the result has the exponent E | |
16945 @pre e >= x.e and the upper e - x.e bits of x.f must be zero. | |
16946 */ | |
16947 static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept | |
16948 { | |
16949 const int delta = x.e - target_exponent; | |
16950 | |
16951 JSON_ASSERT(delta >= 0); | |
16952 JSON_ASSERT(((x.f << delta) >> delta) == x.f); | |
16953 | |
16954 return {x.f << delta, target_exponent}; | |
16955 } | |
16956 }; | |
16957 | |
16958 struct boundaries | |
16959 { | |
16960 diyfp w; | |
16961 diyfp minus; | |
16962 diyfp plus; | |
16963 }; | |
16964 | |
16965 /*! | |
16966 Compute the (normalized) diyfp representing the input number 'value' and its | |
16967 boundaries. | |
16968 | |
16969 @pre value must be finite and positive | |
16970 */ | |
16971 template<typename FloatType> | |
16972 boundaries compute_boundaries(FloatType value) | |
16973 { | |
16974 JSON_ASSERT(std::isfinite(value)); | |
16975 JSON_ASSERT(value > 0); | |
16976 | |
16977 // Convert the IEEE representation into a diyfp. | |
16978 // | |
16979 // If v is denormal: | |
16980 // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) | |
16981 // If v is normalized: | |
16982 // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) | |
16983 | |
16984 static_assert(std::numeric_limits<FloatType>::is_iec559, | |
16985 "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); | |
16986 | |
16987 constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit) | |
16988 constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1); | |
16989 constexpr int kMinExp = 1 - kBias; | |
16990 constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) | |
16991 | |
16992 using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type; | |
16993 | |
16994 const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value)); | |
16995 const std::uint64_t E = bits >> (kPrecision - 1); | |
16996 const std::uint64_t F = bits & (kHiddenBit - 1); | |
16997 | |
16998 const bool is_denormal = E == 0; | |
16999 const diyfp v = is_denormal | |
17000 ? diyfp(F, kMinExp) | |
17001 : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias); | |
17002 | |
17003 // Compute the boundaries m- and m+ of the floating-point value | |
17004 // v = f * 2^e. | |
17005 // | |
17006 // Determine v- and v+, the floating-point predecessor and successor if v, | |
17007 // respectively. | |
17008 // | |
17009 // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) | |
17010 // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) | |
17011 // | |
17012 // v+ = v + 2^e | |
17013 // | |
17014 // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ | |
17015 // between m- and m+ round to v, regardless of how the input rounding | |
17016 // algorithm breaks ties. | |
17017 // | |
17018 // ---+-------------+-------------+-------------+-------------+--- (A) | |
17019 // v- m- v m+ v+ | |
17020 // | |
17021 // -----------------+------+------+-------------+-------------+--- (B) | |
17022 // v- m- v m+ v+ | |
17023 | |
17024 const bool lower_boundary_is_closer = F == 0 && E > 1; | |
17025 const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); | |
17026 const diyfp m_minus = lower_boundary_is_closer | |
17027 ? diyfp(4 * v.f - 1, v.e - 2) // (B) | |
17028 : diyfp(2 * v.f - 1, v.e - 1); // (A) | |
17029 | |
17030 // Determine the normalized w+ = m+. | |
17031 const diyfp w_plus = diyfp::normalize(m_plus); | |
17032 | |
17033 // Determine w- = m- such that e_(w-) = e_(w+). | |
17034 const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); | |
17035 | |
17036 return {diyfp::normalize(v), w_minus, w_plus}; | |
17037 } | |
17038 | |
17039 // Given normalized diyfp w, Grisu needs to find a (normalized) cached | |
17040 // power-of-ten c, such that the exponent of the product c * w = f * 2^e lies | |
17041 // within a certain range [alpha, gamma] (Definition 3.2 from [1]) | |
17042 // | |
17043 // alpha <= e = e_c + e_w + q <= gamma | |
17044 // | |
17045 // or | |
17046 // | |
17047 // f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q | |
17048 // <= f_c * f_w * 2^gamma | |
17049 // | |
17050 // Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies | |
17051 // | |
17052 // 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma | |
17053 // | |
17054 // or | |
17055 // | |
17056 // 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) | |
17057 // | |
17058 // The choice of (alpha,gamma) determines the size of the table and the form of | |
17059 // the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well | |
17060 // in practice: | |
17061 // | |
17062 // The idea is to cut the number c * w = f * 2^e into two parts, which can be | |
17063 // processed independently: An integral part p1, and a fractional part p2: | |
17064 // | |
17065 // f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e | |
17066 // = (f div 2^-e) + (f mod 2^-e) * 2^e | |
17067 // = p1 + p2 * 2^e | |
17068 // | |
17069 // The conversion of p1 into decimal form requires a series of divisions and | |
17070 // modulos by (a power of) 10. These operations are faster for 32-bit than for | |
17071 // 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be | |
17072 // achieved by choosing | |
17073 // | |
17074 // -e >= 32 or e <= -32 := gamma | |
17075 // | |
17076 // In order to convert the fractional part | |
17077 // | |
17078 // p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... | |
17079 // | |
17080 // into decimal form, the fraction is repeatedly multiplied by 10 and the digits | |
17081 // d[-i] are extracted in order: | |
17082 // | |
17083 // (10 * p2) div 2^-e = d[-1] | |
17084 // (10 * p2) mod 2^-e = d[-2] / 10^1 + ... | |
17085 // | |
17086 // The multiplication by 10 must not overflow. It is sufficient to choose | |
17087 // | |
17088 // 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. | |
17089 // | |
17090 // Since p2 = f mod 2^-e < 2^-e, | |
17091 // | |
17092 // -e <= 60 or e >= -60 := alpha | |
17093 | |
17094 constexpr int kAlpha = -60; | |
17095 constexpr int kGamma = -32; | |
17096 | |
17097 struct cached_power // c = f * 2^e ~= 10^k | |
17098 { | |
17099 std::uint64_t f; | |
17100 int e; | |
17101 int k; | |
17102 }; | |
17103 | |
17104 /*! | |
17105 For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached | |
17106 power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c | |
17107 satisfies (Definition 3.2 from [1]) | |
17108 | |
17109 alpha <= e_c + e + q <= gamma. | |
17110 */ | |
17111 inline cached_power get_cached_power_for_binary_exponent(int e) | |
17112 { | |
17113 // Now | |
17114 // | |
17115 // alpha <= e_c + e + q <= gamma (1) | |
17116 // ==> f_c * 2^alpha <= c * 2^e * 2^q | |
17117 // | |
17118 // and since the c's are normalized, 2^(q-1) <= f_c, | |
17119 // | |
17120 // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) | |
17121 // ==> 2^(alpha - e - 1) <= c | |
17122 // | |
17123 // If c were an exact power of ten, i.e. c = 10^k, one may determine k as | |
17124 // | |
17125 // k = ceil( log_10( 2^(alpha - e - 1) ) ) | |
17126 // = ceil( (alpha - e - 1) * log_10(2) ) | |
17127 // | |
17128 // From the paper: | |
17129 // "In theory the result of the procedure could be wrong since c is rounded, | |
17130 // and the computation itself is approximated [...]. In practice, however, | |
17131 // this simple function is sufficient." | |
17132 // | |
17133 // For IEEE double precision floating-point numbers converted into | |
17134 // normalized diyfp's w = f * 2^e, with q = 64, | |
17135 // | |
17136 // e >= -1022 (min IEEE exponent) | |
17137 // -52 (p - 1) | |
17138 // -52 (p - 1, possibly normalize denormal IEEE numbers) | |
17139 // -11 (normalize the diyfp) | |
17140 // = -1137 | |
17141 // | |
17142 // and | |
17143 // | |
17144 // e <= +1023 (max IEEE exponent) | |
17145 // -52 (p - 1) | |
17146 // -11 (normalize the diyfp) | |
17147 // = 960 | |
17148 // | |
17149 // This binary exponent range [-1137,960] results in a decimal exponent | |
17150 // range [-307,324]. One does not need to store a cached power for each | |
17151 // k in this range. For each such k it suffices to find a cached power | |
17152 // such that the exponent of the product lies in [alpha,gamma]. | |
17153 // This implies that the difference of the decimal exponents of adjacent | |
17154 // table entries must be less than or equal to | |
17155 // | |
17156 // floor( (gamma - alpha) * log_10(2) ) = 8. | |
17157 // | |
17158 // (A smaller distance gamma-alpha would require a larger table.) | |
17159 | |
17160 // NB: | |
17161 // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. | |
17162 | |
17163 constexpr int kCachedPowersMinDecExp = -300; | |
17164 constexpr int kCachedPowersDecStep = 8; | |
17165 | |
17166 static constexpr std::array<cached_power, 79> kCachedPowers = | |
17167 { | |
17168 { | |
17169 { 0xAB70FE17C79AC6CA, -1060, -300 }, | |
17170 { 0xFF77B1FCBEBCDC4F, -1034, -292 }, | |
17171 { 0xBE5691EF416BD60C, -1007, -284 }, | |
17172 { 0x8DD01FAD907FFC3C, -980, -276 }, | |
17173 { 0xD3515C2831559A83, -954, -268 }, | |
17174 { 0x9D71AC8FADA6C9B5, -927, -260 }, | |
17175 { 0xEA9C227723EE8BCB, -901, -252 }, | |
17176 { 0xAECC49914078536D, -874, -244 }, | |
17177 { 0x823C12795DB6CE57, -847, -236 }, | |
17178 { 0xC21094364DFB5637, -821, -228 }, | |
17179 { 0x9096EA6F3848984F, -794, -220 }, | |
17180 { 0xD77485CB25823AC7, -768, -212 }, | |
17181 { 0xA086CFCD97BF97F4, -741, -204 }, | |
17182 { 0xEF340A98172AACE5, -715, -196 }, | |
17183 { 0xB23867FB2A35B28E, -688, -188 }, | |
17184 { 0x84C8D4DFD2C63F3B, -661, -180 }, | |
17185 { 0xC5DD44271AD3CDBA, -635, -172 }, | |
17186 { 0x936B9FCEBB25C996, -608, -164 }, | |
17187 { 0xDBAC6C247D62A584, -582, -156 }, | |
17188 { 0xA3AB66580D5FDAF6, -555, -148 }, | |
17189 { 0xF3E2F893DEC3F126, -529, -140 }, | |
17190 { 0xB5B5ADA8AAFF80B8, -502, -132 }, | |
17191 { 0x87625F056C7C4A8B, -475, -124 }, | |
17192 { 0xC9BCFF6034C13053, -449, -116 }, | |
17193 { 0x964E858C91BA2655, -422, -108 }, | |
17194 { 0xDFF9772470297EBD, -396, -100 }, | |
17195 { 0xA6DFBD9FB8E5B88F, -369, -92 }, | |
17196 { 0xF8A95FCF88747D94, -343, -84 }, | |
17197 { 0xB94470938FA89BCF, -316, -76 }, | |
17198 { 0x8A08F0F8BF0F156B, -289, -68 }, | |
17199 { 0xCDB02555653131B6, -263, -60 }, | |
17200 { 0x993FE2C6D07B7FAC, -236, -52 }, | |
17201 { 0xE45C10C42A2B3B06, -210, -44 }, | |
17202 { 0xAA242499697392D3, -183, -36 }, | |
17203 { 0xFD87B5F28300CA0E, -157, -28 }, | |
17204 { 0xBCE5086492111AEB, -130, -20 }, | |
17205 { 0x8CBCCC096F5088CC, -103, -12 }, | |
17206 { 0xD1B71758E219652C, -77, -4 }, | |
17207 { 0x9C40000000000000, -50, 4 }, | |
17208 { 0xE8D4A51000000000, -24, 12 }, | |
17209 { 0xAD78EBC5AC620000, 3, 20 }, | |
17210 { 0x813F3978F8940984, 30, 28 }, | |
17211 { 0xC097CE7BC90715B3, 56, 36 }, | |
17212 { 0x8F7E32CE7BEA5C70, 83, 44 }, | |
17213 { 0xD5D238A4ABE98068, 109, 52 }, | |
17214 { 0x9F4F2726179A2245, 136, 60 }, | |
17215 { 0xED63A231D4C4FB27, 162, 68 }, | |
17216 { 0xB0DE65388CC8ADA8, 189, 76 }, | |
17217 { 0x83C7088E1AAB65DB, 216, 84 }, | |
17218 { 0xC45D1DF942711D9A, 242, 92 }, | |
17219 { 0x924D692CA61BE758, 269, 100 }, | |
17220 { 0xDA01EE641A708DEA, 295, 108 }, | |
17221 { 0xA26DA3999AEF774A, 322, 116 }, | |
17222 { 0xF209787BB47D6B85, 348, 124 }, | |
17223 { 0xB454E4A179DD1877, 375, 132 }, | |
17224 { 0x865B86925B9BC5C2, 402, 140 }, | |
17225 { 0xC83553C5C8965D3D, 428, 148 }, | |
17226 { 0x952AB45CFA97A0B3, 455, 156 }, | |
17227 { 0xDE469FBD99A05FE3, 481, 164 }, | |
17228 { 0xA59BC234DB398C25, 508, 172 }, | |
17229 { 0xF6C69A72A3989F5C, 534, 180 }, | |
17230 { 0xB7DCBF5354E9BECE, 561, 188 }, | |
17231 { 0x88FCF317F22241E2, 588, 196 }, | |
17232 { 0xCC20CE9BD35C78A5, 614, 204 }, | |
17233 { 0x98165AF37B2153DF, 641, 212 }, | |
17234 { 0xE2A0B5DC971F303A, 667, 220 }, | |
17235 { 0xA8D9D1535CE3B396, 694, 228 }, | |
17236 { 0xFB9B7CD9A4A7443C, 720, 236 }, | |
17237 { 0xBB764C4CA7A44410, 747, 244 }, | |
17238 { 0x8BAB8EEFB6409C1A, 774, 252 }, | |
17239 { 0xD01FEF10A657842C, 800, 260 }, | |
17240 { 0x9B10A4E5E9913129, 827, 268 }, | |
17241 { 0xE7109BFBA19C0C9D, 853, 276 }, | |
17242 { 0xAC2820D9623BF429, 880, 284 }, | |
17243 { 0x80444B5E7AA7CF85, 907, 292 }, | |
17244 { 0xBF21E44003ACDD2D, 933, 300 }, | |
17245 { 0x8E679C2F5E44FF8F, 960, 308 }, | |
17246 { 0xD433179D9C8CB841, 986, 316 }, | |
17247 { 0x9E19DB92B4E31BA9, 1013, 324 }, | |
17248 } | |
17249 }; | |
17250 | |
17251 // This computation gives exactly the same results for k as | |
17252 // k = ceil((kAlpha - e - 1) * 0.30102999566398114) | |
17253 // for |e| <= 1500, but doesn't require floating-point operations. | |
17254 // NB: log_10(2) ~= 78913 / 2^18 | |
17255 JSON_ASSERT(e >= -1500); | |
17256 JSON_ASSERT(e <= 1500); | |
17257 const int f = kAlpha - e - 1; | |
17258 const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0); | |
17259 | |
17260 const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; | |
17261 JSON_ASSERT(index >= 0); | |
17262 JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size()); | |
17263 | |
17264 const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)]; | |
17265 JSON_ASSERT(kAlpha <= cached.e + e + 64); | |
17266 JSON_ASSERT(kGamma >= cached.e + e + 64); | |
17267 | |
17268 return cached; | |
17269 } | |
17270 | |
17271 /*! | |
17272 For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. | |
17273 For n == 0, returns 1 and sets pow10 := 1. | |
17274 */ | |
17275 inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) | |
17276 { | |
17277 // LCOV_EXCL_START | |
17278 if (n >= 1000000000) | |
17279 { | |
17280 pow10 = 1000000000; | |
17281 return 10; | |
17282 } | |
17283 // LCOV_EXCL_STOP | |
17284 if (n >= 100000000) | |
17285 { | |
17286 pow10 = 100000000; | |
17287 return 9; | |
17288 } | |
17289 if (n >= 10000000) | |
17290 { | |
17291 pow10 = 10000000; | |
17292 return 8; | |
17293 } | |
17294 if (n >= 1000000) | |
17295 { | |
17296 pow10 = 1000000; | |
17297 return 7; | |
17298 } | |
17299 if (n >= 100000) | |
17300 { | |
17301 pow10 = 100000; | |
17302 return 6; | |
17303 } | |
17304 if (n >= 10000) | |
17305 { | |
17306 pow10 = 10000; | |
17307 return 5; | |
17308 } | |
17309 if (n >= 1000) | |
17310 { | |
17311 pow10 = 1000; | |
17312 return 4; | |
17313 } | |
17314 if (n >= 100) | |
17315 { | |
17316 pow10 = 100; | |
17317 return 3; | |
17318 } | |
17319 if (n >= 10) | |
17320 { | |
17321 pow10 = 10; | |
17322 return 2; | |
17323 } | |
17324 | |
17325 pow10 = 1; | |
17326 return 1; | |
17327 } | |
17328 | |
17329 inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, | |
17330 std::uint64_t rest, std::uint64_t ten_k) | |
17331 { | |
17332 JSON_ASSERT(len >= 1); | |
17333 JSON_ASSERT(dist <= delta); | |
17334 JSON_ASSERT(rest <= delta); | |
17335 JSON_ASSERT(ten_k > 0); | |
17336 | |
17337 // <--------------------------- delta ----> | |
17338 // <---- dist ---------> | |
17339 // --------------[------------------+-------------------]-------------- | |
17340 // M- w M+ | |
17341 // | |
17342 // ten_k | |
17343 // <------> | |
17344 // <---- rest ----> | |
17345 // --------------[------------------+----+--------------]-------------- | |
17346 // w V | |
17347 // = buf * 10^k | |
17348 // | |
17349 // ten_k represents a unit-in-the-last-place in the decimal representation | |
17350 // stored in buf. | |
17351 // Decrement buf by ten_k while this takes buf closer to w. | |
17352 | |
17353 // The tests are written in this order to avoid overflow in unsigned | |
17354 // integer arithmetic. | |
17355 | |
17356 while (rest < dist | |
17357 && delta - rest >= ten_k | |
17358 && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) | |
17359 { | |
17360 JSON_ASSERT(buf[len - 1] != '0'); | |
17361 buf[len - 1]--; | |
17362 rest += ten_k; | |
17363 } | |
17364 } | |
17365 | |
17366 /*! | |
17367 Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. | |
17368 M- and M+ must be normalized and share the same exponent -60 <= e <= -32. | |
17369 */ | |
17370 inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, | |
17371 diyfp M_minus, diyfp w, diyfp M_plus) | |
17372 { | |
17373 static_assert(kAlpha >= -60, "internal error"); | |
17374 static_assert(kGamma <= -32, "internal error"); | |
17375 | |
17376 // Generates the digits (and the exponent) of a decimal floating-point | |
17377 // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's | |
17378 // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. | |
17379 // | |
17380 // <--------------------------- delta ----> | |
17381 // <---- dist ---------> | |
17382 // --------------[------------------+-------------------]-------------- | |
17383 // M- w M+ | |
17384 // | |
17385 // Grisu2 generates the digits of M+ from left to right and stops as soon as | |
17386 // V is in [M-,M+]. | |
17387 | |
17388 JSON_ASSERT(M_plus.e >= kAlpha); | |
17389 JSON_ASSERT(M_plus.e <= kGamma); | |
17390 | |
17391 std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) | |
17392 std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) | |
17393 | |
17394 // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): | |
17395 // | |
17396 // M+ = f * 2^e | |
17397 // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e | |
17398 // = ((p1 ) * 2^-e + (p2 )) * 2^e | |
17399 // = p1 + p2 * 2^e | |
17400 | |
17401 const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); | |
17402 | |
17403 auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) | |
17404 std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e | |
17405 | |
17406 // 1) | |
17407 // | |
17408 // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] | |
17409 | |
17410 JSON_ASSERT(p1 > 0); | |
17411 | |
17412 std::uint32_t pow10{}; | |
17413 const int k = find_largest_pow10(p1, pow10); | |
17414 | |
17415 // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) | |
17416 // | |
17417 // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) | |
17418 // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) | |
17419 // | |
17420 // M+ = p1 + p2 * 2^e | |
17421 // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e | |
17422 // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e | |
17423 // = d[k-1] * 10^(k-1) + ( rest) * 2^e | |
17424 // | |
17425 // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) | |
17426 // | |
17427 // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] | |
17428 // | |
17429 // but stop as soon as | |
17430 // | |
17431 // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e | |
17432 | |
17433 int n = k; | |
17434 while (n > 0) | |
17435 { | |
17436 // Invariants: | |
17437 // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) | |
17438 // pow10 = 10^(n-1) <= p1 < 10^n | |
17439 // | |
17440 const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) | |
17441 const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) | |
17442 // | |
17443 // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e | |
17444 // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) | |
17445 // | |
17446 JSON_ASSERT(d <= 9); | |
17447 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d | |
17448 // | |
17449 // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) | |
17450 // | |
17451 p1 = r; | |
17452 n--; | |
17453 // | |
17454 // M+ = buffer * 10^n + (p1 + p2 * 2^e) | |
17455 // pow10 = 10^n | |
17456 // | |
17457 | |
17458 // Now check if enough digits have been generated. | |
17459 // Compute | |
17460 // | |
17461 // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e | |
17462 // | |
17463 // Note: | |
17464 // Since rest and delta share the same exponent e, it suffices to | |
17465 // compare the significands. | |
17466 const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; | |
17467 if (rest <= delta) | |
17468 { | |
17469 // V = buffer * 10^n, with M- <= V <= M+. | |
17470 | |
17471 decimal_exponent += n; | |
17472 | |
17473 // We may now just stop. But instead look if the buffer could be | |
17474 // decremented to bring V closer to w. | |
17475 // | |
17476 // pow10 = 10^n is now 1 ulp in the decimal representation V. | |
17477 // The rounding procedure works with diyfp's with an implicit | |
17478 // exponent of e. | |
17479 // | |
17480 // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e | |
17481 // | |
17482 const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; | |
17483 grisu2_round(buffer, length, dist, delta, rest, ten_n); | |
17484 | |
17485 return; | |
17486 } | |
17487 | |
17488 pow10 /= 10; | |
17489 // | |
17490 // pow10 = 10^(n-1) <= p1 < 10^n | |
17491 // Invariants restored. | |
17492 } | |
17493 | |
17494 // 2) | |
17495 // | |
17496 // The digits of the integral part have been generated: | |
17497 // | |
17498 // M+ = d[k-1]...d[1]d[0] + p2 * 2^e | |
17499 // = buffer + p2 * 2^e | |
17500 // | |
17501 // Now generate the digits of the fractional part p2 * 2^e. | |
17502 // | |
17503 // Note: | |
17504 // No decimal point is generated: the exponent is adjusted instead. | |
17505 // | |
17506 // p2 actually represents the fraction | |
17507 // | |
17508 // p2 * 2^e | |
17509 // = p2 / 2^-e | |
17510 // = d[-1] / 10^1 + d[-2] / 10^2 + ... | |
17511 // | |
17512 // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) | |
17513 // | |
17514 // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m | |
17515 // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) | |
17516 // | |
17517 // using | |
17518 // | |
17519 // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) | |
17520 // = ( d) * 2^-e + ( r) | |
17521 // | |
17522 // or | |
17523 // 10^m * p2 * 2^e = d + r * 2^e | |
17524 // | |
17525 // i.e. | |
17526 // | |
17527 // M+ = buffer + p2 * 2^e | |
17528 // = buffer + 10^-m * (d + r * 2^e) | |
17529 // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e | |
17530 // | |
17531 // and stop as soon as 10^-m * r * 2^e <= delta * 2^e | |
17532 | |
17533 JSON_ASSERT(p2 > delta); | |
17534 | |
17535 int m = 0; | |
17536 for (;;) | |
17537 { | |
17538 // Invariant: | |
17539 // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e | |
17540 // = buffer * 10^-m + 10^-m * (p2 ) * 2^e | |
17541 // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e | |
17542 // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e | |
17543 // | |
17544 JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10); | |
17545 p2 *= 10; | |
17546 const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e | |
17547 const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e | |
17548 // | |
17549 // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e | |
17550 // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) | |
17551 // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e | |
17552 // | |
17553 JSON_ASSERT(d <= 9); | |
17554 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d | |
17555 // | |
17556 // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e | |
17557 // | |
17558 p2 = r; | |
17559 m++; | |
17560 // | |
17561 // M+ = buffer * 10^-m + 10^-m * p2 * 2^e | |
17562 // Invariant restored. | |
17563 | |
17564 // Check if enough digits have been generated. | |
17565 // | |
17566 // 10^-m * p2 * 2^e <= delta * 2^e | |
17567 // p2 * 2^e <= 10^m * delta * 2^e | |
17568 // p2 <= 10^m * delta | |
17569 delta *= 10; | |
17570 dist *= 10; | |
17571 if (p2 <= delta) | |
17572 { | |
17573 break; | |
17574 } | |
17575 } | |
17576 | |
17577 // V = buffer * 10^-m, with M- <= V <= M+. | |
17578 | |
17579 decimal_exponent -= m; | |
17580 | |
17581 // 1 ulp in the decimal representation is now 10^-m. | |
17582 // Since delta and dist are now scaled by 10^m, we need to do the | |
17583 // same with ulp in order to keep the units in sync. | |
17584 // | |
17585 // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e | |
17586 // | |
17587 const std::uint64_t ten_m = one.f; | |
17588 grisu2_round(buffer, length, dist, delta, p2, ten_m); | |
17589 | |
17590 // By construction this algorithm generates the shortest possible decimal | |
17591 // number (Loitsch, Theorem 6.2) which rounds back to w. | |
17592 // For an input number of precision p, at least | |
17593 // | |
17594 // N = 1 + ceil(p * log_10(2)) | |
17595 // | |
17596 // decimal digits are sufficient to identify all binary floating-point | |
17597 // numbers (Matula, "In-and-Out conversions"). | |
17598 // This implies that the algorithm does not produce more than N decimal | |
17599 // digits. | |
17600 // | |
17601 // N = 17 for p = 53 (IEEE double precision) | |
17602 // N = 9 for p = 24 (IEEE single precision) | |
17603 } | |
17604 | |
17605 /*! | |
17606 v = buf * 10^decimal_exponent | |
17607 len is the length of the buffer (number of decimal digits) | |
17608 The buffer must be large enough, i.e. >= max_digits10. | |
17609 */ | |
17610 JSON_HEDLEY_NON_NULL(1) | |
17611 inline void grisu2(char* buf, int& len, int& decimal_exponent, | |
17612 diyfp m_minus, diyfp v, diyfp m_plus) | |
17613 { | |
17614 JSON_ASSERT(m_plus.e == m_minus.e); | |
17615 JSON_ASSERT(m_plus.e == v.e); | |
17616 | |
17617 // --------(-----------------------+-----------------------)-------- (A) | |
17618 // m- v m+ | |
17619 // | |
17620 // --------------------(-----------+-----------------------)-------- (B) | |
17621 // m- v m+ | |
17622 // | |
17623 // First scale v (and m- and m+) such that the exponent is in the range | |
17624 // [alpha, gamma]. | |
17625 | |
17626 const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); | |
17627 | |
17628 const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k | |
17629 | |
17630 // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] | |
17631 const diyfp w = diyfp::mul(v, c_minus_k); | |
17632 const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); | |
17633 const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); | |
17634 | |
17635 // ----(---+---)---------------(---+---)---------------(---+---)---- | |
17636 // w- w w+ | |
17637 // = c*m- = c*v = c*m+ | |
17638 // | |
17639 // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and | |
17640 // w+ are now off by a small amount. | |
17641 // In fact: | |
17642 // | |
17643 // w - v * 10^k < 1 ulp | |
17644 // | |
17645 // To account for this inaccuracy, add resp. subtract 1 ulp. | |
17646 // | |
17647 // --------+---[---------------(---+---)---------------]---+-------- | |
17648 // w- M- w M+ w+ | |
17649 // | |
17650 // Now any number in [M-, M+] (bounds included) will round to w when input, | |
17651 // regardless of how the input rounding algorithm breaks ties. | |
17652 // | |
17653 // And digit_gen generates the shortest possible such number in [M-, M+]. | |
17654 // Note that this does not mean that Grisu2 always generates the shortest | |
17655 // possible number in the interval (m-, m+). | |
17656 const diyfp M_minus(w_minus.f + 1, w_minus.e); | |
17657 const diyfp M_plus (w_plus.f - 1, w_plus.e ); | |
17658 | |
17659 decimal_exponent = -cached.k; // = -(-k) = k | |
17660 | |
17661 grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); | |
17662 } | |
17663 | |
17664 /*! | |
17665 v = buf * 10^decimal_exponent | |
17666 len is the length of the buffer (number of decimal digits) | |
17667 The buffer must be large enough, i.e. >= max_digits10. | |
17668 */ | |
17669 template<typename FloatType> | |
17670 JSON_HEDLEY_NON_NULL(1) | |
17671 void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) | |
17672 { | |
17673 static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3, | |
17674 "internal error: not enough precision"); | |
17675 | |
17676 JSON_ASSERT(std::isfinite(value)); | |
17677 JSON_ASSERT(value > 0); | |
17678 | |
17679 // If the neighbors (and boundaries) of 'value' are always computed for double-precision | |
17680 // numbers, all float's can be recovered using strtod (and strtof). However, the resulting | |
17681 // decimal representations are not exactly "short". | |
17682 // | |
17683 // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) | |
17684 // says "value is converted to a string as if by std::sprintf in the default ("C") locale" | |
17685 // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars' | |
17686 // does. | |
17687 // On the other hand, the documentation for 'std::to_chars' requires that "parsing the | |
17688 // representation using the corresponding std::from_chars function recovers value exactly". That | |
17689 // indicates that single precision floating-point numbers should be recovered using | |
17690 // 'std::strtof'. | |
17691 // | |
17692 // NB: If the neighbors are computed for single-precision numbers, there is a single float | |
17693 // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision | |
17694 // value is off by 1 ulp. | |
17695 #if 0 | |
17696 const boundaries w = compute_boundaries(static_cast<double>(value)); | |
17697 #else | |
17698 const boundaries w = compute_boundaries(value); | |
17699 #endif | |
17700 | |
17701 grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); | |
17702 } | |
17703 | |
17704 /*! | |
17705 @brief appends a decimal representation of e to buf | |
17706 @return a pointer to the element following the exponent. | |
17707 @pre -1000 < e < 1000 | |
17708 */ | |
17709 JSON_HEDLEY_NON_NULL(1) | |
17710 JSON_HEDLEY_RETURNS_NON_NULL | |
17711 inline char* append_exponent(char* buf, int e) | |
17712 { | |
17713 JSON_ASSERT(e > -1000); | |
17714 JSON_ASSERT(e < 1000); | |
17715 | |
17716 if (e < 0) | |
17717 { | |
17718 e = -e; | |
17719 *buf++ = '-'; | |
17720 } | |
17721 else | |
17722 { | |
17723 *buf++ = '+'; | |
17724 } | |
17725 | |
17726 auto k = static_cast<std::uint32_t>(e); | |
17727 if (k < 10) | |
17728 { | |
17729 // Always print at least two digits in the exponent. | |
17730 // This is for compatibility with printf("%g"). | |
17731 *buf++ = '0'; | |
17732 *buf++ = static_cast<char>('0' + k); | |
17733 } | |
17734 else if (k < 100) | |
17735 { | |
17736 *buf++ = static_cast<char>('0' + k / 10); | |
17737 k %= 10; | |
17738 *buf++ = static_cast<char>('0' + k); | |
17739 } | |
17740 else | |
17741 { | |
17742 *buf++ = static_cast<char>('0' + k / 100); | |
17743 k %= 100; | |
17744 *buf++ = static_cast<char>('0' + k / 10); | |
17745 k %= 10; | |
17746 *buf++ = static_cast<char>('0' + k); | |
17747 } | |
17748 | |
17749 return buf; | |
17750 } | |
17751 | |
17752 /*! | |
17753 @brief prettify v = buf * 10^decimal_exponent | |
17754 | |
17755 If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point | |
17756 notation. Otherwise it will be printed in exponential notation. | |
17757 | |
17758 @pre min_exp < 0 | |
17759 @pre max_exp > 0 | |
17760 */ | |
17761 JSON_HEDLEY_NON_NULL(1) | |
17762 JSON_HEDLEY_RETURNS_NON_NULL | |
17763 inline char* format_buffer(char* buf, int len, int decimal_exponent, | |
17764 int min_exp, int max_exp) | |
17765 { | |
17766 JSON_ASSERT(min_exp < 0); | |
17767 JSON_ASSERT(max_exp > 0); | |
17768 | |
17769 const int k = len; | |
17770 const int n = len + decimal_exponent; | |
17771 | |
17772 // v = buf * 10^(n-k) | |
17773 // k is the length of the buffer (number of decimal digits) | |
17774 // n is the position of the decimal point relative to the start of the buffer. | |
17775 | |
17776 if (k <= n && n <= max_exp) | |
17777 { | |
17778 // digits[000] | |
17779 // len <= max_exp + 2 | |
17780 | |
17781 std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k)); | |
17782 // Make it look like a floating-point number (#362, #378) | |
17783 buf[n + 0] = '.'; | |
17784 buf[n + 1] = '0'; | |
17785 return buf + (static_cast<size_t>(n) + 2); | |
17786 } | |
17787 | |
17788 if (0 < n && n <= max_exp) | |
17789 { | |
17790 // dig.its | |
17791 // len <= max_digits10 + 1 | |
17792 | |
17793 JSON_ASSERT(k > n); | |
17794 | |
17795 std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n)); | |
17796 buf[n] = '.'; | |
17797 return buf + (static_cast<size_t>(k) + 1U); | |
17798 } | |
17799 | |
17800 if (min_exp < n && n <= 0) | |
17801 { | |
17802 // 0.[000]digits | |
17803 // len <= 2 + (-min_exp - 1) + max_digits10 | |
17804 | |
17805 std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k)); | |
17806 buf[0] = '0'; | |
17807 buf[1] = '.'; | |
17808 std::memset(buf + 2, '0', static_cast<size_t>(-n)); | |
17809 return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k)); | |
17810 } | |
17811 | |
17812 if (k == 1) | |
17813 { | |
17814 // dE+123 | |
17815 // len <= 1 + 5 | |
17816 | |
17817 buf += 1; | |
17818 } | |
17819 else | |
17820 { | |
17821 // d.igitsE+123 | |
17822 // len <= max_digits10 + 1 + 5 | |
17823 | |
17824 std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1); | |
17825 buf[1] = '.'; | |
17826 buf += 1 + static_cast<size_t>(k); | |
17827 } | |
17828 | |
17829 *buf++ = 'e'; | |
17830 return append_exponent(buf, n - 1); | |
17831 } | |
17832 | |
17833 } // namespace dtoa_impl | |
17834 | |
17835 /*! | |
17836 @brief generates a decimal representation of the floating-point number value in [first, last). | |
17837 | |
17838 The format of the resulting decimal representation is similar to printf's %g | |
17839 format. Returns an iterator pointing past-the-end of the decimal representation. | |
17840 | |
17841 @note The input number must be finite, i.e. NaN's and Inf's are not supported. | |
17842 @note The buffer must be large enough. | |
17843 @note The result is NOT null-terminated. | |
17844 */ | |
17845 template<typename FloatType> | |
17846 JSON_HEDLEY_NON_NULL(1, 2) | |
17847 JSON_HEDLEY_RETURNS_NON_NULL | |
17848 char* to_chars(char* first, const char* last, FloatType value) | |
17849 { | |
17850 static_cast<void>(last); // maybe unused - fix warning | |
17851 JSON_ASSERT(std::isfinite(value)); | |
17852 | |
17853 // Use signbit(value) instead of (value < 0) since signbit works for -0. | |
17854 if (std::signbit(value)) | |
17855 { | |
17856 value = -value; | |
17857 *first++ = '-'; | |
17858 } | |
17859 | |
17860 #ifdef __GNUC__ | |
17861 #pragma GCC diagnostic push | |
17862 #pragma GCC diagnostic ignored "-Wfloat-equal" | |
17863 #endif | |
17864 if (value == 0) // +-0 | |
17865 { | |
17866 *first++ = '0'; | |
17867 // Make it look like a floating-point number (#362, #378) | |
17868 *first++ = '.'; | |
17869 *first++ = '0'; | |
17870 return first; | |
17871 } | |
17872 #ifdef __GNUC__ | |
17873 #pragma GCC diagnostic pop | |
17874 #endif | |
17875 | |
17876 JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10); | |
17877 | |
17878 // Compute v = buffer * 10^decimal_exponent. | |
17879 // The decimal digits are stored in the buffer, which needs to be interpreted | |
17880 // as an unsigned decimal integer. | |
17881 // len is the length of the buffer, i.e. the number of decimal digits. | |
17882 int len = 0; | |
17883 int decimal_exponent = 0; | |
17884 dtoa_impl::grisu2(first, len, decimal_exponent, value); | |
17885 | |
17886 JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10); | |
17887 | |
17888 // Format the buffer like printf("%.*g", prec, value) | |
17889 constexpr int kMinExp = -4; | |
17890 // Use digits10 here to increase compatibility with version 2. | |
17891 constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10; | |
17892 | |
17893 JSON_ASSERT(last - first >= kMaxExp + 2); | |
17894 JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10); | |
17895 JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6); | |
17896 | |
17897 return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); | |
17898 } | |
17899 | |
17900 } // namespace detail | |
17901 NLOHMANN_JSON_NAMESPACE_END | |
17902 | |
17903 // #include <nlohmann/detail/exceptions.hpp> | |
17904 | |
17905 // #include <nlohmann/detail/macro_scope.hpp> | |
17906 | |
17907 // #include <nlohmann/detail/meta/cpp_future.hpp> | |
17908 | |
17909 // #include <nlohmann/detail/output/binary_writer.hpp> | |
17910 | |
17911 // #include <nlohmann/detail/output/output_adapters.hpp> | |
17912 | |
17913 // #include <nlohmann/detail/string_concat.hpp> | |
17914 | |
17915 // #include <nlohmann/detail/value_t.hpp> | |
17916 | |
17917 | |
17918 NLOHMANN_JSON_NAMESPACE_BEGIN | |
17919 namespace detail | |
17920 { | |
17921 | |
17922 /////////////////// | |
17923 // serialization // | |
17924 /////////////////// | |
17925 | |
17926 /// how to treat decoding errors | |
17927 enum class error_handler_t | |
17928 { | |
17929 strict, ///< throw a type_error exception in case of invalid UTF-8 | |
17930 replace, ///< replace invalid UTF-8 sequences with U+FFFD | |
17931 ignore ///< ignore invalid UTF-8 sequences | |
17932 }; | |
17933 | |
17934 template<typename BasicJsonType> | |
17935 class serializer | |
17936 { | |
17937 using string_t = typename BasicJsonType::string_t; | |
17938 using number_float_t = typename BasicJsonType::number_float_t; | |
17939 using number_integer_t = typename BasicJsonType::number_integer_t; | |
17940 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
17941 using binary_char_t = typename BasicJsonType::binary_t::value_type; | |
17942 static constexpr std::uint8_t UTF8_ACCEPT = 0; | |
17943 static constexpr std::uint8_t UTF8_REJECT = 1; | |
17944 | |
17945 public: | |
17946 /*! | |
17947 @param[in] s output stream to serialize to | |
17948 @param[in] ichar indentation character to use | |
17949 @param[in] error_handler_ how to react on decoding errors | |
17950 */ | |
17951 serializer(output_adapter_t<char> s, const char ichar, | |
17952 error_handler_t error_handler_ = error_handler_t::strict) | |
17953 : o(std::move(s)) | |
17954 , loc(std::localeconv()) | |
17955 , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep))) | |
17956 , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point))) | |
17957 , indent_char(ichar) | |
17958 , indent_string(512, indent_char) | |
17959 , error_handler(error_handler_) | |
17960 {} | |
17961 | |
17962 // delete because of pointer members | |
17963 serializer(const serializer&) = delete; | |
17964 serializer& operator=(const serializer&) = delete; | |
17965 serializer(serializer&&) = delete; | |
17966 serializer& operator=(serializer&&) = delete; | |
17967 ~serializer() = default; | |
17968 | |
17969 /*! | |
17970 @brief internal implementation of the serialization function | |
17971 | |
17972 This function is called by the public member function dump and organizes | |
17973 the serialization internally. The indentation level is propagated as | |
17974 additional parameter. In case of arrays and objects, the function is | |
17975 called recursively. | |
17976 | |
17977 - strings and object keys are escaped using `escape_string()` | |
17978 - integer numbers are converted implicitly via `operator<<` | |
17979 - floating-point numbers are converted to a string using `"%g"` format | |
17980 - binary values are serialized as objects containing the subtype and the | |
17981 byte array | |
17982 | |
17983 @param[in] val value to serialize | |
17984 @param[in] pretty_print whether the output shall be pretty-printed | |
17985 @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters | |
17986 in the output are escaped with `\uXXXX` sequences, and the result consists | |
17987 of ASCII characters only. | |
17988 @param[in] indent_step the indent level | |
17989 @param[in] current_indent the current indent level (only used internally) | |
17990 */ | |
17991 void dump(const BasicJsonType& val, | |
17992 const bool pretty_print, | |
17993 const bool ensure_ascii, | |
17994 const unsigned int indent_step, | |
17995 const unsigned int current_indent = 0) | |
17996 { | |
17997 switch (val.m_type) | |
17998 { | |
17999 case value_t::object: | |
18000 { | |
18001 if (val.m_value.object->empty()) | |
18002 { | |
18003 o->write_characters("{}", 2); | |
18004 return; | |
18005 } | |
18006 | |
18007 if (pretty_print) | |
18008 { | |
18009 o->write_characters("{\n", 2); | |
18010 | |
18011 // variable to hold indentation for recursive calls | |
18012 const auto new_indent = current_indent + indent_step; | |
18013 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) | |
18014 { | |
18015 indent_string.resize(indent_string.size() * 2, ' '); | |
18016 } | |
18017 | |
18018 // first n-1 elements | |
18019 auto i = val.m_value.object->cbegin(); | |
18020 for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) | |
18021 { | |
18022 o->write_characters(indent_string.c_str(), new_indent); | |
18023 o->write_character('\"'); | |
18024 dump_escaped(i->first, ensure_ascii); | |
18025 o->write_characters("\": ", 3); | |
18026 dump(i->second, true, ensure_ascii, indent_step, new_indent); | |
18027 o->write_characters(",\n", 2); | |
18028 } | |
18029 | |
18030 // last element | |
18031 JSON_ASSERT(i != val.m_value.object->cend()); | |
18032 JSON_ASSERT(std::next(i) == val.m_value.object->cend()); | |
18033 o->write_characters(indent_string.c_str(), new_indent); | |
18034 o->write_character('\"'); | |
18035 dump_escaped(i->first, ensure_ascii); | |
18036 o->write_characters("\": ", 3); | |
18037 dump(i->second, true, ensure_ascii, indent_step, new_indent); | |
18038 | |
18039 o->write_character('\n'); | |
18040 o->write_characters(indent_string.c_str(), current_indent); | |
18041 o->write_character('}'); | |
18042 } | |
18043 else | |
18044 { | |
18045 o->write_character('{'); | |
18046 | |
18047 // first n-1 elements | |
18048 auto i = val.m_value.object->cbegin(); | |
18049 for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) | |
18050 { | |
18051 o->write_character('\"'); | |
18052 dump_escaped(i->first, ensure_ascii); | |
18053 o->write_characters("\":", 2); | |
18054 dump(i->second, false, ensure_ascii, indent_step, current_indent); | |
18055 o->write_character(','); | |
18056 } | |
18057 | |
18058 // last element | |
18059 JSON_ASSERT(i != val.m_value.object->cend()); | |
18060 JSON_ASSERT(std::next(i) == val.m_value.object->cend()); | |
18061 o->write_character('\"'); | |
18062 dump_escaped(i->first, ensure_ascii); | |
18063 o->write_characters("\":", 2); | |
18064 dump(i->second, false, ensure_ascii, indent_step, current_indent); | |
18065 | |
18066 o->write_character('}'); | |
18067 } | |
18068 | |
18069 return; | |
18070 } | |
18071 | |
18072 case value_t::array: | |
18073 { | |
18074 if (val.m_value.array->empty()) | |
18075 { | |
18076 o->write_characters("[]", 2); | |
18077 return; | |
18078 } | |
18079 | |
18080 if (pretty_print) | |
18081 { | |
18082 o->write_characters("[\n", 2); | |
18083 | |
18084 // variable to hold indentation for recursive calls | |
18085 const auto new_indent = current_indent + indent_step; | |
18086 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) | |
18087 { | |
18088 indent_string.resize(indent_string.size() * 2, ' '); | |
18089 } | |
18090 | |
18091 // first n-1 elements | |
18092 for (auto i = val.m_value.array->cbegin(); | |
18093 i != val.m_value.array->cend() - 1; ++i) | |
18094 { | |
18095 o->write_characters(indent_string.c_str(), new_indent); | |
18096 dump(*i, true, ensure_ascii, indent_step, new_indent); | |
18097 o->write_characters(",\n", 2); | |
18098 } | |
18099 | |
18100 // last element | |
18101 JSON_ASSERT(!val.m_value.array->empty()); | |
18102 o->write_characters(indent_string.c_str(), new_indent); | |
18103 dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); | |
18104 | |
18105 o->write_character('\n'); | |
18106 o->write_characters(indent_string.c_str(), current_indent); | |
18107 o->write_character(']'); | |
18108 } | |
18109 else | |
18110 { | |
18111 o->write_character('['); | |
18112 | |
18113 // first n-1 elements | |
18114 for (auto i = val.m_value.array->cbegin(); | |
18115 i != val.m_value.array->cend() - 1; ++i) | |
18116 { | |
18117 dump(*i, false, ensure_ascii, indent_step, current_indent); | |
18118 o->write_character(','); | |
18119 } | |
18120 | |
18121 // last element | |
18122 JSON_ASSERT(!val.m_value.array->empty()); | |
18123 dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); | |
18124 | |
18125 o->write_character(']'); | |
18126 } | |
18127 | |
18128 return; | |
18129 } | |
18130 | |
18131 case value_t::string: | |
18132 { | |
18133 o->write_character('\"'); | |
18134 dump_escaped(*val.m_value.string, ensure_ascii); | |
18135 o->write_character('\"'); | |
18136 return; | |
18137 } | |
18138 | |
18139 case value_t::binary: | |
18140 { | |
18141 if (pretty_print) | |
18142 { | |
18143 o->write_characters("{\n", 2); | |
18144 | |
18145 // variable to hold indentation for recursive calls | |
18146 const auto new_indent = current_indent + indent_step; | |
18147 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) | |
18148 { | |
18149 indent_string.resize(indent_string.size() * 2, ' '); | |
18150 } | |
18151 | |
18152 o->write_characters(indent_string.c_str(), new_indent); | |
18153 | |
18154 o->write_characters("\"bytes\": [", 10); | |
18155 | |
18156 if (!val.m_value.binary->empty()) | |
18157 { | |
18158 for (auto i = val.m_value.binary->cbegin(); | |
18159 i != val.m_value.binary->cend() - 1; ++i) | |
18160 { | |
18161 dump_integer(*i); | |
18162 o->write_characters(", ", 2); | |
18163 } | |
18164 dump_integer(val.m_value.binary->back()); | |
18165 } | |
18166 | |
18167 o->write_characters("],\n", 3); | |
18168 o->write_characters(indent_string.c_str(), new_indent); | |
18169 | |
18170 o->write_characters("\"subtype\": ", 11); | |
18171 if (val.m_value.binary->has_subtype()) | |
18172 { | |
18173 dump_integer(val.m_value.binary->subtype()); | |
18174 } | |
18175 else | |
18176 { | |
18177 o->write_characters("null", 4); | |
18178 } | |
18179 o->write_character('\n'); | |
18180 o->write_characters(indent_string.c_str(), current_indent); | |
18181 o->write_character('}'); | |
18182 } | |
18183 else | |
18184 { | |
18185 o->write_characters("{\"bytes\":[", 10); | |
18186 | |
18187 if (!val.m_value.binary->empty()) | |
18188 { | |
18189 for (auto i = val.m_value.binary->cbegin(); | |
18190 i != val.m_value.binary->cend() - 1; ++i) | |
18191 { | |
18192 dump_integer(*i); | |
18193 o->write_character(','); | |
18194 } | |
18195 dump_integer(val.m_value.binary->back()); | |
18196 } | |
18197 | |
18198 o->write_characters("],\"subtype\":", 12); | |
18199 if (val.m_value.binary->has_subtype()) | |
18200 { | |
18201 dump_integer(val.m_value.binary->subtype()); | |
18202 o->write_character('}'); | |
18203 } | |
18204 else | |
18205 { | |
18206 o->write_characters("null}", 5); | |
18207 } | |
18208 } | |
18209 return; | |
18210 } | |
18211 | |
18212 case value_t::boolean: | |
18213 { | |
18214 if (val.m_value.boolean) | |
18215 { | |
18216 o->write_characters("true", 4); | |
18217 } | |
18218 else | |
18219 { | |
18220 o->write_characters("false", 5); | |
18221 } | |
18222 return; | |
18223 } | |
18224 | |
18225 case value_t::number_integer: | |
18226 { | |
18227 dump_integer(val.m_value.number_integer); | |
18228 return; | |
18229 } | |
18230 | |
18231 case value_t::number_unsigned: | |
18232 { | |
18233 dump_integer(val.m_value.number_unsigned); | |
18234 return; | |
18235 } | |
18236 | |
18237 case value_t::number_float: | |
18238 { | |
18239 dump_float(val.m_value.number_float); | |
18240 return; | |
18241 } | |
18242 | |
18243 case value_t::discarded: | |
18244 { | |
18245 o->write_characters("<discarded>", 11); | |
18246 return; | |
18247 } | |
18248 | |
18249 case value_t::null: | |
18250 { | |
18251 o->write_characters("null", 4); | |
18252 return; | |
18253 } | |
18254 | |
18255 default: // LCOV_EXCL_LINE | |
18256 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
18257 } | |
18258 } | |
18259 | |
18260 JSON_PRIVATE_UNLESS_TESTED: | |
18261 /*! | |
18262 @brief dump escaped string | |
18263 | |
18264 Escape a string by replacing certain special characters by a sequence of an | |
18265 escape character (backslash) and another character and other control | |
18266 characters by a sequence of "\u" followed by a four-digit hex | |
18267 representation. The escaped string is written to output stream @a o. | |
18268 | |
18269 @param[in] s the string to escape | |
18270 @param[in] ensure_ascii whether to escape non-ASCII characters with | |
18271 \uXXXX sequences | |
18272 | |
18273 @complexity Linear in the length of string @a s. | |
18274 */ | |
18275 void dump_escaped(const string_t& s, const bool ensure_ascii) | |
18276 { | |
18277 std::uint32_t codepoint{}; | |
18278 std::uint8_t state = UTF8_ACCEPT; | |
18279 std::size_t bytes = 0; // number of bytes written to string_buffer | |
18280 | |
18281 // number of bytes written at the point of the last valid byte | |
18282 std::size_t bytes_after_last_accept = 0; | |
18283 std::size_t undumped_chars = 0; | |
18284 | |
18285 for (std::size_t i = 0; i < s.size(); ++i) | |
18286 { | |
18287 const auto byte = static_cast<std::uint8_t>(s[i]); | |
18288 | |
18289 switch (decode(state, codepoint, byte)) | |
18290 { | |
18291 case UTF8_ACCEPT: // decode found a new code point | |
18292 { | |
18293 switch (codepoint) | |
18294 { | |
18295 case 0x08: // backspace | |
18296 { | |
18297 string_buffer[bytes++] = '\\'; | |
18298 string_buffer[bytes++] = 'b'; | |
18299 break; | |
18300 } | |
18301 | |
18302 case 0x09: // horizontal tab | |
18303 { | |
18304 string_buffer[bytes++] = '\\'; | |
18305 string_buffer[bytes++] = 't'; | |
18306 break; | |
18307 } | |
18308 | |
18309 case 0x0A: // newline | |
18310 { | |
18311 string_buffer[bytes++] = '\\'; | |
18312 string_buffer[bytes++] = 'n'; | |
18313 break; | |
18314 } | |
18315 | |
18316 case 0x0C: // formfeed | |
18317 { | |
18318 string_buffer[bytes++] = '\\'; | |
18319 string_buffer[bytes++] = 'f'; | |
18320 break; | |
18321 } | |
18322 | |
18323 case 0x0D: // carriage return | |
18324 { | |
18325 string_buffer[bytes++] = '\\'; | |
18326 string_buffer[bytes++] = 'r'; | |
18327 break; | |
18328 } | |
18329 | |
18330 case 0x22: // quotation mark | |
18331 { | |
18332 string_buffer[bytes++] = '\\'; | |
18333 string_buffer[bytes++] = '\"'; | |
18334 break; | |
18335 } | |
18336 | |
18337 case 0x5C: // reverse solidus | |
18338 { | |
18339 string_buffer[bytes++] = '\\'; | |
18340 string_buffer[bytes++] = '\\'; | |
18341 break; | |
18342 } | |
18343 | |
18344 default: | |
18345 { | |
18346 // escape control characters (0x00..0x1F) or, if | |
18347 // ensure_ascii parameter is used, non-ASCII characters | |
18348 if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) | |
18349 { | |
18350 if (codepoint <= 0xFFFF) | |
18351 { | |
18352 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
18353 static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", | |
18354 static_cast<std::uint16_t>(codepoint))); | |
18355 bytes += 6; | |
18356 } | |
18357 else | |
18358 { | |
18359 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
18360 static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", | |
18361 static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)), | |
18362 static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)))); | |
18363 bytes += 12; | |
18364 } | |
18365 } | |
18366 else | |
18367 { | |
18368 // copy byte to buffer (all previous bytes | |
18369 // been copied have in default case above) | |
18370 string_buffer[bytes++] = s[i]; | |
18371 } | |
18372 break; | |
18373 } | |
18374 } | |
18375 | |
18376 // write buffer and reset index; there must be 13 bytes | |
18377 // left, as this is the maximal number of bytes to be | |
18378 // written ("\uxxxx\uxxxx\0") for one code point | |
18379 if (string_buffer.size() - bytes < 13) | |
18380 { | |
18381 o->write_characters(string_buffer.data(), bytes); | |
18382 bytes = 0; | |
18383 } | |
18384 | |
18385 // remember the byte position of this accept | |
18386 bytes_after_last_accept = bytes; | |
18387 undumped_chars = 0; | |
18388 break; | |
18389 } | |
18390 | |
18391 case UTF8_REJECT: // decode found invalid UTF-8 byte | |
18392 { | |
18393 switch (error_handler) | |
18394 { | |
18395 case error_handler_t::strict: | |
18396 { | |
18397 JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr)); | |
18398 } | |
18399 | |
18400 case error_handler_t::ignore: | |
18401 case error_handler_t::replace: | |
18402 { | |
18403 // in case we saw this character the first time, we | |
18404 // would like to read it again, because the byte | |
18405 // may be OK for itself, but just not OK for the | |
18406 // previous sequence | |
18407 if (undumped_chars > 0) | |
18408 { | |
18409 --i; | |
18410 } | |
18411 | |
18412 // reset length buffer to the last accepted index; | |
18413 // thus removing/ignoring the invalid characters | |
18414 bytes = bytes_after_last_accept; | |
18415 | |
18416 if (error_handler == error_handler_t::replace) | |
18417 { | |
18418 // add a replacement character | |
18419 if (ensure_ascii) | |
18420 { | |
18421 string_buffer[bytes++] = '\\'; | |
18422 string_buffer[bytes++] = 'u'; | |
18423 string_buffer[bytes++] = 'f'; | |
18424 string_buffer[bytes++] = 'f'; | |
18425 string_buffer[bytes++] = 'f'; | |
18426 string_buffer[bytes++] = 'd'; | |
18427 } | |
18428 else | |
18429 { | |
18430 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF'); | |
18431 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF'); | |
18432 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD'); | |
18433 } | |
18434 | |
18435 // write buffer and reset index; there must be 13 bytes | |
18436 // left, as this is the maximal number of bytes to be | |
18437 // written ("\uxxxx\uxxxx\0") for one code point | |
18438 if (string_buffer.size() - bytes < 13) | |
18439 { | |
18440 o->write_characters(string_buffer.data(), bytes); | |
18441 bytes = 0; | |
18442 } | |
18443 | |
18444 bytes_after_last_accept = bytes; | |
18445 } | |
18446 | |
18447 undumped_chars = 0; | |
18448 | |
18449 // continue processing the string | |
18450 state = UTF8_ACCEPT; | |
18451 break; | |
18452 } | |
18453 | |
18454 default: // LCOV_EXCL_LINE | |
18455 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
18456 } | |
18457 break; | |
18458 } | |
18459 | |
18460 default: // decode found yet incomplete multi-byte code point | |
18461 { | |
18462 if (!ensure_ascii) | |
18463 { | |
18464 // code point will not be escaped - copy byte to buffer | |
18465 string_buffer[bytes++] = s[i]; | |
18466 } | |
18467 ++undumped_chars; | |
18468 break; | |
18469 } | |
18470 } | |
18471 } | |
18472 | |
18473 // we finished processing the string | |
18474 if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) | |
18475 { | |
18476 // write buffer | |
18477 if (bytes > 0) | |
18478 { | |
18479 o->write_characters(string_buffer.data(), bytes); | |
18480 } | |
18481 } | |
18482 else | |
18483 { | |
18484 // we finish reading, but do not accept: string was incomplete | |
18485 switch (error_handler) | |
18486 { | |
18487 case error_handler_t::strict: | |
18488 { | |
18489 JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr)); | |
18490 } | |
18491 | |
18492 case error_handler_t::ignore: | |
18493 { | |
18494 // write all accepted bytes | |
18495 o->write_characters(string_buffer.data(), bytes_after_last_accept); | |
18496 break; | |
18497 } | |
18498 | |
18499 case error_handler_t::replace: | |
18500 { | |
18501 // write all accepted bytes | |
18502 o->write_characters(string_buffer.data(), bytes_after_last_accept); | |
18503 // add a replacement character | |
18504 if (ensure_ascii) | |
18505 { | |
18506 o->write_characters("\\ufffd", 6); | |
18507 } | |
18508 else | |
18509 { | |
18510 o->write_characters("\xEF\xBF\xBD", 3); | |
18511 } | |
18512 break; | |
18513 } | |
18514 | |
18515 default: // LCOV_EXCL_LINE | |
18516 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
18517 } | |
18518 } | |
18519 } | |
18520 | |
18521 private: | |
18522 /*! | |
18523 @brief count digits | |
18524 | |
18525 Count the number of decimal (base 10) digits for an input unsigned integer. | |
18526 | |
18527 @param[in] x unsigned integer number to count its digits | |
18528 @return number of decimal digits | |
18529 */ | |
18530 inline unsigned int count_digits(number_unsigned_t x) noexcept | |
18531 { | |
18532 unsigned int n_digits = 1; | |
18533 for (;;) | |
18534 { | |
18535 if (x < 10) | |
18536 { | |
18537 return n_digits; | |
18538 } | |
18539 if (x < 100) | |
18540 { | |
18541 return n_digits + 1; | |
18542 } | |
18543 if (x < 1000) | |
18544 { | |
18545 return n_digits + 2; | |
18546 } | |
18547 if (x < 10000) | |
18548 { | |
18549 return n_digits + 3; | |
18550 } | |
18551 x = x / 10000u; | |
18552 n_digits += 4; | |
18553 } | |
18554 } | |
18555 | |
18556 /*! | |
18557 * @brief convert a byte to a uppercase hex representation | |
18558 * @param[in] byte byte to represent | |
18559 * @return representation ("00".."FF") | |
18560 */ | |
18561 static std::string hex_bytes(std::uint8_t byte) | |
18562 { | |
18563 std::string result = "FF"; | |
18564 constexpr const char* nibble_to_hex = "0123456789ABCDEF"; | |
18565 result[0] = nibble_to_hex[byte / 16]; | |
18566 result[1] = nibble_to_hex[byte % 16]; | |
18567 return result; | |
18568 } | |
18569 | |
18570 // templates to avoid warnings about useless casts | |
18571 template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0> | |
18572 bool is_negative_number(NumberType x) | |
18573 { | |
18574 return x < 0; | |
18575 } | |
18576 | |
18577 template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 > | |
18578 bool is_negative_number(NumberType /*unused*/) | |
18579 { | |
18580 return false; | |
18581 } | |
18582 | |
18583 /*! | |
18584 @brief dump an integer | |
18585 | |
18586 Dump a given integer to output stream @a o. Works internally with | |
18587 @a number_buffer. | |
18588 | |
18589 @param[in] x integer number (signed or unsigned) to dump | |
18590 @tparam NumberType either @a number_integer_t or @a number_unsigned_t | |
18591 */ | |
18592 template < typename NumberType, detail::enable_if_t < | |
18593 std::is_integral<NumberType>::value || | |
18594 std::is_same<NumberType, number_unsigned_t>::value || | |
18595 std::is_same<NumberType, number_integer_t>::value || | |
18596 std::is_same<NumberType, binary_char_t>::value, | |
18597 int > = 0 > | |
18598 void dump_integer(NumberType x) | |
18599 { | |
18600 static constexpr std::array<std::array<char, 2>, 100> digits_to_99 | |
18601 { | |
18602 { | |
18603 {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, | |
18604 {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, | |
18605 {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, | |
18606 {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, | |
18607 {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, | |
18608 {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, | |
18609 {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, | |
18610 {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, | |
18611 {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, | |
18612 {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, | |
18613 } | |
18614 }; | |
18615 | |
18616 // special case for "0" | |
18617 if (x == 0) | |
18618 { | |
18619 o->write_character('0'); | |
18620 return; | |
18621 } | |
18622 | |
18623 // use a pointer to fill the buffer | |
18624 auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
18625 | |
18626 number_unsigned_t abs_value; | |
18627 | |
18628 unsigned int n_chars{}; | |
18629 | |
18630 if (is_negative_number(x)) | |
18631 { | |
18632 *buffer_ptr = '-'; | |
18633 abs_value = remove_sign(static_cast<number_integer_t>(x)); | |
18634 | |
18635 // account one more byte for the minus sign | |
18636 n_chars = 1 + count_digits(abs_value); | |
18637 } | |
18638 else | |
18639 { | |
18640 abs_value = static_cast<number_unsigned_t>(x); | |
18641 n_chars = count_digits(abs_value); | |
18642 } | |
18643 | |
18644 // spare 1 byte for '\0' | |
18645 JSON_ASSERT(n_chars < number_buffer.size() - 1); | |
18646 | |
18647 // jump to the end to generate the string from backward, | |
18648 // so we later avoid reversing the result | |
18649 buffer_ptr += n_chars; | |
18650 | |
18651 // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu | |
18652 // See: https://www.youtube.com/watch?v=o4-CwDo2zpg | |
18653 while (abs_value >= 100) | |
18654 { | |
18655 const auto digits_index = static_cast<unsigned>((abs_value % 100)); | |
18656 abs_value /= 100; | |
18657 *(--buffer_ptr) = digits_to_99[digits_index][1]; | |
18658 *(--buffer_ptr) = digits_to_99[digits_index][0]; | |
18659 } | |
18660 | |
18661 if (abs_value >= 10) | |
18662 { | |
18663 const auto digits_index = static_cast<unsigned>(abs_value); | |
18664 *(--buffer_ptr) = digits_to_99[digits_index][1]; | |
18665 *(--buffer_ptr) = digits_to_99[digits_index][0]; | |
18666 } | |
18667 else | |
18668 { | |
18669 *(--buffer_ptr) = static_cast<char>('0' + abs_value); | |
18670 } | |
18671 | |
18672 o->write_characters(number_buffer.data(), n_chars); | |
18673 } | |
18674 | |
18675 /*! | |
18676 @brief dump a floating-point number | |
18677 | |
18678 Dump a given floating-point number to output stream @a o. Works internally | |
18679 with @a number_buffer. | |
18680 | |
18681 @param[in] x floating-point number to dump | |
18682 */ | |
18683 void dump_float(number_float_t x) | |
18684 { | |
18685 // NaN / inf | |
18686 if (!std::isfinite(x)) | |
18687 { | |
18688 o->write_characters("null", 4); | |
18689 return; | |
18690 } | |
18691 | |
18692 // If number_float_t is an IEEE-754 single or double precision number, | |
18693 // use the Grisu2 algorithm to produce short numbers which are | |
18694 // guaranteed to round-trip, using strtof and strtod, resp. | |
18695 // | |
18696 // NB: The test below works if <long double> == <double>. | |
18697 static constexpr bool is_ieee_single_or_double | |
18698 = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) || | |
18699 (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024); | |
18700 | |
18701 dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>()); | |
18702 } | |
18703 | |
18704 void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) | |
18705 { | |
18706 auto* begin = number_buffer.data(); | |
18707 auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); | |
18708 | |
18709 o->write_characters(begin, static_cast<size_t>(end - begin)); | |
18710 } | |
18711 | |
18712 void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) | |
18713 { | |
18714 // get number of digits for a float -> text -> float round-trip | |
18715 static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10; | |
18716 | |
18717 // the actual conversion | |
18718 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) | |
18719 std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); | |
18720 | |
18721 // negative value indicates an error | |
18722 JSON_ASSERT(len > 0); | |
18723 // check if buffer was large enough | |
18724 JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size()); | |
18725 | |
18726 // erase thousands separator | |
18727 if (thousands_sep != '\0') | |
18728 { | |
18729 // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 | |
18730 const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); | |
18731 std::fill(end, number_buffer.end(), '\0'); | |
18732 JSON_ASSERT((end - number_buffer.begin()) <= len); | |
18733 len = (end - number_buffer.begin()); | |
18734 } | |
18735 | |
18736 // convert decimal point to '.' | |
18737 if (decimal_point != '\0' && decimal_point != '.') | |
18738 { | |
18739 // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 | |
18740 const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); | |
18741 if (dec_pos != number_buffer.end()) | |
18742 { | |
18743 *dec_pos = '.'; | |
18744 } | |
18745 } | |
18746 | |
18747 o->write_characters(number_buffer.data(), static_cast<std::size_t>(len)); | |
18748 | |
18749 // determine if we need to append ".0" | |
18750 const bool value_is_int_like = | |
18751 std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, | |
18752 [](char c) | |
18753 { | |
18754 return c == '.' || c == 'e'; | |
18755 }); | |
18756 | |
18757 if (value_is_int_like) | |
18758 { | |
18759 o->write_characters(".0", 2); | |
18760 } | |
18761 } | |
18762 | |
18763 /*! | |
18764 @brief check whether a string is UTF-8 encoded | |
18765 | |
18766 The function checks each byte of a string whether it is UTF-8 encoded. The | |
18767 result of the check is stored in the @a state parameter. The function must | |
18768 be called initially with state 0 (accept). State 1 means the string must | |
18769 be rejected, because the current byte is not allowed. If the string is | |
18770 completely processed, but the state is non-zero, the string ended | |
18771 prematurely; that is, the last byte indicated more bytes should have | |
18772 followed. | |
18773 | |
18774 @param[in,out] state the state of the decoding | |
18775 @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) | |
18776 @param[in] byte next byte to decode | |
18777 @return new state | |
18778 | |
18779 @note The function has been edited: a std::array is used. | |
18780 | |
18781 @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> | |
18782 @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ | |
18783 */ | |
18784 static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept | |
18785 { | |
18786 static const std::array<std::uint8_t, 400> utf8d = | |
18787 { | |
18788 { | |
18789 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F | |
18790 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F | |
18791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F | |
18792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F | |
18793 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F | |
18794 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF | |
18795 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF | |
18796 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF | |
18797 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF | |
18798 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 | |
18799 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 | |
18800 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 | |
18801 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 | |
18802 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 | |
18803 } | |
18804 }; | |
18805 | |
18806 JSON_ASSERT(byte < utf8d.size()); | |
18807 const std::uint8_t type = utf8d[byte]; | |
18808 | |
18809 codep = (state != UTF8_ACCEPT) | |
18810 ? (byte & 0x3fu) | (codep << 6u) | |
18811 : (0xFFu >> type) & (byte); | |
18812 | |
18813 std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type); | |
18814 JSON_ASSERT(index < 400); | |
18815 state = utf8d[index]; | |
18816 return state; | |
18817 } | |
18818 | |
18819 /* | |
18820 * Overload to make the compiler happy while it is instantiating | |
18821 * dump_integer for number_unsigned_t. | |
18822 * Must never be called. | |
18823 */ | |
18824 number_unsigned_t remove_sign(number_unsigned_t x) | |
18825 { | |
18826 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
18827 return x; // LCOV_EXCL_LINE | |
18828 } | |
18829 | |
18830 /* | |
18831 * Helper function for dump_integer | |
18832 * | |
18833 * This function takes a negative signed integer and returns its absolute | |
18834 * value as unsigned integer. The plus/minus shuffling is necessary as we can | |
18835 * not directly remove the sign of an arbitrary signed integer as the | |
18836 * absolute values of INT_MIN and INT_MAX are usually not the same. See | |
18837 * #1708 for details. | |
18838 */ | |
18839 inline number_unsigned_t remove_sign(number_integer_t x) noexcept | |
18840 { | |
18841 JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression) | |
18842 return static_cast<number_unsigned_t>(-(x + 1)) + 1; | |
18843 } | |
18844 | |
18845 private: | |
18846 /// the output of the serializer | |
18847 output_adapter_t<char> o = nullptr; | |
18848 | |
18849 /// a (hopefully) large enough character buffer | |
18850 std::array<char, 64> number_buffer{{}}; | |
18851 | |
18852 /// the locale | |
18853 const std::lconv* loc = nullptr; | |
18854 /// the locale's thousand separator character | |
18855 const char thousands_sep = '\0'; | |
18856 /// the locale's decimal point character | |
18857 const char decimal_point = '\0'; | |
18858 | |
18859 /// string buffer | |
18860 std::array<char, 512> string_buffer{{}}; | |
18861 | |
18862 /// the indentation character | |
18863 const char indent_char; | |
18864 /// the indentation string | |
18865 string_t indent_string; | |
18866 | |
18867 /// error_handler how to react on decoding errors | |
18868 const error_handler_t error_handler; | |
18869 }; | |
18870 | |
18871 } // namespace detail | |
18872 NLOHMANN_JSON_NAMESPACE_END | |
18873 | |
18874 // #include <nlohmann/detail/value_t.hpp> | |
18875 | |
18876 // #include <nlohmann/json_fwd.hpp> | |
18877 | |
18878 // #include <nlohmann/ordered_map.hpp> | |
18879 // __ _____ _____ _____ | |
18880 // __| | __| | | | JSON for Modern C++ | |
18881 // | | |__ | | | | | | version 3.11.2 | |
18882 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
18883 // | |
18884 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
18885 // SPDX-License-Identifier: MIT | |
18886 | |
18887 | |
18888 | |
18889 #include <functional> // equal_to, less | |
18890 #include <initializer_list> // initializer_list | |
18891 #include <iterator> // input_iterator_tag, iterator_traits | |
18892 #include <memory> // allocator | |
18893 #include <stdexcept> // for out_of_range | |
18894 #include <type_traits> // enable_if, is_convertible | |
18895 #include <utility> // pair | |
18896 #include <vector> // vector | |
18897 | |
18898 // #include <nlohmann/detail/macro_scope.hpp> | |
18899 | |
18900 // #include <nlohmann/detail/meta/type_traits.hpp> | |
18901 | |
18902 | |
18903 NLOHMANN_JSON_NAMESPACE_BEGIN | |
18904 | |
18905 /// ordered_map: a minimal map-like container that preserves insertion order | |
18906 /// for use within nlohmann::basic_json<ordered_map> | |
18907 template <class Key, class T, class IgnoredLess = std::less<Key>, | |
18908 class Allocator = std::allocator<std::pair<const Key, T>>> | |
18909 struct ordered_map : std::vector<std::pair<const Key, T>, Allocator> | |
18910 { | |
18911 using key_type = Key; | |
18912 using mapped_type = T; | |
18913 using Container = std::vector<std::pair<const Key, T>, Allocator>; | |
18914 using iterator = typename Container::iterator; | |
18915 using const_iterator = typename Container::const_iterator; | |
18916 using size_type = typename Container::size_type; | |
18917 using value_type = typename Container::value_type; | |
18918 #ifdef JSON_HAS_CPP_14 | |
18919 using key_compare = std::equal_to<>; | |
18920 #else | |
18921 using key_compare = std::equal_to<Key>; | |
18922 #endif | |
18923 | |
18924 // Explicit constructors instead of `using Container::Container` | |
18925 // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) | |
18926 ordered_map() noexcept(noexcept(Container())) : Container{} {} | |
18927 explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} | |
18928 template <class It> | |
18929 ordered_map(It first, It last, const Allocator& alloc = Allocator()) | |
18930 : Container{first, last, alloc} {} | |
18931 ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() ) | |
18932 : Container{init, alloc} {} | |
18933 | |
18934 std::pair<iterator, bool> emplace(const key_type& key, T&& t) | |
18935 { | |
18936 for (auto it = this->begin(); it != this->end(); ++it) | |
18937 { | |
18938 if (m_compare(it->first, key)) | |
18939 { | |
18940 return {it, false}; | |
18941 } | |
18942 } | |
18943 Container::emplace_back(key, std::forward<T>(t)); | |
18944 return {std::prev(this->end()), true}; | |
18945 } | |
18946 | |
18947 template<class KeyType, detail::enable_if_t< | |
18948 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
18949 std::pair<iterator, bool> emplace(KeyType && key, T && t) | |
18950 { | |
18951 for (auto it = this->begin(); it != this->end(); ++it) | |
18952 { | |
18953 if (m_compare(it->first, key)) | |
18954 { | |
18955 return {it, false}; | |
18956 } | |
18957 } | |
18958 Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t)); | |
18959 return {std::prev(this->end()), true}; | |
18960 } | |
18961 | |
18962 T& operator[](const key_type& key) | |
18963 { | |
18964 return emplace(key, T{}).first->second; | |
18965 } | |
18966 | |
18967 template<class KeyType, detail::enable_if_t< | |
18968 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
18969 T & operator[](KeyType && key) | |
18970 { | |
18971 return emplace(std::forward<KeyType>(key), T{}).first->second; | |
18972 } | |
18973 | |
18974 const T& operator[](const key_type& key) const | |
18975 { | |
18976 return at(key); | |
18977 } | |
18978 | |
18979 template<class KeyType, detail::enable_if_t< | |
18980 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
18981 const T & operator[](KeyType && key) const | |
18982 { | |
18983 return at(std::forward<KeyType>(key)); | |
18984 } | |
18985 | |
18986 T& at(const key_type& key) | |
18987 { | |
18988 for (auto it = this->begin(); it != this->end(); ++it) | |
18989 { | |
18990 if (m_compare(it->first, key)) | |
18991 { | |
18992 return it->second; | |
18993 } | |
18994 } | |
18995 | |
18996 JSON_THROW(std::out_of_range("key not found")); | |
18997 } | |
18998 | |
18999 template<class KeyType, detail::enable_if_t< | |
19000 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
19001 T & at(KeyType && key) | |
19002 { | |
19003 for (auto it = this->begin(); it != this->end(); ++it) | |
19004 { | |
19005 if (m_compare(it->first, key)) | |
19006 { | |
19007 return it->second; | |
19008 } | |
19009 } | |
19010 | |
19011 JSON_THROW(std::out_of_range("key not found")); | |
19012 } | |
19013 | |
19014 const T& at(const key_type& key) const | |
19015 { | |
19016 for (auto it = this->begin(); it != this->end(); ++it) | |
19017 { | |
19018 if (m_compare(it->first, key)) | |
19019 { | |
19020 return it->second; | |
19021 } | |
19022 } | |
19023 | |
19024 JSON_THROW(std::out_of_range("key not found")); | |
19025 } | |
19026 | |
19027 template<class KeyType, detail::enable_if_t< | |
19028 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
19029 const T & at(KeyType && key) const | |
19030 { | |
19031 for (auto it = this->begin(); it != this->end(); ++it) | |
19032 { | |
19033 if (m_compare(it->first, key)) | |
19034 { | |
19035 return it->second; | |
19036 } | |
19037 } | |
19038 | |
19039 JSON_THROW(std::out_of_range("key not found")); | |
19040 } | |
19041 | |
19042 size_type erase(const key_type& key) | |
19043 { | |
19044 for (auto it = this->begin(); it != this->end(); ++it) | |
19045 { | |
19046 if (m_compare(it->first, key)) | |
19047 { | |
19048 // Since we cannot move const Keys, re-construct them in place | |
19049 for (auto next = it; ++next != this->end(); ++it) | |
19050 { | |
19051 it->~value_type(); // Destroy but keep allocation | |
19052 new (&*it) value_type{std::move(*next)}; | |
19053 } | |
19054 Container::pop_back(); | |
19055 return 1; | |
19056 } | |
19057 } | |
19058 return 0; | |
19059 } | |
19060 | |
19061 template<class KeyType, detail::enable_if_t< | |
19062 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
19063 size_type erase(KeyType && key) | |
19064 { | |
19065 for (auto it = this->begin(); it != this->end(); ++it) | |
19066 { | |
19067 if (m_compare(it->first, key)) | |
19068 { | |
19069 // Since we cannot move const Keys, re-construct them in place | |
19070 for (auto next = it; ++next != this->end(); ++it) | |
19071 { | |
19072 it->~value_type(); // Destroy but keep allocation | |
19073 new (&*it) value_type{std::move(*next)}; | |
19074 } | |
19075 Container::pop_back(); | |
19076 return 1; | |
19077 } | |
19078 } | |
19079 return 0; | |
19080 } | |
19081 | |
19082 iterator erase(iterator pos) | |
19083 { | |
19084 return erase(pos, std::next(pos)); | |
19085 } | |
19086 | |
19087 iterator erase(iterator first, iterator last) | |
19088 { | |
19089 if (first == last) | |
19090 { | |
19091 return first; | |
19092 } | |
19093 | |
19094 const auto elements_affected = std::distance(first, last); | |
19095 const auto offset = std::distance(Container::begin(), first); | |
19096 | |
19097 // This is the start situation. We need to delete elements_affected | |
19098 // elements (3 in this example: e, f, g), and need to return an | |
19099 // iterator past the last deleted element (h in this example). | |
19100 // Note that offset is the distance from the start of the vector | |
19101 // to first. We will need this later. | |
19102 | |
19103 // [ a, b, c, d, e, f, g, h, i, j ] | |
19104 // ^ ^ | |
19105 // first last | |
19106 | |
19107 // Since we cannot move const Keys, we re-construct them in place. | |
19108 // We start at first and re-construct (viz. copy) the elements from | |
19109 // the back of the vector. Example for first iteration: | |
19110 | |
19111 // ,--------. | |
19112 // v | destroy e and re-construct with h | |
19113 // [ a, b, c, d, e, f, g, h, i, j ] | |
19114 // ^ ^ | |
19115 // it it + elements_affected | |
19116 | |
19117 for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) | |
19118 { | |
19119 it->~value_type(); // destroy but keep allocation | |
19120 new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it | |
19121 } | |
19122 | |
19123 // [ a, b, c, d, h, i, j, h, i, j ] | |
19124 // ^ ^ | |
19125 // first last | |
19126 | |
19127 // remove the unneeded elements at the end of the vector | |
19128 Container::resize(this->size() - static_cast<size_type>(elements_affected)); | |
19129 | |
19130 // [ a, b, c, d, h, i, j ] | |
19131 // ^ ^ | |
19132 // first last | |
19133 | |
19134 // first is now pointing past the last deleted element, but we cannot | |
19135 // use this iterator, because it may have been invalidated by the | |
19136 // resize call. Instead, we can return begin() + offset. | |
19137 return Container::begin() + offset; | |
19138 } | |
19139 | |
19140 size_type count(const key_type& key) const | |
19141 { | |
19142 for (auto it = this->begin(); it != this->end(); ++it) | |
19143 { | |
19144 if (m_compare(it->first, key)) | |
19145 { | |
19146 return 1; | |
19147 } | |
19148 } | |
19149 return 0; | |
19150 } | |
19151 | |
19152 template<class KeyType, detail::enable_if_t< | |
19153 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
19154 size_type count(KeyType && key) const | |
19155 { | |
19156 for (auto it = this->begin(); it != this->end(); ++it) | |
19157 { | |
19158 if (m_compare(it->first, key)) | |
19159 { | |
19160 return 1; | |
19161 } | |
19162 } | |
19163 return 0; | |
19164 } | |
19165 | |
19166 iterator find(const key_type& key) | |
19167 { | |
19168 for (auto it = this->begin(); it != this->end(); ++it) | |
19169 { | |
19170 if (m_compare(it->first, key)) | |
19171 { | |
19172 return it; | |
19173 } | |
19174 } | |
19175 return Container::end(); | |
19176 } | |
19177 | |
19178 template<class KeyType, detail::enable_if_t< | |
19179 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | |
19180 iterator find(KeyType && key) | |
19181 { | |
19182 for (auto it = this->begin(); it != this->end(); ++it) | |
19183 { | |
19184 if (m_compare(it->first, key)) | |
19185 { | |
19186 return it; | |
19187 } | |
19188 } | |
19189 return Container::end(); | |
19190 } | |
19191 | |
19192 const_iterator find(const key_type& key) const | |
19193 { | |
19194 for (auto it = this->begin(); it != this->end(); ++it) | |
19195 { | |
19196 if (m_compare(it->first, key)) | |
19197 { | |
19198 return it; | |
19199 } | |
19200 } | |
19201 return Container::end(); | |
19202 } | |
19203 | |
19204 std::pair<iterator, bool> insert( value_type&& value ) | |
19205 { | |
19206 return emplace(value.first, std::move(value.second)); | |
19207 } | |
19208 | |
19209 std::pair<iterator, bool> insert( const value_type& value ) | |
19210 { | |
19211 for (auto it = this->begin(); it != this->end(); ++it) | |
19212 { | |
19213 if (m_compare(it->first, value.first)) | |
19214 { | |
19215 return {it, false}; | |
19216 } | |
19217 } | |
19218 Container::push_back(value); | |
19219 return {--this->end(), true}; | |
19220 } | |
19221 | |
19222 template<typename InputIt> | |
19223 using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category, | |
19224 std::input_iterator_tag>::value>::type; | |
19225 | |
19226 template<typename InputIt, typename = require_input_iter<InputIt>> | |
19227 void insert(InputIt first, InputIt last) | |
19228 { | |
19229 for (auto it = first; it != last; ++it) | |
19230 { | |
19231 insert(*it); | |
19232 } | |
19233 } | |
19234 | |
19235 private: | |
19236 JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare(); | |
19237 }; | |
19238 | |
19239 NLOHMANN_JSON_NAMESPACE_END | |
19240 | |
19241 | |
19242 #if defined(JSON_HAS_CPP_17) | |
19243 #include <any> | |
19244 #include <string_view> | |
19245 #endif | |
19246 | |
19247 /*! | |
19248 @brief namespace for Niels Lohmann | |
19249 @see https://github.com/nlohmann | |
19250 @since version 1.0.0 | |
19251 */ | |
19252 NLOHMANN_JSON_NAMESPACE_BEGIN | |
19253 | |
19254 /*! | |
19255 @brief a class to store JSON values | |
19256 | |
19257 @internal | |
19258 @invariant The member variables @a m_value and @a m_type have the following | |
19259 relationship: | |
19260 - If `m_type == value_t::object`, then `m_value.object != nullptr`. | |
19261 - If `m_type == value_t::array`, then `m_value.array != nullptr`. | |
19262 - If `m_type == value_t::string`, then `m_value.string != nullptr`. | |
19263 The invariants are checked by member function assert_invariant(). | |
19264 | |
19265 @note ObjectType trick from https://stackoverflow.com/a/9860911 | |
19266 @endinternal | |
19267 | |
19268 @since version 1.0.0 | |
19269 | |
19270 @nosubgrouping | |
19271 */ | |
19272 NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
19273 class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) | |
19274 { | |
19275 private: | |
19276 template<detail::value_t> friend struct detail::external_constructor; | |
19277 | |
19278 template<typename> | |
19279 friend class ::nlohmann::json_pointer; | |
19280 // can be restored when json_pointer backwards compatibility is removed | |
19281 // friend ::nlohmann::json_pointer<StringType>; | |
19282 | |
19283 template<typename BasicJsonType, typename InputType> | |
19284 friend class ::nlohmann::detail::parser; | |
19285 friend ::nlohmann::detail::serializer<basic_json>; | |
19286 template<typename BasicJsonType> | |
19287 friend class ::nlohmann::detail::iter_impl; | |
19288 template<typename BasicJsonType, typename CharType> | |
19289 friend class ::nlohmann::detail::binary_writer; | |
19290 template<typename BasicJsonType, typename InputType, typename SAX> | |
19291 friend class ::nlohmann::detail::binary_reader; | |
19292 template<typename BasicJsonType> | |
19293 friend class ::nlohmann::detail::json_sax_dom_parser; | |
19294 template<typename BasicJsonType> | |
19295 friend class ::nlohmann::detail::json_sax_dom_callback_parser; | |
19296 friend class ::nlohmann::detail::exception; | |
19297 | |
19298 /// workaround type for MSVC | |
19299 using basic_json_t = NLOHMANN_BASIC_JSON_TPL; | |
19300 | |
19301 JSON_PRIVATE_UNLESS_TESTED: | |
19302 // convenience aliases for types residing in namespace detail; | |
19303 using lexer = ::nlohmann::detail::lexer_base<basic_json>; | |
19304 | |
19305 template<typename InputAdapterType> | |
19306 static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser( | |
19307 InputAdapterType adapter, | |
19308 detail::parser_callback_t<basic_json>cb = nullptr, | |
19309 const bool allow_exceptions = true, | |
19310 const bool ignore_comments = false | |
19311 ) | |
19312 { | |
19313 return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter), | |
19314 std::move(cb), allow_exceptions, ignore_comments); | |
19315 } | |
19316 | |
19317 private: | |
19318 using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; | |
19319 template<typename BasicJsonType> | |
19320 using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>; | |
19321 template<typename BasicJsonType> | |
19322 using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>; | |
19323 template<typename Iterator> | |
19324 using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>; | |
19325 template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>; | |
19326 | |
19327 template<typename CharType> | |
19328 using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>; | |
19329 | |
19330 template<typename InputType> | |
19331 using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>; | |
19332 template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>; | |
19333 | |
19334 JSON_PRIVATE_UNLESS_TESTED: | |
19335 using serializer = ::nlohmann::detail::serializer<basic_json>; | |
19336 | |
19337 public: | |
19338 using value_t = detail::value_t; | |
19339 /// JSON Pointer, see @ref nlohmann::json_pointer | |
19340 using json_pointer = ::nlohmann::json_pointer<StringType>; | |
19341 template<typename T, typename SFINAE> | |
19342 using json_serializer = JSONSerializer<T, SFINAE>; | |
19343 /// how to treat decoding errors | |
19344 using error_handler_t = detail::error_handler_t; | |
19345 /// how to treat CBOR tags | |
19346 using cbor_tag_handler_t = detail::cbor_tag_handler_t; | |
19347 /// helper type for initializer lists of basic_json values | |
19348 using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>; | |
19349 | |
19350 using input_format_t = detail::input_format_t; | |
19351 /// SAX interface type, see @ref nlohmann::json_sax | |
19352 using json_sax_t = json_sax<basic_json>; | |
19353 | |
19354 //////////////// | |
19355 // exceptions // | |
19356 //////////////// | |
19357 | |
19358 /// @name exceptions | |
19359 /// Classes to implement user-defined exceptions. | |
19360 /// @{ | |
19361 | |
19362 using exception = detail::exception; | |
19363 using parse_error = detail::parse_error; | |
19364 using invalid_iterator = detail::invalid_iterator; | |
19365 using type_error = detail::type_error; | |
19366 using out_of_range = detail::out_of_range; | |
19367 using other_error = detail::other_error; | |
19368 | |
19369 /// @} | |
19370 | |
19371 | |
19372 ///////////////////// | |
19373 // container types // | |
19374 ///////////////////// | |
19375 | |
19376 /// @name container types | |
19377 /// The canonic container types to use @ref basic_json like any other STL | |
19378 /// container. | |
19379 /// @{ | |
19380 | |
19381 /// the type of elements in a basic_json container | |
19382 using value_type = basic_json; | |
19383 | |
19384 /// the type of an element reference | |
19385 using reference = value_type&; | |
19386 /// the type of an element const reference | |
19387 using const_reference = const value_type&; | |
19388 | |
19389 /// a type to represent differences between iterators | |
19390 using difference_type = std::ptrdiff_t; | |
19391 /// a type to represent container sizes | |
19392 using size_type = std::size_t; | |
19393 | |
19394 /// the allocator type | |
19395 using allocator_type = AllocatorType<basic_json>; | |
19396 | |
19397 /// the type of an element pointer | |
19398 using pointer = typename std::allocator_traits<allocator_type>::pointer; | |
19399 /// the type of an element const pointer | |
19400 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; | |
19401 | |
19402 /// an iterator for a basic_json container | |
19403 using iterator = iter_impl<basic_json>; | |
19404 /// a const iterator for a basic_json container | |
19405 using const_iterator = iter_impl<const basic_json>; | |
19406 /// a reverse iterator for a basic_json container | |
19407 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>; | |
19408 /// a const reverse iterator for a basic_json container | |
19409 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>; | |
19410 | |
19411 /// @} | |
19412 | |
19413 | |
19414 /// @brief returns the allocator associated with the container | |
19415 /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/ | |
19416 static allocator_type get_allocator() | |
19417 { | |
19418 return allocator_type(); | |
19419 } | |
19420 | |
19421 /// @brief returns version information on the library | |
19422 /// @sa https://json.nlohmann.me/api/basic_json/meta/ | |
19423 JSON_HEDLEY_WARN_UNUSED_RESULT | |
19424 static basic_json meta() | |
19425 { | |
19426 basic_json result; | |
19427 | |
19428 result["copyright"] = "(C) 2013-2022 Niels Lohmann"; | |
19429 result["name"] = "JSON for Modern C++"; | |
19430 result["url"] = "https://github.com/nlohmann/json"; | |
19431 result["version"]["string"] = | |
19432 detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.', | |
19433 std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.', | |
19434 std::to_string(NLOHMANN_JSON_VERSION_PATCH)); | |
19435 result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; | |
19436 result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; | |
19437 result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; | |
19438 | |
19439 #ifdef _WIN32 | |
19440 result["platform"] = "win32"; | |
19441 #elif defined __linux__ | |
19442 result["platform"] = "linux"; | |
19443 #elif defined __APPLE__ | |
19444 result["platform"] = "apple"; | |
19445 #elif defined __unix__ | |
19446 result["platform"] = "unix"; | |
19447 #else | |
19448 result["platform"] = "unknown"; | |
19449 #endif | |
19450 | |
19451 #if defined(__ICC) || defined(__INTEL_COMPILER) | |
19452 result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; | |
19453 #elif defined(__clang__) | |
19454 result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; | |
19455 #elif defined(__GNUC__) || defined(__GNUG__) | |
19456 result["compiler"] = {{"family", "gcc"}, {"version", detail::concat( | |
19457 std::to_string(__GNUC__), '.', | |
19458 std::to_string(__GNUC_MINOR__), '.', | |
19459 std::to_string(__GNUC_PATCHLEVEL__)) | |
19460 } | |
19461 }; | |
19462 #elif defined(__HP_cc) || defined(__HP_aCC) | |
19463 result["compiler"] = "hp" | |
19464 #elif defined(__IBMCPP__) | |
19465 result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; | |
19466 #elif defined(_MSC_VER) | |
19467 result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; | |
19468 #elif defined(__PGI) | |
19469 result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; | |
19470 #elif defined(__SUNPRO_CC) | |
19471 result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; | |
19472 #else | |
19473 result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; | |
19474 #endif | |
19475 | |
19476 | |
19477 #if defined(_MSVC_LANG) | |
19478 result["compiler"]["c++"] = std::to_string(_MSVC_LANG); | |
19479 #elif defined(__cplusplus) | |
19480 result["compiler"]["c++"] = std::to_string(__cplusplus); | |
19481 #else | |
19482 result["compiler"]["c++"] = "unknown"; | |
19483 #endif | |
19484 return result; | |
19485 } | |
19486 | |
19487 | |
19488 /////////////////////////// | |
19489 // JSON value data types // | |
19490 /////////////////////////// | |
19491 | |
19492 /// @name JSON value data types | |
19493 /// The data types to store a JSON value. These types are derived from | |
19494 /// the template arguments passed to class @ref basic_json. | |
19495 /// @{ | |
19496 | |
19497 /// @brief default object key comparator type | |
19498 /// The actual object key comparator type (@ref object_comparator_t) may be | |
19499 /// different. | |
19500 /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/ | |
19501 #if defined(JSON_HAS_CPP_14) | |
19502 // use of transparent comparator avoids unnecessary repeated construction of temporaries | |
19503 // in functions involving lookup by key with types other than object_t::key_type (aka. StringType) | |
19504 using default_object_comparator_t = std::less<>; | |
19505 #else | |
19506 using default_object_comparator_t = std::less<StringType>; | |
19507 #endif | |
19508 | |
19509 /// @brief a type for an object | |
19510 /// @sa https://json.nlohmann.me/api/basic_json/object_t/ | |
19511 using object_t = ObjectType<StringType, | |
19512 basic_json, | |
19513 default_object_comparator_t, | |
19514 AllocatorType<std::pair<const StringType, | |
19515 basic_json>>>; | |
19516 | |
19517 /// @brief a type for an array | |
19518 /// @sa https://json.nlohmann.me/api/basic_json/array_t/ | |
19519 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>; | |
19520 | |
19521 /// @brief a type for a string | |
19522 /// @sa https://json.nlohmann.me/api/basic_json/string_t/ | |
19523 using string_t = StringType; | |
19524 | |
19525 /// @brief a type for a boolean | |
19526 /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/ | |
19527 using boolean_t = BooleanType; | |
19528 | |
19529 /// @brief a type for a number (integer) | |
19530 /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/ | |
19531 using number_integer_t = NumberIntegerType; | |
19532 | |
19533 /// @brief a type for a number (unsigned) | |
19534 /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/ | |
19535 using number_unsigned_t = NumberUnsignedType; | |
19536 | |
19537 /// @brief a type for a number (floating-point) | |
19538 /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/ | |
19539 using number_float_t = NumberFloatType; | |
19540 | |
19541 /// @brief a type for a packed binary type | |
19542 /// @sa https://json.nlohmann.me/api/basic_json/binary_t/ | |
19543 using binary_t = nlohmann::byte_container_with_subtype<BinaryType>; | |
19544 | |
19545 /// @brief object key comparator type | |
19546 /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/ | |
19547 using object_comparator_t = detail::actual_object_comparator_t<basic_json>; | |
19548 | |
19549 /// @} | |
19550 | |
19551 private: | |
19552 | |
19553 /// helper for exception-safe object creation | |
19554 template<typename T, typename... Args> | |
19555 JSON_HEDLEY_RETURNS_NON_NULL | |
19556 static T* create(Args&& ... args) | |
19557 { | |
19558 AllocatorType<T> alloc; | |
19559 using AllocatorTraits = std::allocator_traits<AllocatorType<T>>; | |
19560 | |
19561 auto deleter = [&](T * obj) | |
19562 { | |
19563 AllocatorTraits::deallocate(alloc, obj, 1); | |
19564 }; | |
19565 std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter); | |
19566 AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...); | |
19567 JSON_ASSERT(obj != nullptr); | |
19568 return obj.release(); | |
19569 } | |
19570 | |
19571 //////////////////////// | |
19572 // JSON value storage // | |
19573 //////////////////////// | |
19574 | |
19575 JSON_PRIVATE_UNLESS_TESTED: | |
19576 /*! | |
19577 @brief a JSON value | |
19578 | |
19579 The actual storage for a JSON value of the @ref basic_json class. This | |
19580 union combines the different storage types for the JSON value types | |
19581 defined in @ref value_t. | |
19582 | |
19583 JSON type | value_t type | used type | |
19584 --------- | --------------- | ------------------------ | |
19585 object | object | pointer to @ref object_t | |
19586 array | array | pointer to @ref array_t | |
19587 string | string | pointer to @ref string_t | |
19588 boolean | boolean | @ref boolean_t | |
19589 number | number_integer | @ref number_integer_t | |
19590 number | number_unsigned | @ref number_unsigned_t | |
19591 number | number_float | @ref number_float_t | |
19592 binary | binary | pointer to @ref binary_t | |
19593 null | null | *no value is stored* | |
19594 | |
19595 @note Variable-length types (objects, arrays, and strings) are stored as | |
19596 pointers. The size of the union should not exceed 64 bits if the default | |
19597 value types are used. | |
19598 | |
19599 @since version 1.0.0 | |
19600 */ | |
19601 union json_value | |
19602 { | |
19603 /// object (stored with pointer to save storage) | |
19604 object_t* object; | |
19605 /// array (stored with pointer to save storage) | |
19606 array_t* array; | |
19607 /// string (stored with pointer to save storage) | |
19608 string_t* string; | |
19609 /// binary (stored with pointer to save storage) | |
19610 binary_t* binary; | |
19611 /// boolean | |
19612 boolean_t boolean; | |
19613 /// number (integer) | |
19614 number_integer_t number_integer; | |
19615 /// number (unsigned integer) | |
19616 number_unsigned_t number_unsigned; | |
19617 /// number (floating-point) | |
19618 number_float_t number_float; | |
19619 | |
19620 /// default constructor (for null values) | |
19621 json_value() = default; | |
19622 /// constructor for booleans | |
19623 json_value(boolean_t v) noexcept : boolean(v) {} | |
19624 /// constructor for numbers (integer) | |
19625 json_value(number_integer_t v) noexcept : number_integer(v) {} | |
19626 /// constructor for numbers (unsigned) | |
19627 json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} | |
19628 /// constructor for numbers (floating-point) | |
19629 json_value(number_float_t v) noexcept : number_float(v) {} | |
19630 /// constructor for empty values of a given type | |
19631 json_value(value_t t) | |
19632 { | |
19633 switch (t) | |
19634 { | |
19635 case value_t::object: | |
19636 { | |
19637 object = create<object_t>(); | |
19638 break; | |
19639 } | |
19640 | |
19641 case value_t::array: | |
19642 { | |
19643 array = create<array_t>(); | |
19644 break; | |
19645 } | |
19646 | |
19647 case value_t::string: | |
19648 { | |
19649 string = create<string_t>(""); | |
19650 break; | |
19651 } | |
19652 | |
19653 case value_t::binary: | |
19654 { | |
19655 binary = create<binary_t>(); | |
19656 break; | |
19657 } | |
19658 | |
19659 case value_t::boolean: | |
19660 { | |
19661 boolean = static_cast<boolean_t>(false); | |
19662 break; | |
19663 } | |
19664 | |
19665 case value_t::number_integer: | |
19666 { | |
19667 number_integer = static_cast<number_integer_t>(0); | |
19668 break; | |
19669 } | |
19670 | |
19671 case value_t::number_unsigned: | |
19672 { | |
19673 number_unsigned = static_cast<number_unsigned_t>(0); | |
19674 break; | |
19675 } | |
19676 | |
19677 case value_t::number_float: | |
19678 { | |
19679 number_float = static_cast<number_float_t>(0.0); | |
19680 break; | |
19681 } | |
19682 | |
19683 case value_t::null: | |
19684 { | |
19685 object = nullptr; // silence warning, see #821 | |
19686 break; | |
19687 } | |
19688 | |
19689 case value_t::discarded: | |
19690 default: | |
19691 { | |
19692 object = nullptr; // silence warning, see #821 | |
19693 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) | |
19694 { | |
19695 JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.2", nullptr)); // LCOV_EXCL_LINE | |
19696 } | |
19697 break; | |
19698 } | |
19699 } | |
19700 } | |
19701 | |
19702 /// constructor for strings | |
19703 json_value(const string_t& value) : string(create<string_t>(value)) {} | |
19704 | |
19705 /// constructor for rvalue strings | |
19706 json_value(string_t&& value) : string(create<string_t>(std::move(value))) {} | |
19707 | |
19708 /// constructor for objects | |
19709 json_value(const object_t& value) : object(create<object_t>(value)) {} | |
19710 | |
19711 /// constructor for rvalue objects | |
19712 json_value(object_t&& value) : object(create<object_t>(std::move(value))) {} | |
19713 | |
19714 /// constructor for arrays | |
19715 json_value(const array_t& value) : array(create<array_t>(value)) {} | |
19716 | |
19717 /// constructor for rvalue arrays | |
19718 json_value(array_t&& value) : array(create<array_t>(std::move(value))) {} | |
19719 | |
19720 /// constructor for binary arrays | |
19721 json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {} | |
19722 | |
19723 /// constructor for rvalue binary arrays | |
19724 json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {} | |
19725 | |
19726 /// constructor for binary arrays (internal type) | |
19727 json_value(const binary_t& value) : binary(create<binary_t>(value)) {} | |
19728 | |
19729 /// constructor for rvalue binary arrays (internal type) | |
19730 json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {} | |
19731 | |
19732 void destroy(value_t t) | |
19733 { | |
19734 if (t == value_t::array || t == value_t::object) | |
19735 { | |
19736 // flatten the current json_value to a heap-allocated stack | |
19737 std::vector<basic_json> stack; | |
19738 | |
19739 // move the top-level items to stack | |
19740 if (t == value_t::array) | |
19741 { | |
19742 stack.reserve(array->size()); | |
19743 std::move(array->begin(), array->end(), std::back_inserter(stack)); | |
19744 } | |
19745 else | |
19746 { | |
19747 stack.reserve(object->size()); | |
19748 for (auto&& it : *object) | |
19749 { | |
19750 stack.push_back(std::move(it.second)); | |
19751 } | |
19752 } | |
19753 | |
19754 while (!stack.empty()) | |
19755 { | |
19756 // move the last item to local variable to be processed | |
19757 basic_json current_item(std::move(stack.back())); | |
19758 stack.pop_back(); | |
19759 | |
19760 // if current_item is array/object, move | |
19761 // its children to the stack to be processed later | |
19762 if (current_item.is_array()) | |
19763 { | |
19764 std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack)); | |
19765 | |
19766 current_item.m_value.array->clear(); | |
19767 } | |
19768 else if (current_item.is_object()) | |
19769 { | |
19770 for (auto&& it : *current_item.m_value.object) | |
19771 { | |
19772 stack.push_back(std::move(it.second)); | |
19773 } | |
19774 | |
19775 current_item.m_value.object->clear(); | |
19776 } | |
19777 | |
19778 // it's now safe that current_item get destructed | |
19779 // since it doesn't have any children | |
19780 } | |
19781 } | |
19782 | |
19783 switch (t) | |
19784 { | |
19785 case value_t::object: | |
19786 { | |
19787 AllocatorType<object_t> alloc; | |
19788 std::allocator_traits<decltype(alloc)>::destroy(alloc, object); | |
19789 std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1); | |
19790 break; | |
19791 } | |
19792 | |
19793 case value_t::array: | |
19794 { | |
19795 AllocatorType<array_t> alloc; | |
19796 std::allocator_traits<decltype(alloc)>::destroy(alloc, array); | |
19797 std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1); | |
19798 break; | |
19799 } | |
19800 | |
19801 case value_t::string: | |
19802 { | |
19803 AllocatorType<string_t> alloc; | |
19804 std::allocator_traits<decltype(alloc)>::destroy(alloc, string); | |
19805 std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1); | |
19806 break; | |
19807 } | |
19808 | |
19809 case value_t::binary: | |
19810 { | |
19811 AllocatorType<binary_t> alloc; | |
19812 std::allocator_traits<decltype(alloc)>::destroy(alloc, binary); | |
19813 std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1); | |
19814 break; | |
19815 } | |
19816 | |
19817 case value_t::null: | |
19818 case value_t::boolean: | |
19819 case value_t::number_integer: | |
19820 case value_t::number_unsigned: | |
19821 case value_t::number_float: | |
19822 case value_t::discarded: | |
19823 default: | |
19824 { | |
19825 break; | |
19826 } | |
19827 } | |
19828 } | |
19829 }; | |
19830 | |
19831 private: | |
19832 /*! | |
19833 @brief checks the class invariants | |
19834 | |
19835 This function asserts the class invariants. It needs to be called at the | |
19836 end of every constructor to make sure that created objects respect the | |
19837 invariant. Furthermore, it has to be called each time the type of a JSON | |
19838 value is changed, because the invariant expresses a relationship between | |
19839 @a m_type and @a m_value. | |
19840 | |
19841 Furthermore, the parent relation is checked for arrays and objects: If | |
19842 @a check_parents true and the value is an array or object, then the | |
19843 container's elements must have the current value as parent. | |
19844 | |
19845 @param[in] check_parents whether the parent relation should be checked. | |
19846 The value is true by default and should only be set to false | |
19847 during destruction of objects when the invariant does not | |
19848 need to hold. | |
19849 */ | |
19850 void assert_invariant(bool check_parents = true) const noexcept | |
19851 { | |
19852 JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr); | |
19853 JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr); | |
19854 JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr); | |
19855 JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr); | |
19856 | |
19857 #if JSON_DIAGNOSTICS | |
19858 JSON_TRY | |
19859 { | |
19860 // cppcheck-suppress assertWithSideEffect | |
19861 JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) | |
19862 { | |
19863 return j.m_parent == this; | |
19864 })); | |
19865 } | |
19866 JSON_CATCH(...) {} // LCOV_EXCL_LINE | |
19867 #endif | |
19868 static_cast<void>(check_parents); | |
19869 } | |
19870 | |
19871 void set_parents() | |
19872 { | |
19873 #if JSON_DIAGNOSTICS | |
19874 switch (m_type) | |
19875 { | |
19876 case value_t::array: | |
19877 { | |
19878 for (auto& element : *m_value.array) | |
19879 { | |
19880 element.m_parent = this; | |
19881 } | |
19882 break; | |
19883 } | |
19884 | |
19885 case value_t::object: | |
19886 { | |
19887 for (auto& element : *m_value.object) | |
19888 { | |
19889 element.second.m_parent = this; | |
19890 } | |
19891 break; | |
19892 } | |
19893 | |
19894 case value_t::null: | |
19895 case value_t::string: | |
19896 case value_t::boolean: | |
19897 case value_t::number_integer: | |
19898 case value_t::number_unsigned: | |
19899 case value_t::number_float: | |
19900 case value_t::binary: | |
19901 case value_t::discarded: | |
19902 default: | |
19903 break; | |
19904 } | |
19905 #endif | |
19906 } | |
19907 | |
19908 iterator set_parents(iterator it, typename iterator::difference_type count_set_parents) | |
19909 { | |
19910 #if JSON_DIAGNOSTICS | |
19911 for (typename iterator::difference_type i = 0; i < count_set_parents; ++i) | |
19912 { | |
19913 (it + i)->m_parent = this; | |
19914 } | |
19915 #else | |
19916 static_cast<void>(count_set_parents); | |
19917 #endif | |
19918 return it; | |
19919 } | |
19920 | |
19921 reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1)) | |
19922 { | |
19923 #if JSON_DIAGNOSTICS | |
19924 if (old_capacity != static_cast<std::size_t>(-1)) | |
19925 { | |
19926 // see https://github.com/nlohmann/json/issues/2838 | |
19927 JSON_ASSERT(type() == value_t::array); | |
19928 if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) | |
19929 { | |
19930 // capacity has changed: update all parents | |
19931 set_parents(); | |
19932 return j; | |
19933 } | |
19934 } | |
19935 | |
19936 // ordered_json uses a vector internally, so pointers could have | |
19937 // been invalidated; see https://github.com/nlohmann/json/issues/2962 | |
19938 #ifdef JSON_HEDLEY_MSVC_VERSION | |
19939 #pragma warning(push ) | |
19940 #pragma warning(disable : 4127) // ignore warning to replace if with if constexpr | |
19941 #endif | |
19942 if (detail::is_ordered_map<object_t>::value) | |
19943 { | |
19944 set_parents(); | |
19945 return j; | |
19946 } | |
19947 #ifdef JSON_HEDLEY_MSVC_VERSION | |
19948 #pragma warning( pop ) | |
19949 #endif | |
19950 | |
19951 j.m_parent = this; | |
19952 #else | |
19953 static_cast<void>(j); | |
19954 static_cast<void>(old_capacity); | |
19955 #endif | |
19956 return j; | |
19957 } | |
19958 | |
19959 public: | |
19960 ////////////////////////// | |
19961 // JSON parser callback // | |
19962 ////////////////////////// | |
19963 | |
19964 /// @brief parser event types | |
19965 /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/ | |
19966 using parse_event_t = detail::parse_event_t; | |
19967 | |
19968 /// @brief per-element parser callback type | |
19969 /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/ | |
19970 using parser_callback_t = detail::parser_callback_t<basic_json>; | |
19971 | |
19972 ////////////////// | |
19973 // constructors // | |
19974 ////////////////// | |
19975 | |
19976 /// @name constructors and destructors | |
19977 /// Constructors of class @ref basic_json, copy/move constructor, copy | |
19978 /// assignment, static functions creating objects, and the destructor. | |
19979 /// @{ | |
19980 | |
19981 /// @brief create an empty value with a given type | |
19982 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
19983 basic_json(const value_t v) | |
19984 : m_type(v), m_value(v) | |
19985 { | |
19986 assert_invariant(); | |
19987 } | |
19988 | |
19989 /// @brief create a null object | |
19990 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
19991 basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape) | |
19992 : basic_json(value_t::null) | |
19993 { | |
19994 assert_invariant(); | |
19995 } | |
19996 | |
19997 /// @brief create a JSON value from compatible types | |
19998 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
19999 template < typename CompatibleType, | |
20000 typename U = detail::uncvref_t<CompatibleType>, | |
20001 detail::enable_if_t < | |
20002 !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 > | |
20003 basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) | |
20004 JSONSerializer<U>::to_json(std::declval<basic_json_t&>(), | |
20005 std::forward<CompatibleType>(val)))) | |
20006 { | |
20007 JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val)); | |
20008 set_parents(); | |
20009 assert_invariant(); | |
20010 } | |
20011 | |
20012 /// @brief create a JSON value from an existing one | |
20013 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
20014 template < typename BasicJsonType, | |
20015 detail::enable_if_t < | |
20016 detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 > | |
20017 basic_json(const BasicJsonType& val) | |
20018 { | |
20019 using other_boolean_t = typename BasicJsonType::boolean_t; | |
20020 using other_number_float_t = typename BasicJsonType::number_float_t; | |
20021 using other_number_integer_t = typename BasicJsonType::number_integer_t; | |
20022 using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; | |
20023 using other_string_t = typename BasicJsonType::string_t; | |
20024 using other_object_t = typename BasicJsonType::object_t; | |
20025 using other_array_t = typename BasicJsonType::array_t; | |
20026 using other_binary_t = typename BasicJsonType::binary_t; | |
20027 | |
20028 switch (val.type()) | |
20029 { | |
20030 case value_t::boolean: | |
20031 JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>()); | |
20032 break; | |
20033 case value_t::number_float: | |
20034 JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>()); | |
20035 break; | |
20036 case value_t::number_integer: | |
20037 JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>()); | |
20038 break; | |
20039 case value_t::number_unsigned: | |
20040 JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>()); | |
20041 break; | |
20042 case value_t::string: | |
20043 JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>()); | |
20044 break; | |
20045 case value_t::object: | |
20046 JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>()); | |
20047 break; | |
20048 case value_t::array: | |
20049 JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>()); | |
20050 break; | |
20051 case value_t::binary: | |
20052 JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>()); | |
20053 break; | |
20054 case value_t::null: | |
20055 *this = nullptr; | |
20056 break; | |
20057 case value_t::discarded: | |
20058 m_type = value_t::discarded; | |
20059 break; | |
20060 default: // LCOV_EXCL_LINE | |
20061 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
20062 } | |
20063 JSON_ASSERT(m_type == val.type()); | |
20064 set_parents(); | |
20065 assert_invariant(); | |
20066 } | |
20067 | |
20068 /// @brief create a container (array or object) from an initializer list | |
20069 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
20070 basic_json(initializer_list_t init, | |
20071 bool type_deduction = true, | |
20072 value_t manual_type = value_t::array) | |
20073 { | |
20074 // check if each element is an array with two elements whose first | |
20075 // element is a string | |
20076 bool is_an_object = std::all_of(init.begin(), init.end(), | |
20077 [](const detail::json_ref<basic_json>& element_ref) | |
20078 { | |
20079 return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string(); | |
20080 }); | |
20081 | |
20082 // adjust type if type deduction is not wanted | |
20083 if (!type_deduction) | |
20084 { | |
20085 // if array is wanted, do not create an object though possible | |
20086 if (manual_type == value_t::array) | |
20087 { | |
20088 is_an_object = false; | |
20089 } | |
20090 | |
20091 // if object is wanted but impossible, throw an exception | |
20092 if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) | |
20093 { | |
20094 JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr)); | |
20095 } | |
20096 } | |
20097 | |
20098 if (is_an_object) | |
20099 { | |
20100 // the initializer list is a list of pairs -> create object | |
20101 m_type = value_t::object; | |
20102 m_value = value_t::object; | |
20103 | |
20104 for (auto& element_ref : init) | |
20105 { | |
20106 auto element = element_ref.moved_or_copied(); | |
20107 m_value.object->emplace( | |
20108 std::move(*((*element.m_value.array)[0].m_value.string)), | |
20109 std::move((*element.m_value.array)[1])); | |
20110 } | |
20111 } | |
20112 else | |
20113 { | |
20114 // the initializer list describes an array -> create array | |
20115 m_type = value_t::array; | |
20116 m_value.array = create<array_t>(init.begin(), init.end()); | |
20117 } | |
20118 | |
20119 set_parents(); | |
20120 assert_invariant(); | |
20121 } | |
20122 | |
20123 /// @brief explicitly create a binary array (without subtype) | |
20124 /// @sa https://json.nlohmann.me/api/basic_json/binary/ | |
20125 JSON_HEDLEY_WARN_UNUSED_RESULT | |
20126 static basic_json binary(const typename binary_t::container_type& init) | |
20127 { | |
20128 auto res = basic_json(); | |
20129 res.m_type = value_t::binary; | |
20130 res.m_value = init; | |
20131 return res; | |
20132 } | |
20133 | |
20134 /// @brief explicitly create a binary array (with subtype) | |
20135 /// @sa https://json.nlohmann.me/api/basic_json/binary/ | |
20136 JSON_HEDLEY_WARN_UNUSED_RESULT | |
20137 static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) | |
20138 { | |
20139 auto res = basic_json(); | |
20140 res.m_type = value_t::binary; | |
20141 res.m_value = binary_t(init, subtype); | |
20142 return res; | |
20143 } | |
20144 | |
20145 /// @brief explicitly create a binary array | |
20146 /// @sa https://json.nlohmann.me/api/basic_json/binary/ | |
20147 JSON_HEDLEY_WARN_UNUSED_RESULT | |
20148 static basic_json binary(typename binary_t::container_type&& init) | |
20149 { | |
20150 auto res = basic_json(); | |
20151 res.m_type = value_t::binary; | |
20152 res.m_value = std::move(init); | |
20153 return res; | |
20154 } | |
20155 | |
20156 /// @brief explicitly create a binary array (with subtype) | |
20157 /// @sa https://json.nlohmann.me/api/basic_json/binary/ | |
20158 JSON_HEDLEY_WARN_UNUSED_RESULT | |
20159 static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) | |
20160 { | |
20161 auto res = basic_json(); | |
20162 res.m_type = value_t::binary; | |
20163 res.m_value = binary_t(std::move(init), subtype); | |
20164 return res; | |
20165 } | |
20166 | |
20167 /// @brief explicitly create an array from an initializer list | |
20168 /// @sa https://json.nlohmann.me/api/basic_json/array/ | |
20169 JSON_HEDLEY_WARN_UNUSED_RESULT | |
20170 static basic_json array(initializer_list_t init = {}) | |
20171 { | |
20172 return basic_json(init, false, value_t::array); | |
20173 } | |
20174 | |
20175 /// @brief explicitly create an object from an initializer list | |
20176 /// @sa https://json.nlohmann.me/api/basic_json/object/ | |
20177 JSON_HEDLEY_WARN_UNUSED_RESULT | |
20178 static basic_json object(initializer_list_t init = {}) | |
20179 { | |
20180 return basic_json(init, false, value_t::object); | |
20181 } | |
20182 | |
20183 /// @brief construct an array with count copies of given value | |
20184 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
20185 basic_json(size_type cnt, const basic_json& val) | |
20186 : m_type(value_t::array) | |
20187 { | |
20188 m_value.array = create<array_t>(cnt, val); | |
20189 set_parents(); | |
20190 assert_invariant(); | |
20191 } | |
20192 | |
20193 /// @brief construct a JSON container given an iterator range | |
20194 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
20195 template < class InputIT, typename std::enable_if < | |
20196 std::is_same<InputIT, typename basic_json_t::iterator>::value || | |
20197 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 > | |
20198 basic_json(InputIT first, InputIT last) | |
20199 { | |
20200 JSON_ASSERT(first.m_object != nullptr); | |
20201 JSON_ASSERT(last.m_object != nullptr); | |
20202 | |
20203 // make sure iterator fits the current value | |
20204 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) | |
20205 { | |
20206 JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr)); | |
20207 } | |
20208 | |
20209 // copy type from first iterator | |
20210 m_type = first.m_object->m_type; | |
20211 | |
20212 // check if iterator range is complete for primitive values | |
20213 switch (m_type) | |
20214 { | |
20215 case value_t::boolean: | |
20216 case value_t::number_float: | |
20217 case value_t::number_integer: | |
20218 case value_t::number_unsigned: | |
20219 case value_t::string: | |
20220 { | |
20221 if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() | |
20222 || !last.m_it.primitive_iterator.is_end())) | |
20223 { | |
20224 JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object)); | |
20225 } | |
20226 break; | |
20227 } | |
20228 | |
20229 case value_t::null: | |
20230 case value_t::object: | |
20231 case value_t::array: | |
20232 case value_t::binary: | |
20233 case value_t::discarded: | |
20234 default: | |
20235 break; | |
20236 } | |
20237 | |
20238 switch (m_type) | |
20239 { | |
20240 case value_t::number_integer: | |
20241 { | |
20242 m_value.number_integer = first.m_object->m_value.number_integer; | |
20243 break; | |
20244 } | |
20245 | |
20246 case value_t::number_unsigned: | |
20247 { | |
20248 m_value.number_unsigned = first.m_object->m_value.number_unsigned; | |
20249 break; | |
20250 } | |
20251 | |
20252 case value_t::number_float: | |
20253 { | |
20254 m_value.number_float = first.m_object->m_value.number_float; | |
20255 break; | |
20256 } | |
20257 | |
20258 case value_t::boolean: | |
20259 { | |
20260 m_value.boolean = first.m_object->m_value.boolean; | |
20261 break; | |
20262 } | |
20263 | |
20264 case value_t::string: | |
20265 { | |
20266 m_value = *first.m_object->m_value.string; | |
20267 break; | |
20268 } | |
20269 | |
20270 case value_t::object: | |
20271 { | |
20272 m_value.object = create<object_t>(first.m_it.object_iterator, | |
20273 last.m_it.object_iterator); | |
20274 break; | |
20275 } | |
20276 | |
20277 case value_t::array: | |
20278 { | |
20279 m_value.array = create<array_t>(first.m_it.array_iterator, | |
20280 last.m_it.array_iterator); | |
20281 break; | |
20282 } | |
20283 | |
20284 case value_t::binary: | |
20285 { | |
20286 m_value = *first.m_object->m_value.binary; | |
20287 break; | |
20288 } | |
20289 | |
20290 case value_t::null: | |
20291 case value_t::discarded: | |
20292 default: | |
20293 JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object)); | |
20294 } | |
20295 | |
20296 set_parents(); | |
20297 assert_invariant(); | |
20298 } | |
20299 | |
20300 | |
20301 /////////////////////////////////////// | |
20302 // other constructors and destructor // | |
20303 /////////////////////////////////////// | |
20304 | |
20305 template<typename JsonRef, | |
20306 detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>, | |
20307 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 > | |
20308 basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} | |
20309 | |
20310 /// @brief copy constructor | |
20311 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
20312 basic_json(const basic_json& other) | |
20313 : m_type(other.m_type) | |
20314 { | |
20315 // check of passed value is valid | |
20316 other.assert_invariant(); | |
20317 | |
20318 switch (m_type) | |
20319 { | |
20320 case value_t::object: | |
20321 { | |
20322 m_value = *other.m_value.object; | |
20323 break; | |
20324 } | |
20325 | |
20326 case value_t::array: | |
20327 { | |
20328 m_value = *other.m_value.array; | |
20329 break; | |
20330 } | |
20331 | |
20332 case value_t::string: | |
20333 { | |
20334 m_value = *other.m_value.string; | |
20335 break; | |
20336 } | |
20337 | |
20338 case value_t::boolean: | |
20339 { | |
20340 m_value = other.m_value.boolean; | |
20341 break; | |
20342 } | |
20343 | |
20344 case value_t::number_integer: | |
20345 { | |
20346 m_value = other.m_value.number_integer; | |
20347 break; | |
20348 } | |
20349 | |
20350 case value_t::number_unsigned: | |
20351 { | |
20352 m_value = other.m_value.number_unsigned; | |
20353 break; | |
20354 } | |
20355 | |
20356 case value_t::number_float: | |
20357 { | |
20358 m_value = other.m_value.number_float; | |
20359 break; | |
20360 } | |
20361 | |
20362 case value_t::binary: | |
20363 { | |
20364 m_value = *other.m_value.binary; | |
20365 break; | |
20366 } | |
20367 | |
20368 case value_t::null: | |
20369 case value_t::discarded: | |
20370 default: | |
20371 break; | |
20372 } | |
20373 | |
20374 set_parents(); | |
20375 assert_invariant(); | |
20376 } | |
20377 | |
20378 /// @brief move constructor | |
20379 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ | |
20380 basic_json(basic_json&& other) noexcept | |
20381 : m_type(std::move(other.m_type)), | |
20382 m_value(std::move(other.m_value)) | |
20383 { | |
20384 // check that passed value is valid | |
20385 other.assert_invariant(false); | |
20386 | |
20387 // invalidate payload | |
20388 other.m_type = value_t::null; | |
20389 other.m_value = {}; | |
20390 | |
20391 set_parents(); | |
20392 assert_invariant(); | |
20393 } | |
20394 | |
20395 /// @brief copy assignment | |
20396 /// @sa https://json.nlohmann.me/api/basic_json/operator=/ | |
20397 basic_json& operator=(basic_json other) noexcept ( | |
20398 std::is_nothrow_move_constructible<value_t>::value&& | |
20399 std::is_nothrow_move_assignable<value_t>::value&& | |
20400 std::is_nothrow_move_constructible<json_value>::value&& | |
20401 std::is_nothrow_move_assignable<json_value>::value | |
20402 ) | |
20403 { | |
20404 // check that passed value is valid | |
20405 other.assert_invariant(); | |
20406 | |
20407 using std::swap; | |
20408 swap(m_type, other.m_type); | |
20409 swap(m_value, other.m_value); | |
20410 | |
20411 set_parents(); | |
20412 assert_invariant(); | |
20413 return *this; | |
20414 } | |
20415 | |
20416 /// @brief destructor | |
20417 /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/ | |
20418 ~basic_json() noexcept | |
20419 { | |
20420 assert_invariant(false); | |
20421 m_value.destroy(m_type); | |
20422 } | |
20423 | |
20424 /// @} | |
20425 | |
20426 public: | |
20427 /////////////////////// | |
20428 // object inspection // | |
20429 /////////////////////// | |
20430 | |
20431 /// @name object inspection | |
20432 /// Functions to inspect the type of a JSON value. | |
20433 /// @{ | |
20434 | |
20435 /// @brief serialization | |
20436 /// @sa https://json.nlohmann.me/api/basic_json/dump/ | |
20437 string_t dump(const int indent = -1, | |
20438 const char indent_char = ' ', | |
20439 const bool ensure_ascii = false, | |
20440 const error_handler_t error_handler = error_handler_t::strict) const | |
20441 { | |
20442 string_t result; | |
20443 serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler); | |
20444 | |
20445 if (indent >= 0) | |
20446 { | |
20447 s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent)); | |
20448 } | |
20449 else | |
20450 { | |
20451 s.dump(*this, false, ensure_ascii, 0); | |
20452 } | |
20453 | |
20454 return result; | |
20455 } | |
20456 | |
20457 /// @brief return the type of the JSON value (explicit) | |
20458 /// @sa https://json.nlohmann.me/api/basic_json/type/ | |
20459 constexpr value_t type() const noexcept | |
20460 { | |
20461 return m_type; | |
20462 } | |
20463 | |
20464 /// @brief return whether type is primitive | |
20465 /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ | |
20466 constexpr bool is_primitive() const noexcept | |
20467 { | |
20468 return is_null() || is_string() || is_boolean() || is_number() || is_binary(); | |
20469 } | |
20470 | |
20471 /// @brief return whether type is structured | |
20472 /// @sa https://json.nlohmann.me/api/basic_json/is_structured/ | |
20473 constexpr bool is_structured() const noexcept | |
20474 { | |
20475 return is_array() || is_object(); | |
20476 } | |
20477 | |
20478 /// @brief return whether value is null | |
20479 /// @sa https://json.nlohmann.me/api/basic_json/is_null/ | |
20480 constexpr bool is_null() const noexcept | |
20481 { | |
20482 return m_type == value_t::null; | |
20483 } | |
20484 | |
20485 /// @brief return whether value is a boolean | |
20486 /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ | |
20487 constexpr bool is_boolean() const noexcept | |
20488 { | |
20489 return m_type == value_t::boolean; | |
20490 } | |
20491 | |
20492 /// @brief return whether value is a number | |
20493 /// @sa https://json.nlohmann.me/api/basic_json/is_number/ | |
20494 constexpr bool is_number() const noexcept | |
20495 { | |
20496 return is_number_integer() || is_number_float(); | |
20497 } | |
20498 | |
20499 /// @brief return whether value is an integer number | |
20500 /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ | |
20501 constexpr bool is_number_integer() const noexcept | |
20502 { | |
20503 return m_type == value_t::number_integer || m_type == value_t::number_unsigned; | |
20504 } | |
20505 | |
20506 /// @brief return whether value is an unsigned integer number | |
20507 /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ | |
20508 constexpr bool is_number_unsigned() const noexcept | |
20509 { | |
20510 return m_type == value_t::number_unsigned; | |
20511 } | |
20512 | |
20513 /// @brief return whether value is a floating-point number | |
20514 /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ | |
20515 constexpr bool is_number_float() const noexcept | |
20516 { | |
20517 return m_type == value_t::number_float; | |
20518 } | |
20519 | |
20520 /// @brief return whether value is an object | |
20521 /// @sa https://json.nlohmann.me/api/basic_json/is_object/ | |
20522 constexpr bool is_object() const noexcept | |
20523 { | |
20524 return m_type == value_t::object; | |
20525 } | |
20526 | |
20527 /// @brief return whether value is an array | |
20528 /// @sa https://json.nlohmann.me/api/basic_json/is_array/ | |
20529 constexpr bool is_array() const noexcept | |
20530 { | |
20531 return m_type == value_t::array; | |
20532 } | |
20533 | |
20534 /// @brief return whether value is a string | |
20535 /// @sa https://json.nlohmann.me/api/basic_json/is_string/ | |
20536 constexpr bool is_string() const noexcept | |
20537 { | |
20538 return m_type == value_t::string; | |
20539 } | |
20540 | |
20541 /// @brief return whether value is a binary array | |
20542 /// @sa https://json.nlohmann.me/api/basic_json/is_binary/ | |
20543 constexpr bool is_binary() const noexcept | |
20544 { | |
20545 return m_type == value_t::binary; | |
20546 } | |
20547 | |
20548 /// @brief return whether value is discarded | |
20549 /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ | |
20550 constexpr bool is_discarded() const noexcept | |
20551 { | |
20552 return m_type == value_t::discarded; | |
20553 } | |
20554 | |
20555 /// @brief return the type of the JSON value (implicit) | |
20556 /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/ | |
20557 constexpr operator value_t() const noexcept | |
20558 { | |
20559 return m_type; | |
20560 } | |
20561 | |
20562 /// @} | |
20563 | |
20564 private: | |
20565 ////////////////// | |
20566 // value access // | |
20567 ////////////////// | |
20568 | |
20569 /// get a boolean (explicit) | |
20570 boolean_t get_impl(boolean_t* /*unused*/) const | |
20571 { | |
20572 if (JSON_HEDLEY_LIKELY(is_boolean())) | |
20573 { | |
20574 return m_value.boolean; | |
20575 } | |
20576 | |
20577 JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this)); | |
20578 } | |
20579 | |
20580 /// get a pointer to the value (object) | |
20581 object_t* get_impl_ptr(object_t* /*unused*/) noexcept | |
20582 { | |
20583 return is_object() ? m_value.object : nullptr; | |
20584 } | |
20585 | |
20586 /// get a pointer to the value (object) | |
20587 constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept | |
20588 { | |
20589 return is_object() ? m_value.object : nullptr; | |
20590 } | |
20591 | |
20592 /// get a pointer to the value (array) | |
20593 array_t* get_impl_ptr(array_t* /*unused*/) noexcept | |
20594 { | |
20595 return is_array() ? m_value.array : nullptr; | |
20596 } | |
20597 | |
20598 /// get a pointer to the value (array) | |
20599 constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept | |
20600 { | |
20601 return is_array() ? m_value.array : nullptr; | |
20602 } | |
20603 | |
20604 /// get a pointer to the value (string) | |
20605 string_t* get_impl_ptr(string_t* /*unused*/) noexcept | |
20606 { | |
20607 return is_string() ? m_value.string : nullptr; | |
20608 } | |
20609 | |
20610 /// get a pointer to the value (string) | |
20611 constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept | |
20612 { | |
20613 return is_string() ? m_value.string : nullptr; | |
20614 } | |
20615 | |
20616 /// get a pointer to the value (boolean) | |
20617 boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept | |
20618 { | |
20619 return is_boolean() ? &m_value.boolean : nullptr; | |
20620 } | |
20621 | |
20622 /// get a pointer to the value (boolean) | |
20623 constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept | |
20624 { | |
20625 return is_boolean() ? &m_value.boolean : nullptr; | |
20626 } | |
20627 | |
20628 /// get a pointer to the value (integer number) | |
20629 number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept | |
20630 { | |
20631 return is_number_integer() ? &m_value.number_integer : nullptr; | |
20632 } | |
20633 | |
20634 /// get a pointer to the value (integer number) | |
20635 constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept | |
20636 { | |
20637 return is_number_integer() ? &m_value.number_integer : nullptr; | |
20638 } | |
20639 | |
20640 /// get a pointer to the value (unsigned number) | |
20641 number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept | |
20642 { | |
20643 return is_number_unsigned() ? &m_value.number_unsigned : nullptr; | |
20644 } | |
20645 | |
20646 /// get a pointer to the value (unsigned number) | |
20647 constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept | |
20648 { | |
20649 return is_number_unsigned() ? &m_value.number_unsigned : nullptr; | |
20650 } | |
20651 | |
20652 /// get a pointer to the value (floating-point number) | |
20653 number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept | |
20654 { | |
20655 return is_number_float() ? &m_value.number_float : nullptr; | |
20656 } | |
20657 | |
20658 /// get a pointer to the value (floating-point number) | |
20659 constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept | |
20660 { | |
20661 return is_number_float() ? &m_value.number_float : nullptr; | |
20662 } | |
20663 | |
20664 /// get a pointer to the value (binary) | |
20665 binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept | |
20666 { | |
20667 return is_binary() ? m_value.binary : nullptr; | |
20668 } | |
20669 | |
20670 /// get a pointer to the value (binary) | |
20671 constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept | |
20672 { | |
20673 return is_binary() ? m_value.binary : nullptr; | |
20674 } | |
20675 | |
20676 /*! | |
20677 @brief helper function to implement get_ref() | |
20678 | |
20679 This function helps to implement get_ref() without code duplication for | |
20680 const and non-const overloads | |
20681 | |
20682 @tparam ThisType will be deduced as `basic_json` or `const basic_json` | |
20683 | |
20684 @throw type_error.303 if ReferenceType does not match underlying value | |
20685 type of the current JSON | |
20686 */ | |
20687 template<typename ReferenceType, typename ThisType> | |
20688 static ReferenceType get_ref_impl(ThisType& obj) | |
20689 { | |
20690 // delegate the call to get_ptr<>() | |
20691 auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>(); | |
20692 | |
20693 if (JSON_HEDLEY_LIKELY(ptr != nullptr)) | |
20694 { | |
20695 return *ptr; | |
20696 } | |
20697 | |
20698 JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj)); | |
20699 } | |
20700 | |
20701 public: | |
20702 /// @name value access | |
20703 /// Direct access to the stored value of a JSON value. | |
20704 /// @{ | |
20705 | |
20706 /// @brief get a pointer value (implicit) | |
20707 /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ | |
20708 template<typename PointerType, typename std::enable_if< | |
20709 std::is_pointer<PointerType>::value, int>::type = 0> | |
20710 auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) | |
20711 { | |
20712 // delegate the call to get_impl_ptr<>() | |
20713 return get_impl_ptr(static_cast<PointerType>(nullptr)); | |
20714 } | |
20715 | |
20716 /// @brief get a pointer value (implicit) | |
20717 /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ | |
20718 template < typename PointerType, typename std::enable_if < | |
20719 std::is_pointer<PointerType>::value&& | |
20720 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 > | |
20721 constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) | |
20722 { | |
20723 // delegate the call to get_impl_ptr<>() const | |
20724 return get_impl_ptr(static_cast<PointerType>(nullptr)); | |
20725 } | |
20726 | |
20727 private: | |
20728 /*! | |
20729 @brief get a value (explicit) | |
20730 | |
20731 Explicit type conversion between the JSON value and a compatible value | |
20732 which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) | |
20733 and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). | |
20734 The value is converted by calling the @ref json_serializer<ValueType> | |
20735 `from_json()` method. | |
20736 | |
20737 The function is equivalent to executing | |
20738 @code {.cpp} | |
20739 ValueType ret; | |
20740 JSONSerializer<ValueType>::from_json(*this, ret); | |
20741 return ret; | |
20742 @endcode | |
20743 | |
20744 This overloads is chosen if: | |
20745 - @a ValueType is not @ref basic_json, | |
20746 - @ref json_serializer<ValueType> has a `from_json()` method of the form | |
20747 `void from_json(const basic_json&, ValueType&)`, and | |
20748 - @ref json_serializer<ValueType> does not have a `from_json()` method of | |
20749 the form `ValueType from_json(const basic_json&)` | |
20750 | |
20751 @tparam ValueType the returned value type | |
20752 | |
20753 @return copy of the JSON value, converted to @a ValueType | |
20754 | |
20755 @throw what @ref json_serializer<ValueType> `from_json()` method throws | |
20756 | |
20757 @liveexample{The example below shows several conversions from JSON values | |
20758 to other types. There a few things to note: (1) Floating-point numbers can | |
20759 be converted to integers\, (2) A JSON array can be converted to a standard | |
20760 `std::vector<short>`\, (3) A JSON object can be converted to C++ | |
20761 associative containers such as `std::unordered_map<std::string\, | |
20762 json>`.,get__ValueType_const} | |
20763 | |
20764 @since version 2.1.0 | |
20765 */ | |
20766 template < typename ValueType, | |
20767 detail::enable_if_t < | |
20768 detail::is_default_constructible<ValueType>::value&& | |
20769 detail::has_from_json<basic_json_t, ValueType>::value, | |
20770 int > = 0 > | |
20771 ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( | |
20772 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>()))) | |
20773 { | |
20774 auto ret = ValueType(); | |
20775 JSONSerializer<ValueType>::from_json(*this, ret); | |
20776 return ret; | |
20777 } | |
20778 | |
20779 /*! | |
20780 @brief get a value (explicit); special case | |
20781 | |
20782 Explicit type conversion between the JSON value and a compatible value | |
20783 which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) | |
20784 and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). | |
20785 The value is converted by calling the @ref json_serializer<ValueType> | |
20786 `from_json()` method. | |
20787 | |
20788 The function is equivalent to executing | |
20789 @code {.cpp} | |
20790 return JSONSerializer<ValueType>::from_json(*this); | |
20791 @endcode | |
20792 | |
20793 This overloads is chosen if: | |
20794 - @a ValueType is not @ref basic_json and | |
20795 - @ref json_serializer<ValueType> has a `from_json()` method of the form | |
20796 `ValueType from_json(const basic_json&)` | |
20797 | |
20798 @note If @ref json_serializer<ValueType> has both overloads of | |
20799 `from_json()`, this one is chosen. | |
20800 | |
20801 @tparam ValueType the returned value type | |
20802 | |
20803 @return copy of the JSON value, converted to @a ValueType | |
20804 | |
20805 @throw what @ref json_serializer<ValueType> `from_json()` method throws | |
20806 | |
20807 @since version 2.1.0 | |
20808 */ | |
20809 template < typename ValueType, | |
20810 detail::enable_if_t < | |
20811 detail::has_non_default_from_json<basic_json_t, ValueType>::value, | |
20812 int > = 0 > | |
20813 ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( | |
20814 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>()))) | |
20815 { | |
20816 return JSONSerializer<ValueType>::from_json(*this); | |
20817 } | |
20818 | |
20819 /*! | |
20820 @brief get special-case overload | |
20821 | |
20822 This overloads converts the current @ref basic_json in a different | |
20823 @ref basic_json type | |
20824 | |
20825 @tparam BasicJsonType == @ref basic_json | |
20826 | |
20827 @return a copy of *this, converted into @a BasicJsonType | |
20828 | |
20829 @complexity Depending on the implementation of the called `from_json()` | |
20830 method. | |
20831 | |
20832 @since version 3.2.0 | |
20833 */ | |
20834 template < typename BasicJsonType, | |
20835 detail::enable_if_t < | |
20836 detail::is_basic_json<BasicJsonType>::value, | |
20837 int > = 0 > | |
20838 BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const | |
20839 { | |
20840 return *this; | |
20841 } | |
20842 | |
20843 /*! | |
20844 @brief get special-case overload | |
20845 | |
20846 This overloads avoids a lot of template boilerplate, it can be seen as the | |
20847 identity method | |
20848 | |
20849 @tparam BasicJsonType == @ref basic_json | |
20850 | |
20851 @return a copy of *this | |
20852 | |
20853 @complexity Constant. | |
20854 | |
20855 @since version 2.1.0 | |
20856 */ | |
20857 template<typename BasicJsonType, | |
20858 detail::enable_if_t< | |
20859 std::is_same<BasicJsonType, basic_json_t>::value, | |
20860 int> = 0> | |
20861 basic_json get_impl(detail::priority_tag<3> /*unused*/) const | |
20862 { | |
20863 return *this; | |
20864 } | |
20865 | |
20866 /*! | |
20867 @brief get a pointer value (explicit) | |
20868 @copydoc get() | |
20869 */ | |
20870 template<typename PointerType, | |
20871 detail::enable_if_t< | |
20872 std::is_pointer<PointerType>::value, | |
20873 int> = 0> | |
20874 constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept | |
20875 -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>()) | |
20876 { | |
20877 // delegate the call to get_ptr | |
20878 return get_ptr<PointerType>(); | |
20879 } | |
20880 | |
20881 public: | |
20882 /*! | |
20883 @brief get a (pointer) value (explicit) | |
20884 | |
20885 Performs explicit type conversion between the JSON value and a compatible value if required. | |
20886 | |
20887 - If the requested type is a pointer to the internally stored JSON value that pointer is returned. | |
20888 No copies are made. | |
20889 | |
20890 - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible | |
20891 from the current @ref basic_json. | |
20892 | |
20893 - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()` | |
20894 method. | |
20895 | |
20896 @tparam ValueTypeCV the provided value type | |
20897 @tparam ValueType the returned value type | |
20898 | |
20899 @return copy of the JSON value, converted to @tparam ValueType if necessary | |
20900 | |
20901 @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required | |
20902 | |
20903 @since version 2.1.0 | |
20904 */ | |
20905 template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>> | |
20906 #if defined(JSON_HAS_CPP_14) | |
20907 constexpr | |
20908 #endif | |
20909 auto get() const noexcept( | |
20910 noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))) | |
20911 -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})) | |
20912 { | |
20913 // we cannot static_assert on ValueTypeCV being non-const, because | |
20914 // there is support for get<const basic_json_t>(), which is why we | |
20915 // still need the uncvref | |
20916 static_assert(!std::is_reference<ValueTypeCV>::value, | |
20917 "get() cannot be used with reference types, you might want to use get_ref()"); | |
20918 return get_impl<ValueType>(detail::priority_tag<4> {}); | |
20919 } | |
20920 | |
20921 /*! | |
20922 @brief get a pointer value (explicit) | |
20923 | |
20924 Explicit pointer access to the internally stored JSON value. No copies are | |
20925 made. | |
20926 | |
20927 @warning The pointer becomes invalid if the underlying JSON object | |
20928 changes. | |
20929 | |
20930 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref | |
20931 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, | |
20932 @ref number_unsigned_t, or @ref number_float_t. | |
20933 | |
20934 @return pointer to the internally stored JSON value if the requested | |
20935 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise | |
20936 | |
20937 @complexity Constant. | |
20938 | |
20939 @liveexample{The example below shows how pointers to internal values of a | |
20940 JSON value can be requested. Note that no type conversions are made and a | |
20941 `nullptr` is returned if the value and the requested pointer type does not | |
20942 match.,get__PointerType} | |
20943 | |
20944 @sa see @ref get_ptr() for explicit pointer-member access | |
20945 | |
20946 @since version 1.0.0 | |
20947 */ | |
20948 template<typename PointerType, typename std::enable_if< | |
20949 std::is_pointer<PointerType>::value, int>::type = 0> | |
20950 auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>()) | |
20951 { | |
20952 // delegate the call to get_ptr | |
20953 return get_ptr<PointerType>(); | |
20954 } | |
20955 | |
20956 /// @brief get a value (explicit) | |
20957 /// @sa https://json.nlohmann.me/api/basic_json/get_to/ | |
20958 template < typename ValueType, | |
20959 detail::enable_if_t < | |
20960 !detail::is_basic_json<ValueType>::value&& | |
20961 detail::has_from_json<basic_json_t, ValueType>::value, | |
20962 int > = 0 > | |
20963 ValueType & get_to(ValueType& v) const noexcept(noexcept( | |
20964 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v))) | |
20965 { | |
20966 JSONSerializer<ValueType>::from_json(*this, v); | |
20967 return v; | |
20968 } | |
20969 | |
20970 // specialization to allow calling get_to with a basic_json value | |
20971 // see https://github.com/nlohmann/json/issues/2175 | |
20972 template<typename ValueType, | |
20973 detail::enable_if_t < | |
20974 detail::is_basic_json<ValueType>::value, | |
20975 int> = 0> | |
20976 ValueType & get_to(ValueType& v) const | |
20977 { | |
20978 v = *this; | |
20979 return v; | |
20980 } | |
20981 | |
20982 template < | |
20983 typename T, std::size_t N, | |
20984 typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) | |
20985 detail::enable_if_t < | |
20986 detail::has_from_json<basic_json_t, Array>::value, int > = 0 > | |
20987 Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) | |
20988 noexcept(noexcept(JSONSerializer<Array>::from_json( | |
20989 std::declval<const basic_json_t&>(), v))) | |
20990 { | |
20991 JSONSerializer<Array>::from_json(*this, v); | |
20992 return v; | |
20993 } | |
20994 | |
20995 /// @brief get a reference value (implicit) | |
20996 /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ | |
20997 template<typename ReferenceType, typename std::enable_if< | |
20998 std::is_reference<ReferenceType>::value, int>::type = 0> | |
20999 ReferenceType get_ref() | |
21000 { | |
21001 // delegate call to get_ref_impl | |
21002 return get_ref_impl<ReferenceType>(*this); | |
21003 } | |
21004 | |
21005 /// @brief get a reference value (implicit) | |
21006 /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ | |
21007 template < typename ReferenceType, typename std::enable_if < | |
21008 std::is_reference<ReferenceType>::value&& | |
21009 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 > | |
21010 ReferenceType get_ref() const | |
21011 { | |
21012 // delegate call to get_ref_impl | |
21013 return get_ref_impl<ReferenceType>(*this); | |
21014 } | |
21015 | |
21016 /*! | |
21017 @brief get a value (implicit) | |
21018 | |
21019 Implicit type conversion between the JSON value and a compatible value. | |
21020 The call is realized by calling @ref get() const. | |
21021 | |
21022 @tparam ValueType non-pointer type compatible to the JSON value, for | |
21023 instance `int` for JSON integer numbers, `bool` for JSON booleans, or | |
21024 `std::vector` types for JSON arrays. The character type of @ref string_t | |
21025 as well as an initializer list of this type is excluded to avoid | |
21026 ambiguities as these types implicitly convert to `std::string`. | |
21027 | |
21028 @return copy of the JSON value, converted to type @a ValueType | |
21029 | |
21030 @throw type_error.302 in case passed type @a ValueType is incompatible | |
21031 to the JSON value type (e.g., the JSON value is of type boolean, but a | |
21032 string is requested); see example below | |
21033 | |
21034 @complexity Linear in the size of the JSON value. | |
21035 | |
21036 @liveexample{The example below shows several conversions from JSON values | |
21037 to other types. There a few things to note: (1) Floating-point numbers can | |
21038 be converted to integers\, (2) A JSON array can be converted to a standard | |
21039 `std::vector<short>`\, (3) A JSON object can be converted to C++ | |
21040 associative containers such as `std::unordered_map<std::string\, | |
21041 json>`.,operator__ValueType} | |
21042 | |
21043 @since version 1.0.0 | |
21044 */ | |
21045 template < typename ValueType, typename std::enable_if < | |
21046 detail::conjunction < | |
21047 detail::negation<std::is_pointer<ValueType>>, | |
21048 detail::negation<std::is_same<ValueType, std::nullptr_t>>, | |
21049 detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>, | |
21050 detail::negation<std::is_same<ValueType, typename string_t::value_type>>, | |
21051 detail::negation<detail::is_basic_json<ValueType>>, | |
21052 detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>, | |
21053 #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) | |
21054 detail::negation<std::is_same<ValueType, std::string_view>>, | |
21055 #endif | |
21056 #if defined(JSON_HAS_CPP_17) | |
21057 detail::negation<std::is_same<ValueType, std::any>>, | |
21058 #endif | |
21059 detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType> | |
21060 >::value, int >::type = 0 > | |
21061 JSON_EXPLICIT operator ValueType() const | |
21062 { | |
21063 // delegate the call to get<>() const | |
21064 return get<ValueType>(); | |
21065 } | |
21066 | |
21067 /// @brief get a binary value | |
21068 /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ | |
21069 binary_t& get_binary() | |
21070 { | |
21071 if (!is_binary()) | |
21072 { | |
21073 JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this)); | |
21074 } | |
21075 | |
21076 return *get_ptr<binary_t*>(); | |
21077 } | |
21078 | |
21079 /// @brief get a binary value | |
21080 /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ | |
21081 const binary_t& get_binary() const | |
21082 { | |
21083 if (!is_binary()) | |
21084 { | |
21085 JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this)); | |
21086 } | |
21087 | |
21088 return *get_ptr<const binary_t*>(); | |
21089 } | |
21090 | |
21091 /// @} | |
21092 | |
21093 | |
21094 //////////////////// | |
21095 // element access // | |
21096 //////////////////// | |
21097 | |
21098 /// @name element access | |
21099 /// Access to the JSON value. | |
21100 /// @{ | |
21101 | |
21102 /// @brief access specified array element with bounds checking | |
21103 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
21104 reference at(size_type idx) | |
21105 { | |
21106 // at only works for arrays | |
21107 if (JSON_HEDLEY_LIKELY(is_array())) | |
21108 { | |
21109 JSON_TRY | |
21110 { | |
21111 return set_parent(m_value.array->at(idx)); | |
21112 } | |
21113 JSON_CATCH (std::out_of_range&) | |
21114 { | |
21115 // create better exception explanation | |
21116 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); | |
21117 } | |
21118 } | |
21119 else | |
21120 { | |
21121 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); | |
21122 } | |
21123 } | |
21124 | |
21125 /// @brief access specified array element with bounds checking | |
21126 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
21127 const_reference at(size_type idx) const | |
21128 { | |
21129 // at only works for arrays | |
21130 if (JSON_HEDLEY_LIKELY(is_array())) | |
21131 { | |
21132 JSON_TRY | |
21133 { | |
21134 return m_value.array->at(idx); | |
21135 } | |
21136 JSON_CATCH (std::out_of_range&) | |
21137 { | |
21138 // create better exception explanation | |
21139 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); | |
21140 } | |
21141 } | |
21142 else | |
21143 { | |
21144 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); | |
21145 } | |
21146 } | |
21147 | |
21148 /// @brief access specified object element with bounds checking | |
21149 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
21150 reference at(const typename object_t::key_type& key) | |
21151 { | |
21152 // at only works for objects | |
21153 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
21154 { | |
21155 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); | |
21156 } | |
21157 | |
21158 auto it = m_value.object->find(key); | |
21159 if (it == m_value.object->end()) | |
21160 { | |
21161 JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this)); | |
21162 } | |
21163 return set_parent(it->second); | |
21164 } | |
21165 | |
21166 /// @brief access specified object element with bounds checking | |
21167 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
21168 template<class KeyType, detail::enable_if_t< | |
21169 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> | |
21170 reference at(KeyType && key) | |
21171 { | |
21172 // at only works for objects | |
21173 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
21174 { | |
21175 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); | |
21176 } | |
21177 | |
21178 auto it = m_value.object->find(std::forward<KeyType>(key)); | |
21179 if (it == m_value.object->end()) | |
21180 { | |
21181 JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this)); | |
21182 } | |
21183 return set_parent(it->second); | |
21184 } | |
21185 | |
21186 /// @brief access specified object element with bounds checking | |
21187 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
21188 const_reference at(const typename object_t::key_type& key) const | |
21189 { | |
21190 // at only works for objects | |
21191 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
21192 { | |
21193 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); | |
21194 } | |
21195 | |
21196 auto it = m_value.object->find(key); | |
21197 if (it == m_value.object->end()) | |
21198 { | |
21199 JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this)); | |
21200 } | |
21201 return it->second; | |
21202 } | |
21203 | |
21204 /// @brief access specified object element with bounds checking | |
21205 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
21206 template<class KeyType, detail::enable_if_t< | |
21207 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> | |
21208 const_reference at(KeyType && key) const | |
21209 { | |
21210 // at only works for objects | |
21211 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
21212 { | |
21213 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); | |
21214 } | |
21215 | |
21216 auto it = m_value.object->find(std::forward<KeyType>(key)); | |
21217 if (it == m_value.object->end()) | |
21218 { | |
21219 JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this)); | |
21220 } | |
21221 return it->second; | |
21222 } | |
21223 | |
21224 /// @brief access specified array element | |
21225 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
21226 reference operator[](size_type idx) | |
21227 { | |
21228 // implicitly convert null value to an empty array | |
21229 if (is_null()) | |
21230 { | |
21231 m_type = value_t::array; | |
21232 m_value.array = create<array_t>(); | |
21233 assert_invariant(); | |
21234 } | |
21235 | |
21236 // operator[] only works for arrays | |
21237 if (JSON_HEDLEY_LIKELY(is_array())) | |
21238 { | |
21239 // fill up array with null values if given idx is outside range | |
21240 if (idx >= m_value.array->size()) | |
21241 { | |
21242 #if JSON_DIAGNOSTICS | |
21243 // remember array size & capacity before resizing | |
21244 const auto old_size = m_value.array->size(); | |
21245 const auto old_capacity = m_value.array->capacity(); | |
21246 #endif | |
21247 m_value.array->resize(idx + 1); | |
21248 | |
21249 #if JSON_DIAGNOSTICS | |
21250 if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) | |
21251 { | |
21252 // capacity has changed: update all parents | |
21253 set_parents(); | |
21254 } | |
21255 else | |
21256 { | |
21257 // set parent for values added above | |
21258 set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size)); | |
21259 } | |
21260 #endif | |
21261 assert_invariant(); | |
21262 } | |
21263 | |
21264 return m_value.array->operator[](idx); | |
21265 } | |
21266 | |
21267 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this)); | |
21268 } | |
21269 | |
21270 /// @brief access specified array element | |
21271 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
21272 const_reference operator[](size_type idx) const | |
21273 { | |
21274 // const operator[] only works for arrays | |
21275 if (JSON_HEDLEY_LIKELY(is_array())) | |
21276 { | |
21277 return m_value.array->operator[](idx); | |
21278 } | |
21279 | |
21280 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this)); | |
21281 } | |
21282 | |
21283 /// @brief access specified object element | |
21284 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
21285 reference operator[](typename object_t::key_type key) | |
21286 { | |
21287 // implicitly convert null value to an empty object | |
21288 if (is_null()) | |
21289 { | |
21290 m_type = value_t::object; | |
21291 m_value.object = create<object_t>(); | |
21292 assert_invariant(); | |
21293 } | |
21294 | |
21295 // operator[] only works for objects | |
21296 if (JSON_HEDLEY_LIKELY(is_object())) | |
21297 { | |
21298 auto result = m_value.object->emplace(std::move(key), nullptr); | |
21299 return set_parent(result.first->second); | |
21300 } | |
21301 | |
21302 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); | |
21303 } | |
21304 | |
21305 /// @brief access specified object element | |
21306 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
21307 const_reference operator[](const typename object_t::key_type& key) const | |
21308 { | |
21309 // const operator[] only works for objects | |
21310 if (JSON_HEDLEY_LIKELY(is_object())) | |
21311 { | |
21312 auto it = m_value.object->find(key); | |
21313 JSON_ASSERT(it != m_value.object->end()); | |
21314 return it->second; | |
21315 } | |
21316 | |
21317 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); | |
21318 } | |
21319 | |
21320 // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC | |
21321 // (they seemingly cannot be constrained to resolve the ambiguity) | |
21322 template<typename T> | |
21323 reference operator[](T* key) | |
21324 { | |
21325 return operator[](typename object_t::key_type(key)); | |
21326 } | |
21327 | |
21328 template<typename T> | |
21329 const_reference operator[](T* key) const | |
21330 { | |
21331 return operator[](typename object_t::key_type(key)); | |
21332 } | |
21333 | |
21334 /// @brief access specified object element | |
21335 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
21336 template<class KeyType, detail::enable_if_t< | |
21337 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 > | |
21338 reference operator[](KeyType && key) | |
21339 { | |
21340 // implicitly convert null value to an empty object | |
21341 if (is_null()) | |
21342 { | |
21343 m_type = value_t::object; | |
21344 m_value.object = create<object_t>(); | |
21345 assert_invariant(); | |
21346 } | |
21347 | |
21348 // operator[] only works for objects | |
21349 if (JSON_HEDLEY_LIKELY(is_object())) | |
21350 { | |
21351 auto result = m_value.object->emplace(std::forward<KeyType>(key), nullptr); | |
21352 return set_parent(result.first->second); | |
21353 } | |
21354 | |
21355 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); | |
21356 } | |
21357 | |
21358 /// @brief access specified object element | |
21359 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
21360 template<class KeyType, detail::enable_if_t< | |
21361 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 > | |
21362 const_reference operator[](KeyType && key) const | |
21363 { | |
21364 // const operator[] only works for objects | |
21365 if (JSON_HEDLEY_LIKELY(is_object())) | |
21366 { | |
21367 auto it = m_value.object->find(std::forward<KeyType>(key)); | |
21368 JSON_ASSERT(it != m_value.object->end()); | |
21369 return it->second; | |
21370 } | |
21371 | |
21372 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); | |
21373 } | |
21374 | |
21375 private: | |
21376 template<typename KeyType> | |
21377 using is_comparable_with_object_key = detail::is_comparable < | |
21378 object_comparator_t, const typename object_t::key_type&, KeyType >; | |
21379 | |
21380 template<typename ValueType> | |
21381 using value_return_type = std::conditional < | |
21382 detail::is_c_string_uncvref<ValueType>::value, | |
21383 string_t, typename std::decay<ValueType>::type >; | |
21384 | |
21385 public: | |
21386 /// @brief access specified object element with default value | |
21387 /// @sa https://json.nlohmann.me/api/basic_json/value/ | |
21388 template < class ValueType, detail::enable_if_t < | |
21389 !detail::is_transparent<object_comparator_t>::value | |
21390 && detail::is_getable<basic_json_t, ValueType>::value | |
21391 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21392 ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const | |
21393 { | |
21394 // value only works for objects | |
21395 if (JSON_HEDLEY_LIKELY(is_object())) | |
21396 { | |
21397 // if key is found, return value and given default value otherwise | |
21398 const auto it = find(key); | |
21399 if (it != end()) | |
21400 { | |
21401 return it->template get<ValueType>(); | |
21402 } | |
21403 | |
21404 return default_value; | |
21405 } | |
21406 | |
21407 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); | |
21408 } | |
21409 | |
21410 /// @brief access specified object element with default value | |
21411 /// @sa https://json.nlohmann.me/api/basic_json/value/ | |
21412 template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type, | |
21413 detail::enable_if_t < | |
21414 !detail::is_transparent<object_comparator_t>::value | |
21415 && detail::is_getable<basic_json_t, ReturnType>::value | |
21416 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21417 ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const | |
21418 { | |
21419 // value only works for objects | |
21420 if (JSON_HEDLEY_LIKELY(is_object())) | |
21421 { | |
21422 // if key is found, return value and given default value otherwise | |
21423 const auto it = find(key); | |
21424 if (it != end()) | |
21425 { | |
21426 return it->template get<ReturnType>(); | |
21427 } | |
21428 | |
21429 return std::forward<ValueType>(default_value); | |
21430 } | |
21431 | |
21432 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); | |
21433 } | |
21434 | |
21435 /// @brief access specified object element with default value | |
21436 /// @sa https://json.nlohmann.me/api/basic_json/value/ | |
21437 template < class ValueType, class KeyType, detail::enable_if_t < | |
21438 detail::is_transparent<object_comparator_t>::value | |
21439 && !detail::is_json_pointer<KeyType>::value | |
21440 && is_comparable_with_object_key<KeyType>::value | |
21441 && detail::is_getable<basic_json_t, ValueType>::value | |
21442 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21443 ValueType value(KeyType && key, const ValueType& default_value) const | |
21444 { | |
21445 // value only works for objects | |
21446 if (JSON_HEDLEY_LIKELY(is_object())) | |
21447 { | |
21448 // if key is found, return value and given default value otherwise | |
21449 const auto it = find(std::forward<KeyType>(key)); | |
21450 if (it != end()) | |
21451 { | |
21452 return it->template get<ValueType>(); | |
21453 } | |
21454 | |
21455 return default_value; | |
21456 } | |
21457 | |
21458 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); | |
21459 } | |
21460 | |
21461 /// @brief access specified object element via JSON Pointer with default value | |
21462 /// @sa https://json.nlohmann.me/api/basic_json/value/ | |
21463 template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type, | |
21464 detail::enable_if_t < | |
21465 detail::is_transparent<object_comparator_t>::value | |
21466 && !detail::is_json_pointer<KeyType>::value | |
21467 && is_comparable_with_object_key<KeyType>::value | |
21468 && detail::is_getable<basic_json_t, ReturnType>::value | |
21469 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21470 ReturnType value(KeyType && key, ValueType && default_value) const | |
21471 { | |
21472 // value only works for objects | |
21473 if (JSON_HEDLEY_LIKELY(is_object())) | |
21474 { | |
21475 // if key is found, return value and given default value otherwise | |
21476 const auto it = find(std::forward<KeyType>(key)); | |
21477 if (it != end()) | |
21478 { | |
21479 return it->template get<ReturnType>(); | |
21480 } | |
21481 | |
21482 return std::forward<ValueType>(default_value); | |
21483 } | |
21484 | |
21485 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); | |
21486 } | |
21487 | |
21488 /// @brief access specified object element via JSON Pointer with default value | |
21489 /// @sa https://json.nlohmann.me/api/basic_json/value/ | |
21490 template < class ValueType, detail::enable_if_t < | |
21491 detail::is_getable<basic_json_t, ValueType>::value | |
21492 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21493 ValueType value(const json_pointer& ptr, const ValueType& default_value) const | |
21494 { | |
21495 // value only works for objects | |
21496 if (JSON_HEDLEY_LIKELY(is_object())) | |
21497 { | |
21498 // if pointer resolves a value, return it or use default value | |
21499 JSON_TRY | |
21500 { | |
21501 return ptr.get_checked(this).template get<ValueType>(); | |
21502 } | |
21503 JSON_INTERNAL_CATCH (out_of_range&) | |
21504 { | |
21505 return default_value; | |
21506 } | |
21507 } | |
21508 | |
21509 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); | |
21510 } | |
21511 | |
21512 /// @brief access specified object element via JSON Pointer with default value | |
21513 /// @sa https://json.nlohmann.me/api/basic_json/value/ | |
21514 template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type, | |
21515 detail::enable_if_t < | |
21516 detail::is_getable<basic_json_t, ReturnType>::value | |
21517 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21518 ReturnType value(const json_pointer& ptr, ValueType && default_value) const | |
21519 { | |
21520 // value only works for objects | |
21521 if (JSON_HEDLEY_LIKELY(is_object())) | |
21522 { | |
21523 // if pointer resolves a value, return it or use default value | |
21524 JSON_TRY | |
21525 { | |
21526 return ptr.get_checked(this).template get<ReturnType>(); | |
21527 } | |
21528 JSON_INTERNAL_CATCH (out_of_range&) | |
21529 { | |
21530 return std::forward<ValueType>(default_value); | |
21531 } | |
21532 } | |
21533 | |
21534 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); | |
21535 } | |
21536 | |
21537 template < class ValueType, class BasicJsonType, detail::enable_if_t < | |
21538 detail::is_basic_json<BasicJsonType>::value | |
21539 && detail::is_getable<basic_json_t, ValueType>::value | |
21540 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21541 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) | |
21542 ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const | |
21543 { | |
21544 return value(ptr.convert(), default_value); | |
21545 } | |
21546 | |
21547 template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type, | |
21548 detail::enable_if_t < | |
21549 detail::is_basic_json<BasicJsonType>::value | |
21550 && detail::is_getable<basic_json_t, ReturnType>::value | |
21551 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > | |
21552 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) | |
21553 ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const | |
21554 { | |
21555 return value(ptr.convert(), std::forward<ValueType>(default_value)); | |
21556 } | |
21557 | |
21558 /// @brief access the first element | |
21559 /// @sa https://json.nlohmann.me/api/basic_json/front/ | |
21560 reference front() | |
21561 { | |
21562 return *begin(); | |
21563 } | |
21564 | |
21565 /// @brief access the first element | |
21566 /// @sa https://json.nlohmann.me/api/basic_json/front/ | |
21567 const_reference front() const | |
21568 { | |
21569 return *cbegin(); | |
21570 } | |
21571 | |
21572 /// @brief access the last element | |
21573 /// @sa https://json.nlohmann.me/api/basic_json/back/ | |
21574 reference back() | |
21575 { | |
21576 auto tmp = end(); | |
21577 --tmp; | |
21578 return *tmp; | |
21579 } | |
21580 | |
21581 /// @brief access the last element | |
21582 /// @sa https://json.nlohmann.me/api/basic_json/back/ | |
21583 const_reference back() const | |
21584 { | |
21585 auto tmp = cend(); | |
21586 --tmp; | |
21587 return *tmp; | |
21588 } | |
21589 | |
21590 /// @brief remove element given an iterator | |
21591 /// @sa https://json.nlohmann.me/api/basic_json/erase/ | |
21592 template < class IteratorType, detail::enable_if_t < | |
21593 std::is_same<IteratorType, typename basic_json_t::iterator>::value || | |
21594 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 > | |
21595 IteratorType erase(IteratorType pos) | |
21596 { | |
21597 // make sure iterator fits the current value | |
21598 if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) | |
21599 { | |
21600 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); | |
21601 } | |
21602 | |
21603 IteratorType result = end(); | |
21604 | |
21605 switch (m_type) | |
21606 { | |
21607 case value_t::boolean: | |
21608 case value_t::number_float: | |
21609 case value_t::number_integer: | |
21610 case value_t::number_unsigned: | |
21611 case value_t::string: | |
21612 case value_t::binary: | |
21613 { | |
21614 if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) | |
21615 { | |
21616 JSON_THROW(invalid_iterator::create(205, "iterator out of range", this)); | |
21617 } | |
21618 | |
21619 if (is_string()) | |
21620 { | |
21621 AllocatorType<string_t> alloc; | |
21622 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string); | |
21623 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1); | |
21624 m_value.string = nullptr; | |
21625 } | |
21626 else if (is_binary()) | |
21627 { | |
21628 AllocatorType<binary_t> alloc; | |
21629 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary); | |
21630 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1); | |
21631 m_value.binary = nullptr; | |
21632 } | |
21633 | |
21634 m_type = value_t::null; | |
21635 assert_invariant(); | |
21636 break; | |
21637 } | |
21638 | |
21639 case value_t::object: | |
21640 { | |
21641 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); | |
21642 break; | |
21643 } | |
21644 | |
21645 case value_t::array: | |
21646 { | |
21647 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); | |
21648 break; | |
21649 } | |
21650 | |
21651 case value_t::null: | |
21652 case value_t::discarded: | |
21653 default: | |
21654 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); | |
21655 } | |
21656 | |
21657 return result; | |
21658 } | |
21659 | |
21660 /// @brief remove elements given an iterator range | |
21661 /// @sa https://json.nlohmann.me/api/basic_json/erase/ | |
21662 template < class IteratorType, detail::enable_if_t < | |
21663 std::is_same<IteratorType, typename basic_json_t::iterator>::value || | |
21664 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 > | |
21665 IteratorType erase(IteratorType first, IteratorType last) | |
21666 { | |
21667 // make sure iterator fits the current value | |
21668 if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) | |
21669 { | |
21670 JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this)); | |
21671 } | |
21672 | |
21673 IteratorType result = end(); | |
21674 | |
21675 switch (m_type) | |
21676 { | |
21677 case value_t::boolean: | |
21678 case value_t::number_float: | |
21679 case value_t::number_integer: | |
21680 case value_t::number_unsigned: | |
21681 case value_t::string: | |
21682 case value_t::binary: | |
21683 { | |
21684 if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() | |
21685 || !last.m_it.primitive_iterator.is_end())) | |
21686 { | |
21687 JSON_THROW(invalid_iterator::create(204, "iterators out of range", this)); | |
21688 } | |
21689 | |
21690 if (is_string()) | |
21691 { | |
21692 AllocatorType<string_t> alloc; | |
21693 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string); | |
21694 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1); | |
21695 m_value.string = nullptr; | |
21696 } | |
21697 else if (is_binary()) | |
21698 { | |
21699 AllocatorType<binary_t> alloc; | |
21700 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary); | |
21701 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1); | |
21702 m_value.binary = nullptr; | |
21703 } | |
21704 | |
21705 m_type = value_t::null; | |
21706 assert_invariant(); | |
21707 break; | |
21708 } | |
21709 | |
21710 case value_t::object: | |
21711 { | |
21712 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, | |
21713 last.m_it.object_iterator); | |
21714 break; | |
21715 } | |
21716 | |
21717 case value_t::array: | |
21718 { | |
21719 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, | |
21720 last.m_it.array_iterator); | |
21721 break; | |
21722 } | |
21723 | |
21724 case value_t::null: | |
21725 case value_t::discarded: | |
21726 default: | |
21727 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); | |
21728 } | |
21729 | |
21730 return result; | |
21731 } | |
21732 | |
21733 private: | |
21734 template < typename KeyType, detail::enable_if_t < | |
21735 detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 > | |
21736 size_type erase_internal(KeyType && key) | |
21737 { | |
21738 // this erase only works for objects | |
21739 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
21740 { | |
21741 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); | |
21742 } | |
21743 | |
21744 return m_value.object->erase(std::forward<KeyType>(key)); | |
21745 } | |
21746 | |
21747 template < typename KeyType, detail::enable_if_t < | |
21748 !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 > | |
21749 size_type erase_internal(KeyType && key) | |
21750 { | |
21751 // this erase only works for objects | |
21752 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
21753 { | |
21754 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); | |
21755 } | |
21756 | |
21757 const auto it = m_value.object->find(std::forward<KeyType>(key)); | |
21758 if (it != m_value.object->end()) | |
21759 { | |
21760 m_value.object->erase(it); | |
21761 return 1; | |
21762 } | |
21763 return 0; | |
21764 } | |
21765 | |
21766 public: | |
21767 | |
21768 /// @brief remove element from a JSON object given a key | |
21769 /// @sa https://json.nlohmann.me/api/basic_json/erase/ | |
21770 size_type erase(const typename object_t::key_type& key) | |
21771 { | |
21772 // the indirection via erase_internal() is added to avoid making this | |
21773 // function a template and thus de-rank it during overload resolution | |
21774 return erase_internal(key); | |
21775 } | |
21776 | |
21777 /// @brief remove element from a JSON object given a key | |
21778 /// @sa https://json.nlohmann.me/api/basic_json/erase/ | |
21779 template<class KeyType, detail::enable_if_t< | |
21780 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> | |
21781 size_type erase(KeyType && key) | |
21782 { | |
21783 return erase_internal(std::forward<KeyType>(key)); | |
21784 } | |
21785 | |
21786 /// @brief remove element from a JSON array given an index | |
21787 /// @sa https://json.nlohmann.me/api/basic_json/erase/ | |
21788 void erase(const size_type idx) | |
21789 { | |
21790 // this erase only works for arrays | |
21791 if (JSON_HEDLEY_LIKELY(is_array())) | |
21792 { | |
21793 if (JSON_HEDLEY_UNLIKELY(idx >= size())) | |
21794 { | |
21795 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); | |
21796 } | |
21797 | |
21798 m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx)); | |
21799 } | |
21800 else | |
21801 { | |
21802 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); | |
21803 } | |
21804 } | |
21805 | |
21806 /// @} | |
21807 | |
21808 | |
21809 //////////// | |
21810 // lookup // | |
21811 //////////// | |
21812 | |
21813 /// @name lookup | |
21814 /// @{ | |
21815 | |
21816 /// @brief find an element in a JSON object | |
21817 /// @sa https://json.nlohmann.me/api/basic_json/find/ | |
21818 iterator find(const typename object_t::key_type& key) | |
21819 { | |
21820 auto result = end(); | |
21821 | |
21822 if (is_object()) | |
21823 { | |
21824 result.m_it.object_iterator = m_value.object->find(key); | |
21825 } | |
21826 | |
21827 return result; | |
21828 } | |
21829 | |
21830 /// @brief find an element in a JSON object | |
21831 /// @sa https://json.nlohmann.me/api/basic_json/find/ | |
21832 const_iterator find(const typename object_t::key_type& key) const | |
21833 { | |
21834 auto result = cend(); | |
21835 | |
21836 if (is_object()) | |
21837 { | |
21838 result.m_it.object_iterator = m_value.object->find(key); | |
21839 } | |
21840 | |
21841 return result; | |
21842 } | |
21843 | |
21844 /// @brief find an element in a JSON object | |
21845 /// @sa https://json.nlohmann.me/api/basic_json/find/ | |
21846 template<class KeyType, detail::enable_if_t< | |
21847 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> | |
21848 iterator find(KeyType && key) | |
21849 { | |
21850 auto result = end(); | |
21851 | |
21852 if (is_object()) | |
21853 { | |
21854 result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key)); | |
21855 } | |
21856 | |
21857 return result; | |
21858 } | |
21859 | |
21860 /// @brief find an element in a JSON object | |
21861 /// @sa https://json.nlohmann.me/api/basic_json/find/ | |
21862 template<class KeyType, detail::enable_if_t< | |
21863 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> | |
21864 const_iterator find(KeyType && key) const | |
21865 { | |
21866 auto result = cend(); | |
21867 | |
21868 if (is_object()) | |
21869 { | |
21870 result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key)); | |
21871 } | |
21872 | |
21873 return result; | |
21874 } | |
21875 | |
21876 /// @brief returns the number of occurrences of a key in a JSON object | |
21877 /// @sa https://json.nlohmann.me/api/basic_json/count/ | |
21878 size_type count(const typename object_t::key_type& key) const | |
21879 { | |
21880 // return 0 for all nonobject types | |
21881 return is_object() ? m_value.object->count(key) : 0; | |
21882 } | |
21883 | |
21884 /// @brief returns the number of occurrences of a key in a JSON object | |
21885 /// @sa https://json.nlohmann.me/api/basic_json/count/ | |
21886 template<class KeyType, detail::enable_if_t< | |
21887 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> | |
21888 size_type count(KeyType && key) const | |
21889 { | |
21890 // return 0 for all nonobject types | |
21891 return is_object() ? m_value.object->count(std::forward<KeyType>(key)) : 0; | |
21892 } | |
21893 | |
21894 /// @brief check the existence of an element in a JSON object | |
21895 /// @sa https://json.nlohmann.me/api/basic_json/contains/ | |
21896 bool contains(const typename object_t::key_type& key) const | |
21897 { | |
21898 return is_object() && m_value.object->find(key) != m_value.object->end(); | |
21899 } | |
21900 | |
21901 /// @brief check the existence of an element in a JSON object | |
21902 /// @sa https://json.nlohmann.me/api/basic_json/contains/ | |
21903 template<class KeyType, detail::enable_if_t< | |
21904 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> | |
21905 bool contains(KeyType && key) const | |
21906 { | |
21907 return is_object() && m_value.object->find(std::forward<KeyType>(key)) != m_value.object->end(); | |
21908 } | |
21909 | |
21910 /// @brief check the existence of an element in a JSON object given a JSON pointer | |
21911 /// @sa https://json.nlohmann.me/api/basic_json/contains/ | |
21912 bool contains(const json_pointer& ptr) const | |
21913 { | |
21914 return ptr.contains(this); | |
21915 } | |
21916 | |
21917 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> | |
21918 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) | |
21919 bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const | |
21920 { | |
21921 return ptr.contains(this); | |
21922 } | |
21923 | |
21924 /// @} | |
21925 | |
21926 | |
21927 /////////////// | |
21928 // iterators // | |
21929 /////////////// | |
21930 | |
21931 /// @name iterators | |
21932 /// @{ | |
21933 | |
21934 /// @brief returns an iterator to the first element | |
21935 /// @sa https://json.nlohmann.me/api/basic_json/begin/ | |
21936 iterator begin() noexcept | |
21937 { | |
21938 iterator result(this); | |
21939 result.set_begin(); | |
21940 return result; | |
21941 } | |
21942 | |
21943 /// @brief returns an iterator to the first element | |
21944 /// @sa https://json.nlohmann.me/api/basic_json/begin/ | |
21945 const_iterator begin() const noexcept | |
21946 { | |
21947 return cbegin(); | |
21948 } | |
21949 | |
21950 /// @brief returns a const iterator to the first element | |
21951 /// @sa https://json.nlohmann.me/api/basic_json/cbegin/ | |
21952 const_iterator cbegin() const noexcept | |
21953 { | |
21954 const_iterator result(this); | |
21955 result.set_begin(); | |
21956 return result; | |
21957 } | |
21958 | |
21959 /// @brief returns an iterator to one past the last element | |
21960 /// @sa https://json.nlohmann.me/api/basic_json/end/ | |
21961 iterator end() noexcept | |
21962 { | |
21963 iterator result(this); | |
21964 result.set_end(); | |
21965 return result; | |
21966 } | |
21967 | |
21968 /// @brief returns an iterator to one past the last element | |
21969 /// @sa https://json.nlohmann.me/api/basic_json/end/ | |
21970 const_iterator end() const noexcept | |
21971 { | |
21972 return cend(); | |
21973 } | |
21974 | |
21975 /// @brief returns an iterator to one past the last element | |
21976 /// @sa https://json.nlohmann.me/api/basic_json/cend/ | |
21977 const_iterator cend() const noexcept | |
21978 { | |
21979 const_iterator result(this); | |
21980 result.set_end(); | |
21981 return result; | |
21982 } | |
21983 | |
21984 /// @brief returns an iterator to the reverse-beginning | |
21985 /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ | |
21986 reverse_iterator rbegin() noexcept | |
21987 { | |
21988 return reverse_iterator(end()); | |
21989 } | |
21990 | |
21991 /// @brief returns an iterator to the reverse-beginning | |
21992 /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ | |
21993 const_reverse_iterator rbegin() const noexcept | |
21994 { | |
21995 return crbegin(); | |
21996 } | |
21997 | |
21998 /// @brief returns an iterator to the reverse-end | |
21999 /// @sa https://json.nlohmann.me/api/basic_json/rend/ | |
22000 reverse_iterator rend() noexcept | |
22001 { | |
22002 return reverse_iterator(begin()); | |
22003 } | |
22004 | |
22005 /// @brief returns an iterator to the reverse-end | |
22006 /// @sa https://json.nlohmann.me/api/basic_json/rend/ | |
22007 const_reverse_iterator rend() const noexcept | |
22008 { | |
22009 return crend(); | |
22010 } | |
22011 | |
22012 /// @brief returns a const reverse iterator to the last element | |
22013 /// @sa https://json.nlohmann.me/api/basic_json/crbegin/ | |
22014 const_reverse_iterator crbegin() const noexcept | |
22015 { | |
22016 return const_reverse_iterator(cend()); | |
22017 } | |
22018 | |
22019 /// @brief returns a const reverse iterator to one before the first | |
22020 /// @sa https://json.nlohmann.me/api/basic_json/crend/ | |
22021 const_reverse_iterator crend() const noexcept | |
22022 { | |
22023 return const_reverse_iterator(cbegin()); | |
22024 } | |
22025 | |
22026 public: | |
22027 /// @brief wrapper to access iterator member functions in range-based for | |
22028 /// @sa https://json.nlohmann.me/api/basic_json/items/ | |
22029 /// @deprecated This function is deprecated since 3.1.0 and will be removed in | |
22030 /// version 4.0.0 of the library. Please use @ref items() instead; | |
22031 /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. | |
22032 JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) | |
22033 static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept | |
22034 { | |
22035 return ref.items(); | |
22036 } | |
22037 | |
22038 /// @brief wrapper to access iterator member functions in range-based for | |
22039 /// @sa https://json.nlohmann.me/api/basic_json/items/ | |
22040 /// @deprecated This function is deprecated since 3.1.0 and will be removed in | |
22041 /// version 4.0.0 of the library. Please use @ref items() instead; | |
22042 /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. | |
22043 JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) | |
22044 static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept | |
22045 { | |
22046 return ref.items(); | |
22047 } | |
22048 | |
22049 /// @brief helper to access iterator member functions in range-based for | |
22050 /// @sa https://json.nlohmann.me/api/basic_json/items/ | |
22051 iteration_proxy<iterator> items() noexcept | |
22052 { | |
22053 return iteration_proxy<iterator>(*this); | |
22054 } | |
22055 | |
22056 /// @brief helper to access iterator member functions in range-based for | |
22057 /// @sa https://json.nlohmann.me/api/basic_json/items/ | |
22058 iteration_proxy<const_iterator> items() const noexcept | |
22059 { | |
22060 return iteration_proxy<const_iterator>(*this); | |
22061 } | |
22062 | |
22063 /// @} | |
22064 | |
22065 | |
22066 ////////////// | |
22067 // capacity // | |
22068 ////////////// | |
22069 | |
22070 /// @name capacity | |
22071 /// @{ | |
22072 | |
22073 /// @brief checks whether the container is empty. | |
22074 /// @sa https://json.nlohmann.me/api/basic_json/empty/ | |
22075 bool empty() const noexcept | |
22076 { | |
22077 switch (m_type) | |
22078 { | |
22079 case value_t::null: | |
22080 { | |
22081 // null values are empty | |
22082 return true; | |
22083 } | |
22084 | |
22085 case value_t::array: | |
22086 { | |
22087 // delegate call to array_t::empty() | |
22088 return m_value.array->empty(); | |
22089 } | |
22090 | |
22091 case value_t::object: | |
22092 { | |
22093 // delegate call to object_t::empty() | |
22094 return m_value.object->empty(); | |
22095 } | |
22096 | |
22097 case value_t::string: | |
22098 case value_t::boolean: | |
22099 case value_t::number_integer: | |
22100 case value_t::number_unsigned: | |
22101 case value_t::number_float: | |
22102 case value_t::binary: | |
22103 case value_t::discarded: | |
22104 default: | |
22105 { | |
22106 // all other types are nonempty | |
22107 return false; | |
22108 } | |
22109 } | |
22110 } | |
22111 | |
22112 /// @brief returns the number of elements | |
22113 /// @sa https://json.nlohmann.me/api/basic_json/size/ | |
22114 size_type size() const noexcept | |
22115 { | |
22116 switch (m_type) | |
22117 { | |
22118 case value_t::null: | |
22119 { | |
22120 // null values are empty | |
22121 return 0; | |
22122 } | |
22123 | |
22124 case value_t::array: | |
22125 { | |
22126 // delegate call to array_t::size() | |
22127 return m_value.array->size(); | |
22128 } | |
22129 | |
22130 case value_t::object: | |
22131 { | |
22132 // delegate call to object_t::size() | |
22133 return m_value.object->size(); | |
22134 } | |
22135 | |
22136 case value_t::string: | |
22137 case value_t::boolean: | |
22138 case value_t::number_integer: | |
22139 case value_t::number_unsigned: | |
22140 case value_t::number_float: | |
22141 case value_t::binary: | |
22142 case value_t::discarded: | |
22143 default: | |
22144 { | |
22145 // all other types have size 1 | |
22146 return 1; | |
22147 } | |
22148 } | |
22149 } | |
22150 | |
22151 /// @brief returns the maximum possible number of elements | |
22152 /// @sa https://json.nlohmann.me/api/basic_json/max_size/ | |
22153 size_type max_size() const noexcept | |
22154 { | |
22155 switch (m_type) | |
22156 { | |
22157 case value_t::array: | |
22158 { | |
22159 // delegate call to array_t::max_size() | |
22160 return m_value.array->max_size(); | |
22161 } | |
22162 | |
22163 case value_t::object: | |
22164 { | |
22165 // delegate call to object_t::max_size() | |
22166 return m_value.object->max_size(); | |
22167 } | |
22168 | |
22169 case value_t::null: | |
22170 case value_t::string: | |
22171 case value_t::boolean: | |
22172 case value_t::number_integer: | |
22173 case value_t::number_unsigned: | |
22174 case value_t::number_float: | |
22175 case value_t::binary: | |
22176 case value_t::discarded: | |
22177 default: | |
22178 { | |
22179 // all other types have max_size() == size() | |
22180 return size(); | |
22181 } | |
22182 } | |
22183 } | |
22184 | |
22185 /// @} | |
22186 | |
22187 | |
22188 /////////////// | |
22189 // modifiers // | |
22190 /////////////// | |
22191 | |
22192 /// @name modifiers | |
22193 /// @{ | |
22194 | |
22195 /// @brief clears the contents | |
22196 /// @sa https://json.nlohmann.me/api/basic_json/clear/ | |
22197 void clear() noexcept | |
22198 { | |
22199 switch (m_type) | |
22200 { | |
22201 case value_t::number_integer: | |
22202 { | |
22203 m_value.number_integer = 0; | |
22204 break; | |
22205 } | |
22206 | |
22207 case value_t::number_unsigned: | |
22208 { | |
22209 m_value.number_unsigned = 0; | |
22210 break; | |
22211 } | |
22212 | |
22213 case value_t::number_float: | |
22214 { | |
22215 m_value.number_float = 0.0; | |
22216 break; | |
22217 } | |
22218 | |
22219 case value_t::boolean: | |
22220 { | |
22221 m_value.boolean = false; | |
22222 break; | |
22223 } | |
22224 | |
22225 case value_t::string: | |
22226 { | |
22227 m_value.string->clear(); | |
22228 break; | |
22229 } | |
22230 | |
22231 case value_t::binary: | |
22232 { | |
22233 m_value.binary->clear(); | |
22234 break; | |
22235 } | |
22236 | |
22237 case value_t::array: | |
22238 { | |
22239 m_value.array->clear(); | |
22240 break; | |
22241 } | |
22242 | |
22243 case value_t::object: | |
22244 { | |
22245 m_value.object->clear(); | |
22246 break; | |
22247 } | |
22248 | |
22249 case value_t::null: | |
22250 case value_t::discarded: | |
22251 default: | |
22252 break; | |
22253 } | |
22254 } | |
22255 | |
22256 /// @brief add an object to an array | |
22257 /// @sa https://json.nlohmann.me/api/basic_json/push_back/ | |
22258 void push_back(basic_json&& val) | |
22259 { | |
22260 // push_back only works for null objects or arrays | |
22261 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) | |
22262 { | |
22263 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); | |
22264 } | |
22265 | |
22266 // transform null object into an array | |
22267 if (is_null()) | |
22268 { | |
22269 m_type = value_t::array; | |
22270 m_value = value_t::array; | |
22271 assert_invariant(); | |
22272 } | |
22273 | |
22274 // add element to array (move semantics) | |
22275 const auto old_capacity = m_value.array->capacity(); | |
22276 m_value.array->push_back(std::move(val)); | |
22277 set_parent(m_value.array->back(), old_capacity); | |
22278 // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor | |
22279 } | |
22280 | |
22281 /// @brief add an object to an array | |
22282 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ | |
22283 reference operator+=(basic_json&& val) | |
22284 { | |
22285 push_back(std::move(val)); | |
22286 return *this; | |
22287 } | |
22288 | |
22289 /// @brief add an object to an array | |
22290 /// @sa https://json.nlohmann.me/api/basic_json/push_back/ | |
22291 void push_back(const basic_json& val) | |
22292 { | |
22293 // push_back only works for null objects or arrays | |
22294 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) | |
22295 { | |
22296 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); | |
22297 } | |
22298 | |
22299 // transform null object into an array | |
22300 if (is_null()) | |
22301 { | |
22302 m_type = value_t::array; | |
22303 m_value = value_t::array; | |
22304 assert_invariant(); | |
22305 } | |
22306 | |
22307 // add element to array | |
22308 const auto old_capacity = m_value.array->capacity(); | |
22309 m_value.array->push_back(val); | |
22310 set_parent(m_value.array->back(), old_capacity); | |
22311 } | |
22312 | |
22313 /// @brief add an object to an array | |
22314 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ | |
22315 reference operator+=(const basic_json& val) | |
22316 { | |
22317 push_back(val); | |
22318 return *this; | |
22319 } | |
22320 | |
22321 /// @brief add an object to an object | |
22322 /// @sa https://json.nlohmann.me/api/basic_json/push_back/ | |
22323 void push_back(const typename object_t::value_type& val) | |
22324 { | |
22325 // push_back only works for null objects or objects | |
22326 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) | |
22327 { | |
22328 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); | |
22329 } | |
22330 | |
22331 // transform null object into an object | |
22332 if (is_null()) | |
22333 { | |
22334 m_type = value_t::object; | |
22335 m_value = value_t::object; | |
22336 assert_invariant(); | |
22337 } | |
22338 | |
22339 // add element to object | |
22340 auto res = m_value.object->insert(val); | |
22341 set_parent(res.first->second); | |
22342 } | |
22343 | |
22344 /// @brief add an object to an object | |
22345 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ | |
22346 reference operator+=(const typename object_t::value_type& val) | |
22347 { | |
22348 push_back(val); | |
22349 return *this; | |
22350 } | |
22351 | |
22352 /// @brief add an object to an object | |
22353 /// @sa https://json.nlohmann.me/api/basic_json/push_back/ | |
22354 void push_back(initializer_list_t init) | |
22355 { | |
22356 if (is_object() && init.size() == 2 && (*init.begin())->is_string()) | |
22357 { | |
22358 basic_json&& key = init.begin()->moved_or_copied(); | |
22359 push_back(typename object_t::value_type( | |
22360 std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied())); | |
22361 } | |
22362 else | |
22363 { | |
22364 push_back(basic_json(init)); | |
22365 } | |
22366 } | |
22367 | |
22368 /// @brief add an object to an object | |
22369 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ | |
22370 reference operator+=(initializer_list_t init) | |
22371 { | |
22372 push_back(init); | |
22373 return *this; | |
22374 } | |
22375 | |
22376 /// @brief add an object to an array | |
22377 /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/ | |
22378 template<class... Args> | |
22379 reference emplace_back(Args&& ... args) | |
22380 { | |
22381 // emplace_back only works for null objects or arrays | |
22382 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) | |
22383 { | |
22384 JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this)); | |
22385 } | |
22386 | |
22387 // transform null object into an array | |
22388 if (is_null()) | |
22389 { | |
22390 m_type = value_t::array; | |
22391 m_value = value_t::array; | |
22392 assert_invariant(); | |
22393 } | |
22394 | |
22395 // add element to array (perfect forwarding) | |
22396 const auto old_capacity = m_value.array->capacity(); | |
22397 m_value.array->emplace_back(std::forward<Args>(args)...); | |
22398 return set_parent(m_value.array->back(), old_capacity); | |
22399 } | |
22400 | |
22401 /// @brief add an object to an object if key does not exist | |
22402 /// @sa https://json.nlohmann.me/api/basic_json/emplace/ | |
22403 template<class... Args> | |
22404 std::pair<iterator, bool> emplace(Args&& ... args) | |
22405 { | |
22406 // emplace only works for null objects or arrays | |
22407 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) | |
22408 { | |
22409 JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this)); | |
22410 } | |
22411 | |
22412 // transform null object into an object | |
22413 if (is_null()) | |
22414 { | |
22415 m_type = value_t::object; | |
22416 m_value = value_t::object; | |
22417 assert_invariant(); | |
22418 } | |
22419 | |
22420 // add element to array (perfect forwarding) | |
22421 auto res = m_value.object->emplace(std::forward<Args>(args)...); | |
22422 set_parent(res.first->second); | |
22423 | |
22424 // create result iterator and set iterator to the result of emplace | |
22425 auto it = begin(); | |
22426 it.m_it.object_iterator = res.first; | |
22427 | |
22428 // return pair of iterator and boolean | |
22429 return {it, res.second}; | |
22430 } | |
22431 | |
22432 /// Helper for insertion of an iterator | |
22433 /// @note: This uses std::distance to support GCC 4.8, | |
22434 /// see https://github.com/nlohmann/json/pull/1257 | |
22435 template<typename... Args> | |
22436 iterator insert_iterator(const_iterator pos, Args&& ... args) | |
22437 { | |
22438 iterator result(this); | |
22439 JSON_ASSERT(m_value.array != nullptr); | |
22440 | |
22441 auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); | |
22442 m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...); | |
22443 result.m_it.array_iterator = m_value.array->begin() + insert_pos; | |
22444 | |
22445 // This could have been written as: | |
22446 // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); | |
22447 // but the return value of insert is missing in GCC 4.8, so it is written this way instead. | |
22448 | |
22449 set_parents(); | |
22450 return result; | |
22451 } | |
22452 | |
22453 /// @brief inserts element into array | |
22454 /// @sa https://json.nlohmann.me/api/basic_json/insert/ | |
22455 iterator insert(const_iterator pos, const basic_json& val) | |
22456 { | |
22457 // insert only works for arrays | |
22458 if (JSON_HEDLEY_LIKELY(is_array())) | |
22459 { | |
22460 // check if iterator pos fits to this JSON value | |
22461 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) | |
22462 { | |
22463 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); | |
22464 } | |
22465 | |
22466 // insert to array and return iterator | |
22467 return insert_iterator(pos, val); | |
22468 } | |
22469 | |
22470 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); | |
22471 } | |
22472 | |
22473 /// @brief inserts element into array | |
22474 /// @sa https://json.nlohmann.me/api/basic_json/insert/ | |
22475 iterator insert(const_iterator pos, basic_json&& val) | |
22476 { | |
22477 return insert(pos, val); | |
22478 } | |
22479 | |
22480 /// @brief inserts copies of element into array | |
22481 /// @sa https://json.nlohmann.me/api/basic_json/insert/ | |
22482 iterator insert(const_iterator pos, size_type cnt, const basic_json& val) | |
22483 { | |
22484 // insert only works for arrays | |
22485 if (JSON_HEDLEY_LIKELY(is_array())) | |
22486 { | |
22487 // check if iterator pos fits to this JSON value | |
22488 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) | |
22489 { | |
22490 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); | |
22491 } | |
22492 | |
22493 // insert to array and return iterator | |
22494 return insert_iterator(pos, cnt, val); | |
22495 } | |
22496 | |
22497 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); | |
22498 } | |
22499 | |
22500 /// @brief inserts range of elements into array | |
22501 /// @sa https://json.nlohmann.me/api/basic_json/insert/ | |
22502 iterator insert(const_iterator pos, const_iterator first, const_iterator last) | |
22503 { | |
22504 // insert only works for arrays | |
22505 if (JSON_HEDLEY_UNLIKELY(!is_array())) | |
22506 { | |
22507 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); | |
22508 } | |
22509 | |
22510 // check if iterator pos fits to this JSON value | |
22511 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) | |
22512 { | |
22513 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); | |
22514 } | |
22515 | |
22516 // check if range iterators belong to the same JSON object | |
22517 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) | |
22518 { | |
22519 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); | |
22520 } | |
22521 | |
22522 if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) | |
22523 { | |
22524 JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this)); | |
22525 } | |
22526 | |
22527 // insert to array and return iterator | |
22528 return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); | |
22529 } | |
22530 | |
22531 /// @brief inserts elements from initializer list into array | |
22532 /// @sa https://json.nlohmann.me/api/basic_json/insert/ | |
22533 iterator insert(const_iterator pos, initializer_list_t ilist) | |
22534 { | |
22535 // insert only works for arrays | |
22536 if (JSON_HEDLEY_UNLIKELY(!is_array())) | |
22537 { | |
22538 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); | |
22539 } | |
22540 | |
22541 // check if iterator pos fits to this JSON value | |
22542 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) | |
22543 { | |
22544 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); | |
22545 } | |
22546 | |
22547 // insert to array and return iterator | |
22548 return insert_iterator(pos, ilist.begin(), ilist.end()); | |
22549 } | |
22550 | |
22551 /// @brief inserts range of elements into object | |
22552 /// @sa https://json.nlohmann.me/api/basic_json/insert/ | |
22553 void insert(const_iterator first, const_iterator last) | |
22554 { | |
22555 // insert only works for objects | |
22556 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
22557 { | |
22558 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); | |
22559 } | |
22560 | |
22561 // check if range iterators belong to the same JSON object | |
22562 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) | |
22563 { | |
22564 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); | |
22565 } | |
22566 | |
22567 // passed iterators must belong to objects | |
22568 if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) | |
22569 { | |
22570 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this)); | |
22571 } | |
22572 | |
22573 m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); | |
22574 } | |
22575 | |
22576 /// @brief updates a JSON object from another object, overwriting existing keys | |
22577 /// @sa https://json.nlohmann.me/api/basic_json/update/ | |
22578 void update(const_reference j, bool merge_objects = false) | |
22579 { | |
22580 update(j.begin(), j.end(), merge_objects); | |
22581 } | |
22582 | |
22583 /// @brief updates a JSON object from another object, overwriting existing keys | |
22584 /// @sa https://json.nlohmann.me/api/basic_json/update/ | |
22585 void update(const_iterator first, const_iterator last, bool merge_objects = false) | |
22586 { | |
22587 // implicitly convert null value to an empty object | |
22588 if (is_null()) | |
22589 { | |
22590 m_type = value_t::object; | |
22591 m_value.object = create<object_t>(); | |
22592 assert_invariant(); | |
22593 } | |
22594 | |
22595 if (JSON_HEDLEY_UNLIKELY(!is_object())) | |
22596 { | |
22597 JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this)); | |
22598 } | |
22599 | |
22600 // check if range iterators belong to the same JSON object | |
22601 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) | |
22602 { | |
22603 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); | |
22604 } | |
22605 | |
22606 // passed iterators must belong to objects | |
22607 if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) | |
22608 { | |
22609 JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object)); | |
22610 } | |
22611 | |
22612 for (auto it = first; it != last; ++it) | |
22613 { | |
22614 if (merge_objects && it.value().is_object()) | |
22615 { | |
22616 auto it2 = m_value.object->find(it.key()); | |
22617 if (it2 != m_value.object->end()) | |
22618 { | |
22619 it2->second.update(it.value(), true); | |
22620 continue; | |
22621 } | |
22622 } | |
22623 m_value.object->operator[](it.key()) = it.value(); | |
22624 #if JSON_DIAGNOSTICS | |
22625 m_value.object->operator[](it.key()).m_parent = this; | |
22626 #endif | |
22627 } | |
22628 } | |
22629 | |
22630 /// @brief exchanges the values | |
22631 /// @sa https://json.nlohmann.me/api/basic_json/swap/ | |
22632 void swap(reference other) noexcept ( | |
22633 std::is_nothrow_move_constructible<value_t>::value&& | |
22634 std::is_nothrow_move_assignable<value_t>::value&& | |
22635 std::is_nothrow_move_constructible<json_value>::value&& | |
22636 std::is_nothrow_move_assignable<json_value>::value | |
22637 ) | |
22638 { | |
22639 std::swap(m_type, other.m_type); | |
22640 std::swap(m_value, other.m_value); | |
22641 | |
22642 set_parents(); | |
22643 other.set_parents(); | |
22644 assert_invariant(); | |
22645 } | |
22646 | |
22647 /// @brief exchanges the values | |
22648 /// @sa https://json.nlohmann.me/api/basic_json/swap/ | |
22649 friend void swap(reference left, reference right) noexcept ( | |
22650 std::is_nothrow_move_constructible<value_t>::value&& | |
22651 std::is_nothrow_move_assignable<value_t>::value&& | |
22652 std::is_nothrow_move_constructible<json_value>::value&& | |
22653 std::is_nothrow_move_assignable<json_value>::value | |
22654 ) | |
22655 { | |
22656 left.swap(right); | |
22657 } | |
22658 | |
22659 /// @brief exchanges the values | |
22660 /// @sa https://json.nlohmann.me/api/basic_json/swap/ | |
22661 void swap(array_t& other) // NOLINT(bugprone-exception-escape) | |
22662 { | |
22663 // swap only works for arrays | |
22664 if (JSON_HEDLEY_LIKELY(is_array())) | |
22665 { | |
22666 using std::swap; | |
22667 swap(*(m_value.array), other); | |
22668 } | |
22669 else | |
22670 { | |
22671 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this)); | |
22672 } | |
22673 } | |
22674 | |
22675 /// @brief exchanges the values | |
22676 /// @sa https://json.nlohmann.me/api/basic_json/swap/ | |
22677 void swap(object_t& other) // NOLINT(bugprone-exception-escape) | |
22678 { | |
22679 // swap only works for objects | |
22680 if (JSON_HEDLEY_LIKELY(is_object())) | |
22681 { | |
22682 using std::swap; | |
22683 swap(*(m_value.object), other); | |
22684 } | |
22685 else | |
22686 { | |
22687 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this)); | |
22688 } | |
22689 } | |
22690 | |
22691 /// @brief exchanges the values | |
22692 /// @sa https://json.nlohmann.me/api/basic_json/swap/ | |
22693 void swap(string_t& other) // NOLINT(bugprone-exception-escape) | |
22694 { | |
22695 // swap only works for strings | |
22696 if (JSON_HEDLEY_LIKELY(is_string())) | |
22697 { | |
22698 using std::swap; | |
22699 swap(*(m_value.string), other); | |
22700 } | |
22701 else | |
22702 { | |
22703 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this)); | |
22704 } | |
22705 } | |
22706 | |
22707 /// @brief exchanges the values | |
22708 /// @sa https://json.nlohmann.me/api/basic_json/swap/ | |
22709 void swap(binary_t& other) // NOLINT(bugprone-exception-escape) | |
22710 { | |
22711 // swap only works for strings | |
22712 if (JSON_HEDLEY_LIKELY(is_binary())) | |
22713 { | |
22714 using std::swap; | |
22715 swap(*(m_value.binary), other); | |
22716 } | |
22717 else | |
22718 { | |
22719 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this)); | |
22720 } | |
22721 } | |
22722 | |
22723 /// @brief exchanges the values | |
22724 /// @sa https://json.nlohmann.me/api/basic_json/swap/ | |
22725 void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape) | |
22726 { | |
22727 // swap only works for strings | |
22728 if (JSON_HEDLEY_LIKELY(is_binary())) | |
22729 { | |
22730 using std::swap; | |
22731 swap(*(m_value.binary), other); | |
22732 } | |
22733 else | |
22734 { | |
22735 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this)); | |
22736 } | |
22737 } | |
22738 | |
22739 /// @} | |
22740 | |
22741 ////////////////////////////////////////// | |
22742 // lexicographical comparison operators // | |
22743 ////////////////////////////////////////// | |
22744 | |
22745 /// @name lexicographical comparison operators | |
22746 /// @{ | |
22747 | |
22748 // note parentheses around operands are necessary; see | |
22749 // https://github.com/nlohmann/json/issues/1530 | |
22750 #define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \ | |
22751 const auto lhs_type = lhs.type(); \ | |
22752 const auto rhs_type = rhs.type(); \ | |
22753 \ | |
22754 if (lhs_type == rhs_type) /* NOLINT(readability/braces) */ \ | |
22755 { \ | |
22756 switch (lhs_type) \ | |
22757 { \ | |
22758 case value_t::array: \ | |
22759 return (*lhs.m_value.array) op (*rhs.m_value.array); \ | |
22760 \ | |
22761 case value_t::object: \ | |
22762 return (*lhs.m_value.object) op (*rhs.m_value.object); \ | |
22763 \ | |
22764 case value_t::null: \ | |
22765 return (null_result); \ | |
22766 \ | |
22767 case value_t::string: \ | |
22768 return (*lhs.m_value.string) op (*rhs.m_value.string); \ | |
22769 \ | |
22770 case value_t::boolean: \ | |
22771 return (lhs.m_value.boolean) op (rhs.m_value.boolean); \ | |
22772 \ | |
22773 case value_t::number_integer: \ | |
22774 return (lhs.m_value.number_integer) op (rhs.m_value.number_integer); \ | |
22775 \ | |
22776 case value_t::number_unsigned: \ | |
22777 return (lhs.m_value.number_unsigned) op (rhs.m_value.number_unsigned); \ | |
22778 \ | |
22779 case value_t::number_float: \ | |
22780 return (lhs.m_value.number_float) op (rhs.m_value.number_float); \ | |
22781 \ | |
22782 case value_t::binary: \ | |
22783 return (*lhs.m_value.binary) op (*rhs.m_value.binary); \ | |
22784 \ | |
22785 case value_t::discarded: \ | |
22786 default: \ | |
22787 return (unordered_result); \ | |
22788 } \ | |
22789 } \ | |
22790 else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \ | |
22791 { \ | |
22792 return static_cast<number_float_t>(lhs.m_value.number_integer) op rhs.m_value.number_float; \ | |
22793 } \ | |
22794 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \ | |
22795 { \ | |
22796 return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_integer); \ | |
22797 } \ | |
22798 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \ | |
22799 { \ | |
22800 return static_cast<number_float_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_float; \ | |
22801 } \ | |
22802 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \ | |
22803 { \ | |
22804 return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_unsigned); \ | |
22805 } \ | |
22806 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \ | |
22807 { \ | |
22808 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_integer; \ | |
22809 } \ | |
22810 else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \ | |
22811 { \ | |
22812 return lhs.m_value.number_integer op static_cast<number_integer_t>(rhs.m_value.number_unsigned); \ | |
22813 } \ | |
22814 else if(compares_unordered(lhs, rhs))\ | |
22815 {\ | |
22816 return (unordered_result);\ | |
22817 }\ | |
22818 \ | |
22819 return (default_result); | |
22820 | |
22821 JSON_PRIVATE_UNLESS_TESTED: | |
22822 // returns true if: | |
22823 // - any operand is NaN and the other operand is of number type | |
22824 // - any operand is discarded | |
22825 // in legacy mode, discarded values are considered ordered if | |
22826 // an operation is computed as an odd number of inverses of others | |
22827 static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept | |
22828 { | |
22829 if ((lhs.is_number_float() && std::isnan(lhs.m_value.number_float) && rhs.is_number()) | |
22830 || (rhs.is_number_float() && std::isnan(rhs.m_value.number_float) && lhs.is_number())) | |
22831 { | |
22832 return true; | |
22833 } | |
22834 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON | |
22835 return (lhs.is_discarded() || rhs.is_discarded()) && !inverse; | |
22836 #else | |
22837 static_cast<void>(inverse); | |
22838 return lhs.is_discarded() || rhs.is_discarded(); | |
22839 #endif | |
22840 } | |
22841 | |
22842 private: | |
22843 bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept | |
22844 { | |
22845 return compares_unordered(*this, rhs, inverse); | |
22846 } | |
22847 | |
22848 public: | |
22849 #if JSON_HAS_THREE_WAY_COMPARISON | |
22850 /// @brief comparison: equal | |
22851 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ | |
22852 bool operator==(const_reference rhs) const noexcept | |
22853 { | |
22854 #ifdef __GNUC__ | |
22855 #pragma GCC diagnostic push | |
22856 #pragma GCC diagnostic ignored "-Wfloat-equal" | |
22857 #endif | |
22858 const_reference lhs = *this; | |
22859 JSON_IMPLEMENT_OPERATOR( ==, true, false, false) | |
22860 #ifdef __GNUC__ | |
22861 #pragma GCC diagnostic pop | |
22862 #endif | |
22863 } | |
22864 | |
22865 /// @brief comparison: equal | |
22866 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ | |
22867 template<typename ScalarType> | |
22868 requires std::is_scalar_v<ScalarType> | |
22869 bool operator==(ScalarType rhs) const noexcept | |
22870 { | |
22871 return *this == basic_json(rhs); | |
22872 } | |
22873 | |
22874 /// @brief comparison: not equal | |
22875 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ | |
22876 bool operator!=(const_reference rhs) const noexcept | |
22877 { | |
22878 if (compares_unordered(rhs, true)) | |
22879 { | |
22880 return false; | |
22881 } | |
22882 return !operator==(rhs); | |
22883 } | |
22884 | |
22885 /// @brief comparison: 3-way | |
22886 /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ | |
22887 std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD* | |
22888 { | |
22889 const_reference lhs = *this; | |
22890 // default_result is used if we cannot compare values. In that case, | |
22891 // we compare types. | |
22892 JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD* | |
22893 std::partial_ordering::equivalent, | |
22894 std::partial_ordering::unordered, | |
22895 lhs_type <=> rhs_type) // *NOPAD* | |
22896 } | |
22897 | |
22898 /// @brief comparison: 3-way | |
22899 /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ | |
22900 template<typename ScalarType> | |
22901 requires std::is_scalar_v<ScalarType> | |
22902 std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD* | |
22903 { | |
22904 return *this <=> basic_json(rhs); // *NOPAD* | |
22905 } | |
22906 | |
22907 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON | |
22908 // all operators that are computed as an odd number of inverses of others | |
22909 // need to be overloaded to emulate the legacy comparison behavior | |
22910 | |
22911 /// @brief comparison: less than or equal | |
22912 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ | |
22913 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON) | |
22914 bool operator<=(const_reference rhs) const noexcept | |
22915 { | |
22916 if (compares_unordered(rhs, true)) | |
22917 { | |
22918 return false; | |
22919 } | |
22920 return !(rhs < *this); | |
22921 } | |
22922 | |
22923 /// @brief comparison: less than or equal | |
22924 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ | |
22925 template<typename ScalarType> | |
22926 requires std::is_scalar_v<ScalarType> | |
22927 bool operator<=(ScalarType rhs) const noexcept | |
22928 { | |
22929 return *this <= basic_json(rhs); | |
22930 } | |
22931 | |
22932 /// @brief comparison: greater than or equal | |
22933 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ | |
22934 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON) | |
22935 bool operator>=(const_reference rhs) const noexcept | |
22936 { | |
22937 if (compares_unordered(rhs, true)) | |
22938 { | |
22939 return false; | |
22940 } | |
22941 return !(*this < rhs); | |
22942 } | |
22943 | |
22944 /// @brief comparison: greater than or equal | |
22945 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ | |
22946 template<typename ScalarType> | |
22947 requires std::is_scalar_v<ScalarType> | |
22948 bool operator>=(ScalarType rhs) const noexcept | |
22949 { | |
22950 return *this >= basic_json(rhs); | |
22951 } | |
22952 #endif | |
22953 #else | |
22954 /// @brief comparison: equal | |
22955 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ | |
22956 friend bool operator==(const_reference lhs, const_reference rhs) noexcept | |
22957 { | |
22958 #ifdef __GNUC__ | |
22959 #pragma GCC diagnostic push | |
22960 #pragma GCC diagnostic ignored "-Wfloat-equal" | |
22961 #endif | |
22962 JSON_IMPLEMENT_OPERATOR( ==, true, false, false) | |
22963 #ifdef __GNUC__ | |
22964 #pragma GCC diagnostic pop | |
22965 #endif | |
22966 } | |
22967 | |
22968 /// @brief comparison: equal | |
22969 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ | |
22970 template<typename ScalarType, typename std::enable_if< | |
22971 std::is_scalar<ScalarType>::value, int>::type = 0> | |
22972 friend bool operator==(const_reference lhs, ScalarType rhs) noexcept | |
22973 { | |
22974 return lhs == basic_json(rhs); | |
22975 } | |
22976 | |
22977 /// @brief comparison: equal | |
22978 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ | |
22979 template<typename ScalarType, typename std::enable_if< | |
22980 std::is_scalar<ScalarType>::value, int>::type = 0> | |
22981 friend bool operator==(ScalarType lhs, const_reference rhs) noexcept | |
22982 { | |
22983 return basic_json(lhs) == rhs; | |
22984 } | |
22985 | |
22986 /// @brief comparison: not equal | |
22987 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ | |
22988 friend bool operator!=(const_reference lhs, const_reference rhs) noexcept | |
22989 { | |
22990 if (compares_unordered(lhs, rhs, true)) | |
22991 { | |
22992 return false; | |
22993 } | |
22994 return !(lhs == rhs); | |
22995 } | |
22996 | |
22997 /// @brief comparison: not equal | |
22998 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ | |
22999 template<typename ScalarType, typename std::enable_if< | |
23000 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23001 friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept | |
23002 { | |
23003 return lhs != basic_json(rhs); | |
23004 } | |
23005 | |
23006 /// @brief comparison: not equal | |
23007 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ | |
23008 template<typename ScalarType, typename std::enable_if< | |
23009 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23010 friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept | |
23011 { | |
23012 return basic_json(lhs) != rhs; | |
23013 } | |
23014 | |
23015 /// @brief comparison: less than | |
23016 /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ | |
23017 friend bool operator<(const_reference lhs, const_reference rhs) noexcept | |
23018 { | |
23019 // default_result is used if we cannot compare values. In that case, | |
23020 // we compare types. Note we have to call the operator explicitly, | |
23021 // because MSVC has problems otherwise. | |
23022 JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type)) | |
23023 } | |
23024 | |
23025 /// @brief comparison: less than | |
23026 /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ | |
23027 template<typename ScalarType, typename std::enable_if< | |
23028 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23029 friend bool operator<(const_reference lhs, ScalarType rhs) noexcept | |
23030 { | |
23031 return lhs < basic_json(rhs); | |
23032 } | |
23033 | |
23034 /// @brief comparison: less than | |
23035 /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ | |
23036 template<typename ScalarType, typename std::enable_if< | |
23037 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23038 friend bool operator<(ScalarType lhs, const_reference rhs) noexcept | |
23039 { | |
23040 return basic_json(lhs) < rhs; | |
23041 } | |
23042 | |
23043 /// @brief comparison: less than or equal | |
23044 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ | |
23045 friend bool operator<=(const_reference lhs, const_reference rhs) noexcept | |
23046 { | |
23047 if (compares_unordered(lhs, rhs, true)) | |
23048 { | |
23049 return false; | |
23050 } | |
23051 return !(rhs < lhs); | |
23052 } | |
23053 | |
23054 /// @brief comparison: less than or equal | |
23055 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ | |
23056 template<typename ScalarType, typename std::enable_if< | |
23057 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23058 friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept | |
23059 { | |
23060 return lhs <= basic_json(rhs); | |
23061 } | |
23062 | |
23063 /// @brief comparison: less than or equal | |
23064 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ | |
23065 template<typename ScalarType, typename std::enable_if< | |
23066 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23067 friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept | |
23068 { | |
23069 return basic_json(lhs) <= rhs; | |
23070 } | |
23071 | |
23072 /// @brief comparison: greater than | |
23073 /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ | |
23074 friend bool operator>(const_reference lhs, const_reference rhs) noexcept | |
23075 { | |
23076 // double inverse | |
23077 if (compares_unordered(lhs, rhs)) | |
23078 { | |
23079 return false; | |
23080 } | |
23081 return !(lhs <= rhs); | |
23082 } | |
23083 | |
23084 /// @brief comparison: greater than | |
23085 /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ | |
23086 template<typename ScalarType, typename std::enable_if< | |
23087 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23088 friend bool operator>(const_reference lhs, ScalarType rhs) noexcept | |
23089 { | |
23090 return lhs > basic_json(rhs); | |
23091 } | |
23092 | |
23093 /// @brief comparison: greater than | |
23094 /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ | |
23095 template<typename ScalarType, typename std::enable_if< | |
23096 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23097 friend bool operator>(ScalarType lhs, const_reference rhs) noexcept | |
23098 { | |
23099 return basic_json(lhs) > rhs; | |
23100 } | |
23101 | |
23102 /// @brief comparison: greater than or equal | |
23103 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ | |
23104 friend bool operator>=(const_reference lhs, const_reference rhs) noexcept | |
23105 { | |
23106 if (compares_unordered(lhs, rhs, true)) | |
23107 { | |
23108 return false; | |
23109 } | |
23110 return !(lhs < rhs); | |
23111 } | |
23112 | |
23113 /// @brief comparison: greater than or equal | |
23114 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ | |
23115 template<typename ScalarType, typename std::enable_if< | |
23116 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23117 friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept | |
23118 { | |
23119 return lhs >= basic_json(rhs); | |
23120 } | |
23121 | |
23122 /// @brief comparison: greater than or equal | |
23123 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ | |
23124 template<typename ScalarType, typename std::enable_if< | |
23125 std::is_scalar<ScalarType>::value, int>::type = 0> | |
23126 friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept | |
23127 { | |
23128 return basic_json(lhs) >= rhs; | |
23129 } | |
23130 #endif | |
23131 | |
23132 #undef JSON_IMPLEMENT_OPERATOR | |
23133 | |
23134 /// @} | |
23135 | |
23136 /////////////////// | |
23137 // serialization // | |
23138 /////////////////// | |
23139 | |
23140 /// @name serialization | |
23141 /// @{ | |
23142 #ifndef JSON_NO_IO | |
23143 /// @brief serialize to stream | |
23144 /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ | |
23145 friend std::ostream& operator<<(std::ostream& o, const basic_json& j) | |
23146 { | |
23147 // read width member and use it as indentation parameter if nonzero | |
23148 const bool pretty_print = o.width() > 0; | |
23149 const auto indentation = pretty_print ? o.width() : 0; | |
23150 | |
23151 // reset width to 0 for subsequent calls to this stream | |
23152 o.width(0); | |
23153 | |
23154 // do the actual serialization | |
23155 serializer s(detail::output_adapter<char>(o), o.fill()); | |
23156 s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation)); | |
23157 return o; | |
23158 } | |
23159 | |
23160 /// @brief serialize to stream | |
23161 /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ | |
23162 /// @deprecated This function is deprecated since 3.0.0 and will be removed in | |
23163 /// version 4.0.0 of the library. Please use | |
23164 /// operator<<(std::ostream&, const basic_json&) instead; that is, | |
23165 /// replace calls like `j >> o;` with `o << j;`. | |
23166 JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) | |
23167 friend std::ostream& operator>>(const basic_json& j, std::ostream& o) | |
23168 { | |
23169 return o << j; | |
23170 } | |
23171 #endif // JSON_NO_IO | |
23172 /// @} | |
23173 | |
23174 | |
23175 ///////////////////// | |
23176 // deserialization // | |
23177 ///////////////////// | |
23178 | |
23179 /// @name deserialization | |
23180 /// @{ | |
23181 | |
23182 /// @brief deserialize from a compatible input | |
23183 /// @sa https://json.nlohmann.me/api/basic_json/parse/ | |
23184 template<typename InputType> | |
23185 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23186 static basic_json parse(InputType&& i, | |
23187 const parser_callback_t cb = nullptr, | |
23188 const bool allow_exceptions = true, | |
23189 const bool ignore_comments = false) | |
23190 { | |
23191 basic_json result; | |
23192 parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result); | |
23193 return result; | |
23194 } | |
23195 | |
23196 /// @brief deserialize from a pair of character iterators | |
23197 /// @sa https://json.nlohmann.me/api/basic_json/parse/ | |
23198 template<typename IteratorType> | |
23199 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23200 static basic_json parse(IteratorType first, | |
23201 IteratorType last, | |
23202 const parser_callback_t cb = nullptr, | |
23203 const bool allow_exceptions = true, | |
23204 const bool ignore_comments = false) | |
23205 { | |
23206 basic_json result; | |
23207 parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); | |
23208 return result; | |
23209 } | |
23210 | |
23211 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23212 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) | |
23213 static basic_json parse(detail::span_input_adapter&& i, | |
23214 const parser_callback_t cb = nullptr, | |
23215 const bool allow_exceptions = true, | |
23216 const bool ignore_comments = false) | |
23217 { | |
23218 basic_json result; | |
23219 parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); | |
23220 return result; | |
23221 } | |
23222 | |
23223 /// @brief check if the input is valid JSON | |
23224 /// @sa https://json.nlohmann.me/api/basic_json/accept/ | |
23225 template<typename InputType> | |
23226 static bool accept(InputType&& i, | |
23227 const bool ignore_comments = false) | |
23228 { | |
23229 return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true); | |
23230 } | |
23231 | |
23232 /// @brief check if the input is valid JSON | |
23233 /// @sa https://json.nlohmann.me/api/basic_json/accept/ | |
23234 template<typename IteratorType> | |
23235 static bool accept(IteratorType first, IteratorType last, | |
23236 const bool ignore_comments = false) | |
23237 { | |
23238 return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); | |
23239 } | |
23240 | |
23241 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23242 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) | |
23243 static bool accept(detail::span_input_adapter&& i, | |
23244 const bool ignore_comments = false) | |
23245 { | |
23246 return parser(i.get(), nullptr, false, ignore_comments).accept(true); | |
23247 } | |
23248 | |
23249 /// @brief generate SAX events | |
23250 /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ | |
23251 template <typename InputType, typename SAX> | |
23252 JSON_HEDLEY_NON_NULL(2) | |
23253 static bool sax_parse(InputType&& i, SAX* sax, | |
23254 input_format_t format = input_format_t::json, | |
23255 const bool strict = true, | |
23256 const bool ignore_comments = false) | |
23257 { | |
23258 auto ia = detail::input_adapter(std::forward<InputType>(i)); | |
23259 return format == input_format_t::json | |
23260 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) | |
23261 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); | |
23262 } | |
23263 | |
23264 /// @brief generate SAX events | |
23265 /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ | |
23266 template<class IteratorType, class SAX> | |
23267 JSON_HEDLEY_NON_NULL(3) | |
23268 static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, | |
23269 input_format_t format = input_format_t::json, | |
23270 const bool strict = true, | |
23271 const bool ignore_comments = false) | |
23272 { | |
23273 auto ia = detail::input_adapter(std::move(first), std::move(last)); | |
23274 return format == input_format_t::json | |
23275 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) | |
23276 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); | |
23277 } | |
23278 | |
23279 /// @brief generate SAX events | |
23280 /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ | |
23281 /// @deprecated This function is deprecated since 3.8.0 and will be removed in | |
23282 /// version 4.0.0 of the library. Please use | |
23283 /// sax_parse(ptr, ptr + len) instead. | |
23284 template <typename SAX> | |
23285 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) | |
23286 JSON_HEDLEY_NON_NULL(2) | |
23287 static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, | |
23288 input_format_t format = input_format_t::json, | |
23289 const bool strict = true, | |
23290 const bool ignore_comments = false) | |
23291 { | |
23292 auto ia = i.get(); | |
23293 return format == input_format_t::json | |
23294 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) | |
23295 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) | |
23296 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) | |
23297 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); | |
23298 } | |
23299 #ifndef JSON_NO_IO | |
23300 /// @brief deserialize from stream | |
23301 /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ | |
23302 /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in | |
23303 /// version 4.0.0 of the library. Please use | |
23304 /// operator>>(std::istream&, basic_json&) instead; that is, | |
23305 /// replace calls like `j << i;` with `i >> j;`. | |
23306 JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) | |
23307 friend std::istream& operator<<(basic_json& j, std::istream& i) | |
23308 { | |
23309 return operator>>(i, j); | |
23310 } | |
23311 | |
23312 /// @brief deserialize from stream | |
23313 /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ | |
23314 friend std::istream& operator>>(std::istream& i, basic_json& j) | |
23315 { | |
23316 parser(detail::input_adapter(i)).parse(false, j); | |
23317 return i; | |
23318 } | |
23319 #endif // JSON_NO_IO | |
23320 /// @} | |
23321 | |
23322 /////////////////////////// | |
23323 // convenience functions // | |
23324 /////////////////////////// | |
23325 | |
23326 /// @brief return the type as string | |
23327 /// @sa https://json.nlohmann.me/api/basic_json/type_name/ | |
23328 JSON_HEDLEY_RETURNS_NON_NULL | |
23329 const char* type_name() const noexcept | |
23330 { | |
23331 switch (m_type) | |
23332 { | |
23333 case value_t::null: | |
23334 return "null"; | |
23335 case value_t::object: | |
23336 return "object"; | |
23337 case value_t::array: | |
23338 return "array"; | |
23339 case value_t::string: | |
23340 return "string"; | |
23341 case value_t::boolean: | |
23342 return "boolean"; | |
23343 case value_t::binary: | |
23344 return "binary"; | |
23345 case value_t::discarded: | |
23346 return "discarded"; | |
23347 case value_t::number_integer: | |
23348 case value_t::number_unsigned: | |
23349 case value_t::number_float: | |
23350 default: | |
23351 return "number"; | |
23352 } | |
23353 } | |
23354 | |
23355 | |
23356 JSON_PRIVATE_UNLESS_TESTED: | |
23357 ////////////////////// | |
23358 // member variables // | |
23359 ////////////////////// | |
23360 | |
23361 /// the type of the current element | |
23362 value_t m_type = value_t::null; | |
23363 | |
23364 /// the value of the current element | |
23365 json_value m_value = {}; | |
23366 | |
23367 #if JSON_DIAGNOSTICS | |
23368 /// a pointer to a parent value (for debugging purposes) | |
23369 basic_json* m_parent = nullptr; | |
23370 #endif | |
23371 | |
23372 ////////////////////////////////////////// | |
23373 // binary serialization/deserialization // | |
23374 ////////////////////////////////////////// | |
23375 | |
23376 /// @name binary serialization/deserialization support | |
23377 /// @{ | |
23378 | |
23379 public: | |
23380 /// @brief create a CBOR serialization of a given JSON value | |
23381 /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ | |
23382 static std::vector<std::uint8_t> to_cbor(const basic_json& j) | |
23383 { | |
23384 std::vector<std::uint8_t> result; | |
23385 to_cbor(j, result); | |
23386 return result; | |
23387 } | |
23388 | |
23389 /// @brief create a CBOR serialization of a given JSON value | |
23390 /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ | |
23391 static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o) | |
23392 { | |
23393 binary_writer<std::uint8_t>(o).write_cbor(j); | |
23394 } | |
23395 | |
23396 /// @brief create a CBOR serialization of a given JSON value | |
23397 /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ | |
23398 static void to_cbor(const basic_json& j, detail::output_adapter<char> o) | |
23399 { | |
23400 binary_writer<char>(o).write_cbor(j); | |
23401 } | |
23402 | |
23403 /// @brief create a MessagePack serialization of a given JSON value | |
23404 /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ | |
23405 static std::vector<std::uint8_t> to_msgpack(const basic_json& j) | |
23406 { | |
23407 std::vector<std::uint8_t> result; | |
23408 to_msgpack(j, result); | |
23409 return result; | |
23410 } | |
23411 | |
23412 /// @brief create a MessagePack serialization of a given JSON value | |
23413 /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ | |
23414 static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o) | |
23415 { | |
23416 binary_writer<std::uint8_t>(o).write_msgpack(j); | |
23417 } | |
23418 | |
23419 /// @brief create a MessagePack serialization of a given JSON value | |
23420 /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ | |
23421 static void to_msgpack(const basic_json& j, detail::output_adapter<char> o) | |
23422 { | |
23423 binary_writer<char>(o).write_msgpack(j); | |
23424 } | |
23425 | |
23426 /// @brief create a UBJSON serialization of a given JSON value | |
23427 /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ | |
23428 static std::vector<std::uint8_t> to_ubjson(const basic_json& j, | |
23429 const bool use_size = false, | |
23430 const bool use_type = false) | |
23431 { | |
23432 std::vector<std::uint8_t> result; | |
23433 to_ubjson(j, result, use_size, use_type); | |
23434 return result; | |
23435 } | |
23436 | |
23437 /// @brief create a UBJSON serialization of a given JSON value | |
23438 /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ | |
23439 static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o, | |
23440 const bool use_size = false, const bool use_type = false) | |
23441 { | |
23442 binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type); | |
23443 } | |
23444 | |
23445 /// @brief create a UBJSON serialization of a given JSON value | |
23446 /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ | |
23447 static void to_ubjson(const basic_json& j, detail::output_adapter<char> o, | |
23448 const bool use_size = false, const bool use_type = false) | |
23449 { | |
23450 binary_writer<char>(o).write_ubjson(j, use_size, use_type); | |
23451 } | |
23452 | |
23453 /// @brief create a BJData serialization of a given JSON value | |
23454 /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ | |
23455 static std::vector<std::uint8_t> to_bjdata(const basic_json& j, | |
23456 const bool use_size = false, | |
23457 const bool use_type = false) | |
23458 { | |
23459 std::vector<std::uint8_t> result; | |
23460 to_bjdata(j, result, use_size, use_type); | |
23461 return result; | |
23462 } | |
23463 | |
23464 /// @brief create a BJData serialization of a given JSON value | |
23465 /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ | |
23466 static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o, | |
23467 const bool use_size = false, const bool use_type = false) | |
23468 { | |
23469 binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true); | |
23470 } | |
23471 | |
23472 /// @brief create a BJData serialization of a given JSON value | |
23473 /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ | |
23474 static void to_bjdata(const basic_json& j, detail::output_adapter<char> o, | |
23475 const bool use_size = false, const bool use_type = false) | |
23476 { | |
23477 binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true); | |
23478 } | |
23479 | |
23480 /// @brief create a BSON serialization of a given JSON value | |
23481 /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ | |
23482 static std::vector<std::uint8_t> to_bson(const basic_json& j) | |
23483 { | |
23484 std::vector<std::uint8_t> result; | |
23485 to_bson(j, result); | |
23486 return result; | |
23487 } | |
23488 | |
23489 /// @brief create a BSON serialization of a given JSON value | |
23490 /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ | |
23491 static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o) | |
23492 { | |
23493 binary_writer<std::uint8_t>(o).write_bson(j); | |
23494 } | |
23495 | |
23496 /// @brief create a BSON serialization of a given JSON value | |
23497 /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ | |
23498 static void to_bson(const basic_json& j, detail::output_adapter<char> o) | |
23499 { | |
23500 binary_writer<char>(o).write_bson(j); | |
23501 } | |
23502 | |
23503 /// @brief create a JSON value from an input in CBOR format | |
23504 /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ | |
23505 template<typename InputType> | |
23506 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23507 static basic_json from_cbor(InputType&& i, | |
23508 const bool strict = true, | |
23509 const bool allow_exceptions = true, | |
23510 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) | |
23511 { | |
23512 basic_json result; | |
23513 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23514 auto ia = detail::input_adapter(std::forward<InputType>(i)); | |
23515 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); | |
23516 return res ? result : basic_json(value_t::discarded); | |
23517 } | |
23518 | |
23519 /// @brief create a JSON value from an input in CBOR format | |
23520 /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ | |
23521 template<typename IteratorType> | |
23522 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23523 static basic_json from_cbor(IteratorType first, IteratorType last, | |
23524 const bool strict = true, | |
23525 const bool allow_exceptions = true, | |
23526 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) | |
23527 { | |
23528 basic_json result; | |
23529 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23530 auto ia = detail::input_adapter(std::move(first), std::move(last)); | |
23531 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); | |
23532 return res ? result : basic_json(value_t::discarded); | |
23533 } | |
23534 | |
23535 template<typename T> | |
23536 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23537 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) | |
23538 static basic_json from_cbor(const T* ptr, std::size_t len, | |
23539 const bool strict = true, | |
23540 const bool allow_exceptions = true, | |
23541 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) | |
23542 { | |
23543 return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); | |
23544 } | |
23545 | |
23546 | |
23547 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23548 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) | |
23549 static basic_json from_cbor(detail::span_input_adapter&& i, | |
23550 const bool strict = true, | |
23551 const bool allow_exceptions = true, | |
23552 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) | |
23553 { | |
23554 basic_json result; | |
23555 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23556 auto ia = i.get(); | |
23557 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) | |
23558 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); | |
23559 return res ? result : basic_json(value_t::discarded); | |
23560 } | |
23561 | |
23562 /// @brief create a JSON value from an input in MessagePack format | |
23563 /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ | |
23564 template<typename InputType> | |
23565 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23566 static basic_json from_msgpack(InputType&& i, | |
23567 const bool strict = true, | |
23568 const bool allow_exceptions = true) | |
23569 { | |
23570 basic_json result; | |
23571 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23572 auto ia = detail::input_adapter(std::forward<InputType>(i)); | |
23573 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); | |
23574 return res ? result : basic_json(value_t::discarded); | |
23575 } | |
23576 | |
23577 /// @brief create a JSON value from an input in MessagePack format | |
23578 /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ | |
23579 template<typename IteratorType> | |
23580 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23581 static basic_json from_msgpack(IteratorType first, IteratorType last, | |
23582 const bool strict = true, | |
23583 const bool allow_exceptions = true) | |
23584 { | |
23585 basic_json result; | |
23586 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23587 auto ia = detail::input_adapter(std::move(first), std::move(last)); | |
23588 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); | |
23589 return res ? result : basic_json(value_t::discarded); | |
23590 } | |
23591 | |
23592 template<typename T> | |
23593 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23594 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) | |
23595 static basic_json from_msgpack(const T* ptr, std::size_t len, | |
23596 const bool strict = true, | |
23597 const bool allow_exceptions = true) | |
23598 { | |
23599 return from_msgpack(ptr, ptr + len, strict, allow_exceptions); | |
23600 } | |
23601 | |
23602 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23603 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) | |
23604 static basic_json from_msgpack(detail::span_input_adapter&& i, | |
23605 const bool strict = true, | |
23606 const bool allow_exceptions = true) | |
23607 { | |
23608 basic_json result; | |
23609 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23610 auto ia = i.get(); | |
23611 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) | |
23612 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); | |
23613 return res ? result : basic_json(value_t::discarded); | |
23614 } | |
23615 | |
23616 /// @brief create a JSON value from an input in UBJSON format | |
23617 /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ | |
23618 template<typename InputType> | |
23619 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23620 static basic_json from_ubjson(InputType&& i, | |
23621 const bool strict = true, | |
23622 const bool allow_exceptions = true) | |
23623 { | |
23624 basic_json result; | |
23625 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23626 auto ia = detail::input_adapter(std::forward<InputType>(i)); | |
23627 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); | |
23628 return res ? result : basic_json(value_t::discarded); | |
23629 } | |
23630 | |
23631 /// @brief create a JSON value from an input in UBJSON format | |
23632 /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ | |
23633 template<typename IteratorType> | |
23634 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23635 static basic_json from_ubjson(IteratorType first, IteratorType last, | |
23636 const bool strict = true, | |
23637 const bool allow_exceptions = true) | |
23638 { | |
23639 basic_json result; | |
23640 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23641 auto ia = detail::input_adapter(std::move(first), std::move(last)); | |
23642 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); | |
23643 return res ? result : basic_json(value_t::discarded); | |
23644 } | |
23645 | |
23646 template<typename T> | |
23647 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23648 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) | |
23649 static basic_json from_ubjson(const T* ptr, std::size_t len, | |
23650 const bool strict = true, | |
23651 const bool allow_exceptions = true) | |
23652 { | |
23653 return from_ubjson(ptr, ptr + len, strict, allow_exceptions); | |
23654 } | |
23655 | |
23656 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23657 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) | |
23658 static basic_json from_ubjson(detail::span_input_adapter&& i, | |
23659 const bool strict = true, | |
23660 const bool allow_exceptions = true) | |
23661 { | |
23662 basic_json result; | |
23663 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23664 auto ia = i.get(); | |
23665 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) | |
23666 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); | |
23667 return res ? result : basic_json(value_t::discarded); | |
23668 } | |
23669 | |
23670 | |
23671 /// @brief create a JSON value from an input in BJData format | |
23672 /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ | |
23673 template<typename InputType> | |
23674 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23675 static basic_json from_bjdata(InputType&& i, | |
23676 const bool strict = true, | |
23677 const bool allow_exceptions = true) | |
23678 { | |
23679 basic_json result; | |
23680 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23681 auto ia = detail::input_adapter(std::forward<InputType>(i)); | |
23682 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); | |
23683 return res ? result : basic_json(value_t::discarded); | |
23684 } | |
23685 | |
23686 /// @brief create a JSON value from an input in BJData format | |
23687 /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ | |
23688 template<typename IteratorType> | |
23689 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23690 static basic_json from_bjdata(IteratorType first, IteratorType last, | |
23691 const bool strict = true, | |
23692 const bool allow_exceptions = true) | |
23693 { | |
23694 basic_json result; | |
23695 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23696 auto ia = detail::input_adapter(std::move(first), std::move(last)); | |
23697 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); | |
23698 return res ? result : basic_json(value_t::discarded); | |
23699 } | |
23700 | |
23701 /// @brief create a JSON value from an input in BSON format | |
23702 /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ | |
23703 template<typename InputType> | |
23704 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23705 static basic_json from_bson(InputType&& i, | |
23706 const bool strict = true, | |
23707 const bool allow_exceptions = true) | |
23708 { | |
23709 basic_json result; | |
23710 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23711 auto ia = detail::input_adapter(std::forward<InputType>(i)); | |
23712 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); | |
23713 return res ? result : basic_json(value_t::discarded); | |
23714 } | |
23715 | |
23716 /// @brief create a JSON value from an input in BSON format | |
23717 /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ | |
23718 template<typename IteratorType> | |
23719 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23720 static basic_json from_bson(IteratorType first, IteratorType last, | |
23721 const bool strict = true, | |
23722 const bool allow_exceptions = true) | |
23723 { | |
23724 basic_json result; | |
23725 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23726 auto ia = detail::input_adapter(std::move(first), std::move(last)); | |
23727 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); | |
23728 return res ? result : basic_json(value_t::discarded); | |
23729 } | |
23730 | |
23731 template<typename T> | |
23732 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23733 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) | |
23734 static basic_json from_bson(const T* ptr, std::size_t len, | |
23735 const bool strict = true, | |
23736 const bool allow_exceptions = true) | |
23737 { | |
23738 return from_bson(ptr, ptr + len, strict, allow_exceptions); | |
23739 } | |
23740 | |
23741 JSON_HEDLEY_WARN_UNUSED_RESULT | |
23742 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) | |
23743 static basic_json from_bson(detail::span_input_adapter&& i, | |
23744 const bool strict = true, | |
23745 const bool allow_exceptions = true) | |
23746 { | |
23747 basic_json result; | |
23748 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | |
23749 auto ia = i.get(); | |
23750 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) | |
23751 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); | |
23752 return res ? result : basic_json(value_t::discarded); | |
23753 } | |
23754 /// @} | |
23755 | |
23756 ////////////////////////// | |
23757 // JSON Pointer support // | |
23758 ////////////////////////// | |
23759 | |
23760 /// @name JSON Pointer functions | |
23761 /// @{ | |
23762 | |
23763 /// @brief access specified element via JSON Pointer | |
23764 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
23765 reference operator[](const json_pointer& ptr) | |
23766 { | |
23767 return ptr.get_unchecked(this); | |
23768 } | |
23769 | |
23770 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> | |
23771 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) | |
23772 reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) | |
23773 { | |
23774 return ptr.get_unchecked(this); | |
23775 } | |
23776 | |
23777 /// @brief access specified element via JSON Pointer | |
23778 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ | |
23779 const_reference operator[](const json_pointer& ptr) const | |
23780 { | |
23781 return ptr.get_unchecked(this); | |
23782 } | |
23783 | |
23784 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> | |
23785 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) | |
23786 const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const | |
23787 { | |
23788 return ptr.get_unchecked(this); | |
23789 } | |
23790 | |
23791 /// @brief access specified element via JSON Pointer | |
23792 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
23793 reference at(const json_pointer& ptr) | |
23794 { | |
23795 return ptr.get_checked(this); | |
23796 } | |
23797 | |
23798 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> | |
23799 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) | |
23800 reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) | |
23801 { | |
23802 return ptr.get_checked(this); | |
23803 } | |
23804 | |
23805 /// @brief access specified element via JSON Pointer | |
23806 /// @sa https://json.nlohmann.me/api/basic_json/at/ | |
23807 const_reference at(const json_pointer& ptr) const | |
23808 { | |
23809 return ptr.get_checked(this); | |
23810 } | |
23811 | |
23812 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> | |
23813 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) | |
23814 const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const | |
23815 { | |
23816 return ptr.get_checked(this); | |
23817 } | |
23818 | |
23819 /// @brief return flattened JSON value | |
23820 /// @sa https://json.nlohmann.me/api/basic_json/flatten/ | |
23821 basic_json flatten() const | |
23822 { | |
23823 basic_json result(value_t::object); | |
23824 json_pointer::flatten("", *this, result); | |
23825 return result; | |
23826 } | |
23827 | |
23828 /// @brief unflatten a previously flattened JSON value | |
23829 /// @sa https://json.nlohmann.me/api/basic_json/unflatten/ | |
23830 basic_json unflatten() const | |
23831 { | |
23832 return json_pointer::unflatten(*this); | |
23833 } | |
23834 | |
23835 /// @} | |
23836 | |
23837 ////////////////////////// | |
23838 // JSON Patch functions // | |
23839 ////////////////////////// | |
23840 | |
23841 /// @name JSON Patch functions | |
23842 /// @{ | |
23843 | |
23844 /// @brief applies a JSON patch in-place without copying the object | |
23845 /// @sa https://json.nlohmann.me/api/basic_json/patch/ | |
23846 void patch_inplace(const basic_json& json_patch) | |
23847 { | |
23848 basic_json& result = *this; | |
23849 // the valid JSON Patch operations | |
23850 enum class patch_operations {add, remove, replace, move, copy, test, invalid}; | |
23851 | |
23852 const auto get_op = [](const std::string & op) | |
23853 { | |
23854 if (op == "add") | |
23855 { | |
23856 return patch_operations::add; | |
23857 } | |
23858 if (op == "remove") | |
23859 { | |
23860 return patch_operations::remove; | |
23861 } | |
23862 if (op == "replace") | |
23863 { | |
23864 return patch_operations::replace; | |
23865 } | |
23866 if (op == "move") | |
23867 { | |
23868 return patch_operations::move; | |
23869 } | |
23870 if (op == "copy") | |
23871 { | |
23872 return patch_operations::copy; | |
23873 } | |
23874 if (op == "test") | |
23875 { | |
23876 return patch_operations::test; | |
23877 } | |
23878 | |
23879 return patch_operations::invalid; | |
23880 }; | |
23881 | |
23882 // wrapper for "add" operation; add value at ptr | |
23883 const auto operation_add = [&result](json_pointer & ptr, basic_json val) | |
23884 { | |
23885 // adding to the root of the target document means replacing it | |
23886 if (ptr.empty()) | |
23887 { | |
23888 result = val; | |
23889 return; | |
23890 } | |
23891 | |
23892 // make sure the top element of the pointer exists | |
23893 json_pointer top_pointer = ptr.top(); | |
23894 if (top_pointer != ptr) | |
23895 { | |
23896 result.at(top_pointer); | |
23897 } | |
23898 | |
23899 // get reference to parent of JSON pointer ptr | |
23900 const auto last_path = ptr.back(); | |
23901 ptr.pop_back(); | |
23902 // parent must exist when performing patch add per RFC6902 specs | |
23903 basic_json& parent = result.at(ptr); | |
23904 | |
23905 switch (parent.m_type) | |
23906 { | |
23907 case value_t::null: | |
23908 case value_t::object: | |
23909 { | |
23910 // use operator[] to add value | |
23911 parent[last_path] = val; | |
23912 break; | |
23913 } | |
23914 | |
23915 case value_t::array: | |
23916 { | |
23917 if (last_path == "-") | |
23918 { | |
23919 // special case: append to back | |
23920 parent.push_back(val); | |
23921 } | |
23922 else | |
23923 { | |
23924 const auto idx = json_pointer::template array_index<basic_json_t>(last_path); | |
23925 if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) | |
23926 { | |
23927 // avoid undefined behavior | |
23928 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); | |
23929 } | |
23930 | |
23931 // default case: insert add offset | |
23932 parent.insert(parent.begin() + static_cast<difference_type>(idx), val); | |
23933 } | |
23934 break; | |
23935 } | |
23936 | |
23937 // if there exists a parent it cannot be primitive | |
23938 case value_t::string: // LCOV_EXCL_LINE | |
23939 case value_t::boolean: // LCOV_EXCL_LINE | |
23940 case value_t::number_integer: // LCOV_EXCL_LINE | |
23941 case value_t::number_unsigned: // LCOV_EXCL_LINE | |
23942 case value_t::number_float: // LCOV_EXCL_LINE | |
23943 case value_t::binary: // LCOV_EXCL_LINE | |
23944 case value_t::discarded: // LCOV_EXCL_LINE | |
23945 default: // LCOV_EXCL_LINE | |
23946 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE | |
23947 } | |
23948 }; | |
23949 | |
23950 // wrapper for "remove" operation; remove value at ptr | |
23951 const auto operation_remove = [this, &result](json_pointer & ptr) | |
23952 { | |
23953 // get reference to parent of JSON pointer ptr | |
23954 const auto last_path = ptr.back(); | |
23955 ptr.pop_back(); | |
23956 basic_json& parent = result.at(ptr); | |
23957 | |
23958 // remove child | |
23959 if (parent.is_object()) | |
23960 { | |
23961 // perform range check | |
23962 auto it = parent.find(last_path); | |
23963 if (JSON_HEDLEY_LIKELY(it != parent.end())) | |
23964 { | |
23965 parent.erase(it); | |
23966 } | |
23967 else | |
23968 { | |
23969 JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this)); | |
23970 } | |
23971 } | |
23972 else if (parent.is_array()) | |
23973 { | |
23974 // note erase performs range check | |
23975 parent.erase(json_pointer::template array_index<basic_json_t>(last_path)); | |
23976 } | |
23977 }; | |
23978 | |
23979 // type check: top level value must be an array | |
23980 if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) | |
23981 { | |
23982 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch)); | |
23983 } | |
23984 | |
23985 // iterate and apply the operations | |
23986 for (const auto& val : json_patch) | |
23987 { | |
23988 // wrapper to get a value for an operation | |
23989 const auto get_value = [&val](const std::string & op, | |
23990 const std::string & member, | |
23991 bool string_type) -> basic_json & | |
23992 { | |
23993 // find value | |
23994 auto it = val.m_value.object->find(member); | |
23995 | |
23996 // context-sensitive error message | |
23997 const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); | |
23998 | |
23999 // check if desired value is present | |
24000 if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end())) | |
24001 { | |
24002 // NOLINTNEXTLINE(performance-inefficient-string-concatenation) | |
24003 JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); | |
24004 } | |
24005 | |
24006 // check if result is of type string | |
24007 if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) | |
24008 { | |
24009 // NOLINTNEXTLINE(performance-inefficient-string-concatenation) | |
24010 JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val)); | |
24011 } | |
24012 | |
24013 // no error: return value | |
24014 return it->second; | |
24015 }; | |
24016 | |
24017 // type check: every element of the array must be an object | |
24018 if (JSON_HEDLEY_UNLIKELY(!val.is_object())) | |
24019 { | |
24020 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val)); | |
24021 } | |
24022 | |
24023 // collect mandatory members | |
24024 const auto op = get_value("op", "op", true).template get<std::string>(); | |
24025 const auto path = get_value(op, "path", true).template get<std::string>(); | |
24026 json_pointer ptr(path); | |
24027 | |
24028 switch (get_op(op)) | |
24029 { | |
24030 case patch_operations::add: | |
24031 { | |
24032 operation_add(ptr, get_value("add", "value", false)); | |
24033 break; | |
24034 } | |
24035 | |
24036 case patch_operations::remove: | |
24037 { | |
24038 operation_remove(ptr); | |
24039 break; | |
24040 } | |
24041 | |
24042 case patch_operations::replace: | |
24043 { | |
24044 // the "path" location must exist - use at() | |
24045 result.at(ptr) = get_value("replace", "value", false); | |
24046 break; | |
24047 } | |
24048 | |
24049 case patch_operations::move: | |
24050 { | |
24051 const auto from_path = get_value("move", "from", true).template get<std::string>(); | |
24052 json_pointer from_ptr(from_path); | |
24053 | |
24054 // the "from" location must exist - use at() | |
24055 basic_json v = result.at(from_ptr); | |
24056 | |
24057 // The move operation is functionally identical to a | |
24058 // "remove" operation on the "from" location, followed | |
24059 // immediately by an "add" operation at the target | |
24060 // location with the value that was just removed. | |
24061 operation_remove(from_ptr); | |
24062 operation_add(ptr, v); | |
24063 break; | |
24064 } | |
24065 | |
24066 case patch_operations::copy: | |
24067 { | |
24068 const auto from_path = get_value("copy", "from", true).template get<std::string>(); | |
24069 const json_pointer from_ptr(from_path); | |
24070 | |
24071 // the "from" location must exist - use at() | |
24072 basic_json v = result.at(from_ptr); | |
24073 | |
24074 // The copy is functionally identical to an "add" | |
24075 // operation at the target location using the value | |
24076 // specified in the "from" member. | |
24077 operation_add(ptr, v); | |
24078 break; | |
24079 } | |
24080 | |
24081 case patch_operations::test: | |
24082 { | |
24083 bool success = false; | |
24084 JSON_TRY | |
24085 { | |
24086 // check if "value" matches the one at "path" | |
24087 // the "path" location must exist - use at() | |
24088 success = (result.at(ptr) == get_value("test", "value", false)); | |
24089 } | |
24090 JSON_INTERNAL_CATCH (out_of_range&) | |
24091 { | |
24092 // ignore out of range errors: success remains false | |
24093 } | |
24094 | |
24095 // throw an exception if test fails | |
24096 if (JSON_HEDLEY_UNLIKELY(!success)) | |
24097 { | |
24098 JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val)); | |
24099 } | |
24100 | |
24101 break; | |
24102 } | |
24103 | |
24104 case patch_operations::invalid: | |
24105 default: | |
24106 { | |
24107 // op must be "add", "remove", "replace", "move", "copy", or | |
24108 // "test" | |
24109 JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val)); | |
24110 } | |
24111 } | |
24112 } | |
24113 } | |
24114 | |
24115 /// @brief applies a JSON patch to a copy of the current object | |
24116 /// @sa https://json.nlohmann.me/api/basic_json/patch/ | |
24117 basic_json patch(const basic_json& json_patch) const | |
24118 { | |
24119 basic_json result = *this; | |
24120 result.patch_inplace(json_patch); | |
24121 return result; | |
24122 } | |
24123 | |
24124 /// @brief creates a diff as a JSON patch | |
24125 /// @sa https://json.nlohmann.me/api/basic_json/diff/ | |
24126 JSON_HEDLEY_WARN_UNUSED_RESULT | |
24127 static basic_json diff(const basic_json& source, const basic_json& target, | |
24128 const std::string& path = "") | |
24129 { | |
24130 // the patch | |
24131 basic_json result(value_t::array); | |
24132 | |
24133 // if the values are the same, return empty patch | |
24134 if (source == target) | |
24135 { | |
24136 return result; | |
24137 } | |
24138 | |
24139 if (source.type() != target.type()) | |
24140 { | |
24141 // different types: replace value | |
24142 result.push_back( | |
24143 { | |
24144 {"op", "replace"}, {"path", path}, {"value", target} | |
24145 }); | |
24146 return result; | |
24147 } | |
24148 | |
24149 switch (source.type()) | |
24150 { | |
24151 case value_t::array: | |
24152 { | |
24153 // first pass: traverse common elements | |
24154 std::size_t i = 0; | |
24155 while (i < source.size() && i < target.size()) | |
24156 { | |
24157 // recursive call to compare array values at index i | |
24158 auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i))); | |
24159 result.insert(result.end(), temp_diff.begin(), temp_diff.end()); | |
24160 ++i; | |
24161 } | |
24162 | |
24163 // We now reached the end of at least one array | |
24164 // in a second pass, traverse the remaining elements | |
24165 | |
24166 // remove my remaining elements | |
24167 const auto end_index = static_cast<difference_type>(result.size()); | |
24168 while (i < source.size()) | |
24169 { | |
24170 // add operations in reverse order to avoid invalid | |
24171 // indices | |
24172 result.insert(result.begin() + end_index, object( | |
24173 { | |
24174 {"op", "remove"}, | |
24175 {"path", detail::concat(path, '/', std::to_string(i))} | |
24176 })); | |
24177 ++i; | |
24178 } | |
24179 | |
24180 // add other remaining elements | |
24181 while (i < target.size()) | |
24182 { | |
24183 result.push_back( | |
24184 { | |
24185 {"op", "add"}, | |
24186 {"path", detail::concat(path, "/-")}, | |
24187 {"value", target[i]} | |
24188 }); | |
24189 ++i; | |
24190 } | |
24191 | |
24192 break; | |
24193 } | |
24194 | |
24195 case value_t::object: | |
24196 { | |
24197 // first pass: traverse this object's elements | |
24198 for (auto it = source.cbegin(); it != source.cend(); ++it) | |
24199 { | |
24200 // escape the key name to be used in a JSON patch | |
24201 const auto path_key = detail::concat(path, '/', detail::escape(it.key())); | |
24202 | |
24203 if (target.find(it.key()) != target.end()) | |
24204 { | |
24205 // recursive call to compare object values at key it | |
24206 auto temp_diff = diff(it.value(), target[it.key()], path_key); | |
24207 result.insert(result.end(), temp_diff.begin(), temp_diff.end()); | |
24208 } | |
24209 else | |
24210 { | |
24211 // found a key that is not in o -> remove it | |
24212 result.push_back(object( | |
24213 { | |
24214 {"op", "remove"}, {"path", path_key} | |
24215 })); | |
24216 } | |
24217 } | |
24218 | |
24219 // second pass: traverse other object's elements | |
24220 for (auto it = target.cbegin(); it != target.cend(); ++it) | |
24221 { | |
24222 if (source.find(it.key()) == source.end()) | |
24223 { | |
24224 // found a key that is not in this -> add it | |
24225 const auto path_key = detail::concat(path, '/', detail::escape(it.key())); | |
24226 result.push_back( | |
24227 { | |
24228 {"op", "add"}, {"path", path_key}, | |
24229 {"value", it.value()} | |
24230 }); | |
24231 } | |
24232 } | |
24233 | |
24234 break; | |
24235 } | |
24236 | |
24237 case value_t::null: | |
24238 case value_t::string: | |
24239 case value_t::boolean: | |
24240 case value_t::number_integer: | |
24241 case value_t::number_unsigned: | |
24242 case value_t::number_float: | |
24243 case value_t::binary: | |
24244 case value_t::discarded: | |
24245 default: | |
24246 { | |
24247 // both primitive type: replace value | |
24248 result.push_back( | |
24249 { | |
24250 {"op", "replace"}, {"path", path}, {"value", target} | |
24251 }); | |
24252 break; | |
24253 } | |
24254 } | |
24255 | |
24256 return result; | |
24257 } | |
24258 /// @} | |
24259 | |
24260 //////////////////////////////// | |
24261 // JSON Merge Patch functions // | |
24262 //////////////////////////////// | |
24263 | |
24264 /// @name JSON Merge Patch functions | |
24265 /// @{ | |
24266 | |
24267 /// @brief applies a JSON Merge Patch | |
24268 /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/ | |
24269 void merge_patch(const basic_json& apply_patch) | |
24270 { | |
24271 if (apply_patch.is_object()) | |
24272 { | |
24273 if (!is_object()) | |
24274 { | |
24275 *this = object(); | |
24276 } | |
24277 for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) | |
24278 { | |
24279 if (it.value().is_null()) | |
24280 { | |
24281 erase(it.key()); | |
24282 } | |
24283 else | |
24284 { | |
24285 operator[](it.key()).merge_patch(it.value()); | |
24286 } | |
24287 } | |
24288 } | |
24289 else | |
24290 { | |
24291 *this = apply_patch; | |
24292 } | |
24293 } | |
24294 | |
24295 /// @} | |
24296 }; | |
24297 | |
24298 /// @brief user-defined to_string function for JSON values | |
24299 /// @sa https://json.nlohmann.me/api/basic_json/to_string/ | |
24300 NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
24301 std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) | |
24302 { | |
24303 return j.dump(); | |
24304 } | |
24305 | |
24306 inline namespace literals | |
24307 { | |
24308 inline namespace json_literals | |
24309 { | |
24310 | |
24311 /// @brief user-defined string literal for JSON values | |
24312 /// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ | |
24313 JSON_HEDLEY_NON_NULL(1) | |
24314 inline nlohmann::json operator "" _json(const char* s, std::size_t n) | |
24315 { | |
24316 return nlohmann::json::parse(s, s + n); | |
24317 } | |
24318 | |
24319 /// @brief user-defined string literal for JSON pointer | |
24320 /// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ | |
24321 JSON_HEDLEY_NON_NULL(1) | |
24322 inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) | |
24323 { | |
24324 return nlohmann::json::json_pointer(std::string(s, n)); | |
24325 } | |
24326 | |
24327 } // namespace json_literals | |
24328 } // namespace literals | |
24329 NLOHMANN_JSON_NAMESPACE_END | |
24330 | |
24331 /////////////////////// | |
24332 // nonmember support // | |
24333 /////////////////////// | |
24334 | |
24335 namespace std // NOLINT(cert-dcl58-cpp) | |
24336 { | |
24337 | |
24338 /// @brief hash value for JSON objects | |
24339 /// @sa https://json.nlohmann.me/api/basic_json/std_hash/ | |
24340 NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
24341 struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> | |
24342 { | |
24343 std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const | |
24344 { | |
24345 return nlohmann::detail::hash(j); | |
24346 } | |
24347 }; | |
24348 | |
24349 // specialization for std::less<value_t> | |
24350 template<> | |
24351 struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679 | |
24352 { | |
24353 /*! | |
24354 @brief compare two value_t enum values | |
24355 @since version 3.0.0 | |
24356 */ | |
24357 bool operator()(::nlohmann::detail::value_t lhs, | |
24358 ::nlohmann::detail::value_t rhs) const noexcept | |
24359 { | |
24360 #if JSON_HAS_THREE_WAY_COMPARISON | |
24361 return std::is_lt(lhs <=> rhs); // *NOPAD* | |
24362 #else | |
24363 return ::nlohmann::detail::operator<(lhs, rhs); | |
24364 #endif | |
24365 } | |
24366 }; | |
24367 | |
24368 // C++20 prohibit function specialization in the std namespace. | |
24369 #ifndef JSON_HAS_CPP_20 | |
24370 | |
24371 /// @brief exchanges the values of two JSON objects | |
24372 /// @sa https://json.nlohmann.me/api/basic_json/std_swap/ | |
24373 NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
24374 inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name) | |
24375 is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression) | |
24376 is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value) | |
24377 { | |
24378 j1.swap(j2); | |
24379 } | |
24380 | |
24381 #endif | |
24382 | |
24383 } // namespace std | |
24384 | |
24385 #if JSON_USE_GLOBAL_UDLS | |
24386 using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) | |
24387 using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) | |
24388 #endif | |
24389 | |
24390 // #include <nlohmann/detail/macro_unscope.hpp> | |
24391 // __ _____ _____ _____ | |
24392 // __| | __| | | | JSON for Modern C++ | |
24393 // | | |__ | | | | | | version 3.11.2 | |
24394 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
24395 // | |
24396 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
24397 // SPDX-License-Identifier: MIT | |
24398 | |
24399 | |
24400 | |
24401 // restore clang diagnostic settings | |
24402 #if defined(__clang__) | |
24403 #pragma clang diagnostic pop | |
24404 #endif | |
24405 | |
24406 // clean up | |
24407 #undef JSON_ASSERT | |
24408 #undef JSON_INTERNAL_CATCH | |
24409 #undef JSON_THROW | |
24410 #undef JSON_PRIVATE_UNLESS_TESTED | |
24411 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION | |
24412 #undef NLOHMANN_BASIC_JSON_TPL | |
24413 #undef JSON_EXPLICIT | |
24414 #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL | |
24415 #undef JSON_INLINE_VARIABLE | |
24416 #undef JSON_NO_UNIQUE_ADDRESS | |
24417 #undef JSON_DISABLE_ENUM_SERIALIZATION | |
24418 #undef JSON_USE_GLOBAL_UDLS | |
24419 | |
24420 #ifndef JSON_TEST_KEEP_MACROS | |
24421 #undef JSON_CATCH | |
24422 #undef JSON_TRY | |
24423 #undef JSON_HAS_CPP_11 | |
24424 #undef JSON_HAS_CPP_14 | |
24425 #undef JSON_HAS_CPP_17 | |
24426 #undef JSON_HAS_CPP_20 | |
24427 #undef JSON_HAS_FILESYSTEM | |
24428 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM | |
24429 #undef JSON_HAS_THREE_WAY_COMPARISON | |
24430 #undef JSON_HAS_RANGES | |
24431 #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON | |
24432 #endif | |
24433 | |
24434 // #include <nlohmann/thirdparty/hedley/hedley_undef.hpp> | |
24435 // __ _____ _____ _____ | |
24436 // __| | __| | | | JSON for Modern C++ | |
24437 // | | |__ | | | | | | version 3.11.2 | |
24438 // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
24439 // | |
24440 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> | |
24441 // SPDX-License-Identifier: MIT | |
24442 | |
24443 | |
24444 | |
24445 #undef JSON_HEDLEY_ALWAYS_INLINE | |
24446 #undef JSON_HEDLEY_ARM_VERSION | |
24447 #undef JSON_HEDLEY_ARM_VERSION_CHECK | |
24448 #undef JSON_HEDLEY_ARRAY_PARAM | |
24449 #undef JSON_HEDLEY_ASSUME | |
24450 #undef JSON_HEDLEY_BEGIN_C_DECLS | |
24451 #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE | |
24452 #undef JSON_HEDLEY_CLANG_HAS_BUILTIN | |
24453 #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE | |
24454 #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE | |
24455 #undef JSON_HEDLEY_CLANG_HAS_EXTENSION | |
24456 #undef JSON_HEDLEY_CLANG_HAS_FEATURE | |
24457 #undef JSON_HEDLEY_CLANG_HAS_WARNING | |
24458 #undef JSON_HEDLEY_COMPCERT_VERSION | |
24459 #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK | |
24460 #undef JSON_HEDLEY_CONCAT | |
24461 #undef JSON_HEDLEY_CONCAT3 | |
24462 #undef JSON_HEDLEY_CONCAT3_EX | |
24463 #undef JSON_HEDLEY_CONCAT_EX | |
24464 #undef JSON_HEDLEY_CONST | |
24465 #undef JSON_HEDLEY_CONSTEXPR | |
24466 #undef JSON_HEDLEY_CONST_CAST | |
24467 #undef JSON_HEDLEY_CPP_CAST | |
24468 #undef JSON_HEDLEY_CRAY_VERSION | |
24469 #undef JSON_HEDLEY_CRAY_VERSION_CHECK | |
24470 #undef JSON_HEDLEY_C_DECL | |
24471 #undef JSON_HEDLEY_DEPRECATED | |
24472 #undef JSON_HEDLEY_DEPRECATED_FOR | |
24473 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL | |
24474 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ | |
24475 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED | |
24476 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES | |
24477 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS | |
24478 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION | |
24479 #undef JSON_HEDLEY_DIAGNOSTIC_POP | |
24480 #undef JSON_HEDLEY_DIAGNOSTIC_PUSH | |
24481 #undef JSON_HEDLEY_DMC_VERSION | |
24482 #undef JSON_HEDLEY_DMC_VERSION_CHECK | |
24483 #undef JSON_HEDLEY_EMPTY_BASES | |
24484 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION | |
24485 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK | |
24486 #undef JSON_HEDLEY_END_C_DECLS | |
24487 #undef JSON_HEDLEY_FLAGS | |
24488 #undef JSON_HEDLEY_FLAGS_CAST | |
24489 #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE | |
24490 #undef JSON_HEDLEY_GCC_HAS_BUILTIN | |
24491 #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE | |
24492 #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE | |
24493 #undef JSON_HEDLEY_GCC_HAS_EXTENSION | |
24494 #undef JSON_HEDLEY_GCC_HAS_FEATURE | |
24495 #undef JSON_HEDLEY_GCC_HAS_WARNING | |
24496 #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK | |
24497 #undef JSON_HEDLEY_GCC_VERSION | |
24498 #undef JSON_HEDLEY_GCC_VERSION_CHECK | |
24499 #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE | |
24500 #undef JSON_HEDLEY_GNUC_HAS_BUILTIN | |
24501 #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE | |
24502 #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE | |
24503 #undef JSON_HEDLEY_GNUC_HAS_EXTENSION | |
24504 #undef JSON_HEDLEY_GNUC_HAS_FEATURE | |
24505 #undef JSON_HEDLEY_GNUC_HAS_WARNING | |
24506 #undef JSON_HEDLEY_GNUC_VERSION | |
24507 #undef JSON_HEDLEY_GNUC_VERSION_CHECK | |
24508 #undef JSON_HEDLEY_HAS_ATTRIBUTE | |
24509 #undef JSON_HEDLEY_HAS_BUILTIN | |
24510 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE | |
24511 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS | |
24512 #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE | |
24513 #undef JSON_HEDLEY_HAS_EXTENSION | |
24514 #undef JSON_HEDLEY_HAS_FEATURE | |
24515 #undef JSON_HEDLEY_HAS_WARNING | |
24516 #undef JSON_HEDLEY_IAR_VERSION | |
24517 #undef JSON_HEDLEY_IAR_VERSION_CHECK | |
24518 #undef JSON_HEDLEY_IBM_VERSION | |
24519 #undef JSON_HEDLEY_IBM_VERSION_CHECK | |
24520 #undef JSON_HEDLEY_IMPORT | |
24521 #undef JSON_HEDLEY_INLINE | |
24522 #undef JSON_HEDLEY_INTEL_CL_VERSION | |
24523 #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK | |
24524 #undef JSON_HEDLEY_INTEL_VERSION | |
24525 #undef JSON_HEDLEY_INTEL_VERSION_CHECK | |
24526 #undef JSON_HEDLEY_IS_CONSTANT | |
24527 #undef JSON_HEDLEY_IS_CONSTEXPR_ | |
24528 #undef JSON_HEDLEY_LIKELY | |
24529 #undef JSON_HEDLEY_MALLOC | |
24530 #undef JSON_HEDLEY_MCST_LCC_VERSION | |
24531 #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK | |
24532 #undef JSON_HEDLEY_MESSAGE | |
24533 #undef JSON_HEDLEY_MSVC_VERSION | |
24534 #undef JSON_HEDLEY_MSVC_VERSION_CHECK | |
24535 #undef JSON_HEDLEY_NEVER_INLINE | |
24536 #undef JSON_HEDLEY_NON_NULL | |
24537 #undef JSON_HEDLEY_NO_ESCAPE | |
24538 #undef JSON_HEDLEY_NO_RETURN | |
24539 #undef JSON_HEDLEY_NO_THROW | |
24540 #undef JSON_HEDLEY_NULL | |
24541 #undef JSON_HEDLEY_PELLES_VERSION | |
24542 #undef JSON_HEDLEY_PELLES_VERSION_CHECK | |
24543 #undef JSON_HEDLEY_PGI_VERSION | |
24544 #undef JSON_HEDLEY_PGI_VERSION_CHECK | |
24545 #undef JSON_HEDLEY_PREDICT | |
24546 #undef JSON_HEDLEY_PRINTF_FORMAT | |
24547 #undef JSON_HEDLEY_PRIVATE | |
24548 #undef JSON_HEDLEY_PUBLIC | |
24549 #undef JSON_HEDLEY_PURE | |
24550 #undef JSON_HEDLEY_REINTERPRET_CAST | |
24551 #undef JSON_HEDLEY_REQUIRE | |
24552 #undef JSON_HEDLEY_REQUIRE_CONSTEXPR | |
24553 #undef JSON_HEDLEY_REQUIRE_MSG | |
24554 #undef JSON_HEDLEY_RESTRICT | |
24555 #undef JSON_HEDLEY_RETURNS_NON_NULL | |
24556 #undef JSON_HEDLEY_SENTINEL | |
24557 #undef JSON_HEDLEY_STATIC_ASSERT | |
24558 #undef JSON_HEDLEY_STATIC_CAST | |
24559 #undef JSON_HEDLEY_STRINGIFY | |
24560 #undef JSON_HEDLEY_STRINGIFY_EX | |
24561 #undef JSON_HEDLEY_SUNPRO_VERSION | |
24562 #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK | |
24563 #undef JSON_HEDLEY_TINYC_VERSION | |
24564 #undef JSON_HEDLEY_TINYC_VERSION_CHECK | |
24565 #undef JSON_HEDLEY_TI_ARMCL_VERSION | |
24566 #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK | |
24567 #undef JSON_HEDLEY_TI_CL2000_VERSION | |
24568 #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK | |
24569 #undef JSON_HEDLEY_TI_CL430_VERSION | |
24570 #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK | |
24571 #undef JSON_HEDLEY_TI_CL6X_VERSION | |
24572 #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK | |
24573 #undef JSON_HEDLEY_TI_CL7X_VERSION | |
24574 #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK | |
24575 #undef JSON_HEDLEY_TI_CLPRU_VERSION | |
24576 #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK | |
24577 #undef JSON_HEDLEY_TI_VERSION | |
24578 #undef JSON_HEDLEY_TI_VERSION_CHECK | |
24579 #undef JSON_HEDLEY_UNAVAILABLE | |
24580 #undef JSON_HEDLEY_UNLIKELY | |
24581 #undef JSON_HEDLEY_UNPREDICTABLE | |
24582 #undef JSON_HEDLEY_UNREACHABLE | |
24583 #undef JSON_HEDLEY_UNREACHABLE_RETURN | |
24584 #undef JSON_HEDLEY_VERSION | |
24585 #undef JSON_HEDLEY_VERSION_DECODE_MAJOR | |
24586 #undef JSON_HEDLEY_VERSION_DECODE_MINOR | |
24587 #undef JSON_HEDLEY_VERSION_DECODE_REVISION | |
24588 #undef JSON_HEDLEY_VERSION_ENCODE | |
24589 #undef JSON_HEDLEY_WARNING | |
24590 #undef JSON_HEDLEY_WARN_UNUSED_RESULT | |
24591 #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG | |
24592 #undef JSON_HEDLEY_FALL_THROUGH | |
24593 | |
24594 | |
24595 | |
24596 #endif // INCLUDE_NLOHMANN_JSON_HPP_ |