• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 
3 #include <algorithm> // reverse, remove, fill, find, none_of
4 #include <array> // array
5 #include <clocale> // localeconv, lconv
6 #include <cmath> // labs, isfinite, isnan, signbit
7 #include <cstddef> // size_t, ptrdiff_t
8 #include <cstdint> // uint8_t
9 #include <cstdio> // snprintf
10 #include <limits> // numeric_limits
11 #include <string> // string, char_traits
12 #include <type_traits> // is_same
13 #include <utility> // move
14 
15 #include <nlohmann/detail/conversions/to_chars.hpp>
16 #include <nlohmann/detail/exceptions.hpp>
17 #include <nlohmann/detail/macro_scope.hpp>
18 #include <nlohmann/detail/meta/cpp_future.hpp>
19 #include <nlohmann/detail/output/binary_writer.hpp>
20 #include <nlohmann/detail/output/output_adapters.hpp>
21 #include <nlohmann/detail/value_t.hpp>
22 
23 namespace nlohmann
24 {
25 namespace detail
26 {
27 ///////////////////
28 // serialization //
29 ///////////////////
30 
31 /// how to treat decoding errors
32 enum class error_handler_t
33 {
34     strict,  ///< throw a type_error exception in case of invalid UTF-8
35     replace, ///< replace invalid UTF-8 sequences with U+FFFD
36     ignore   ///< ignore invalid UTF-8 sequences
37 };
38 
39 template<typename BasicJsonType>
40 class serializer
41 {
42     using string_t = typename BasicJsonType::string_t;
43     using number_float_t = typename BasicJsonType::number_float_t;
44     using number_integer_t = typename BasicJsonType::number_integer_t;
45     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
46     using binary_char_t = typename BasicJsonType::binary_t::value_type;
47     static constexpr std::uint8_t UTF8_ACCEPT = 0;
48     static constexpr std::uint8_t UTF8_REJECT = 1;
49 
50   public:
51     /*!
52     @param[in] s  output stream to serialize to
53     @param[in] ichar  indentation character to use
54     @param[in] error_handler_  how to react on decoding errors
55     */
serializer(output_adapter_t<char> s,const char ichar,error_handler_t error_handler_=error_handler_t::strict)56     serializer(output_adapter_t<char> s, const char ichar,
57                error_handler_t error_handler_ = error_handler_t::strict)
58         : o(std::move(s))
59         , loc(std::localeconv())
60         , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
61         , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
62         , indent_char(ichar)
63         , indent_string(512, indent_char)
64         , error_handler(error_handler_)
65     {}
66 
67     // delete because of pointer members
68     serializer(const serializer&) = delete;
69     serializer& operator=(const serializer&) = delete;
70     serializer(serializer&&) = delete;
71     serializer& operator=(serializer&&) = delete;
72     ~serializer() = default;
73 
74     /*!
75     @brief internal implementation of the serialization function
76 
77     This function is called by the public member function dump and organizes
78     the serialization internally. The indentation level is propagated as
79     additional parameter. In case of arrays and objects, the function is
80     called recursively.
81 
82     - strings and object keys are escaped using `escape_string()`
83     - integer numbers are converted implicitly via `operator<<`
84     - floating-point numbers are converted to a string using `"%g"` format
85     - binary values are serialized as objects containing the subtype and the
86       byte array
87 
88     @param[in] val               value to serialize
89     @param[in] pretty_print      whether the output shall be pretty-printed
90     @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
91     in the output are escaped with `\uXXXX` sequences, and the result consists
92     of ASCII characters only.
93     @param[in] indent_step       the indent level
94     @param[in] current_indent    the current indent level (only used internally)
95     */
dump(const BasicJsonType & val,const bool pretty_print,const bool ensure_ascii,const unsigned int indent_step,const unsigned int current_indent=0)96     void dump(const BasicJsonType& val,
97               const bool pretty_print,
98               const bool ensure_ascii,
99               const unsigned int indent_step,
100               const unsigned int current_indent = 0)
101     {
102         switch (val.m_type)
103         {
104             case value_t::object:
105             {
106                 if (val.m_value.object->empty())
107                 {
108                     o->write_characters("{}", 2);
109                     return;
110                 }
111 
112                 if (pretty_print)
113                 {
114                     o->write_characters("{\n", 2);
115 
116                     // variable to hold indentation for recursive calls
117                     const auto new_indent = current_indent + indent_step;
118                     if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
119                     {
120                         indent_string.resize(indent_string.size() * 2, ' ');
121                     }
122 
123                     // first n-1 elements
124                     auto i = val.m_value.object->cbegin();
125                     for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
126                     {
127                         o->write_characters(indent_string.c_str(), new_indent);
128                         o->write_character('\"');
129                         dump_escaped(i->first, ensure_ascii);
130                         o->write_characters("\": ", 3);
131                         dump(i->second, true, ensure_ascii, indent_step, new_indent);
132                         o->write_characters(",\n", 2);
133                     }
134 
135                     // last element
136                     JSON_ASSERT(i != val.m_value.object->cend());
137                     JSON_ASSERT(std::next(i) == val.m_value.object->cend());
138                     o->write_characters(indent_string.c_str(), new_indent);
139                     o->write_character('\"');
140                     dump_escaped(i->first, ensure_ascii);
141                     o->write_characters("\": ", 3);
142                     dump(i->second, true, ensure_ascii, indent_step, new_indent);
143 
144                     o->write_character('\n');
145                     o->write_characters(indent_string.c_str(), current_indent);
146                     o->write_character('}');
147                 }
148                 else
149                 {
150                     o->write_character('{');
151 
152                     // first n-1 elements
153                     auto i = val.m_value.object->cbegin();
154                     for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
155                     {
156                         o->write_character('\"');
157                         dump_escaped(i->first, ensure_ascii);
158                         o->write_characters("\":", 2);
159                         dump(i->second, false, ensure_ascii, indent_step, current_indent);
160                         o->write_character(',');
161                     }
162 
163                     // last element
164                     JSON_ASSERT(i != val.m_value.object->cend());
165                     JSON_ASSERT(std::next(i) == val.m_value.object->cend());
166                     o->write_character('\"');
167                     dump_escaped(i->first, ensure_ascii);
168                     o->write_characters("\":", 2);
169                     dump(i->second, false, ensure_ascii, indent_step, current_indent);
170 
171                     o->write_character('}');
172                 }
173 
174                 return;
175             }
176 
177             case value_t::array:
178             {
179                 if (val.m_value.array->empty())
180                 {
181                     o->write_characters("[]", 2);
182                     return;
183                 }
184 
185                 if (pretty_print)
186                 {
187                     o->write_characters("[\n", 2);
188 
189                     // variable to hold indentation for recursive calls
190                     const auto new_indent = current_indent + indent_step;
191                     if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
192                     {
193                         indent_string.resize(indent_string.size() * 2, ' ');
194                     }
195 
196                     // first n-1 elements
197                     for (auto i = val.m_value.array->cbegin();
198                             i != val.m_value.array->cend() - 1; ++i)
199                     {
200                         o->write_characters(indent_string.c_str(), new_indent);
201                         dump(*i, true, ensure_ascii, indent_step, new_indent);
202                         o->write_characters(",\n", 2);
203                     }
204 
205                     // last element
206                     JSON_ASSERT(!val.m_value.array->empty());
207                     o->write_characters(indent_string.c_str(), new_indent);
208                     dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
209 
210                     o->write_character('\n');
211                     o->write_characters(indent_string.c_str(), current_indent);
212                     o->write_character(']');
213                 }
214                 else
215                 {
216                     o->write_character('[');
217 
218                     // first n-1 elements
219                     for (auto i = val.m_value.array->cbegin();
220                             i != val.m_value.array->cend() - 1; ++i)
221                     {
222                         dump(*i, false, ensure_ascii, indent_step, current_indent);
223                         o->write_character(',');
224                     }
225 
226                     // last element
227                     JSON_ASSERT(!val.m_value.array->empty());
228                     dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
229 
230                     o->write_character(']');
231                 }
232 
233                 return;
234             }
235 
236             case value_t::string:
237             {
238                 o->write_character('\"');
239                 dump_escaped(*val.m_value.string, ensure_ascii);
240                 o->write_character('\"');
241                 return;
242             }
243 
244             case value_t::binary:
245             {
246                 if (pretty_print)
247                 {
248                     o->write_characters("{\n", 2);
249 
250                     // variable to hold indentation for recursive calls
251                     const auto new_indent = current_indent + indent_step;
252                     if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
253                     {
254                         indent_string.resize(indent_string.size() * 2, ' ');
255                     }
256 
257                     o->write_characters(indent_string.c_str(), new_indent);
258 
259                     o->write_characters("\"bytes\": [", 10);
260 
261                     if (!val.m_value.binary->empty())
262                     {
263                         for (auto i = val.m_value.binary->cbegin();
264                                 i != val.m_value.binary->cend() - 1; ++i)
265                         {
266                             dump_integer(*i);
267                             o->write_characters(", ", 2);
268                         }
269                         dump_integer(val.m_value.binary->back());
270                     }
271 
272                     o->write_characters("],\n", 3);
273                     o->write_characters(indent_string.c_str(), new_indent);
274 
275                     o->write_characters("\"subtype\": ", 11);
276                     if (val.m_value.binary->has_subtype())
277                     {
278                         dump_integer(val.m_value.binary->subtype());
279                     }
280                     else
281                     {
282                         o->write_characters("null", 4);
283                     }
284                     o->write_character('\n');
285                     o->write_characters(indent_string.c_str(), current_indent);
286                     o->write_character('}');
287                 }
288                 else
289                 {
290                     o->write_characters("{\"bytes\":[", 10);
291 
292                     if (!val.m_value.binary->empty())
293                     {
294                         for (auto i = val.m_value.binary->cbegin();
295                                 i != val.m_value.binary->cend() - 1; ++i)
296                         {
297                             dump_integer(*i);
298                             o->write_character(',');
299                         }
300                         dump_integer(val.m_value.binary->back());
301                     }
302 
303                     o->write_characters("],\"subtype\":", 12);
304                     if (val.m_value.binary->has_subtype())
305                     {
306                         dump_integer(val.m_value.binary->subtype());
307                         o->write_character('}');
308                     }
309                     else
310                     {
311                         o->write_characters("null}", 5);
312                     }
313                 }
314                 return;
315             }
316 
317             case value_t::boolean:
318             {
319                 if (val.m_value.boolean)
320                 {
321                     o->write_characters("true", 4);
322                 }
323                 else
324                 {
325                     o->write_characters("false", 5);
326                 }
327                 return;
328             }
329 
330             case value_t::number_integer:
331             {
332                 dump_integer(val.m_value.number_integer);
333                 return;
334             }
335 
336             case value_t::number_unsigned:
337             {
338                 dump_integer(val.m_value.number_unsigned);
339                 return;
340             }
341 
342             case value_t::number_float:
343             {
344                 dump_float(val.m_value.number_float);
345                 return;
346             }
347 
348             case value_t::discarded:
349             {
350                 o->write_characters("<discarded>", 11);
351                 return;
352             }
353 
354             case value_t::null:
355             {
356                 o->write_characters("null", 4);
357                 return;
358             }
359 
360             default:            // LCOV_EXCL_LINE
361                 JSON_ASSERT(false);  // LCOV_EXCL_LINE
362         }
363     }
364 
365   private:
366     /*!
367     @brief dump escaped string
368 
369     Escape a string by replacing certain special characters by a sequence of an
370     escape character (backslash) and another character and other control
371     characters by a sequence of "\u" followed by a four-digit hex
372     representation. The escaped string is written to output stream @a o.
373 
374     @param[in] s  the string to escape
375     @param[in] ensure_ascii  whether to escape non-ASCII characters with
376                              \uXXXX sequences
377 
378     @complexity Linear in the length of string @a s.
379     */
dump_escaped(const string_t & s,const bool ensure_ascii)380     void dump_escaped(const string_t& s, const bool ensure_ascii)
381     {
382         std::uint32_t codepoint;
383         std::uint8_t state = UTF8_ACCEPT;
384         std::size_t bytes = 0;  // number of bytes written to string_buffer
385 
386         // number of bytes written at the point of the last valid byte
387         std::size_t bytes_after_last_accept = 0;
388         std::size_t undumped_chars = 0;
389 
390         for (std::size_t i = 0; i < s.size(); ++i)
391         {
392             const auto byte = static_cast<uint8_t>(s[i]);
393 
394             switch (decode(state, codepoint, byte))
395             {
396                 case UTF8_ACCEPT:  // decode found a new code point
397                 {
398                     switch (codepoint)
399                     {
400                         case 0x08: // backspace
401                         {
402                             string_buffer[bytes++] = '\\';
403                             string_buffer[bytes++] = 'b';
404                             break;
405                         }
406 
407                         case 0x09: // horizontal tab
408                         {
409                             string_buffer[bytes++] = '\\';
410                             string_buffer[bytes++] = 't';
411                             break;
412                         }
413 
414                         case 0x0A: // newline
415                         {
416                             string_buffer[bytes++] = '\\';
417                             string_buffer[bytes++] = 'n';
418                             break;
419                         }
420 
421                         case 0x0C: // formfeed
422                         {
423                             string_buffer[bytes++] = '\\';
424                             string_buffer[bytes++] = 'f';
425                             break;
426                         }
427 
428                         case 0x0D: // carriage return
429                         {
430                             string_buffer[bytes++] = '\\';
431                             string_buffer[bytes++] = 'r';
432                             break;
433                         }
434 
435                         case 0x22: // quotation mark
436                         {
437                             string_buffer[bytes++] = '\\';
438                             string_buffer[bytes++] = '\"';
439                             break;
440                         }
441 
442                         case 0x5C: // reverse solidus
443                         {
444                             string_buffer[bytes++] = '\\';
445                             string_buffer[bytes++] = '\\';
446                             break;
447                         }
448 
449                         default:
450                         {
451                             // escape control characters (0x00..0x1F) or, if
452                             // ensure_ascii parameter is used, non-ASCII characters
453                             if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
454                             {
455                                 if (codepoint <= 0xFFFF)
456                                 {
457                                     (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
458                                                     static_cast<std::uint16_t>(codepoint));
459                                     bytes += 6;
460                                 }
461                                 else
462                                 {
463                                     (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
464                                                     static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
465                                                     static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
466                                     bytes += 12;
467                                 }
468                             }
469                             else
470                             {
471                                 // copy byte to buffer (all previous bytes
472                                 // been copied have in default case above)
473                                 string_buffer[bytes++] = s[i];
474                             }
475                             break;
476                         }
477                     }
478 
479                     // write buffer and reset index; there must be 13 bytes
480                     // left, as this is the maximal number of bytes to be
481                     // written ("\uxxxx\uxxxx\0") for one code point
482                     if (string_buffer.size() - bytes < 13)
483                     {
484                         o->write_characters(string_buffer.data(), bytes);
485                         bytes = 0;
486                     }
487 
488                     // remember the byte position of this accept
489                     bytes_after_last_accept = bytes;
490                     undumped_chars = 0;
491                     break;
492                 }
493 
494                 case UTF8_REJECT:  // decode found invalid UTF-8 byte
495                 {
496                     switch (error_handler)
497                     {
498                         case error_handler_t::strict:
499                         {
500                             std::string sn(3, '\0');
501                             (std::snprintf)(&sn[0], sn.size(), "%.2X", byte);
502                             JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
503                         }
504 
505                         case error_handler_t::ignore:
506                         case error_handler_t::replace:
507                         {
508                             // in case we saw this character the first time, we
509                             // would like to read it again, because the byte
510                             // may be OK for itself, but just not OK for the
511                             // previous sequence
512                             if (undumped_chars > 0)
513                             {
514                                 --i;
515                             }
516 
517                             // reset length buffer to the last accepted index;
518                             // thus removing/ignoring the invalid characters
519                             bytes = bytes_after_last_accept;
520 
521                             if (error_handler == error_handler_t::replace)
522                             {
523                                 // add a replacement character
524                                 if (ensure_ascii)
525                                 {
526                                     string_buffer[bytes++] = '\\';
527                                     string_buffer[bytes++] = 'u';
528                                     string_buffer[bytes++] = 'f';
529                                     string_buffer[bytes++] = 'f';
530                                     string_buffer[bytes++] = 'f';
531                                     string_buffer[bytes++] = 'd';
532                                 }
533                                 else
534                                 {
535                                     string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
536                                     string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
537                                     string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
538                                 }
539 
540                                 // write buffer and reset index; there must be 13 bytes
541                                 // left, as this is the maximal number of bytes to be
542                                 // written ("\uxxxx\uxxxx\0") for one code point
543                                 if (string_buffer.size() - bytes < 13)
544                                 {
545                                     o->write_characters(string_buffer.data(), bytes);
546                                     bytes = 0;
547                                 }
548 
549                                 bytes_after_last_accept = bytes;
550                             }
551 
552                             undumped_chars = 0;
553 
554                             // continue processing the string
555                             state = UTF8_ACCEPT;
556                             break;
557                         }
558 
559                         default:            // LCOV_EXCL_LINE
560                             JSON_ASSERT(false);  // LCOV_EXCL_LINE
561                     }
562                     break;
563                 }
564 
565                 default:  // decode found yet incomplete multi-byte code point
566                 {
567                     if (!ensure_ascii)
568                     {
569                         // code point will not be escaped - copy byte to buffer
570                         string_buffer[bytes++] = s[i];
571                     }
572                     ++undumped_chars;
573                     break;
574                 }
575             }
576         }
577 
578         // we finished processing the string
579         if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
580         {
581             // write buffer
582             if (bytes > 0)
583             {
584                 o->write_characters(string_buffer.data(), bytes);
585             }
586         }
587         else
588         {
589             // we finish reading, but do not accept: string was incomplete
590             switch (error_handler)
591             {
592                 case error_handler_t::strict:
593                 {
594                     std::string sn(3, '\0');
595                     (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<std::uint8_t>(s.back()));
596                     JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
597                 }
598 
599                 case error_handler_t::ignore:
600                 {
601                     // write all accepted bytes
602                     o->write_characters(string_buffer.data(), bytes_after_last_accept);
603                     break;
604                 }
605 
606                 case error_handler_t::replace:
607                 {
608                     // write all accepted bytes
609                     o->write_characters(string_buffer.data(), bytes_after_last_accept);
610                     // add a replacement character
611                     if (ensure_ascii)
612                     {
613                         o->write_characters("\\ufffd", 6);
614                     }
615                     else
616                     {
617                         o->write_characters("\xEF\xBF\xBD", 3);
618                     }
619                     break;
620                 }
621 
622                 default:            // LCOV_EXCL_LINE
623                     JSON_ASSERT(false);  // LCOV_EXCL_LINE
624             }
625         }
626     }
627 
628     /*!
629     @brief count digits
630 
631     Count the number of decimal (base 10) digits for an input unsigned integer.
632 
633     @param[in] x  unsigned integer number to count its digits
634     @return    number of decimal digits
635     */
count_digits(number_unsigned_t x)636     inline unsigned int count_digits(number_unsigned_t x) noexcept
637     {
638         unsigned int n_digits = 1;
639         for (;;)
640         {
641             if (x < 10)
642             {
643                 return n_digits;
644             }
645             if (x < 100)
646             {
647                 return n_digits + 1;
648             }
649             if (x < 1000)
650             {
651                 return n_digits + 2;
652             }
653             if (x < 10000)
654             {
655                 return n_digits + 3;
656             }
657             x = x / 10000u;
658             n_digits += 4;
659         }
660     }
661 
662     /*!
663     @brief dump an integer
664 
665     Dump a given integer to output stream @a o. Works internally with
666     @a number_buffer.
667 
668     @param[in] x  integer number (signed or unsigned) to dump
669     @tparam NumberType either @a number_integer_t or @a number_unsigned_t
670     */
671     template < typename NumberType, detail::enable_if_t <
672                    std::is_same<NumberType, number_unsigned_t>::value ||
673                    std::is_same<NumberType, number_integer_t>::value ||
674                    std::is_same<NumberType, binary_char_t>::value,
675                    int > = 0 >
dump_integer(NumberType x)676     void dump_integer(NumberType x)
677     {
678         static constexpr std::array<std::array<char, 2>, 100> digits_to_99
679         {
680             {
681                 {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
682                 {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
683                 {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
684                 {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
685                 {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
686                 {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
687                 {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
688                 {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
689                 {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
690                 {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
691             }
692         };
693 
694         // special case for "0"
695         if (x == 0)
696         {
697             o->write_character('0');
698             return;
699         }
700 
701         // use a pointer to fill the buffer
702         auto buffer_ptr = number_buffer.begin();
703 
704         const bool is_negative = std::is_same<NumberType, number_integer_t>::value && !(x >= 0); // see issue #755
705         number_unsigned_t abs_value;
706 
707         unsigned int n_chars;
708 
709         if (is_negative)
710         {
711             *buffer_ptr = '-';
712             abs_value = remove_sign(static_cast<number_integer_t>(x));
713 
714             // account one more byte for the minus sign
715             n_chars = 1 + count_digits(abs_value);
716         }
717         else
718         {
719             abs_value = static_cast<number_unsigned_t>(x);
720             n_chars = count_digits(abs_value);
721         }
722 
723         // spare 1 byte for '\0'
724         JSON_ASSERT(n_chars < number_buffer.size() - 1);
725 
726         // jump to the end to generate the string from backward
727         // so we later avoid reversing the result
728         buffer_ptr += n_chars;
729 
730         // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
731         // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
732         while (abs_value >= 100)
733         {
734             const auto digits_index = static_cast<unsigned>((abs_value % 100));
735             abs_value /= 100;
736             *(--buffer_ptr) = digits_to_99[digits_index][1];
737             *(--buffer_ptr) = digits_to_99[digits_index][0];
738         }
739 
740         if (abs_value >= 10)
741         {
742             const auto digits_index = static_cast<unsigned>(abs_value);
743             *(--buffer_ptr) = digits_to_99[digits_index][1];
744             *(--buffer_ptr) = digits_to_99[digits_index][0];
745         }
746         else
747         {
748             *(--buffer_ptr) = static_cast<char>('0' + abs_value);
749         }
750 
751         o->write_characters(number_buffer.data(), n_chars);
752     }
753 
754     /*!
755     @brief dump a floating-point number
756 
757     Dump a given floating-point number to output stream @a o. Works internally
758     with @a number_buffer.
759 
760     @param[in] x  floating-point number to dump
761     */
dump_float(number_float_t x)762     void dump_float(number_float_t x)
763     {
764         // NaN / inf
765         if (!std::isfinite(x))
766         {
767             o->write_characters("null", 4);
768             return;
769         }
770 
771         // If number_float_t is an IEEE-754 single or double precision number,
772         // use the Grisu2 algorithm to produce short numbers which are
773         // guaranteed to round-trip, using strtof and strtod, resp.
774         //
775         // NB: The test below works if <long double> == <double>.
776         static constexpr bool is_ieee_single_or_double
777             = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
778               (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
779 
780         dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
781     }
782 
dump_float(number_float_t x,std::true_type)783     void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
784     {
785         char* begin = number_buffer.data();
786         char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
787 
788         o->write_characters(begin, static_cast<size_t>(end - begin));
789     }
790 
dump_float(number_float_t x,std::false_type)791     void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
792     {
793         // get number of digits for a float -> text -> float round-trip
794         static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
795 
796         // the actual conversion
797         std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
798 
799         // negative value indicates an error
800         JSON_ASSERT(len > 0);
801         // check if buffer was large enough
802         JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
803 
804         // erase thousands separator
805         if (thousands_sep != '\0')
806         {
807             const auto end = std::remove(number_buffer.begin(),
808                                          number_buffer.begin() + len, thousands_sep);
809             std::fill(end, number_buffer.end(), '\0');
810             JSON_ASSERT((end - number_buffer.begin()) <= len);
811             len = (end - number_buffer.begin());
812         }
813 
814         // convert decimal point to '.'
815         if (decimal_point != '\0' && decimal_point != '.')
816         {
817             const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
818             if (dec_pos != number_buffer.end())
819             {
820                 *dec_pos = '.';
821             }
822         }
823 
824         o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
825 
826         // determine if need to append ".0"
827         const bool value_is_int_like =
828             std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
829                          [](char c)
830         {
831             return c == '.' || c == 'e';
832         });
833 
834         if (value_is_int_like)
835         {
836             o->write_characters(".0", 2);
837         }
838     }
839 
840     /*!
841     @brief check whether a string is UTF-8 encoded
842 
843     The function checks each byte of a string whether it is UTF-8 encoded. The
844     result of the check is stored in the @a state parameter. The function must
845     be called initially with state 0 (accept). State 1 means the string must
846     be rejected, because the current byte is not allowed. If the string is
847     completely processed, but the state is non-zero, the string ended
848     prematurely; that is, the last byte indicated more bytes should have
849     followed.
850 
851     @param[in,out] state  the state of the decoding
852     @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)
853     @param[in] byte       next byte to decode
854     @return               new state
855 
856     @note The function has been edited: a std::array is used.
857 
858     @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
859     @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
860     */
decode(std::uint8_t & state,std::uint32_t & codep,const std::uint8_t byte)861     static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
862     {
863         static const std::array<std::uint8_t, 400> utf8d =
864         {
865             {
866                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
867                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
868                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
869                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
870                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
871                 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
872                 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
873                 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
874                 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
875                 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
876                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
877                 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
878                 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
879                 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
880             }
881         };
882 
883         const std::uint8_t type = utf8d[byte];
884 
885         codep = (state != UTF8_ACCEPT)
886                 ? (byte & 0x3fu) | (codep << 6u)
887                 : (0xFFu >> type) & (byte);
888 
889         std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
890         JSON_ASSERT(index < 400);
891         state = utf8d[index];
892         return state;
893     }
894 
895     /*
896      * Overload to make the compiler happy while it is instantiating
897      * dump_integer for number_unsigned_t.
898      * Must never be called.
899      */
remove_sign(number_unsigned_t x)900     number_unsigned_t remove_sign(number_unsigned_t x)
901     {
902         JSON_ASSERT(false); // LCOV_EXCL_LINE
903         return x; // LCOV_EXCL_LINE
904     }
905 
906     /*
907      * Helper function for dump_integer
908      *
909      * This function takes a negative signed integer and returns its absolute
910      * value as unsigned integer. The plus/minus shuffling is necessary as we can
911      * not directly remove the sign of an arbitrary signed integer as the
912      * absolute values of INT_MIN and INT_MAX are usually not the same. See
913      * #1708 for details.
914      */
remove_sign(number_integer_t x)915     inline number_unsigned_t remove_sign(number_integer_t x) noexcept
916     {
917         JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());
918         return static_cast<number_unsigned_t>(-(x + 1)) + 1;
919     }
920 
921   private:
922     /// the output of the serializer
923     output_adapter_t<char> o = nullptr;
924 
925     /// a (hopefully) large enough character buffer
926     std::array<char, 64> number_buffer{{}};
927 
928     /// the locale
929     const std::lconv* loc = nullptr;
930     /// the locale's thousand separator character
931     const char thousands_sep = '\0';
932     /// the locale's decimal point character
933     const char decimal_point = '\0';
934 
935     /// string buffer
936     std::array<char, 512> string_buffer{{}};
937 
938     /// the indentation character
939     const char indent_char;
940     /// the indentation string
941     string_t indent_string;
942 
943     /// error_handler how to react on decoding errors
944     const error_handler_t error_handler;
945 };
946 }  // namespace detail
947 }  // namespace nlohmann
948