Horizon
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 
16 namespace nlohmann
17 {
18 namespace detail
19 {
21 // binary writer //
23 
27 template<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:
62  case value_t::boolean:
66  case value_t::binary:
67  case value_t::discarded:
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 
88  case value_t::boolean:
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 
393  case value_t::discarded:
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 
715  case value_t::discarded:
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 
920  case value_t::discarded:
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 
1157  case value_t::number_float:
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 
1204  case value_t::number_float:
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 
1498  case value_t::number_float:
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
zip_uint64_t uint64_t
zip_uint64_t_t typedef.
Definition: zip.hpp:108
zip_int64_t int64_t
zip_int64_t typedef.
Definition: zip.hpp:103
zip_uint32_t uint32_t
zip_uint32_t typedef.
Definition: zip.hpp:98
zip_int32_t int32_t
zip_int32_t typedef.
Definition: zip.hpp:93
zip_uint8_t uint8_t
zip_uint8_t typedef.
Definition: zip.hpp:78
zip_uint16_t uint16_t
zip_uint16_t typedef.
Definition: zip.hpp:88
zip_int16_t int16_t
zip_int16_t typedef.
Definition: zip.hpp:83
zip_int8_t int8_t
zip_int8_t typedef.
Definition: zip.hpp:73
@ 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