Horizon
Loading...
Searching...
No Matches
binary_writer.hpp
1#pragma once
2
3#include <algorithm> // reverse
4#include <array> // array
5#include <cmath> // isnan, isinf
6#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
7#include <cstring> // memcpy
8#include <limits> // numeric_limits
9#include <string> // string
10#include <utility> // move
11
12#include <nlohmann/detail/input/binary_reader.hpp>
13#include <nlohmann/detail/macro_scope.hpp>
14#include <nlohmann/detail/output/output_adapters.hpp>
15
16namespace nlohmann
17{
18namespace detail
19{
21// binary writer //
23
27template<typename BasicJsonType, typename CharType>
29{
30 using string_t = typename BasicJsonType::string_t;
31 using binary_t = typename BasicJsonType::binary_t;
32 using number_float_t = typename BasicJsonType::number_float_t;
33
34 public:
40 explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))
41 {
42 JSON_ASSERT(oa);
43 }
44
49 void write_bson(const BasicJsonType& j)
50 {
51 switch (j.type())
52 {
53 case value_t::object:
54 {
55 write_bson_object(*j.m_value.object);
56 break;
57 }
58
59 case value_t::null:
60 case value_t::array:
61 case value_t::string:
66 case value_t::binary:
68 default:
69 {
70 JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()), j));
71 }
72 }
73 }
74
78 void write_cbor(const BasicJsonType& j)
79 {
80 switch (j.type())
81 {
82 case value_t::null:
83 {
84 oa->write_character(to_char_type(0xF6));
85 break;
86 }
87
89 {
90 oa->write_character(j.m_value.boolean
91 ? to_char_type(0xF5)
92 : to_char_type(0xF4));
93 break;
94 }
95
97 {
98 if (j.m_value.number_integer >= 0)
99 {
100 // CBOR does not differentiate between positive signed
101 // integers and unsigned integers. Therefore, we used the
102 // code from the value_t::number_unsigned case here.
103 if (j.m_value.number_integer <= 0x17)
104 {
105 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
106 }
107 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
108 {
109 oa->write_character(to_char_type(0x18));
110 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
111 }
112 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
113 {
114 oa->write_character(to_char_type(0x19));
115 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
116 }
117 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
118 {
119 oa->write_character(to_char_type(0x1A));
120 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
121 }
122 else
123 {
124 oa->write_character(to_char_type(0x1B));
125 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
126 }
127 }
128 else
129 {
130 // The conversions below encode the sign in the first
131 // byte, and the value is converted to a positive number.
132 const auto positive_number = -1 - j.m_value.number_integer;
133 if (j.m_value.number_integer >= -24)
134 {
135 write_number(static_cast<std::uint8_t>(0x20 + positive_number));
136 }
137 else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
138 {
139 oa->write_character(to_char_type(0x38));
140 write_number(static_cast<std::uint8_t>(positive_number));
141 }
142 else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
143 {
144 oa->write_character(to_char_type(0x39));
145 write_number(static_cast<std::uint16_t>(positive_number));
146 }
147 else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
148 {
149 oa->write_character(to_char_type(0x3A));
150 write_number(static_cast<std::uint32_t>(positive_number));
151 }
152 else
153 {
154 oa->write_character(to_char_type(0x3B));
155 write_number(static_cast<std::uint64_t>(positive_number));
156 }
157 }
158 break;
159 }
160
162 {
163 if (j.m_value.number_unsigned <= 0x17)
164 {
165 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
166 }
167 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
168 {
169 oa->write_character(to_char_type(0x18));
170 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
171 }
172 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
173 {
174 oa->write_character(to_char_type(0x19));
175 write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
176 }
177 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
178 {
179 oa->write_character(to_char_type(0x1A));
180 write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
181 }
182 else
183 {
184 oa->write_character(to_char_type(0x1B));
185 write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
186 }
187 break;
188 }
189
191 {
192 if (std::isnan(j.m_value.number_float))
193 {
194 // NaN is 0xf97e00 in CBOR
195 oa->write_character(to_char_type(0xF9));
196 oa->write_character(to_char_type(0x7E));
197 oa->write_character(to_char_type(0x00));
198 }
199 else if (std::isinf(j.m_value.number_float))
200 {
201 // Infinity is 0xf97c00, -Infinity is 0xf9fc00
202 oa->write_character(to_char_type(0xf9));
203 oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
204 oa->write_character(to_char_type(0x00));
205 }
206 else
207 {
208 write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);
209 }
210 break;
211 }
212
213 case value_t::string:
214 {
215 // step 1: write control byte and the string length
216 const auto N = j.m_value.string->size();
217 if (N <= 0x17)
218 {
219 write_number(static_cast<std::uint8_t>(0x60 + N));
220 }
221 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
222 {
223 oa->write_character(to_char_type(0x78));
224 write_number(static_cast<std::uint8_t>(N));
225 }
226 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
227 {
228 oa->write_character(to_char_type(0x79));
229 write_number(static_cast<std::uint16_t>(N));
230 }
231 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
232 {
233 oa->write_character(to_char_type(0x7A));
234 write_number(static_cast<std::uint32_t>(N));
235 }
236 // LCOV_EXCL_START
237 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
238 {
239 oa->write_character(to_char_type(0x7B));
240 write_number(static_cast<std::uint64_t>(N));
241 }
242 // LCOV_EXCL_STOP
243
244 // step 2: write the string
245 oa->write_characters(
246 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
247 j.m_value.string->size());
248 break;
249 }
250
251 case value_t::array:
252 {
253 // step 1: write control byte and the array size
254 const auto N = j.m_value.array->size();
255 if (N <= 0x17)
256 {
257 write_number(static_cast<std::uint8_t>(0x80 + N));
258 }
259 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
260 {
261 oa->write_character(to_char_type(0x98));
262 write_number(static_cast<std::uint8_t>(N));
263 }
264 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
265 {
266 oa->write_character(to_char_type(0x99));
267 write_number(static_cast<std::uint16_t>(N));
268 }
269 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
270 {
271 oa->write_character(to_char_type(0x9A));
272 write_number(static_cast<std::uint32_t>(N));
273 }
274 // LCOV_EXCL_START
275 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
276 {
277 oa->write_character(to_char_type(0x9B));
278 write_number(static_cast<std::uint64_t>(N));
279 }
280 // LCOV_EXCL_STOP
281
282 // step 2: write each element
283 for (const auto& el : *j.m_value.array)
284 {
285 write_cbor(el);
286 }
287 break;
288 }
289
290 case value_t::binary:
291 {
292 if (j.m_value.binary->has_subtype())
293 {
294 if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
295 {
296 write_number(static_cast<std::uint8_t>(0xd8));
297 write_number(static_cast<std::uint8_t>(j.m_value.binary->subtype()));
298 }
299 else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
300 {
301 write_number(static_cast<std::uint8_t>(0xd9));
302 write_number(static_cast<std::uint16_t>(j.m_value.binary->subtype()));
303 }
304 else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
305 {
306 write_number(static_cast<std::uint8_t>(0xda));
307 write_number(static_cast<std::uint32_t>(j.m_value.binary->subtype()));
308 }
309 else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
310 {
311 write_number(static_cast<std::uint8_t>(0xdb));
312 write_number(static_cast<std::uint64_t>(j.m_value.binary->subtype()));
313 }
314 }
315
316 // step 1: write control byte and the binary array size
317 const auto N = j.m_value.binary->size();
318 if (N <= 0x17)
319 {
320 write_number(static_cast<std::uint8_t>(0x40 + N));
321 }
322 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
323 {
324 oa->write_character(to_char_type(0x58));
325 write_number(static_cast<std::uint8_t>(N));
326 }
327 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
328 {
329 oa->write_character(to_char_type(0x59));
330 write_number(static_cast<std::uint16_t>(N));
331 }
332 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
333 {
334 oa->write_character(to_char_type(0x5A));
335 write_number(static_cast<std::uint32_t>(N));
336 }
337 // LCOV_EXCL_START
338 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
339 {
340 oa->write_character(to_char_type(0x5B));
341 write_number(static_cast<std::uint64_t>(N));
342 }
343 // LCOV_EXCL_STOP
344
345 // step 2: write each element
346 oa->write_characters(
347 reinterpret_cast<const CharType*>(j.m_value.binary->data()),
348 N);
349
350 break;
351 }
352
353 case value_t::object:
354 {
355 // step 1: write control byte and the object size
356 const auto N = j.m_value.object->size();
357 if (N <= 0x17)
358 {
359 write_number(static_cast<std::uint8_t>(0xA0 + N));
360 }
361 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
362 {
363 oa->write_character(to_char_type(0xB8));
364 write_number(static_cast<std::uint8_t>(N));
365 }
366 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
367 {
368 oa->write_character(to_char_type(0xB9));
369 write_number(static_cast<std::uint16_t>(N));
370 }
371 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
372 {
373 oa->write_character(to_char_type(0xBA));
374 write_number(static_cast<std::uint32_t>(N));
375 }
376 // LCOV_EXCL_START
377 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
378 {
379 oa->write_character(to_char_type(0xBB));
380 write_number(static_cast<std::uint64_t>(N));
381 }
382 // LCOV_EXCL_STOP
383
384 // step 2: write each element
385 for (const auto& el : *j.m_value.object)
386 {
387 write_cbor(el.first);
388 write_cbor(el.second);
389 }
390 break;
391 }
392
394 default:
395 break;
396 }
397 }
398
402 void write_msgpack(const BasicJsonType& j)
403 {
404 switch (j.type())
405 {
406 case value_t::null: // nil
407 {
408 oa->write_character(to_char_type(0xC0));
409 break;
410 }
411
412 case value_t::boolean: // true and false
413 {
414 oa->write_character(j.m_value.boolean
415 ? to_char_type(0xC3)
416 : to_char_type(0xC2));
417 break;
418 }
419
421 {
422 if (j.m_value.number_integer >= 0)
423 {
424 // MessagePack does not differentiate between positive
425 // signed integers and unsigned integers. Therefore, we used
426 // the code from the value_t::number_unsigned case here.
427 if (j.m_value.number_unsigned < 128)
428 {
429 // positive fixnum
430 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
431 }
432 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
433 {
434 // uint 8
435 oa->write_character(to_char_type(0xCC));
436 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
437 }
438 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
439 {
440 // uint 16
441 oa->write_character(to_char_type(0xCD));
442 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
443 }
444 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
445 {
446 // uint 32
447 oa->write_character(to_char_type(0xCE));
448 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
449 }
450 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
451 {
452 // uint 64
453 oa->write_character(to_char_type(0xCF));
454 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
455 }
456 }
457 else
458 {
459 if (j.m_value.number_integer >= -32)
460 {
461 // negative fixnum
462 write_number(static_cast<std::int8_t>(j.m_value.number_integer));
463 }
464 else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
465 j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
466 {
467 // int 8
468 oa->write_character(to_char_type(0xD0));
469 write_number(static_cast<std::int8_t>(j.m_value.number_integer));
470 }
471 else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
472 j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
473 {
474 // int 16
475 oa->write_character(to_char_type(0xD1));
476 write_number(static_cast<std::int16_t>(j.m_value.number_integer));
477 }
478 else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
479 j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
480 {
481 // int 32
482 oa->write_character(to_char_type(0xD2));
483 write_number(static_cast<std::int32_t>(j.m_value.number_integer));
484 }
485 else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
486 j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
487 {
488 // int 64
489 oa->write_character(to_char_type(0xD3));
490 write_number(static_cast<std::int64_t>(j.m_value.number_integer));
491 }
492 }
493 break;
494 }
495
497 {
498 if (j.m_value.number_unsigned < 128)
499 {
500 // positive fixnum
501 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
502 }
503 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
504 {
505 // uint 8
506 oa->write_character(to_char_type(0xCC));
507 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
508 }
509 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
510 {
511 // uint 16
512 oa->write_character(to_char_type(0xCD));
513 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
514 }
515 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
516 {
517 // uint 32
518 oa->write_character(to_char_type(0xCE));
519 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
520 }
521 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
522 {
523 // uint 64
524 oa->write_character(to_char_type(0xCF));
525 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
526 }
527 break;
528 }
529
531 {
532 write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);
533 break;
534 }
535
536 case value_t::string:
537 {
538 // step 1: write control byte and the string length
539 const auto N = j.m_value.string->size();
540 if (N <= 31)
541 {
542 // fixstr
543 write_number(static_cast<std::uint8_t>(0xA0 | N));
544 }
545 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
546 {
547 // str 8
548 oa->write_character(to_char_type(0xD9));
549 write_number(static_cast<std::uint8_t>(N));
550 }
551 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
552 {
553 // str 16
554 oa->write_character(to_char_type(0xDA));
555 write_number(static_cast<std::uint16_t>(N));
556 }
557 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
558 {
559 // str 32
560 oa->write_character(to_char_type(0xDB));
561 write_number(static_cast<std::uint32_t>(N));
562 }
563
564 // step 2: write the string
565 oa->write_characters(
566 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
567 j.m_value.string->size());
568 break;
569 }
570
571 case value_t::array:
572 {
573 // step 1: write control byte and the array size
574 const auto N = j.m_value.array->size();
575 if (N <= 15)
576 {
577 // fixarray
578 write_number(static_cast<std::uint8_t>(0x90 | N));
579 }
580 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
581 {
582 // array 16
583 oa->write_character(to_char_type(0xDC));
584 write_number(static_cast<std::uint16_t>(N));
585 }
586 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
587 {
588 // array 32
589 oa->write_character(to_char_type(0xDD));
590 write_number(static_cast<std::uint32_t>(N));
591 }
592
593 // step 2: write each element
594 for (const auto& el : *j.m_value.array)
595 {
596 write_msgpack(el);
597 }
598 break;
599 }
600
601 case value_t::binary:
602 {
603 // step 0: determine if the binary type has a set subtype to
604 // determine whether or not to use the ext or fixext types
605 const bool use_ext = j.m_value.binary->has_subtype();
606
607 // step 1: write control byte and the byte string length
608 const auto N = j.m_value.binary->size();
609 if (N <= (std::numeric_limits<std::uint8_t>::max)())
610 {
611 std::uint8_t output_type{};
612 bool fixed = true;
613 if (use_ext)
614 {
615 switch (N)
616 {
617 case 1:
618 output_type = 0xD4; // fixext 1
619 break;
620 case 2:
621 output_type = 0xD5; // fixext 2
622 break;
623 case 4:
624 output_type = 0xD6; // fixext 4
625 break;
626 case 8:
627 output_type = 0xD7; // fixext 8
628 break;
629 case 16:
630 output_type = 0xD8; // fixext 16
631 break;
632 default:
633 output_type = 0xC7; // ext 8
634 fixed = false;
635 break;
636 }
637
638 }
639 else
640 {
641 output_type = 0xC4; // bin 8
642 fixed = false;
643 }
644
645 oa->write_character(to_char_type(output_type));
646 if (!fixed)
647 {
648 write_number(static_cast<std::uint8_t>(N));
649 }
650 }
651 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
652 {
653 std::uint8_t output_type = use_ext
654 ? 0xC8 // ext 16
655 : 0xC5; // bin 16
656
657 oa->write_character(to_char_type(output_type));
658 write_number(static_cast<std::uint16_t>(N));
659 }
660 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
661 {
662 std::uint8_t output_type = use_ext
663 ? 0xC9 // ext 32
664 : 0xC6; // bin 32
665
666 oa->write_character(to_char_type(output_type));
667 write_number(static_cast<std::uint32_t>(N));
668 }
669
670 // step 1.5: if this is an ext type, write the subtype
671 if (use_ext)
672 {
673 write_number(static_cast<std::int8_t>(j.m_value.binary->subtype()));
674 }
675
676 // step 2: write the byte string
677 oa->write_characters(
678 reinterpret_cast<const CharType*>(j.m_value.binary->data()),
679 N);
680
681 break;
682 }
683
684 case value_t::object:
685 {
686 // step 1: write control byte and the object size
687 const auto N = j.m_value.object->size();
688 if (N <= 15)
689 {
690 // fixmap
691 write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
692 }
693 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
694 {
695 // map 16
696 oa->write_character(to_char_type(0xDE));
697 write_number(static_cast<std::uint16_t>(N));
698 }
699 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
700 {
701 // map 32
702 oa->write_character(to_char_type(0xDF));
703 write_number(static_cast<std::uint32_t>(N));
704 }
705
706 // step 2: write each element
707 for (const auto& el : *j.m_value.object)
708 {
709 write_msgpack(el.first);
710 write_msgpack(el.second);
711 }
712 break;
713 }
714
716 default:
717 break;
718 }
719 }
720
727 void write_ubjson(const BasicJsonType& j, const bool use_count,
728 const bool use_type, const bool add_prefix = true)
729 {
730 switch (j.type())
731 {
732 case value_t::null:
733 {
734 if (add_prefix)
735 {
736 oa->write_character(to_char_type('Z'));
737 }
738 break;
739 }
740
741 case value_t::boolean:
742 {
743 if (add_prefix)
744 {
745 oa->write_character(j.m_value.boolean
746 ? to_char_type('T')
747 : to_char_type('F'));
748 }
749 break;
750 }
751
753 {
754 write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
755 break;
756 }
757
759 {
760 write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
761 break;
762 }
763
765 {
766 write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
767 break;
768 }
769
770 case value_t::string:
771 {
772 if (add_prefix)
773 {
774 oa->write_character(to_char_type('S'));
775 }
776 write_number_with_ubjson_prefix(j.m_value.string->size(), true);
777 oa->write_characters(
778 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
779 j.m_value.string->size());
780 break;
781 }
782
783 case value_t::array:
784 {
785 if (add_prefix)
786 {
787 oa->write_character(to_char_type('['));
788 }
789
790 bool prefix_required = true;
791 if (use_type && !j.m_value.array->empty())
792 {
793 JSON_ASSERT(use_count);
794 const CharType first_prefix = ubjson_prefix(j.front());
795 const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
796 [this, first_prefix](const BasicJsonType & v)
797 {
798 return ubjson_prefix(v) == first_prefix;
799 });
800
801 if (same_prefix)
802 {
803 prefix_required = false;
804 oa->write_character(to_char_type('$'));
805 oa->write_character(first_prefix);
806 }
807 }
808
809 if (use_count)
810 {
811 oa->write_character(to_char_type('#'));
812 write_number_with_ubjson_prefix(j.m_value.array->size(), true);
813 }
814
815 for (const auto& el : *j.m_value.array)
816 {
817 write_ubjson(el, use_count, use_type, prefix_required);
818 }
819
820 if (!use_count)
821 {
822 oa->write_character(to_char_type(']'));
823 }
824
825 break;
826 }
827
828 case value_t::binary:
829 {
830 if (add_prefix)
831 {
832 oa->write_character(to_char_type('['));
833 }
834
835 if (use_type && !j.m_value.binary->empty())
836 {
837 JSON_ASSERT(use_count);
838 oa->write_character(to_char_type('$'));
839 oa->write_character('U');
840 }
841
842 if (use_count)
843 {
844 oa->write_character(to_char_type('#'));
845 write_number_with_ubjson_prefix(j.m_value.binary->size(), true);
846 }
847
848 if (use_type)
849 {
850 oa->write_characters(
851 reinterpret_cast<const CharType*>(j.m_value.binary->data()),
852 j.m_value.binary->size());
853 }
854 else
855 {
856 for (size_t i = 0; i < j.m_value.binary->size(); ++i)
857 {
858 oa->write_character(to_char_type('U'));
859 oa->write_character(j.m_value.binary->data()[i]);
860 }
861 }
862
863 if (!use_count)
864 {
865 oa->write_character(to_char_type(']'));
866 }
867
868 break;
869 }
870
871 case value_t::object:
872 {
873 if (add_prefix)
874 {
875 oa->write_character(to_char_type('{'));
876 }
877
878 bool prefix_required = true;
879 if (use_type && !j.m_value.object->empty())
880 {
881 JSON_ASSERT(use_count);
882 const CharType first_prefix = ubjson_prefix(j.front());
883 const bool same_prefix = std::all_of(j.begin(), j.end(),
884 [this, first_prefix](const BasicJsonType & v)
885 {
886 return ubjson_prefix(v) == first_prefix;
887 });
888
889 if (same_prefix)
890 {
891 prefix_required = false;
892 oa->write_character(to_char_type('$'));
893 oa->write_character(first_prefix);
894 }
895 }
896
897 if (use_count)
898 {
899 oa->write_character(to_char_type('#'));
900 write_number_with_ubjson_prefix(j.m_value.object->size(), true);
901 }
902
903 for (const auto& el : *j.m_value.object)
904 {
905 write_number_with_ubjson_prefix(el.first.size(), true);
906 oa->write_characters(
907 reinterpret_cast<const CharType*>(el.first.c_str()),
908 el.first.size());
909 write_ubjson(el.second, use_count, use_type, prefix_required);
910 }
911
912 if (!use_count)
913 {
914 oa->write_character(to_char_type('}'));
915 }
916
917 break;
918 }
919
921 default:
922 break;
923 }
924 }
925
926 private:
928 // BSON //
930
935 static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)
936 {
937 const auto it = name.find(static_cast<typename string_t::value_type>(0));
938 if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
939 {
940 JSON_THROW(out_of_range::create(409, "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")", j));
941 static_cast<void>(j);
942 }
943
944 return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
945 }
946
950 void write_bson_entry_header(const string_t& name,
951 const std::uint8_t element_type)
952 {
953 oa->write_character(to_char_type(element_type)); // boolean
954 oa->write_characters(
955 reinterpret_cast<const CharType*>(name.c_str()),
956 name.size() + 1u);
957 }
958
962 void write_bson_boolean(const string_t& name,
963 const bool value)
964 {
965 write_bson_entry_header(name, 0x08);
966 oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
967 }
968
972 void write_bson_double(const string_t& name,
973 const double value)
974 {
975 write_bson_entry_header(name, 0x01);
976 write_number<double, true>(value);
977 }
978
982 static std::size_t calc_bson_string_size(const string_t& value)
983 {
984 return sizeof(std::int32_t) + value.size() + 1ul;
985 }
986
990 void write_bson_string(const string_t& name,
991 const string_t& value)
992 {
993 write_bson_entry_header(name, 0x02);
994
995 write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));
996 oa->write_characters(
997 reinterpret_cast<const CharType*>(value.c_str()),
998 value.size() + 1);
999 }
1000
1004 void write_bson_null(const string_t& name)
1005 {
1006 write_bson_entry_header(name, 0x0A);
1007 }
1008
1012 static std::size_t calc_bson_integer_size(const std::int64_t value)
1013 {
1014 return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
1015 ? sizeof(std::int32_t)
1016 : sizeof(std::int64_t);
1017 }
1018
1022 void write_bson_integer(const string_t& name,
1023 const std::int64_t value)
1024 {
1025 if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
1026 {
1027 write_bson_entry_header(name, 0x10); // int32
1028 write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
1029 }
1030 else
1031 {
1032 write_bson_entry_header(name, 0x12); // int64
1033 write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
1034 }
1035 }
1036
1040 static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
1041 {
1042 return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1043 ? sizeof(std::int32_t)
1044 : sizeof(std::int64_t);
1045 }
1046
1050 void write_bson_unsigned(const string_t& name,
1051 const BasicJsonType& j)
1052 {
1053 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1054 {
1055 write_bson_entry_header(name, 0x10 /* int32 */);
1056 write_number<std::int32_t, true>(static_cast<std::int32_t>(j.m_value.number_unsigned));
1057 }
1058 else if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
1059 {
1060 write_bson_entry_header(name, 0x12 /* int64 */);
1061 write_number<std::int64_t, true>(static_cast<std::int64_t>(j.m_value.number_unsigned));
1062 }
1063 else
1064 {
1065 JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(j.m_value.number_unsigned) + " cannot be represented by BSON as it does not fit int64", j));
1066 }
1067 }
1068
1072 void write_bson_object_entry(const string_t& name,
1073 const typename BasicJsonType::object_t& value)
1074 {
1075 write_bson_entry_header(name, 0x03); // object
1076 write_bson_object(value);
1077 }
1078
1082 static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
1083 {
1084 std::size_t array_index = 0ul;
1085
1086 const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
1087 {
1088 return result + calc_bson_element_size(std::to_string(array_index++), el);
1089 });
1090
1091 return sizeof(std::int32_t) + embedded_document_size + 1ul;
1092 }
1093
1097 static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
1098 {
1099 return sizeof(std::int32_t) + value.size() + 1ul;
1100 }
1101
1105 void write_bson_array(const string_t& name,
1106 const typename BasicJsonType::array_t& value)
1107 {
1108 write_bson_entry_header(name, 0x04); // array
1109 write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));
1110
1111 std::size_t array_index = 0ul;
1112
1113 for (const auto& el : value)
1114 {
1115 write_bson_element(std::to_string(array_index++), el);
1116 }
1117
1118 oa->write_character(to_char_type(0x00));
1119 }
1120
1124 void write_bson_binary(const string_t& name,
1125 const binary_t& value)
1126 {
1127 write_bson_entry_header(name, 0x05);
1128
1129 write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size()));
1130 write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : std::uint8_t(0x00));
1131
1132 oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
1133 }
1134
1139 static std::size_t calc_bson_element_size(const string_t& name,
1140 const BasicJsonType& j)
1141 {
1142 const auto header_size = calc_bson_entry_header_size(name, j);
1143 switch (j.type())
1144 {
1145 case value_t::object:
1146 return header_size + calc_bson_object_size(*j.m_value.object);
1147
1148 case value_t::array:
1149 return header_size + calc_bson_array_size(*j.m_value.array);
1150
1151 case value_t::binary:
1152 return header_size + calc_bson_binary_size(*j.m_value.binary);
1153
1154 case value_t::boolean:
1155 return header_size + 1ul;
1156
1158 return header_size + 8ul;
1159
1161 return header_size + calc_bson_integer_size(j.m_value.number_integer);
1162
1164 return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
1165
1166 case value_t::string:
1167 return header_size + calc_bson_string_size(*j.m_value.string);
1168
1169 case value_t::null:
1170 return header_size + 0ul;
1171
1172 // LCOV_EXCL_START
1173 case value_t::discarded:
1174 default:
1175 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
1176 return 0ul;
1177 // LCOV_EXCL_STOP
1178 }
1179 }
1180
1187 void write_bson_element(const string_t& name,
1188 const BasicJsonType& j)
1189 {
1190 switch (j.type())
1191 {
1192 case value_t::object:
1193 return write_bson_object_entry(name, *j.m_value.object);
1194
1195 case value_t::array:
1196 return write_bson_array(name, *j.m_value.array);
1197
1198 case value_t::binary:
1199 return write_bson_binary(name, *j.m_value.binary);
1200
1201 case value_t::boolean:
1202 return write_bson_boolean(name, j.m_value.boolean);
1203
1205 return write_bson_double(name, j.m_value.number_float);
1206
1208 return write_bson_integer(name, j.m_value.number_integer);
1209
1211 return write_bson_unsigned(name, j);
1212
1213 case value_t::string:
1214 return write_bson_string(name, *j.m_value.string);
1215
1216 case value_t::null:
1217 return write_bson_null(name);
1218
1219 // LCOV_EXCL_START
1220 case value_t::discarded:
1221 default:
1222 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
1223 return;
1224 // LCOV_EXCL_STOP
1225 }
1226 }
1227
1234 static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
1235 {
1236 std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0),
1237 [](size_t result, const typename BasicJsonType::object_t::value_type & el)
1238 {
1239 return result += calc_bson_element_size(el.first, el.second);
1240 });
1241
1242 return sizeof(std::int32_t) + document_size + 1ul;
1243 }
1244
1249 void write_bson_object(const typename BasicJsonType::object_t& value)
1250 {
1251 write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));
1252
1253 for (const auto& el : value)
1254 {
1255 write_bson_element(el.first, el.second);
1256 }
1257
1258 oa->write_character(to_char_type(0x00));
1259 }
1260
1262 // CBOR //
1264
1265 static constexpr CharType get_cbor_float_prefix(float /*unused*/)
1266 {
1267 return to_char_type(0xFA); // Single-Precision Float
1268 }
1269
1270 static constexpr CharType get_cbor_float_prefix(double /*unused*/)
1271 {
1272 return to_char_type(0xFB); // Double-Precision Float
1273 }
1274
1276 // MsgPack //
1278
1279 static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
1280 {
1281 return to_char_type(0xCA); // float 32
1282 }
1283
1284 static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
1285 {
1286 return to_char_type(0xCB); // float 64
1287 }
1288
1290 // UBJSON //
1292
1293 // UBJSON: write number (floating point)
1294 template<typename NumberType, typename std::enable_if<
1295 std::is_floating_point<NumberType>::value, int>::type = 0>
1296 void write_number_with_ubjson_prefix(const NumberType n,
1297 const bool add_prefix)
1298 {
1299 if (add_prefix)
1300 {
1301 oa->write_character(get_ubjson_float_prefix(n));
1302 }
1303 write_number(n);
1304 }
1305
1306 // UBJSON: write number (unsigned integer)
1307 template<typename NumberType, typename std::enable_if<
1308 std::is_unsigned<NumberType>::value, int>::type = 0>
1309 void write_number_with_ubjson_prefix(const NumberType n,
1310 const bool add_prefix)
1311 {
1312 if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
1313 {
1314 if (add_prefix)
1315 {
1316 oa->write_character(to_char_type('i')); // int8
1317 }
1318 write_number(static_cast<std::uint8_t>(n));
1319 }
1320 else if (n <= (std::numeric_limits<std::uint8_t>::max)())
1321 {
1322 if (add_prefix)
1323 {
1324 oa->write_character(to_char_type('U')); // uint8
1325 }
1326 write_number(static_cast<std::uint8_t>(n));
1327 }
1328 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
1329 {
1330 if (add_prefix)
1331 {
1332 oa->write_character(to_char_type('I')); // int16
1333 }
1334 write_number(static_cast<std::int16_t>(n));
1335 }
1336 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1337 {
1338 if (add_prefix)
1339 {
1340 oa->write_character(to_char_type('l')); // int32
1341 }
1342 write_number(static_cast<std::int32_t>(n));
1343 }
1344 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
1345 {
1346 if (add_prefix)
1347 {
1348 oa->write_character(to_char_type('L')); // int64
1349 }
1350 write_number(static_cast<std::int64_t>(n));
1351 }
1352 else
1353 {
1354 if (add_prefix)
1355 {
1356 oa->write_character(to_char_type('H')); // high-precision number
1357 }
1358
1359 const auto number = BasicJsonType(n).dump();
1360 write_number_with_ubjson_prefix(number.size(), true);
1361 for (std::size_t i = 0; i < number.size(); ++i)
1362 {
1363 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
1364 }
1365 }
1366 }
1367
1368 // UBJSON: write number (signed integer)
1369 template < typename NumberType, typename std::enable_if <
1370 std::is_signed<NumberType>::value&&
1371 !std::is_floating_point<NumberType>::value, int >::type = 0 >
1372 void write_number_with_ubjson_prefix(const NumberType n,
1373 const bool add_prefix)
1374 {
1375 if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
1376 {
1377 if (add_prefix)
1378 {
1379 oa->write_character(to_char_type('i')); // int8
1380 }
1381 write_number(static_cast<std::int8_t>(n));
1382 }
1383 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)()))
1384 {
1385 if (add_prefix)
1386 {
1387 oa->write_character(to_char_type('U')); // uint8
1388 }
1389 write_number(static_cast<std::uint8_t>(n));
1390 }
1391 else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
1392 {
1393 if (add_prefix)
1394 {
1395 oa->write_character(to_char_type('I')); // int16
1396 }
1397 write_number(static_cast<std::int16_t>(n));
1398 }
1399 else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
1400 {
1401 if (add_prefix)
1402 {
1403 oa->write_character(to_char_type('l')); // int32
1404 }
1405 write_number(static_cast<std::int32_t>(n));
1406 }
1407 else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
1408 {
1409 if (add_prefix)
1410 {
1411 oa->write_character(to_char_type('L')); // int64
1412 }
1413 write_number(static_cast<std::int64_t>(n));
1414 }
1415 // LCOV_EXCL_START
1416 else
1417 {
1418 if (add_prefix)
1419 {
1420 oa->write_character(to_char_type('H')); // high-precision number
1421 }
1422
1423 const auto number = BasicJsonType(n).dump();
1424 write_number_with_ubjson_prefix(number.size(), true);
1425 for (std::size_t i = 0; i < number.size(); ++i)
1426 {
1427 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
1428 }
1429 }
1430 // LCOV_EXCL_STOP
1431 }
1432
1436 CharType ubjson_prefix(const BasicJsonType& j) const noexcept
1437 {
1438 switch (j.type())
1439 {
1440 case value_t::null:
1441 return 'Z';
1442
1443 case value_t::boolean:
1444 return j.m_value.boolean ? 'T' : 'F';
1445
1447 {
1448 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)())
1449 {
1450 return 'i';
1451 }
1452 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)())
1453 {
1454 return 'U';
1455 }
1456 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)())
1457 {
1458 return 'I';
1459 }
1460 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)())
1461 {
1462 return 'l';
1463 }
1464 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)())
1465 {
1466 return 'L';
1467 }
1468 // anything else is treated as high-precision number
1469 return 'H'; // LCOV_EXCL_LINE
1470 }
1471
1473 {
1474 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
1475 {
1476 return 'i';
1477 }
1478 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
1479 {
1480 return 'U';
1481 }
1482 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
1483 {
1484 return 'I';
1485 }
1486 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1487 {
1488 return 'l';
1489 }
1490 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
1491 {
1492 return 'L';
1493 }
1494 // anything else is treated as high-precision number
1495 return 'H'; // LCOV_EXCL_LINE
1496 }
1497
1499 return get_ubjson_float_prefix(j.m_value.number_float);
1500
1501 case value_t::string:
1502 return 'S';
1503
1504 case value_t::array: // fallthrough
1505 case value_t::binary:
1506 return '[';
1507
1508 case value_t::object:
1509 return '{';
1510
1511 case value_t::discarded:
1512 default: // discarded values
1513 return 'N';
1514 }
1515 }
1516
1517 static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
1518 {
1519 return 'd'; // float 32
1520 }
1521
1522 static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
1523 {
1524 return 'D'; // float 64
1525 }
1526
1528 // Utility functions //
1530
1531 /*
1532 @brief write a number to output input
1533 @param[in] n number of type @a NumberType
1534 @tparam NumberType the type of the number
1535 @tparam OutputIsLittleEndian Set to true if output data is
1536 required to be little endian
1537
1538 @note This function needs to respect the system's endianess, because bytes
1539 in CBOR, MessagePack, and UBJSON are stored in network order (big
1540 endian) and therefore need reordering on little endian systems.
1541 */
1542 template<typename NumberType, bool OutputIsLittleEndian = false>
1543 void write_number(const NumberType n)
1544 {
1545 // step 1: write number to array of length NumberType
1546 std::array<CharType, sizeof(NumberType)> vec{};
1547 std::memcpy(vec.data(), &n, sizeof(NumberType));
1548
1549 // step 2: write array to output (with possible reordering)
1550 if (is_little_endian != OutputIsLittleEndian)
1551 {
1552 // reverse byte order prior to conversion if necessary
1553 std::reverse(vec.begin(), vec.end());
1554 }
1555
1556 oa->write_characters(vec.data(), sizeof(NumberType));
1557 }
1558
1559 void write_compact_float(const number_float_t n, detail::input_format_t format)
1560 {
1561#ifdef __GNUC__
1562#pragma GCC diagnostic push
1563#pragma GCC diagnostic ignored "-Wfloat-equal"
1564#endif
1565 if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
1566 static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
1567 static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
1568 {
1569 oa->write_character(format == detail::input_format_t::cbor
1570 ? get_cbor_float_prefix(static_cast<float>(n))
1571 : get_msgpack_float_prefix(static_cast<float>(n)));
1572 write_number(static_cast<float>(n));
1573 }
1574 else
1575 {
1576 oa->write_character(format == detail::input_format_t::cbor
1577 ? get_cbor_float_prefix(n)
1578 : get_msgpack_float_prefix(n));
1579 write_number(n);
1580 }
1581#ifdef __GNUC__
1582#pragma GCC diagnostic pop
1583#endif
1584 }
1585
1586 public:
1587 // The following to_char_type functions are implement the conversion
1588 // between uint8_t and CharType. In case CharType is not unsigned,
1589 // such a conversion is required to allow values greater than 128.
1590 // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
1591 template < typename C = CharType,
1592 enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
1593 static constexpr CharType to_char_type(std::uint8_t x) noexcept
1594 {
1595 return *reinterpret_cast<char*>(&x);
1596 }
1597
1598 template < typename C = CharType,
1599 enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
1600 static CharType to_char_type(std::uint8_t x) noexcept
1601 {
1602 static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
1603 static_assert(std::is_trivial<CharType>::value, "CharType must be trivial");
1604 CharType result;
1605 std::memcpy(&result, &x, sizeof(x));
1606 return result;
1607 }
1608
1609 template<typename C = CharType,
1610 enable_if_t<std::is_unsigned<C>::value>* = nullptr>
1611 static constexpr CharType to_char_type(std::uint8_t x) noexcept
1612 {
1613 return x;
1614 }
1615
1616 template < typename InputCharType, typename C = CharType,
1617 enable_if_t <
1618 std::is_signed<C>::value &&
1619 std::is_signed<char>::value &&
1620 std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
1621 > * = nullptr >
1622 static constexpr CharType to_char_type(InputCharType x) noexcept
1623 {
1624 return x;
1625 }
1626
1627 private:
1629 const bool is_little_endian = little_endianess();
1630
1632 output_adapter_t<CharType> oa = nullptr;
1633};
1634} // namespace detail
1635} // namespace nlohmann
serialization to CBOR and MessagePack values
Definition binary_writer.hpp:29
void write_ubjson(const BasicJsonType &j, const bool use_count, const bool use_type, const bool add_prefix=true)
Definition binary_writer.hpp:727
binary_writer(output_adapter_t< CharType > adapter)
create a binary writer
Definition binary_writer.hpp:40
void write_bson(const BasicJsonType &j)
Definition binary_writer.hpp:49
void write_cbor(const BasicJsonType &j)
Definition binary_writer.hpp:78
void write_msgpack(const BasicJsonType &j)
Definition binary_writer.hpp:402
@ number_integer
number value (signed integer)
@ discarded
discarded by the parser callback function
@ binary
binary array (ordered collection of bytes)
@ object
object (unordered set of name/value pairs)
@ number_float
number value (floating-point)
@ number_unsigned
number value (unsigned integer)
@ array
array (ordered collection of values)
@ value
the parser finished reading a JSON value
std::shared_ptr< output_adapter_protocol< CharType > > output_adapter_t
a type to simplify interfaces
Definition output_adapters.hpp:37
input_format_t
the supported input formats
Definition input_adapters.hpp:26
namespace for Niels Lohmann
Definition adl_serializer.hpp:12