Horizon
binary_writer.hpp
1 #pragma once
2 
3 #include <algorithm> // reverse
4 #include <array> // array
5 #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
6 #include <cstring> // memcpy
7 #include <limits> // numeric_limits
8 
9 #include <nlohmann/detail/input/binary_reader.hpp>
10 #include <nlohmann/detail/output/output_adapters.hpp>
11 
12 namespace nlohmann
13 {
14 namespace detail
15 {
17 // binary writer //
19 
23 template<typename BasicJsonType, typename CharType>
25 {
26  public:
32  explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
33  {
34  assert(oa);
35  }
36 
40  void write_cbor(const BasicJsonType& j)
41  {
42  switch (j.type())
43  {
44  case value_t::null:
45  {
46  oa->write_character(static_cast<CharType>(0xF6));
47  break;
48  }
49 
50  case value_t::boolean:
51  {
52  oa->write_character(j.m_value.boolean
53  ? static_cast<CharType>(0xF5)
54  : static_cast<CharType>(0xF4));
55  break;
56  }
57 
59  {
60  if (j.m_value.number_integer >= 0)
61  {
62  // CBOR does not differentiate between positive signed
63  // integers and unsigned integers. Therefore, we used the
64  // code from the value_t::number_unsigned case here.
65  if (j.m_value.number_integer <= 0x17)
66  {
67  write_number(static_cast<uint8_t>(j.m_value.number_integer));
68  }
69  else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
70  {
71  oa->write_character(static_cast<CharType>(0x18));
72  write_number(static_cast<uint8_t>(j.m_value.number_integer));
73  }
74  else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
75  {
76  oa->write_character(static_cast<CharType>(0x19));
77  write_number(static_cast<uint16_t>(j.m_value.number_integer));
78  }
79  else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
80  {
81  oa->write_character(static_cast<CharType>(0x1A));
82  write_number(static_cast<uint32_t>(j.m_value.number_integer));
83  }
84  else
85  {
86  oa->write_character(static_cast<CharType>(0x1B));
87  write_number(static_cast<uint64_t>(j.m_value.number_integer));
88  }
89  }
90  else
91  {
92  // The conversions below encode the sign in the first
93  // byte, and the value is converted to a positive number.
94  const auto positive_number = -1 - j.m_value.number_integer;
95  if (j.m_value.number_integer >= -24)
96  {
97  write_number(static_cast<uint8_t>(0x20 + positive_number));
98  }
99  else if (positive_number <= (std::numeric_limits<uint8_t>::max)())
100  {
101  oa->write_character(static_cast<CharType>(0x38));
102  write_number(static_cast<uint8_t>(positive_number));
103  }
104  else if (positive_number <= (std::numeric_limits<uint16_t>::max)())
105  {
106  oa->write_character(static_cast<CharType>(0x39));
107  write_number(static_cast<uint16_t>(positive_number));
108  }
109  else if (positive_number <= (std::numeric_limits<uint32_t>::max)())
110  {
111  oa->write_character(static_cast<CharType>(0x3A));
112  write_number(static_cast<uint32_t>(positive_number));
113  }
114  else
115  {
116  oa->write_character(static_cast<CharType>(0x3B));
117  write_number(static_cast<uint64_t>(positive_number));
118  }
119  }
120  break;
121  }
122 
124  {
125  if (j.m_value.number_unsigned <= 0x17)
126  {
127  write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
128  }
129  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
130  {
131  oa->write_character(static_cast<CharType>(0x18));
132  write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
133  }
134  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
135  {
136  oa->write_character(static_cast<CharType>(0x19));
137  write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
138  }
139  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
140  {
141  oa->write_character(static_cast<CharType>(0x1A));
142  write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
143  }
144  else
145  {
146  oa->write_character(static_cast<CharType>(0x1B));
147  write_number(static_cast<uint64_t>(j.m_value.number_unsigned));
148  }
149  break;
150  }
151 
152  case value_t::number_float: // Double-Precision Float
153  {
154  oa->write_character(static_cast<CharType>(0xFB));
155  write_number(j.m_value.number_float);
156  break;
157  }
158 
159  case value_t::string:
160  {
161  // step 1: write control byte and the string length
162  const auto N = j.m_value.string->size();
163  if (N <= 0x17)
164  {
165  write_number(static_cast<uint8_t>(0x60 + N));
166  }
167  else if (N <= (std::numeric_limits<uint8_t>::max)())
168  {
169  oa->write_character(static_cast<CharType>(0x78));
170  write_number(static_cast<uint8_t>(N));
171  }
172  else if (N <= (std::numeric_limits<uint16_t>::max)())
173  {
174  oa->write_character(static_cast<CharType>(0x79));
175  write_number(static_cast<uint16_t>(N));
176  }
177  else if (N <= (std::numeric_limits<uint32_t>::max)())
178  {
179  oa->write_character(static_cast<CharType>(0x7A));
180  write_number(static_cast<uint32_t>(N));
181  }
182  // LCOV_EXCL_START
183  else if (N <= (std::numeric_limits<uint64_t>::max)())
184  {
185  oa->write_character(static_cast<CharType>(0x7B));
186  write_number(static_cast<uint64_t>(N));
187  }
188  // LCOV_EXCL_STOP
189 
190  // step 2: write the string
191  oa->write_characters(
192  reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
193  j.m_value.string->size());
194  break;
195  }
196 
197  case value_t::array:
198  {
199  // step 1: write control byte and the array size
200  const auto N = j.m_value.array->size();
201  if (N <= 0x17)
202  {
203  write_number(static_cast<uint8_t>(0x80 + N));
204  }
205  else if (N <= (std::numeric_limits<uint8_t>::max)())
206  {
207  oa->write_character(static_cast<CharType>(0x98));
208  write_number(static_cast<uint8_t>(N));
209  }
210  else if (N <= (std::numeric_limits<uint16_t>::max)())
211  {
212  oa->write_character(static_cast<CharType>(0x99));
213  write_number(static_cast<uint16_t>(N));
214  }
215  else if (N <= (std::numeric_limits<uint32_t>::max)())
216  {
217  oa->write_character(static_cast<CharType>(0x9A));
218  write_number(static_cast<uint32_t>(N));
219  }
220  // LCOV_EXCL_START
221  else if (N <= (std::numeric_limits<uint64_t>::max)())
222  {
223  oa->write_character(static_cast<CharType>(0x9B));
224  write_number(static_cast<uint64_t>(N));
225  }
226  // LCOV_EXCL_STOP
227 
228  // step 2: write each element
229  for (const auto& el : *j.m_value.array)
230  {
231  write_cbor(el);
232  }
233  break;
234  }
235 
236  case value_t::object:
237  {
238  // step 1: write control byte and the object size
239  const auto N = j.m_value.object->size();
240  if (N <= 0x17)
241  {
242  write_number(static_cast<uint8_t>(0xA0 + N));
243  }
244  else if (N <= (std::numeric_limits<uint8_t>::max)())
245  {
246  oa->write_character(static_cast<CharType>(0xB8));
247  write_number(static_cast<uint8_t>(N));
248  }
249  else if (N <= (std::numeric_limits<uint16_t>::max)())
250  {
251  oa->write_character(static_cast<CharType>(0xB9));
252  write_number(static_cast<uint16_t>(N));
253  }
254  else if (N <= (std::numeric_limits<uint32_t>::max)())
255  {
256  oa->write_character(static_cast<CharType>(0xBA));
257  write_number(static_cast<uint32_t>(N));
258  }
259  // LCOV_EXCL_START
260  else if (N <= (std::numeric_limits<uint64_t>::max)())
261  {
262  oa->write_character(static_cast<CharType>(0xBB));
263  write_number(static_cast<uint64_t>(N));
264  }
265  // LCOV_EXCL_STOP
266 
267  // step 2: write each element
268  for (const auto& el : *j.m_value.object)
269  {
270  write_cbor(el.first);
271  write_cbor(el.second);
272  }
273  break;
274  }
275 
276  default:
277  break;
278  }
279  }
280 
284  void write_msgpack(const BasicJsonType& j)
285  {
286  switch (j.type())
287  {
288  case value_t::null: // nil
289  {
290  oa->write_character(static_cast<CharType>(0xC0));
291  break;
292  }
293 
294  case value_t::boolean: // true and false
295  {
296  oa->write_character(j.m_value.boolean
297  ? static_cast<CharType>(0xC3)
298  : static_cast<CharType>(0xC2));
299  break;
300  }
301 
303  {
304  if (j.m_value.number_integer >= 0)
305  {
306  // MessagePack does not differentiate between positive
307  // signed integers and unsigned integers. Therefore, we used
308  // the code from the value_t::number_unsigned case here.
309  if (j.m_value.number_unsigned < 128)
310  {
311  // positive fixnum
312  write_number(static_cast<uint8_t>(j.m_value.number_integer));
313  }
314  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
315  {
316  // uint 8
317  oa->write_character(static_cast<CharType>(0xCC));
318  write_number(static_cast<uint8_t>(j.m_value.number_integer));
319  }
320  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
321  {
322  // uint 16
323  oa->write_character(static_cast<CharType>(0xCD));
324  write_number(static_cast<uint16_t>(j.m_value.number_integer));
325  }
326  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
327  {
328  // uint 32
329  oa->write_character(static_cast<CharType>(0xCE));
330  write_number(static_cast<uint32_t>(j.m_value.number_integer));
331  }
332  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
333  {
334  // uint 64
335  oa->write_character(static_cast<CharType>(0xCF));
336  write_number(static_cast<uint64_t>(j.m_value.number_integer));
337  }
338  }
339  else
340  {
341  if (j.m_value.number_integer >= -32)
342  {
343  // negative fixnum
344  write_number(static_cast<int8_t>(j.m_value.number_integer));
345  }
346  else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and
347  j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
348  {
349  // int 8
350  oa->write_character(static_cast<CharType>(0xD0));
351  write_number(static_cast<int8_t>(j.m_value.number_integer));
352  }
353  else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and
354  j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
355  {
356  // int 16
357  oa->write_character(static_cast<CharType>(0xD1));
358  write_number(static_cast<int16_t>(j.m_value.number_integer));
359  }
360  else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and
361  j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
362  {
363  // int 32
364  oa->write_character(static_cast<CharType>(0xD2));
365  write_number(static_cast<int32_t>(j.m_value.number_integer));
366  }
367  else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and
368  j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
369  {
370  // int 64
371  oa->write_character(static_cast<CharType>(0xD3));
372  write_number(static_cast<int64_t>(j.m_value.number_integer));
373  }
374  }
375  break;
376  }
377 
379  {
380  if (j.m_value.number_unsigned < 128)
381  {
382  // positive fixnum
383  write_number(static_cast<uint8_t>(j.m_value.number_integer));
384  }
385  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
386  {
387  // uint 8
388  oa->write_character(static_cast<CharType>(0xCC));
389  write_number(static_cast<uint8_t>(j.m_value.number_integer));
390  }
391  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
392  {
393  // uint 16
394  oa->write_character(static_cast<CharType>(0xCD));
395  write_number(static_cast<uint16_t>(j.m_value.number_integer));
396  }
397  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
398  {
399  // uint 32
400  oa->write_character(static_cast<CharType>(0xCE));
401  write_number(static_cast<uint32_t>(j.m_value.number_integer));
402  }
403  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
404  {
405  // uint 64
406  oa->write_character(static_cast<CharType>(0xCF));
407  write_number(static_cast<uint64_t>(j.m_value.number_integer));
408  }
409  break;
410  }
411 
412  case value_t::number_float: // float 64
413  {
414  oa->write_character(static_cast<CharType>(0xCB));
415  write_number(j.m_value.number_float);
416  break;
417  }
418 
419  case value_t::string:
420  {
421  // step 1: write control byte and the string length
422  const auto N = j.m_value.string->size();
423  if (N <= 31)
424  {
425  // fixstr
426  write_number(static_cast<uint8_t>(0xA0 | N));
427  }
428  else if (N <= (std::numeric_limits<uint8_t>::max)())
429  {
430  // str 8
431  oa->write_character(static_cast<CharType>(0xD9));
432  write_number(static_cast<uint8_t>(N));
433  }
434  else if (N <= (std::numeric_limits<uint16_t>::max)())
435  {
436  // str 16
437  oa->write_character(static_cast<CharType>(0xDA));
438  write_number(static_cast<uint16_t>(N));
439  }
440  else if (N <= (std::numeric_limits<uint32_t>::max)())
441  {
442  // str 32
443  oa->write_character(static_cast<CharType>(0xDB));
444  write_number(static_cast<uint32_t>(N));
445  }
446 
447  // step 2: write the string
448  oa->write_characters(
449  reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
450  j.m_value.string->size());
451  break;
452  }
453 
454  case value_t::array:
455  {
456  // step 1: write control byte and the array size
457  const auto N = j.m_value.array->size();
458  if (N <= 15)
459  {
460  // fixarray
461  write_number(static_cast<uint8_t>(0x90 | N));
462  }
463  else if (N <= (std::numeric_limits<uint16_t>::max)())
464  {
465  // array 16
466  oa->write_character(static_cast<CharType>(0xDC));
467  write_number(static_cast<uint16_t>(N));
468  }
469  else if (N <= (std::numeric_limits<uint32_t>::max)())
470  {
471  // array 32
472  oa->write_character(static_cast<CharType>(0xDD));
473  write_number(static_cast<uint32_t>(N));
474  }
475 
476  // step 2: write each element
477  for (const auto& el : *j.m_value.array)
478  {
479  write_msgpack(el);
480  }
481  break;
482  }
483 
484  case value_t::object:
485  {
486  // step 1: write control byte and the object size
487  const auto N = j.m_value.object->size();
488  if (N <= 15)
489  {
490  // fixmap
491  write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));
492  }
493  else if (N <= (std::numeric_limits<uint16_t>::max)())
494  {
495  // map 16
496  oa->write_character(static_cast<CharType>(0xDE));
497  write_number(static_cast<uint16_t>(N));
498  }
499  else if (N <= (std::numeric_limits<uint32_t>::max)())
500  {
501  // map 32
502  oa->write_character(static_cast<CharType>(0xDF));
503  write_number(static_cast<uint32_t>(N));
504  }
505 
506  // step 2: write each element
507  for (const auto& el : *j.m_value.object)
508  {
509  write_msgpack(el.first);
510  write_msgpack(el.second);
511  }
512  break;
513  }
514 
515  default:
516  break;
517  }
518  }
519 
526  void write_ubjson(const BasicJsonType& j, const bool use_count,
527  const bool use_type, const bool add_prefix = true)
528  {
529  switch (j.type())
530  {
531  case value_t::null:
532  {
533  if (add_prefix)
534  {
535  oa->write_character(static_cast<CharType>('Z'));
536  }
537  break;
538  }
539 
540  case value_t::boolean:
541  {
542  if (add_prefix)
543  oa->write_character(j.m_value.boolean
544  ? static_cast<CharType>('T')
545  : static_cast<CharType>('F'));
546  break;
547  }
548 
550  {
551  write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
552  break;
553  }
554 
556  {
557  write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
558  break;
559  }
560 
562  {
563  write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
564  break;
565  }
566 
567  case value_t::string:
568  {
569  if (add_prefix)
570  {
571  oa->write_character(static_cast<CharType>('S'));
572  }
573  write_number_with_ubjson_prefix(j.m_value.string->size(), true);
574  oa->write_characters(
575  reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
576  j.m_value.string->size());
577  break;
578  }
579 
580  case value_t::array:
581  {
582  if (add_prefix)
583  {
584  oa->write_character(static_cast<CharType>('['));
585  }
586 
587  bool prefix_required = true;
588  if (use_type and not j.m_value.array->empty())
589  {
590  assert(use_count);
591  const char first_prefix = ubjson_prefix(j.front());
592  const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
593  [this, first_prefix](const BasicJsonType & v)
594  {
595  return ubjson_prefix(v) == first_prefix;
596  });
597 
598  if (same_prefix)
599  {
600  prefix_required = false;
601  oa->write_character(static_cast<CharType>('$'));
602  oa->write_character(static_cast<CharType>(first_prefix));
603  }
604  }
605 
606  if (use_count)
607  {
608  oa->write_character(static_cast<CharType>('#'));
609  write_number_with_ubjson_prefix(j.m_value.array->size(), true);
610  }
611 
612  for (const auto& el : *j.m_value.array)
613  {
614  write_ubjson(el, use_count, use_type, prefix_required);
615  }
616 
617  if (not use_count)
618  {
619  oa->write_character(static_cast<CharType>(']'));
620  }
621 
622  break;
623  }
624 
625  case value_t::object:
626  {
627  if (add_prefix)
628  {
629  oa->write_character(static_cast<CharType>('{'));
630  }
631 
632  bool prefix_required = true;
633  if (use_type and not j.m_value.object->empty())
634  {
635  assert(use_count);
636  const char first_prefix = ubjson_prefix(j.front());
637  const bool same_prefix = std::all_of(j.begin(), j.end(),
638  [this, first_prefix](const BasicJsonType & v)
639  {
640  return ubjson_prefix(v) == first_prefix;
641  });
642 
643  if (same_prefix)
644  {
645  prefix_required = false;
646  oa->write_character(static_cast<CharType>('$'));
647  oa->write_character(static_cast<CharType>(first_prefix));
648  }
649  }
650 
651  if (use_count)
652  {
653  oa->write_character(static_cast<CharType>('#'));
654  write_number_with_ubjson_prefix(j.m_value.object->size(), true);
655  }
656 
657  for (const auto& el : *j.m_value.object)
658  {
659  write_number_with_ubjson_prefix(el.first.size(), true);
660  oa->write_characters(
661  reinterpret_cast<const CharType*>(el.first.c_str()),
662  el.first.size());
663  write_ubjson(el.second, use_count, use_type, prefix_required);
664  }
665 
666  if (not use_count)
667  {
668  oa->write_character(static_cast<CharType>('}'));
669  }
670 
671  break;
672  }
673 
674  default:
675  break;
676  }
677  }
678 
679  private:
680  /*
681  @brief write a number to output input
682 
683  @param[in] n number of type @a NumberType
684  @tparam NumberType the type of the number
685 
686  @note This function needs to respect the system's endianess, because bytes
687  in CBOR, MessagePack, and UBJSON are stored in network order (big
688  endian) and therefore need reordering on little endian systems.
689  */
690  template<typename NumberType>
691  void write_number(const NumberType n)
692  {
693  // step 1: write number to array of length NumberType
694  std::array<CharType, sizeof(NumberType)> vec;
695  std::memcpy(vec.data(), &n, sizeof(NumberType));
696 
697  // step 2: write array to output (with possible reordering)
698  if (is_little_endian)
699  {
700  // reverse byte order prior to conversion if necessary
701  std::reverse(vec.begin(), vec.end());
702  }
703 
704  oa->write_characters(vec.data(), sizeof(NumberType));
705  }
706 
707  template<typename NumberType>
708  void write_number_with_ubjson_prefix(const NumberType n,
709  const bool add_prefix)
710  {
711  if (std::is_floating_point<NumberType>::value)
712  {
713  if (add_prefix)
714  {
715  oa->write_character(static_cast<CharType>('D')); // float64
716  }
717  write_number(n);
718  }
719  else if (std::is_unsigned<NumberType>::value)
720  {
721  if (n <= (std::numeric_limits<int8_t>::max)())
722  {
723  if (add_prefix)
724  {
725  oa->write_character(static_cast<CharType>('i')); // int8
726  }
727  write_number(static_cast<uint8_t>(n));
728  }
729  else if (n <= (std::numeric_limits<uint8_t>::max)())
730  {
731  if (add_prefix)
732  {
733  oa->write_character(static_cast<CharType>('U')); // uint8
734  }
735  write_number(static_cast<uint8_t>(n));
736  }
737  else if (n <= (std::numeric_limits<int16_t>::max)())
738  {
739  if (add_prefix)
740  {
741  oa->write_character(static_cast<CharType>('I')); // int16
742  }
743  write_number(static_cast<int16_t>(n));
744  }
745  else if (n <= (std::numeric_limits<int32_t>::max)())
746  {
747  if (add_prefix)
748  {
749  oa->write_character(static_cast<CharType>('l')); // int32
750  }
751  write_number(static_cast<int32_t>(n));
752  }
753  else if (n <= (std::numeric_limits<int64_t>::max)())
754  {
755  if (add_prefix)
756  {
757  oa->write_character(static_cast<CharType>('L')); // int64
758  }
759  write_number(static_cast<int64_t>(n));
760  }
761  else
762  {
763  JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
764  }
765  }
766  else
767  {
768  if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
769  {
770  if (add_prefix)
771  {
772  oa->write_character(static_cast<CharType>('i')); // int8
773  }
774  write_number(static_cast<int8_t>(n));
775  }
776  else if ((std::numeric_limits<uint8_t>::min)() <= n and n <= (std::numeric_limits<uint8_t>::max)())
777  {
778  if (add_prefix)
779  {
780  oa->write_character(static_cast<CharType>('U')); // uint8
781  }
782  write_number(static_cast<uint8_t>(n));
783  }
784  else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
785  {
786  if (add_prefix)
787  {
788  oa->write_character(static_cast<CharType>('I')); // int16
789  }
790  write_number(static_cast<int16_t>(n));
791  }
792  else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
793  {
794  if (add_prefix)
795  {
796  oa->write_character(static_cast<CharType>('l')); // int32
797  }
798  write_number(static_cast<int32_t>(n));
799  }
800  else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
801  {
802  if (add_prefix)
803  {
804  oa->write_character(static_cast<CharType>('L')); // int64
805  }
806  write_number(static_cast<int64_t>(n));
807  }
808  // LCOV_EXCL_START
809  else
810  {
811  JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
812  }
813  // LCOV_EXCL_STOP
814  }
815  }
816 
826  char ubjson_prefix(const BasicJsonType& j) const noexcept
827  {
828  switch (j.type())
829  {
830  case value_t::null:
831  return 'Z';
832 
833  case value_t::boolean:
834  return j.m_value.boolean ? 'T' : 'F';
835 
837  {
838  if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
839  {
840  return 'i';
841  }
842  else if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
843  {
844  return 'U';
845  }
846  else if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
847  {
848  return 'I';
849  }
850  else if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
851  {
852  return 'l';
853  }
854  else // no check and assume int64_t (see note above)
855  {
856  return 'L';
857  }
858  }
859 
861  {
862  if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())
863  {
864  return 'i';
865  }
866  else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
867  {
868  return 'U';
869  }
870  else if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())
871  {
872  return 'I';
873  }
874  else if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())
875  {
876  return 'l';
877  }
878  else // no check and assume int64_t (see note above)
879  {
880  return 'L';
881  }
882  }
883 
885  return 'D';
886 
887  case value_t::string:
888  return 'S';
889 
890  case value_t::array:
891  return '[';
892 
893  case value_t::object:
894  return '{';
895 
896  default: // discarded values
897  return 'N';
898  }
899  }
900 
901  private:
903  const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
904 
906  output_adapter_t<CharType> oa = nullptr;
907 };
908 }
909 }
nlohmann::detail::binary_writer::write_cbor
void write_cbor(const BasicJsonType &j)
[in] j JSON value to serialize
Definition: binary_writer.hpp:40
nlohmann::detail::value_t::null
null value
nlohmann::detail::value_t::object
object (unordered set of name/value pairs)
nlohmann::detail::binary_writer::write_msgpack
void write_msgpack(const BasicJsonType &j)
[in] j JSON value to serialize
Definition: binary_writer.hpp:284
nlohmann::detail::binary_reader::little_endianess
static constexpr bool little_endianess(int num=1) noexcept
determine system byte order
Definition: binary_reader.hpp:122
nlohmann::detail::binary_writer::write_ubjson
void write_ubjson(const BasicJsonType &j, const bool use_count, const bool use_type, const bool add_prefix=true)
Definition: binary_writer.hpp:526
nlohmann
namespace for Niels Lohmann
Definition: adl_serializer.hpp:8
nlohmann::detail::binary_writer
serialization to CBOR and MessagePack values
Definition: binary_writer.hpp:24
nlohmann::detail::value_t::number_float
number value (floating-point)
nlohmann::detail::value_t::number_integer
number value (signed integer)
nlohmann::detail::value_t::string
string value
nlohmann::detail::output_adapter_t
std::shared_ptr< output_adapter_protocol< CharType > > output_adapter_t
a type to simplify interfaces
Definition: output_adapters.hpp:26
nlohmann::detail::value_t::number_unsigned
number value (unsigned integer)
nlohmann::detail::value_t::array
array (ordered collection of values)
nlohmann::detail::value_t::boolean
boolean value
nlohmann::detail::binary_writer::binary_writer
binary_writer(output_adapter_t< CharType > adapter)
create a binary writer
Definition: binary_writer.hpp:32