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