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