RflySimSDK v4.10
RflySimSDK说明文档
载入中...
搜索中...
未找到
binary_writer.hpp
1// __ _____ _____ _____
2// __| | __| | | | JSON for Modern C++
3// | | |__ | | | | | | version 3.12.0
4// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2025 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#pragma once
10
11#include <algorithm> // reverse
12#include <array> // array
13#include <map> // map
14#include <cmath> // isnan, isinf
15#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
16#include <cstring> // memcpy
17#include <limits> // numeric_limits
18#include <string> // string
19#include <utility> // move
20#include <vector> // vector
21
22#include <nlohmann/detail/input/binary_reader.hpp>
23#include <nlohmann/detail/macro_scope.hpp>
24#include <nlohmann/detail/output/output_adapters.hpp>
25#include <nlohmann/detail/string_concat.hpp>
26
27NLOHMANN_JSON_NAMESPACE_BEGIN
28namespace detail
29{
30
31/// how to encode BJData
33{
34 draft2,
35 draft3,
36};
37
38///////////////////
39// binary writer //
40///////////////////
41
42/*!
43@brief serialization to CBOR and MessagePack values
44*/
45template<typename BasicJsonType, typename CharType>
47{
48 using string_t = typename BasicJsonType::string_t;
49 using binary_t = typename BasicJsonType::binary_t;
50 using number_float_t = typename BasicJsonType::number_float_t;
51
52 public:
53 /*!
54 @brief create a binary writer
55
56 @param[in] adapter output adapter to write to
57 */
58 explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))
59 {
60 JSON_ASSERT(oa);
61 }
62
63 /*!
64 @param[in] j JSON value to serialize
65 @pre j.type() == value_t::object
66 */
67 void write_bson(const BasicJsonType& j)
68 {
69 switch (j.type())
70 {
71 case value_t::object:
72 {
73 write_bson_object(*j.m_data.m_value.object);
74 break;
75 }
76
77 case value_t::null:
78 case value_t::array:
79 case value_t::string:
84 case value_t::binary:
86 default:
87 {
88 JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
89 }
90 }
91 }
92
93 /*!
94 @param[in] j JSON value to serialize
95 */
96 void write_cbor(const BasicJsonType& j)
97 {
98 switch (j.type())
99 {
100 case value_t::null:
101 {
102 oa->write_character(to_char_type(0xF6));
103 break;
104 }
105
106 case value_t::boolean:
107 {
108 oa->write_character(j.m_data.m_value.boolean
109 ? to_char_type(0xF5)
110 : to_char_type(0xF4));
111 break;
112 }
113
115 {
116 if (j.m_data.m_value.number_integer >= 0)
117 {
118 // CBOR does not differentiate between positive signed
119 // integers and unsigned integers. Therefore, we used the
120 // code from the value_t::number_unsigned case here.
121 if (j.m_data.m_value.number_integer <= 0x17)
122 {
123 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
124 }
125 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
126 {
127 oa->write_character(to_char_type(0x18));
128 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
129 }
130 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
131 {
132 oa->write_character(to_char_type(0x19));
133 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
134 }
135 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
136 {
137 oa->write_character(to_char_type(0x1A));
138 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
139 }
140 else
141 {
142 oa->write_character(to_char_type(0x1B));
143 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
144 }
145 }
146 else
147 {
148 // The conversions below encode the sign in the first
149 // byte, and the value is converted to a positive number.
150 const auto positive_number = -1 - j.m_data.m_value.number_integer;
151 if (j.m_data.m_value.number_integer >= -24)
152 {
153 write_number(static_cast<std::uint8_t>(0x20 + positive_number));
154 }
155 else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
156 {
157 oa->write_character(to_char_type(0x38));
158 write_number(static_cast<std::uint8_t>(positive_number));
159 }
160 else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
161 {
162 oa->write_character(to_char_type(0x39));
163 write_number(static_cast<std::uint16_t>(positive_number));
164 }
165 else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
166 {
167 oa->write_character(to_char_type(0x3A));
168 write_number(static_cast<std::uint32_t>(positive_number));
169 }
170 else
171 {
172 oa->write_character(to_char_type(0x3B));
173 write_number(static_cast<std::uint64_t>(positive_number));
174 }
175 }
176 break;
177 }
178
180 {
181 if (j.m_data.m_value.number_unsigned <= 0x17)
182 {
183 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
184 }
185 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
186 {
187 oa->write_character(to_char_type(0x18));
188 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
189 }
190 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
191 {
192 oa->write_character(to_char_type(0x19));
193 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));
194 }
195 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
196 {
197 oa->write_character(to_char_type(0x1A));
198 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned));
199 }
200 else
201 {
202 oa->write_character(to_char_type(0x1B));
203 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));
204 }
205 break;
206 }
207
209 {
210 if (std::isnan(j.m_data.m_value.number_float))
211 {
212 // NaN is 0xf97e00 in CBOR
213 oa->write_character(to_char_type(0xF9));
214 oa->write_character(to_char_type(0x7E));
215 oa->write_character(to_char_type(0x00));
216 }
217 else if (std::isinf(j.m_data.m_value.number_float))
218 {
219 // Infinity is 0xf97c00, -Infinity is 0xf9fc00
220 oa->write_character(to_char_type(0xf9));
221 oa->write_character(j.m_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
222 oa->write_character(to_char_type(0x00));
223 }
224 else
225 {
226 write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::cbor);
227 }
228 break;
229 }
230
231 case value_t::string:
232 {
233 // step 1: write control byte and the string length
234 const auto N = j.m_data.m_value.string->size();
235 if (N <= 0x17)
236 {
237 write_number(static_cast<std::uint8_t>(0x60 + N));
238 }
239 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
240 {
241 oa->write_character(to_char_type(0x78));
242 write_number(static_cast<std::uint8_t>(N));
243 }
244 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
245 {
246 oa->write_character(to_char_type(0x79));
247 write_number(static_cast<std::uint16_t>(N));
248 }
249 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
250 {
251 oa->write_character(to_char_type(0x7A));
252 write_number(static_cast<std::uint32_t>(N));
253 }
254 // LCOV_EXCL_START
255 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
256 {
257 oa->write_character(to_char_type(0x7B));
258 write_number(static_cast<std::uint64_t>(N));
259 }
260 // LCOV_EXCL_STOP
261
262 // step 2: write the string
263 oa->write_characters(
264 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
265 j.m_data.m_value.string->size());
266 break;
267 }
268
269 case value_t::array:
270 {
271 // step 1: write control byte and the array size
272 const auto N = j.m_data.m_value.array->size();
273 if (N <= 0x17)
274 {
275 write_number(static_cast<std::uint8_t>(0x80 + N));
276 }
277 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
278 {
279 oa->write_character(to_char_type(0x98));
280 write_number(static_cast<std::uint8_t>(N));
281 }
282 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
283 {
284 oa->write_character(to_char_type(0x99));
285 write_number(static_cast<std::uint16_t>(N));
286 }
287 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
288 {
289 oa->write_character(to_char_type(0x9A));
290 write_number(static_cast<std::uint32_t>(N));
291 }
292 // LCOV_EXCL_START
293 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
294 {
295 oa->write_character(to_char_type(0x9B));
296 write_number(static_cast<std::uint64_t>(N));
297 }
298 // LCOV_EXCL_STOP
299
300 // step 2: write each element
301 for (const auto& el : *j.m_data.m_value.array)
302 {
303 write_cbor(el);
304 }
305 break;
306 }
307
308 case value_t::binary:
309 {
310 if (j.m_data.m_value.binary->has_subtype())
311 {
312 if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
313 {
314 write_number(static_cast<std::uint8_t>(0xd8));
315 write_number(static_cast<std::uint8_t>(j.m_data.m_value.binary->subtype()));
316 }
317 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
318 {
319 write_number(static_cast<std::uint8_t>(0xd9));
320 write_number(static_cast<std::uint16_t>(j.m_data.m_value.binary->subtype()));
321 }
322 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
323 {
324 write_number(static_cast<std::uint8_t>(0xda));
325 write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
326 }
327 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
328 {
329 write_number(static_cast<std::uint8_t>(0xdb));
330 write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
331 }
332 }
333
334 // step 1: write control byte and the binary array size
335 const auto N = j.m_data.m_value.binary->size();
336 if (N <= 0x17)
337 {
338 write_number(static_cast<std::uint8_t>(0x40 + N));
339 }
340 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
341 {
342 oa->write_character(to_char_type(0x58));
343 write_number(static_cast<std::uint8_t>(N));
344 }
345 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
346 {
347 oa->write_character(to_char_type(0x59));
348 write_number(static_cast<std::uint16_t>(N));
349 }
350 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
351 {
352 oa->write_character(to_char_type(0x5A));
353 write_number(static_cast<std::uint32_t>(N));
354 }
355 // LCOV_EXCL_START
356 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
357 {
358 oa->write_character(to_char_type(0x5B));
359 write_number(static_cast<std::uint64_t>(N));
360 }
361 // LCOV_EXCL_STOP
362
363 // step 2: write each element
364 oa->write_characters(
365 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
366 N);
367
368 break;
369 }
370
371 case value_t::object:
372 {
373 // step 1: write control byte and the object size
374 const auto N = j.m_data.m_value.object->size();
375 if (N <= 0x17)
376 {
377 write_number(static_cast<std::uint8_t>(0xA0 + N));
378 }
379 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
380 {
381 oa->write_character(to_char_type(0xB8));
382 write_number(static_cast<std::uint8_t>(N));
383 }
384 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
385 {
386 oa->write_character(to_char_type(0xB9));
387 write_number(static_cast<std::uint16_t>(N));
388 }
389 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
390 {
391 oa->write_character(to_char_type(0xBA));
392 write_number(static_cast<std::uint32_t>(N));
393 }
394 // LCOV_EXCL_START
395 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
396 {
397 oa->write_character(to_char_type(0xBB));
398 write_number(static_cast<std::uint64_t>(N));
399 }
400 // LCOV_EXCL_STOP
401
402 // step 2: write each element
403 for (const auto& el : *j.m_data.m_value.object)
404 {
405 write_cbor(el.first);
406 write_cbor(el.second);
407 }
408 break;
409 }
410
412 default:
413 break;
414 }
415 }
416
417 /*!
418 @param[in] j JSON value to serialize
419 */
420 void write_msgpack(const BasicJsonType& j)
421 {
422 switch (j.type())
423 {
424 case value_t::null: // nil
425 {
426 oa->write_character(to_char_type(0xC0));
427 break;
428 }
429
430 case value_t::boolean: // true and false
431 {
432 oa->write_character(j.m_data.m_value.boolean
433 ? to_char_type(0xC3)
434 : to_char_type(0xC2));
435 break;
436 }
437
439 {
440 if (j.m_data.m_value.number_integer >= 0)
441 {
442 // MessagePack does not differentiate between positive
443 // signed integers and unsigned integers. Therefore, we used
444 // the code from the value_t::number_unsigned case here.
445 if (j.m_data.m_value.number_unsigned < 128)
446 {
447 // positive fixnum
448 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
449 }
450 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
451 {
452 // uint 8
453 oa->write_character(to_char_type(0xCC));
454 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
455 }
456 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
457 {
458 // uint 16
459 oa->write_character(to_char_type(0xCD));
460 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
461 }
462 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
463 {
464 // uint 32
465 oa->write_character(to_char_type(0xCE));
466 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
467 }
468 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
469 {
470 // uint 64
471 oa->write_character(to_char_type(0xCF));
472 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
473 }
474 }
475 else
476 {
477 if (j.m_data.m_value.number_integer >= -32)
478 {
479 // negative fixnum
480 write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
481 }
482 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
483 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
484 {
485 // int 8
486 oa->write_character(to_char_type(0xD0));
487 write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
488 }
489 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
490 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
491 {
492 // int 16
493 oa->write_character(to_char_type(0xD1));
494 write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
495 }
496 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
497 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
498 {
499 // int 32
500 oa->write_character(to_char_type(0xD2));
501 write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
502 }
503 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
504 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
505 {
506 // int 64
507 oa->write_character(to_char_type(0xD3));
508 write_number(static_cast<std::int64_t>(j.m_data.m_value.number_integer));
509 }
510 }
511 break;
512 }
513
515 {
516 if (j.m_data.m_value.number_unsigned < 128)
517 {
518 // positive fixnum
519 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
520 }
521 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
522 {
523 // uint 8
524 oa->write_character(to_char_type(0xCC));
525 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
526 }
527 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
528 {
529 // uint 16
530 oa->write_character(to_char_type(0xCD));
531 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
532 }
533 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
534 {
535 // uint 32
536 oa->write_character(to_char_type(0xCE));
537 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
538 }
539 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
540 {
541 // uint 64
542 oa->write_character(to_char_type(0xCF));
543 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
544 }
545 break;
546 }
547
549 {
550 write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::msgpack);
551 break;
552 }
553
554 case value_t::string:
555 {
556 // step 1: write control byte and the string length
557 const auto N = j.m_data.m_value.string->size();
558 if (N <= 31)
559 {
560 // fixstr
561 write_number(static_cast<std::uint8_t>(0xA0 | N));
562 }
563 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
564 {
565 // str 8
566 oa->write_character(to_char_type(0xD9));
567 write_number(static_cast<std::uint8_t>(N));
568 }
569 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
570 {
571 // str 16
572 oa->write_character(to_char_type(0xDA));
573 write_number(static_cast<std::uint16_t>(N));
574 }
575 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
576 {
577 // str 32
578 oa->write_character(to_char_type(0xDB));
579 write_number(static_cast<std::uint32_t>(N));
580 }
581
582 // step 2: write the string
583 oa->write_characters(
584 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
585 j.m_data.m_value.string->size());
586 break;
587 }
588
589 case value_t::array:
590 {
591 // step 1: write control byte and the array size
592 const auto N = j.m_data.m_value.array->size();
593 if (N <= 15)
594 {
595 // fixarray
596 write_number(static_cast<std::uint8_t>(0x90 | N));
597 }
598 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
599 {
600 // array 16
601 oa->write_character(to_char_type(0xDC));
602 write_number(static_cast<std::uint16_t>(N));
603 }
604 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
605 {
606 // array 32
607 oa->write_character(to_char_type(0xDD));
608 write_number(static_cast<std::uint32_t>(N));
609 }
610
611 // step 2: write each element
612 for (const auto& el : *j.m_data.m_value.array)
613 {
614 write_msgpack(el);
615 }
616 break;
617 }
618
619 case value_t::binary:
620 {
621 // step 0: determine if the binary type has a set subtype to
622 // determine whether to use the ext or fixext types
623 const bool use_ext = j.m_data.m_value.binary->has_subtype();
624
625 // step 1: write control byte and the byte string length
626 const auto N = j.m_data.m_value.binary->size();
627 if (N <= (std::numeric_limits<std::uint8_t>::max)())
628 {
629 std::uint8_t output_type{};
630 bool fixed = true;
631 if (use_ext)
632 {
633 switch (N)
634 {
635 case 1:
636 output_type = 0xD4; // fixext 1
637 break;
638 case 2:
639 output_type = 0xD5; // fixext 2
640 break;
641 case 4:
642 output_type = 0xD6; // fixext 4
643 break;
644 case 8:
645 output_type = 0xD7; // fixext 8
646 break;
647 case 16:
648 output_type = 0xD8; // fixext 16
649 break;
650 default:
651 output_type = 0xC7; // ext 8
652 fixed = false;
653 break;
654 }
655
656 }
657 else
658 {
659 output_type = 0xC4; // bin 8
660 fixed = false;
661 }
662
663 oa->write_character(to_char_type(output_type));
664 if (!fixed)
665 {
666 write_number(static_cast<std::uint8_t>(N));
667 }
668 }
669 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
670 {
671 const std::uint8_t output_type = use_ext
672 ? 0xC8 // ext 16
673 : 0xC5; // bin 16
674
675 oa->write_character(to_char_type(output_type));
676 write_number(static_cast<std::uint16_t>(N));
677 }
678 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
679 {
680 const std::uint8_t output_type = use_ext
681 ? 0xC9 // ext 32
682 : 0xC6; // bin 32
683
684 oa->write_character(to_char_type(output_type));
685 write_number(static_cast<std::uint32_t>(N));
686 }
687
688 // step 1.5: if this is an ext type, write the subtype
689 if (use_ext)
690 {
691 write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
692 }
693
694 // step 2: write the byte string
695 oa->write_characters(
696 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
697 N);
698
699 break;
700 }
701
702 case value_t::object:
703 {
704 // step 1: write control byte and the object size
705 const auto N = j.m_data.m_value.object->size();
706 if (N <= 15)
707 {
708 // fixmap
709 write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
710 }
711 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
712 {
713 // map 16
714 oa->write_character(to_char_type(0xDE));
715 write_number(static_cast<std::uint16_t>(N));
716 }
717 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
718 {
719 // map 32
720 oa->write_character(to_char_type(0xDF));
721 write_number(static_cast<std::uint32_t>(N));
722 }
723
724 // step 2: write each element
725 for (const auto& el : *j.m_data.m_value.object)
726 {
727 write_msgpack(el.first);
728 write_msgpack(el.second);
729 }
730 break;
731 }
732
734 default:
735 break;
736 }
737 }
738
739 /*!
740 @param[in] j JSON value to serialize
741 @param[in] use_count whether to use '#' prefixes (optimized format)
742 @param[in] use_type whether to use '$' prefixes (optimized format)
743 @param[in] add_prefix whether prefixes need to be used for this value
744 @param[in] use_bjdata whether write in BJData format, default is false
745 @param[in] bjdata_version which BJData version to use, default is draft2
746 */
747 void write_ubjson(const BasicJsonType& j, const bool use_count,
748 const bool use_type, const bool add_prefix = true,
749 const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2)
750 {
751 const bool bjdata_draft3 = use_bjdata && bjdata_version == bjdata_version_t::draft3;
752
753 switch (j.type())
754 {
755 case value_t::null:
756 {
757 if (add_prefix)
758 {
759 oa->write_character(to_char_type('Z'));
760 }
761 break;
762 }
763
764 case value_t::boolean:
765 {
766 if (add_prefix)
767 {
768 oa->write_character(j.m_data.m_value.boolean
769 ? to_char_type('T')
770 : to_char_type('F'));
771 }
772 break;
773 }
774
776 {
777 write_number_with_ubjson_prefix(j.m_data.m_value.number_integer, add_prefix, use_bjdata);
778 break;
779 }
780
782 {
783 write_number_with_ubjson_prefix(j.m_data.m_value.number_unsigned, add_prefix, use_bjdata);
784 break;
785 }
786
788 {
789 write_number_with_ubjson_prefix(j.m_data.m_value.number_float, add_prefix, use_bjdata);
790 break;
791 }
792
793 case value_t::string:
794 {
795 if (add_prefix)
796 {
797 oa->write_character(to_char_type('S'));
798 }
799 write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);
800 oa->write_characters(
801 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
802 j.m_data.m_value.string->size());
803 break;
804 }
805
806 case value_t::array:
807 {
808 if (add_prefix)
809 {
810 oa->write_character(to_char_type('['));
811 }
812
813 bool prefix_required = true;
814 if (use_type && !j.m_data.m_value.array->empty())
815 {
816 JSON_ASSERT(use_count);
817 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
818 const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
819 [this, first_prefix, use_bjdata](const BasicJsonType & v)
820 {
821 return ubjson_prefix(v, use_bjdata) == first_prefix;
822 });
823
824 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
825
826 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
827 {
828 prefix_required = false;
829 oa->write_character(to_char_type('$'));
830 oa->write_character(first_prefix);
831 }
832 }
833
834 if (use_count)
835 {
836 oa->write_character(to_char_type('#'));
837 write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata);
838 }
839
840 for (const auto& el : *j.m_data.m_value.array)
841 {
842 write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version);
843 }
844
845 if (!use_count)
846 {
847 oa->write_character(to_char_type(']'));
848 }
849
850 break;
851 }
852
853 case value_t::binary:
854 {
855 if (add_prefix)
856 {
857 oa->write_character(to_char_type('['));
858 }
859
860 if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty()))
861 {
862 JSON_ASSERT(use_count);
863 oa->write_character(to_char_type('$'));
864 oa->write_character(bjdata_draft3 ? 'B' : 'U');
865 }
866
867 if (use_count)
868 {
869 oa->write_character(to_char_type('#'));
870 write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata);
871 }
872
873 if (use_type)
874 {
875 oa->write_characters(
876 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
877 j.m_data.m_value.binary->size());
878 }
879 else
880 {
881 for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)
882 {
883 oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U'));
884 oa->write_character(j.m_data.m_value.binary->data()[i]);
885 }
886 }
887
888 if (!use_count)
889 {
890 oa->write_character(to_char_type(']'));
891 }
892
893 break;
894 }
895
896 case value_t::object:
897 {
898 if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end())
899 {
900 if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)
901 {
902 break;
903 }
904 }
905
906 if (add_prefix)
907 {
908 oa->write_character(to_char_type('{'));
909 }
910
911 bool prefix_required = true;
912 if (use_type && !j.m_data.m_value.object->empty())
913 {
914 JSON_ASSERT(use_count);
915 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
916 const bool same_prefix = std::all_of(j.begin(), j.end(),
917 [this, first_prefix, use_bjdata](const BasicJsonType & v)
918 {
919 return ubjson_prefix(v, use_bjdata) == first_prefix;
920 });
921
922 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
923
924 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
925 {
926 prefix_required = false;
927 oa->write_character(to_char_type('$'));
928 oa->write_character(first_prefix);
929 }
930 }
931
932 if (use_count)
933 {
934 oa->write_character(to_char_type('#'));
935 write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata);
936 }
937
938 for (const auto& el : *j.m_data.m_value.object)
939 {
940 write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
941 oa->write_characters(
942 reinterpret_cast<const CharType*>(el.first.c_str()),
943 el.first.size());
944 write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version);
945 }
946
947 if (!use_count)
948 {
949 oa->write_character(to_char_type('}'));
950 }
951
952 break;
953 }
954
956 default:
957 break;
958 }
959 }
960
961 private:
962 //////////
963 // BSON //
964 //////////
965
966 /*!
967 @return The size of a BSON document entry header, including the id marker
968 and the entry name size (and its null-terminator).
969 */
970 static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)
971 {
972 const auto it = name.find(static_cast<typename string_t::value_type>(0));
973 if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
974 {
975 JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
976 }
977
978 static_cast<void>(j);
979 return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
980 }
981
982 /*!
983 @brief Writes the given @a element_type and @a name to the output adapter
984 */
985 void write_bson_entry_header(const string_t& name,
986 const std::uint8_t element_type)
987 {
988 oa->write_character(to_char_type(element_type)); // boolean
989 oa->write_characters(
990 reinterpret_cast<const CharType*>(name.c_str()),
991 name.size() + 1u);
992 }
993
994 /*!
995 @brief Writes a BSON element with key @a name and boolean value @a value
996 */
997 void write_bson_boolean(const string_t& name,
998 const bool value)
999 {
1000 write_bson_entry_header(name, 0x08);
1001 oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
1002 }
1003
1004 /*!
1005 @brief Writes a BSON element with key @a name and double value @a value
1006 */
1007 void write_bson_double(const string_t& name,
1008 const double value)
1009 {
1010 write_bson_entry_header(name, 0x01);
1011 write_number<double>(value, true);
1012 }
1013
1014 /*!
1015 @return The size of the BSON-encoded string in @a value
1016 */
1017 static std::size_t calc_bson_string_size(const string_t& value)
1018 {
1019 return sizeof(std::int32_t) + value.size() + 1ul;
1020 }
1021
1022 /*!
1023 @brief Writes a BSON element with key @a name and string value @a value
1024 */
1025 void write_bson_string(const string_t& name,
1026 const string_t& value)
1027 {
1028 write_bson_entry_header(name, 0x02);
1029
1030 write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true);
1031 oa->write_characters(
1032 reinterpret_cast<const CharType*>(value.c_str()),
1033 value.size() + 1);
1034 }
1035
1036 /*!
1037 @brief Writes a BSON element with key @a name and null value
1038 */
1039 void write_bson_null(const string_t& name)
1040 {
1041 write_bson_entry_header(name, 0x0A);
1042 }
1043
1044 /*!
1045 @return The size of the BSON-encoded integer @a value
1046 */
1047 static std::size_t calc_bson_integer_size(const std::int64_t value)
1048 {
1049 return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
1050 ? sizeof(std::int32_t)
1051 : sizeof(std::int64_t);
1052 }
1053
1054 /*!
1055 @brief Writes a BSON element with key @a name and integer @a value
1056 */
1057 void write_bson_integer(const string_t& name,
1058 const std::int64_t value)
1059 {
1060 if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
1061 {
1062 write_bson_entry_header(name, 0x10); // int32
1063 write_number<std::int32_t>(static_cast<std::int32_t>(value), true);
1064 }
1065 else
1066 {
1067 write_bson_entry_header(name, 0x12); // int64
1068 write_number<std::int64_t>(static_cast<std::int64_t>(value), true);
1069 }
1070 }
1071
1072 /*!
1073 @return The size of the BSON-encoded unsigned integer in @a j
1074 */
1075 static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
1076 {
1077 return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1078 ? sizeof(std::int32_t)
1079 : sizeof(std::int64_t);
1080 }
1081
1082 /*!
1083 @brief Writes a BSON element with key @a name and unsigned @a value
1084 */
1085 void write_bson_unsigned(const string_t& name,
1086 const BasicJsonType& j)
1087 {
1088 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1089 {
1090 write_bson_entry_header(name, 0x10 /* int32 */);
1091 write_number<std::int32_t>(static_cast<std::int32_t>(j.m_data.m_value.number_unsigned), true);
1092 }
1093 else if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
1094 {
1095 write_bson_entry_header(name, 0x12 /* int64 */);
1096 write_number<std::int64_t>(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned), true);
1097 }
1098 else
1099 {
1100 write_bson_entry_header(name, 0x11 /* uint64 */);
1101 write_number<std::uint64_t>(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned), true);
1102 }
1103 }
1104
1105 /*!
1106 @brief Writes a BSON element with key @a name and object @a value
1107 */
1108 void write_bson_object_entry(const string_t& name,
1109 const typename BasicJsonType::object_t& value)
1110 {
1111 write_bson_entry_header(name, 0x03); // object
1112 write_bson_object(value);
1113 }
1114
1115 /*!
1116 @return The size of the BSON-encoded array @a value
1117 */
1118 static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
1119 {
1120 std::size_t array_index = 0ul;
1121
1122 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)
1123 {
1124 return result + calc_bson_element_size(std::to_string(array_index++), el);
1125 });
1126
1127 return sizeof(std::int32_t) + embedded_document_size + 1ul;
1128 }
1129
1130 /*!
1131 @return The size of the BSON-encoded binary array @a value
1132 */
1133 static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
1134 {
1135 return sizeof(std::int32_t) + value.size() + 1ul;
1136 }
1137
1138 /*!
1139 @brief Writes a BSON element with key @a name and array @a value
1140 */
1141 void write_bson_array(const string_t& name,
1142 const typename BasicJsonType::array_t& value)
1143 {
1144 write_bson_entry_header(name, 0x04); // array
1145 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true);
1146
1147 std::size_t array_index = 0ul;
1148
1149 for (const auto& el : value)
1150 {
1151 write_bson_element(std::to_string(array_index++), el);
1152 }
1153
1154 oa->write_character(to_char_type(0x00));
1155 }
1156
1157 /*!
1158 @brief Writes a BSON element with key @a name and binary value @a value
1159 */
1160 void write_bson_binary(const string_t& name,
1161 const binary_t& value)
1162 {
1163 write_bson_entry_header(name, 0x05);
1164
1165 write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true);
1166 write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
1167
1168 oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
1169 }
1170
1171 /*!
1172 @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
1173 @return The calculated size for the BSON document entry for @a j with the given @a name.
1174 */
1175 static std::size_t calc_bson_element_size(const string_t& name,
1176 const BasicJsonType& j)
1177 {
1178 const auto header_size = calc_bson_entry_header_size(name, j);
1179 switch (j.type())
1180 {
1181 case value_t::object:
1182 return header_size + calc_bson_object_size(*j.m_data.m_value.object);
1183
1184 case value_t::array:
1185 return header_size + calc_bson_array_size(*j.m_data.m_value.array);
1186
1187 case value_t::binary:
1188 return header_size + calc_bson_binary_size(*j.m_data.m_value.binary);
1189
1190 case value_t::boolean:
1191 return header_size + 1ul;
1192
1194 return header_size + 8ul;
1195
1197 return header_size + calc_bson_integer_size(j.m_data.m_value.number_integer);
1198
1200 return header_size + calc_bson_unsigned_size(j.m_data.m_value.number_unsigned);
1201
1202 case value_t::string:
1203 return header_size + calc_bson_string_size(*j.m_data.m_value.string);
1204
1205 case value_t::null:
1206 return header_size + 0ul;
1207
1208 // LCOV_EXCL_START
1209 case value_t::discarded:
1210 default:
1211 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
1212 return 0ul;
1213 // LCOV_EXCL_STOP
1214 }
1215 }
1216
1217 /*!
1218 @brief Serializes the JSON value @a j to BSON and associates it with the
1219 key @a name.
1220 @param name The name to associate with the JSON entity @a j within the
1221 current BSON document
1222 */
1223 void write_bson_element(const string_t& name,
1224 const BasicJsonType& j)
1225 {
1226 switch (j.type())
1227 {
1228 case value_t::object:
1229 return write_bson_object_entry(name, *j.m_data.m_value.object);
1230
1231 case value_t::array:
1232 return write_bson_array(name, *j.m_data.m_value.array);
1233
1234 case value_t::binary:
1235 return write_bson_binary(name, *j.m_data.m_value.binary);
1236
1237 case value_t::boolean:
1238 return write_bson_boolean(name, j.m_data.m_value.boolean);
1239
1241 return write_bson_double(name, j.m_data.m_value.number_float);
1242
1244 return write_bson_integer(name, j.m_data.m_value.number_integer);
1245
1247 return write_bson_unsigned(name, j);
1248
1249 case value_t::string:
1250 return write_bson_string(name, *j.m_data.m_value.string);
1251
1252 case value_t::null:
1253 return write_bson_null(name);
1254
1255 // LCOV_EXCL_START
1256 case value_t::discarded:
1257 default:
1258 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
1259 return;
1260 // LCOV_EXCL_STOP
1261 }
1262 }
1263
1264 /*!
1265 @brief Calculates the size of the BSON serialization of the given
1266 JSON-object @a j.
1267 @param[in] value JSON value to serialize
1268 @pre value.type() == value_t::object
1269 */
1270 static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
1271 {
1272 const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),
1273 [](size_t result, const typename BasicJsonType::object_t::value_type & el)
1274 {
1275 return result += calc_bson_element_size(el.first, el.second);
1276 });
1277
1278 return sizeof(std::int32_t) + document_size + 1ul;
1279 }
1280
1281 /*!
1282 @param[in] value JSON value to serialize
1283 @pre value.type() == value_t::object
1284 */
1285 void write_bson_object(const typename BasicJsonType::object_t& value)
1286 {
1287 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true);
1288
1289 for (const auto& el : value)
1290 {
1291 write_bson_element(el.first, el.second);
1292 }
1293
1294 oa->write_character(to_char_type(0x00));
1295 }
1296
1297 //////////
1298 // CBOR //
1299 //////////
1300
1301 static constexpr CharType get_cbor_float_prefix(float /*unused*/)
1302 {
1303 return to_char_type(0xFA); // Single-Precision Float
1304 }
1305
1306 static constexpr CharType get_cbor_float_prefix(double /*unused*/)
1307 {
1308 return to_char_type(0xFB); // Double-Precision Float
1309 }
1310
1311 /////////////
1312 // MsgPack //
1313 /////////////
1314
1315 static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
1316 {
1317 return to_char_type(0xCA); // float 32
1318 }
1319
1320 static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
1321 {
1322 return to_char_type(0xCB); // float 64
1323 }
1324
1325 ////////////
1326 // UBJSON //
1327 ////////////
1328
1329 // UBJSON: write number (floating point)
1330 template<typename NumberType, typename std::enable_if<
1331 std::is_floating_point<NumberType>::value, int>::type = 0>
1332 void write_number_with_ubjson_prefix(const NumberType n,
1333 const bool add_prefix,
1334 const bool use_bjdata)
1335 {
1336 if (add_prefix)
1337 {
1338 oa->write_character(get_ubjson_float_prefix(n));
1339 }
1340 write_number(n, use_bjdata);
1341 }
1342
1343 // UBJSON: write number (unsigned integer)
1344 template<typename NumberType, typename std::enable_if<
1345 std::is_unsigned<NumberType>::value, int>::type = 0>
1346 void write_number_with_ubjson_prefix(const NumberType n,
1347 const bool add_prefix,
1348 const bool use_bjdata)
1349 {
1350 if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
1351 {
1352 if (add_prefix)
1353 {
1354 oa->write_character(to_char_type('i')); // int8
1355 }
1356 write_number(static_cast<std::uint8_t>(n), use_bjdata);
1357 }
1358 else if (n <= (std::numeric_limits<std::uint8_t>::max)())
1359 {
1360 if (add_prefix)
1361 {
1362 oa->write_character(to_char_type('U')); // uint8
1363 }
1364 write_number(static_cast<std::uint8_t>(n), use_bjdata);
1365 }
1366 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
1367 {
1368 if (add_prefix)
1369 {
1370 oa->write_character(to_char_type('I')); // int16
1371 }
1372 write_number(static_cast<std::int16_t>(n), use_bjdata);
1373 }
1374 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)()))
1375 {
1376 if (add_prefix)
1377 {
1378 oa->write_character(to_char_type('u')); // uint16 - bjdata only
1379 }
1380 write_number(static_cast<std::uint16_t>(n), use_bjdata);
1381 }
1382 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1383 {
1384 if (add_prefix)
1385 {
1386 oa->write_character(to_char_type('l')); // int32
1387 }
1388 write_number(static_cast<std::int32_t>(n), use_bjdata);
1389 }
1390 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))
1391 {
1392 if (add_prefix)
1393 {
1394 oa->write_character(to_char_type('m')); // uint32 - bjdata only
1395 }
1396 write_number(static_cast<std::uint32_t>(n), use_bjdata);
1397 }
1398 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
1399 {
1400 if (add_prefix)
1401 {
1402 oa->write_character(to_char_type('L')); // int64
1403 }
1404 write_number(static_cast<std::int64_t>(n), use_bjdata);
1405 }
1406 else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())
1407 {
1408 if (add_prefix)
1409 {
1410 oa->write_character(to_char_type('M')); // uint64 - bjdata only
1411 }
1412 write_number(static_cast<std::uint64_t>(n), use_bjdata);
1413 }
1414 else
1415 {
1416 if (add_prefix)
1417 {
1418 oa->write_character(to_char_type('H')); // high-precision number
1419 }
1420
1421 const auto number = BasicJsonType(n).dump();
1422 write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
1423 for (std::size_t i = 0; i < number.size(); ++i)
1424 {
1425 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
1426 }
1427 }
1428 }
1429
1430 // UBJSON: write number (signed integer)
1431 template < typename NumberType, typename std::enable_if <
1432 std::is_signed<NumberType>::value&&
1433 !std::is_floating_point<NumberType>::value, int >::type = 0 >
1434 void write_number_with_ubjson_prefix(const NumberType n,
1435 const bool add_prefix,
1436 const bool use_bjdata)
1437 {
1438 if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
1439 {
1440 if (add_prefix)
1441 {
1442 oa->write_character(to_char_type('i')); // int8
1443 }
1444 write_number(static_cast<std::int8_t>(n), use_bjdata);
1445 }
1446 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)()))
1447 {
1448 if (add_prefix)
1449 {
1450 oa->write_character(to_char_type('U')); // uint8
1451 }
1452 write_number(static_cast<std::uint8_t>(n), use_bjdata);
1453 }
1454 else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
1455 {
1456 if (add_prefix)
1457 {
1458 oa->write_character(to_char_type('I')); // int16
1459 }
1460 write_number(static_cast<std::int16_t>(n), use_bjdata);
1461 }
1462 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)())))
1463 {
1464 if (add_prefix)
1465 {
1466 oa->write_character(to_char_type('u')); // uint16 - bjdata only
1467 }
1468 write_number(static_cast<uint16_t>(n), use_bjdata);
1469 }
1470 else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
1471 {
1472 if (add_prefix)
1473 {
1474 oa->write_character(to_char_type('l')); // int32
1475 }
1476 write_number(static_cast<std::int32_t>(n), use_bjdata);
1477 }
1478 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)())))
1479 {
1480 if (add_prefix)
1481 {
1482 oa->write_character(to_char_type('m')); // uint32 - bjdata only
1483 }
1484 write_number(static_cast<uint32_t>(n), use_bjdata);
1485 }
1486 else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
1487 {
1488 if (add_prefix)
1489 {
1490 oa->write_character(to_char_type('L')); // int64
1491 }
1492 write_number(static_cast<std::int64_t>(n), use_bjdata);
1493 }
1494 // LCOV_EXCL_START
1495 else
1496 {
1497 if (add_prefix)
1498 {
1499 oa->write_character(to_char_type('H')); // high-precision number
1500 }
1501
1502 const auto number = BasicJsonType(n).dump();
1503 write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
1504 for (std::size_t i = 0; i < number.size(); ++i)
1505 {
1506 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
1507 }
1508 }
1509 // LCOV_EXCL_STOP
1510 }
1511
1512 /*!
1513 @brief determine the type prefix of container values
1514 */
1515 CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept
1516 {
1517 switch (j.type())
1518 {
1519 case value_t::null:
1520 return 'Z';
1521
1522 case value_t::boolean:
1523 return j.m_data.m_value.boolean ? 'T' : 'F';
1524
1526 {
1527 if ((std::numeric_limits<std::int8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
1528 {
1529 return 'i';
1530 }
1531 if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
1532 {
1533 return 'U';
1534 }
1535 if ((std::numeric_limits<std::int16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
1536 {
1537 return 'I';
1538 }
1539 if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))
1540 {
1541 return 'u';
1542 }
1543 if ((std::numeric_limits<std::int32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
1544 {
1545 return 'l';
1546 }
1547 if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))
1548 {
1549 return 'm';
1550 }
1551 if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
1552 {
1553 return 'L';
1554 }
1555 // anything else is treated as a high-precision number
1556 return 'H'; // LCOV_EXCL_LINE
1557 }
1558
1560 {
1561 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
1562 {
1563 return 'i';
1564 }
1565 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
1566 {
1567 return 'U';
1568 }
1569 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
1570 {
1571 return 'I';
1572 }
1573 if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))
1574 {
1575 return 'u';
1576 }
1577 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1578 {
1579 return 'l';
1580 }
1581 if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))
1582 {
1583 return 'm';
1584 }
1585 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
1586 {
1587 return 'L';
1588 }
1589 if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
1590 {
1591 return 'M';
1592 }
1593 // anything else is treated as a high-precision number
1594 return 'H'; // LCOV_EXCL_LINE
1595 }
1596
1598 return get_ubjson_float_prefix(j.m_data.m_value.number_float);
1599
1600 case value_t::string:
1601 return 'S';
1602
1603 case value_t::array: // fallthrough
1604 case value_t::binary:
1605 return '[';
1606
1607 case value_t::object:
1608 return '{';
1609
1610 case value_t::discarded:
1611 default: // discarded values
1612 return 'N';
1613 }
1614 }
1615
1616 static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
1617 {
1618 return 'd'; // float 32
1619 }
1620
1621 static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
1622 {
1623 return 'D'; // float 64
1624 }
1625
1626 /*!
1627 @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid
1628 */
1629 bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type, const bjdata_version_t bjdata_version)
1630 {
1631 std::map<string_t, CharType> bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'},
1632 {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'},
1633 {"char", 'C'}, {"byte", 'B'}
1634 };
1635
1636 string_t key = "_ArrayType_";
1637 auto it = bjdtype.find(static_cast<string_t>(value.at(key)));
1638 if (it == bjdtype.end())
1639 {
1640 return true;
1641 }
1642 CharType dtype = it->second;
1643
1644 key = "_ArraySize_";
1645 std::size_t len = (value.at(key).empty() ? 0 : 1);
1646 for (const auto& el : value.at(key))
1647 {
1648 len *= static_cast<std::size_t>(el.m_data.m_value.number_unsigned);
1649 }
1650
1651 key = "_ArrayData_";
1652 if (value.at(key).size() != len)
1653 {
1654 return true;
1655 }
1656
1657 oa->write_character('[');
1658 oa->write_character('$');
1659 oa->write_character(dtype);
1660 oa->write_character('#');
1661
1662 key = "_ArraySize_";
1663 write_ubjson(value.at(key), use_count, use_type, true, true, bjdata_version);
1664
1665 key = "_ArrayData_";
1666 if (dtype == 'U' || dtype == 'C' || dtype == 'B')
1667 {
1668 for (const auto& el : value.at(key))
1669 {
1670 write_number(static_cast<std::uint8_t>(el.m_data.m_value.number_unsigned), true);
1671 }
1672 }
1673 else if (dtype == 'i')
1674 {
1675 for (const auto& el : value.at(key))
1676 {
1677 write_number(static_cast<std::int8_t>(el.m_data.m_value.number_integer), true);
1678 }
1679 }
1680 else if (dtype == 'u')
1681 {
1682 for (const auto& el : value.at(key))
1683 {
1684 write_number(static_cast<std::uint16_t>(el.m_data.m_value.number_unsigned), true);
1685 }
1686 }
1687 else if (dtype == 'I')
1688 {
1689 for (const auto& el : value.at(key))
1690 {
1691 write_number(static_cast<std::int16_t>(el.m_data.m_value.number_integer), true);
1692 }
1693 }
1694 else if (dtype == 'm')
1695 {
1696 for (const auto& el : value.at(key))
1697 {
1698 write_number(static_cast<std::uint32_t>(el.m_data.m_value.number_unsigned), true);
1699 }
1700 }
1701 else if (dtype == 'l')
1702 {
1703 for (const auto& el : value.at(key))
1704 {
1705 write_number(static_cast<std::int32_t>(el.m_data.m_value.number_integer), true);
1706 }
1707 }
1708 else if (dtype == 'M')
1709 {
1710 for (const auto& el : value.at(key))
1711 {
1712 write_number(static_cast<std::uint64_t>(el.m_data.m_value.number_unsigned), true);
1713 }
1714 }
1715 else if (dtype == 'L')
1716 {
1717 for (const auto& el : value.at(key))
1718 {
1719 write_number(static_cast<std::int64_t>(el.m_data.m_value.number_integer), true);
1720 }
1721 }
1722 else if (dtype == 'd')
1723 {
1724 for (const auto& el : value.at(key))
1725 {
1726 write_number(static_cast<float>(el.m_data.m_value.number_float), true);
1727 }
1728 }
1729 else if (dtype == 'D')
1730 {
1731 for (const auto& el : value.at(key))
1732 {
1733 write_number(static_cast<double>(el.m_data.m_value.number_float), true);
1734 }
1735 }
1736 return false;
1737 }
1738
1739 ///////////////////////
1740 // Utility functions //
1741 ///////////////////////
1742
1743 /*
1744 @brief write a number to output input
1745 @param[in] n number of type @a NumberType
1746 @param[in] OutputIsLittleEndian Set to true if output data is
1747 required to be little endian
1748 @tparam NumberType the type of the number
1749
1750 @note This function needs to respect the system's endianness, because bytes
1751 in CBOR, MessagePack, and UBJSON are stored in network order (big
1752 endian) and therefore need reordering on little endian systems.
1753 On the other hand, BSON and BJData use little endian and should reorder
1754 on big endian systems.
1755 */
1756 template<typename NumberType>
1757 void write_number(const NumberType n, const bool OutputIsLittleEndian = false)
1758 {
1759 // step 1: write the number to an array of length NumberType
1760 std::array<CharType, sizeof(NumberType)> vec{};
1761 std::memcpy(vec.data(), &n, sizeof(NumberType));
1762
1763 // step 2: write the array to output (with possible reordering)
1764 if (is_little_endian != OutputIsLittleEndian)
1765 {
1766 // reverse byte order prior to conversion if necessary
1767 std::reverse(vec.begin(), vec.end());
1768 }
1769
1770 oa->write_characters(vec.data(), sizeof(NumberType));
1771 }
1772
1773 void write_compact_float(const number_float_t n, detail::input_format_t format)
1774 {
1775#ifdef __GNUC__
1776#pragma GCC diagnostic push
1777#pragma GCC diagnostic ignored "-Wfloat-equal"
1778#endif
1779 if (!std::isfinite(n) || ((static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
1780 static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
1781 static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))))
1782 {
1783 oa->write_character(format == detail::input_format_t::cbor
1784 ? get_cbor_float_prefix(static_cast<float>(n))
1785 : get_msgpack_float_prefix(static_cast<float>(n)));
1786 write_number(static_cast<float>(n));
1787 }
1788 else
1789 {
1790 oa->write_character(format == detail::input_format_t::cbor
1791 ? get_cbor_float_prefix(n)
1792 : get_msgpack_float_prefix(n));
1793 write_number(n);
1794 }
1795#ifdef __GNUC__
1796#pragma GCC diagnostic pop
1797#endif
1798 }
1799
1800 public:
1801 // The following to_char_type functions are implement the conversion
1802 // between uint8_t and CharType. In case CharType is not unsigned,
1803 // such a conversion is required to allow values greater than 128.
1804 // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
1805 template < typename C = CharType,
1806 enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
1807 static constexpr CharType to_char_type(std::uint8_t x) noexcept
1808 {
1809 return *reinterpret_cast<char*>(&x);
1810 }
1811
1812 template < typename C = CharType,
1813 enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
1814 static CharType to_char_type(std::uint8_t x) noexcept
1815 {
1816 // The std::is_trivial trait is deprecated in C++26. The replacement is to use
1817 // std::is_trivially_copyable and std::is_trivially_default_constructible.
1818 // However, some older library implementations support std::is_trivial
1819 // but not all the std::is_trivially_* traits.
1820 // Since detecting full support across all libraries is difficult,
1821 // we use std::is_trivial unless we are using a standard where it has been deprecated.
1822 // For more details, see: https://github.com/nlohmann/json/pull/4775#issuecomment-2884361627
1823#ifdef JSON_HAS_CPP_26
1824 static_assert(std::is_trivially_copyable<CharType>::value, "CharType must be trivially copyable");
1825 static_assert(std::is_trivially_default_constructible<CharType>::value, "CharType must be trivially default constructible");
1826#else
1827 static_assert(std::is_trivial<CharType>::value, "CharType must be trivial");
1828#endif
1829
1830 static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
1831 CharType result;
1832 std::memcpy(&result, &x, sizeof(x));
1833 return result;
1834 }
1835
1836 template<typename C = CharType,
1837 enable_if_t<std::is_unsigned<C>::value>* = nullptr>
1838 static constexpr CharType to_char_type(std::uint8_t x) noexcept
1839 {
1840 return x;
1841 }
1842
1843 template < typename InputCharType, typename C = CharType,
1844 enable_if_t <
1845 std::is_signed<C>::value &&
1846 std::is_signed<char>::value &&
1847 std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
1848 > * = nullptr >
1849 static constexpr CharType to_char_type(InputCharType x) noexcept
1850 {
1851 return x;
1852 }
1853
1854 private:
1855 /// whether we can assume little endianness
1856 const bool is_little_endian = little_endianness();
1857
1858 /// the output
1859 output_adapter_t<CharType> oa = nullptr;
1860};
1861
1862} // namespace detail
1863NLOHMANN_JSON_NAMESPACE_END
void write_cbor(const BasicJsonType &j)
定义 binary_writer.hpp:96
void write_bson(const BasicJsonType &j)
定义 binary_writer.hpp:67
binary_writer(output_adapter_t< CharType > adapter)
create a binary writer
定义 binary_writer.hpp:58
void write_msgpack(const BasicJsonType &j)
定义 binary_writer.hpp:420
void write_ubjson(const BasicJsonType &j, const bool use_count, const bool use_type, const bool add_prefix=true, const bool use_bjdata=false, const bjdata_version_t bjdata_version=bjdata_version_t::draft2)
定义 binary_writer.hpp:747
detail namespace with internal helper functions
定义 from_json.hpp:43
bool little_endianness(int num=1) noexcept
determine system byte order
定义 binary_reader.hpp:56
@ key
the parser read a key of a value in an object
定义 parser.hpp:45
@ null
null value
定义 value_t.hpp:55
@ number_integer
number value (signed integer)
定义 value_t.hpp:60
@ boolean
boolean value
定义 value_t.hpp:59
@ discarded
discarded by the parser callback function
定义 value_t.hpp:64
@ binary
binary array (ordered collection of bytes)
定义 value_t.hpp:63
@ object
object (unordered set of name/value pairs)
定义 value_t.hpp:56
@ string
string value
定义 value_t.hpp:58
@ number_float
number value (floating-point)
定义 value_t.hpp:62
@ number_unsigned
number value (unsigned integer)
定义 value_t.hpp:61
@ array
array (ordered collection of values)
定义 value_t.hpp:57
input_format_t
the supported input formats
定义 input_adapters.hpp:37
bjdata_version_t
how to encode BJData
定义 binary_writer.hpp:33
std::shared_ptr< output_adapter_protocol< CharType > > output_adapter_t
a type to simplify interfaces
定义 output_adapters.hpp:45