Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:02:20

0001 //     __ _____ _____ _____
0002 //  __|  |   __|     |   | |  JSON for Modern C++
0003 // |  |  |__   |  |  | | | |  version 3.11.2
0004 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
0005 //
0006 // SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de>
0007 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
0008 // SPDX-License-Identifier: MIT
0009 
0010 #pragma once
0011 
0012 #include <algorithm> // reverse, remove, fill, find, none_of
0013 #include <array> // array
0014 #include <clocale> // localeconv, lconv
0015 #include <cmath> // labs, isfinite, isnan, signbit
0016 #include <cstddef> // size_t, ptrdiff_t
0017 #include <cstdint> // uint8_t
0018 #include <cstdio> // snprintf
0019 #include <limits> // numeric_limits
0020 #include <string> // string, char_traits
0021 #include <iomanip> // setfill, setw
0022 #include <type_traits> // is_same
0023 #include <utility> // move
0024 
0025 #include <nlohmann/detail/conversions/to_chars.hpp>
0026 #include <nlohmann/detail/exceptions.hpp>
0027 #include <nlohmann/detail/macro_scope.hpp>
0028 #include <nlohmann/detail/meta/cpp_future.hpp>
0029 #include <nlohmann/detail/output/binary_writer.hpp>
0030 #include <nlohmann/detail/output/output_adapters.hpp>
0031 #include <nlohmann/detail/string_concat.hpp>
0032 #include <nlohmann/detail/value_t.hpp>
0033 
0034 NLOHMANN_JSON_NAMESPACE_BEGIN
0035 namespace detail
0036 {
0037 
0038 ///////////////////
0039 // serialization //
0040 ///////////////////
0041 
0042 /// how to treat decoding errors
0043 enum class error_handler_t
0044 {
0045     strict,  ///< throw a type_error exception in case of invalid UTF-8
0046     replace, ///< replace invalid UTF-8 sequences with U+FFFD
0047     ignore   ///< ignore invalid UTF-8 sequences
0048 };
0049 
0050 template<typename BasicJsonType>
0051 class serializer
0052 {
0053     using string_t = typename BasicJsonType::string_t;
0054     using number_float_t = typename BasicJsonType::number_float_t;
0055     using number_integer_t = typename BasicJsonType::number_integer_t;
0056     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
0057     using binary_char_t = typename BasicJsonType::binary_t::value_type;
0058     static constexpr std::uint8_t UTF8_ACCEPT = 0;
0059     static constexpr std::uint8_t UTF8_REJECT = 1;
0060 
0061   public:
0062     /*!
0063     @param[in] s  output stream to serialize to
0064     @param[in] ichar  indentation character to use
0065     @param[in] error_handler_  how to react on decoding errors
0066     */
0067     serializer(output_adapter_t<char> s, const char ichar,
0068                error_handler_t error_handler_ = error_handler_t::strict)
0069         : o(std::move(s))
0070         , loc(std::localeconv())
0071         , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
0072         , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
0073         , indent_char(ichar)
0074         , indent_string(512, indent_char)
0075         , error_handler(error_handler_)
0076     {}
0077 
0078     // delete because of pointer members
0079     serializer(const serializer&) = delete;
0080     serializer& operator=(const serializer&) = delete;
0081     serializer(serializer&&) = delete;
0082     serializer& operator=(serializer&&) = delete;
0083     ~serializer() = default;
0084 
0085     /*!
0086     @brief internal implementation of the serialization function
0087 
0088     This function is called by the public member function dump and organizes
0089     the serialization internally. The indentation level is propagated as
0090     additional parameter. In case of arrays and objects, the function is
0091     called recursively.
0092 
0093     - strings and object keys are escaped using `escape_string()`
0094     - integer numbers are converted implicitly via `operator<<`
0095     - floating-point numbers are converted to a string using `"%g"` format
0096     - binary values are serialized as objects containing the subtype and the
0097       byte array
0098 
0099     @param[in] val               value to serialize
0100     @param[in] pretty_print      whether the output shall be pretty-printed
0101     @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
0102     in the output are escaped with `\uXXXX` sequences, and the result consists
0103     of ASCII characters only.
0104     @param[in] indent_step       the indent level
0105     @param[in] current_indent    the current indent level (only used internally)
0106     */
0107     void dump(const BasicJsonType& val,
0108               const bool pretty_print,
0109               const bool ensure_ascii,
0110               const unsigned int indent_step,
0111               const unsigned int current_indent = 0)
0112     {
0113         switch (val.m_type)
0114         {
0115             case value_t::object:
0116             {
0117                 if (val.m_value.object->empty())
0118                 {
0119                     o->write_characters("{}", 2);
0120                     return;
0121                 }
0122 
0123                 if (pretty_print)
0124                 {
0125                     o->write_characters("{\n", 2);
0126 
0127                     // variable to hold indentation for recursive calls
0128                     const auto new_indent = current_indent + indent_step;
0129                     if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
0130                     {
0131                         indent_string.resize(indent_string.size() * 2, ' ');
0132                     }
0133 
0134                     // first n-1 elements
0135                     auto i = val.m_value.object->cbegin();
0136                     for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
0137                     {
0138                         o->write_characters(indent_string.c_str(), new_indent);
0139                         o->write_character('\"');
0140                         dump_escaped(i->first, ensure_ascii);
0141                         o->write_characters("\": ", 3);
0142                         dump(i->second, true, ensure_ascii, indent_step, new_indent);
0143                         o->write_characters(",\n", 2);
0144                     }
0145 
0146                     // last element
0147                     JSON_ASSERT(i != val.m_value.object->cend());
0148                     JSON_ASSERT(std::next(i) == val.m_value.object->cend());
0149                     o->write_characters(indent_string.c_str(), new_indent);
0150                     o->write_character('\"');
0151                     dump_escaped(i->first, ensure_ascii);
0152                     o->write_characters("\": ", 3);
0153                     dump(i->second, true, ensure_ascii, indent_step, new_indent);
0154 
0155                     o->write_character('\n');
0156                     o->write_characters(indent_string.c_str(), current_indent);
0157                     o->write_character('}');
0158                 }
0159                 else
0160                 {
0161                     o->write_character('{');
0162 
0163                     // first n-1 elements
0164                     auto i = val.m_value.object->cbegin();
0165                     for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
0166                     {
0167                         o->write_character('\"');
0168                         dump_escaped(i->first, ensure_ascii);
0169                         o->write_characters("\":", 2);
0170                         dump(i->second, false, ensure_ascii, indent_step, current_indent);
0171                         o->write_character(',');
0172                     }
0173 
0174                     // last element
0175                     JSON_ASSERT(i != val.m_value.object->cend());
0176                     JSON_ASSERT(std::next(i) == val.m_value.object->cend());
0177                     o->write_character('\"');
0178                     dump_escaped(i->first, ensure_ascii);
0179                     o->write_characters("\":", 2);
0180                     dump(i->second, false, ensure_ascii, indent_step, current_indent);
0181 
0182                     o->write_character('}');
0183                 }
0184 
0185                 return;
0186             }
0187 
0188             case value_t::array:
0189             {
0190                 if (val.m_value.array->empty())
0191                 {
0192                     o->write_characters("[]", 2);
0193                     return;
0194                 }
0195 
0196                 if (pretty_print)
0197                 {
0198                     o->write_characters("[\n", 2);
0199 
0200                     // variable to hold indentation for recursive calls
0201                     const auto new_indent = current_indent + indent_step;
0202                     if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
0203                     {
0204                         indent_string.resize(indent_string.size() * 2, ' ');
0205                     }
0206 
0207                     // first n-1 elements
0208                     for (auto i = val.m_value.array->cbegin();
0209                             i != val.m_value.array->cend() - 1; ++i)
0210                     {
0211                         o->write_characters(indent_string.c_str(), new_indent);
0212                         dump(*i, true, ensure_ascii, indent_step, new_indent);
0213                         o->write_characters(",\n", 2);
0214                     }
0215 
0216                     // last element
0217                     JSON_ASSERT(!val.m_value.array->empty());
0218                     o->write_characters(indent_string.c_str(), new_indent);
0219                     dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
0220 
0221                     o->write_character('\n');
0222                     o->write_characters(indent_string.c_str(), current_indent);
0223                     o->write_character(']');
0224                 }
0225                 else
0226                 {
0227                     o->write_character('[');
0228 
0229                     // first n-1 elements
0230                     for (auto i = val.m_value.array->cbegin();
0231                             i != val.m_value.array->cend() - 1; ++i)
0232                     {
0233                         dump(*i, false, ensure_ascii, indent_step, current_indent);
0234                         o->write_character(',');
0235                     }
0236 
0237                     // last element
0238                     JSON_ASSERT(!val.m_value.array->empty());
0239                     dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
0240 
0241                     o->write_character(']');
0242                 }
0243 
0244                 return;
0245             }
0246 
0247             case value_t::string:
0248             {
0249                 o->write_character('\"');
0250                 dump_escaped(*val.m_value.string, ensure_ascii);
0251                 o->write_character('\"');
0252                 return;
0253             }
0254 
0255             case value_t::binary:
0256             {
0257                 if (pretty_print)
0258                 {
0259                     o->write_characters("{\n", 2);
0260 
0261                     // variable to hold indentation for recursive calls
0262                     const auto new_indent = current_indent + indent_step;
0263                     if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
0264                     {
0265                         indent_string.resize(indent_string.size() * 2, ' ');
0266                     }
0267 
0268                     o->write_characters(indent_string.c_str(), new_indent);
0269 
0270                     o->write_characters("\"bytes\": [", 10);
0271 
0272                     if (!val.m_value.binary->empty())
0273                     {
0274                         for (auto i = val.m_value.binary->cbegin();
0275                                 i != val.m_value.binary->cend() - 1; ++i)
0276                         {
0277                             dump_integer(*i);
0278                             o->write_characters(", ", 2);
0279                         }
0280                         dump_integer(val.m_value.binary->back());
0281                     }
0282 
0283                     o->write_characters("],\n", 3);
0284                     o->write_characters(indent_string.c_str(), new_indent);
0285 
0286                     o->write_characters("\"subtype\": ", 11);
0287                     if (val.m_value.binary->has_subtype())
0288                     {
0289                         dump_integer(val.m_value.binary->subtype());
0290                     }
0291                     else
0292                     {
0293                         o->write_characters("null", 4);
0294                     }
0295                     o->write_character('\n');
0296                     o->write_characters(indent_string.c_str(), current_indent);
0297                     o->write_character('}');
0298                 }
0299                 else
0300                 {
0301                     o->write_characters("{\"bytes\":[", 10);
0302 
0303                     if (!val.m_value.binary->empty())
0304                     {
0305                         for (auto i = val.m_value.binary->cbegin();
0306                                 i != val.m_value.binary->cend() - 1; ++i)
0307                         {
0308                             dump_integer(*i);
0309                             o->write_character(',');
0310                         }
0311                         dump_integer(val.m_value.binary->back());
0312                     }
0313 
0314                     o->write_characters("],\"subtype\":", 12);
0315                     if (val.m_value.binary->has_subtype())
0316                     {
0317                         dump_integer(val.m_value.binary->subtype());
0318                         o->write_character('}');
0319                     }
0320                     else
0321                     {
0322                         o->write_characters("null}", 5);
0323                     }
0324                 }
0325                 return;
0326             }
0327 
0328             case value_t::boolean:
0329             {
0330                 if (val.m_value.boolean)
0331                 {
0332                     o->write_characters("true", 4);
0333                 }
0334                 else
0335                 {
0336                     o->write_characters("false", 5);
0337                 }
0338                 return;
0339             }
0340 
0341             case value_t::number_integer:
0342             {
0343                 dump_integer(val.m_value.number_integer);
0344                 return;
0345             }
0346 
0347             case value_t::number_unsigned:
0348             {
0349                 dump_integer(val.m_value.number_unsigned);
0350                 return;
0351             }
0352 
0353             case value_t::number_float:
0354             {
0355                 dump_float(val.m_value.number_float);
0356                 return;
0357             }
0358 
0359             case value_t::discarded:
0360             {
0361                 o->write_characters("<discarded>", 11);
0362                 return;
0363             }
0364 
0365             case value_t::null:
0366             {
0367                 o->write_characters("null", 4);
0368                 return;
0369             }
0370 
0371             default:            // LCOV_EXCL_LINE
0372                 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
0373         }
0374     }
0375 
0376   JSON_PRIVATE_UNLESS_TESTED:
0377     /*!
0378     @brief dump escaped string
0379 
0380     Escape a string by replacing certain special characters by a sequence of an
0381     escape character (backslash) and another character and other control
0382     characters by a sequence of "\u" followed by a four-digit hex
0383     representation. The escaped string is written to output stream @a o.
0384 
0385     @param[in] s  the string to escape
0386     @param[in] ensure_ascii  whether to escape non-ASCII characters with
0387                              \uXXXX sequences
0388 
0389     @complexity Linear in the length of string @a s.
0390     */
0391     void dump_escaped(const string_t& s, const bool ensure_ascii)
0392     {
0393         std::uint32_t codepoint{};
0394         std::uint8_t state = UTF8_ACCEPT;
0395         std::size_t bytes = 0;  // number of bytes written to string_buffer
0396 
0397         // number of bytes written at the point of the last valid byte
0398         std::size_t bytes_after_last_accept = 0;
0399         std::size_t undumped_chars = 0;
0400 
0401         for (std::size_t i = 0; i < s.size(); ++i)
0402         {
0403             const auto byte = static_cast<std::uint8_t>(s[i]);
0404 
0405             switch (decode(state, codepoint, byte))
0406             {
0407                 case UTF8_ACCEPT:  // decode found a new code point
0408                 {
0409                     switch (codepoint)
0410                     {
0411                         case 0x08: // backspace
0412                         {
0413                             string_buffer[bytes++] = '\\';
0414                             string_buffer[bytes++] = 'b';
0415                             break;
0416                         }
0417 
0418                         case 0x09: // horizontal tab
0419                         {
0420                             string_buffer[bytes++] = '\\';
0421                             string_buffer[bytes++] = 't';
0422                             break;
0423                         }
0424 
0425                         case 0x0A: // newline
0426                         {
0427                             string_buffer[bytes++] = '\\';
0428                             string_buffer[bytes++] = 'n';
0429                             break;
0430                         }
0431 
0432                         case 0x0C: // formfeed
0433                         {
0434                             string_buffer[bytes++] = '\\';
0435                             string_buffer[bytes++] = 'f';
0436                             break;
0437                         }
0438 
0439                         case 0x0D: // carriage return
0440                         {
0441                             string_buffer[bytes++] = '\\';
0442                             string_buffer[bytes++] = 'r';
0443                             break;
0444                         }
0445 
0446                         case 0x22: // quotation mark
0447                         {
0448                             string_buffer[bytes++] = '\\';
0449                             string_buffer[bytes++] = '\"';
0450                             break;
0451                         }
0452 
0453                         case 0x5C: // reverse solidus
0454                         {
0455                             string_buffer[bytes++] = '\\';
0456                             string_buffer[bytes++] = '\\';
0457                             break;
0458                         }
0459 
0460                         default:
0461                         {
0462                             // escape control characters (0x00..0x1F) or, if
0463                             // ensure_ascii parameter is used, non-ASCII characters
0464                             if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
0465                             {
0466                                 if (codepoint <= 0xFFFF)
0467                                 {
0468                                     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
0469                                     static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
0470                                                                       static_cast<std::uint16_t>(codepoint)));
0471                                     bytes += 6;
0472                                 }
0473                                 else
0474                                 {
0475                                     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
0476                                     static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
0477                                                                       static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
0478                                                                       static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
0479                                     bytes += 12;
0480                                 }
0481                             }
0482                             else
0483                             {
0484                                 // copy byte to buffer (all previous bytes
0485                                 // been copied have in default case above)
0486                                 string_buffer[bytes++] = s[i];
0487                             }
0488                             break;
0489                         }
0490                     }
0491 
0492                     // write buffer and reset index; there must be 13 bytes
0493                     // left, as this is the maximal number of bytes to be
0494                     // written ("\uxxxx\uxxxx\0") for one code point
0495                     if (string_buffer.size() - bytes < 13)
0496                     {
0497                         o->write_characters(string_buffer.data(), bytes);
0498                         bytes = 0;
0499                     }
0500 
0501                     // remember the byte position of this accept
0502                     bytes_after_last_accept = bytes;
0503                     undumped_chars = 0;
0504                     break;
0505                 }
0506 
0507                 case UTF8_REJECT:  // decode found invalid UTF-8 byte
0508                 {
0509                     switch (error_handler)
0510                     {
0511                         case error_handler_t::strict:
0512                         {
0513                             JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr));
0514                         }
0515 
0516                         case error_handler_t::ignore:
0517                         case error_handler_t::replace:
0518                         {
0519                             // in case we saw this character the first time, we
0520                             // would like to read it again, because the byte
0521                             // may be OK for itself, but just not OK for the
0522                             // previous sequence
0523                             if (undumped_chars > 0)
0524                             {
0525                                 --i;
0526                             }
0527 
0528                             // reset length buffer to the last accepted index;
0529                             // thus removing/ignoring the invalid characters
0530                             bytes = bytes_after_last_accept;
0531 
0532                             if (error_handler == error_handler_t::replace)
0533                             {
0534                                 // add a replacement character
0535                                 if (ensure_ascii)
0536                                 {
0537                                     string_buffer[bytes++] = '\\';
0538                                     string_buffer[bytes++] = 'u';
0539                                     string_buffer[bytes++] = 'f';
0540                                     string_buffer[bytes++] = 'f';
0541                                     string_buffer[bytes++] = 'f';
0542                                     string_buffer[bytes++] = 'd';
0543                                 }
0544                                 else
0545                                 {
0546                                     string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
0547                                     string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
0548                                     string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
0549                                 }
0550 
0551                                 // write buffer and reset index; there must be 13 bytes
0552                                 // left, as this is the maximal number of bytes to be
0553                                 // written ("\uxxxx\uxxxx\0") for one code point
0554                                 if (string_buffer.size() - bytes < 13)
0555                                 {
0556                                     o->write_characters(string_buffer.data(), bytes);
0557                                     bytes = 0;
0558                                 }
0559 
0560                                 bytes_after_last_accept = bytes;
0561                             }
0562 
0563                             undumped_chars = 0;
0564 
0565                             // continue processing the string
0566                             state = UTF8_ACCEPT;
0567                             break;
0568                         }
0569 
0570                         default:            // LCOV_EXCL_LINE
0571                             JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
0572                     }
0573                     break;
0574                 }
0575 
0576                 default:  // decode found yet incomplete multi-byte code point
0577                 {
0578                     if (!ensure_ascii)
0579                     {
0580                         // code point will not be escaped - copy byte to buffer
0581                         string_buffer[bytes++] = s[i];
0582                     }
0583                     ++undumped_chars;
0584                     break;
0585                 }
0586             }
0587         }
0588 
0589         // we finished processing the string
0590         if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
0591         {
0592             // write buffer
0593             if (bytes > 0)
0594             {
0595                 o->write_characters(string_buffer.data(), bytes);
0596             }
0597         }
0598         else
0599         {
0600             // we finish reading, but do not accept: string was incomplete
0601             switch (error_handler)
0602             {
0603                 case error_handler_t::strict:
0604                 {
0605                     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));
0606                 }
0607 
0608                 case error_handler_t::ignore:
0609                 {
0610                     // write all accepted bytes
0611                     o->write_characters(string_buffer.data(), bytes_after_last_accept);
0612                     break;
0613                 }
0614 
0615                 case error_handler_t::replace:
0616                 {
0617                     // write all accepted bytes
0618                     o->write_characters(string_buffer.data(), bytes_after_last_accept);
0619                     // add a replacement character
0620                     if (ensure_ascii)
0621                     {
0622                         o->write_characters("\\ufffd", 6);
0623                     }
0624                     else
0625                     {
0626                         o->write_characters("\xEF\xBF\xBD", 3);
0627                     }
0628                     break;
0629                 }
0630 
0631                 default:            // LCOV_EXCL_LINE
0632                     JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
0633             }
0634         }
0635     }
0636 
0637   private:
0638     /*!
0639     @brief count digits
0640 
0641     Count the number of decimal (base 10) digits for an input unsigned integer.
0642 
0643     @param[in] x  unsigned integer number to count its digits
0644     @return    number of decimal digits
0645     */
0646     inline unsigned int count_digits(number_unsigned_t x) noexcept
0647     {
0648         unsigned int n_digits = 1;
0649         for (;;)
0650         {
0651             if (x < 10)
0652             {
0653                 return n_digits;
0654             }
0655             if (x < 100)
0656             {
0657                 return n_digits + 1;
0658             }
0659             if (x < 1000)
0660             {
0661                 return n_digits + 2;
0662             }
0663             if (x < 10000)
0664             {
0665                 return n_digits + 3;
0666             }
0667             x = x / 10000u;
0668             n_digits += 4;
0669         }
0670     }
0671 
0672     /*!
0673      * @brief convert a byte to a uppercase hex representation
0674      * @param[in] byte byte to represent
0675      * @return representation ("00".."FF")
0676      */
0677     static std::string hex_bytes(std::uint8_t byte)
0678     {
0679         std::string result = "FF";
0680         constexpr const char* nibble_to_hex = "0123456789ABCDEF";
0681         result[0] = nibble_to_hex[byte / 16];
0682         result[1] = nibble_to_hex[byte % 16];
0683         return result;
0684     }
0685 
0686     // templates to avoid warnings about useless casts
0687     template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
0688     bool is_negative_number(NumberType x)
0689     {
0690         return x < 0;
0691     }
0692 
0693     template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
0694     bool is_negative_number(NumberType /*unused*/)
0695     {
0696         return false;
0697     }
0698 
0699     /*!
0700     @brief dump an integer
0701 
0702     Dump a given integer to output stream @a o. Works internally with
0703     @a number_buffer.
0704 
0705     @param[in] x  integer number (signed or unsigned) to dump
0706     @tparam NumberType either @a number_integer_t or @a number_unsigned_t
0707     */
0708     template < typename NumberType, detail::enable_if_t <
0709                    std::is_integral<NumberType>::value ||
0710                    std::is_same<NumberType, number_unsigned_t>::value ||
0711                    std::is_same<NumberType, number_integer_t>::value ||
0712                    std::is_same<NumberType, binary_char_t>::value,
0713                    int > = 0 >
0714     void dump_integer(NumberType x)
0715     {
0716         static constexpr std::array<std::array<char, 2>, 100> digits_to_99
0717         {
0718             {
0719                 {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
0720                 {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
0721                 {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
0722                 {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
0723                 {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
0724                 {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
0725                 {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
0726                 {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
0727                 {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
0728                 {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
0729             }
0730         };
0731 
0732         // special case for "0"
0733         if (x == 0)
0734         {
0735             o->write_character('0');
0736             return;
0737         }
0738 
0739         // use a pointer to fill the buffer
0740         auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
0741 
0742         number_unsigned_t abs_value;
0743 
0744         unsigned int n_chars{};
0745 
0746         if (is_negative_number(x))
0747         {
0748             *buffer_ptr = '-';
0749             abs_value = remove_sign(static_cast<number_integer_t>(x));
0750 
0751             // account one more byte for the minus sign
0752             n_chars = 1 + count_digits(abs_value);
0753         }
0754         else
0755         {
0756             abs_value = static_cast<number_unsigned_t>(x);
0757             n_chars = count_digits(abs_value);
0758         }
0759 
0760         // spare 1 byte for '\0'
0761         JSON_ASSERT(n_chars < number_buffer.size() - 1);
0762 
0763         // jump to the end to generate the string from backward,
0764         // so we later avoid reversing the result
0765         buffer_ptr += n_chars;
0766 
0767         // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
0768         // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
0769         while (abs_value >= 100)
0770         {
0771             const auto digits_index = static_cast<unsigned>((abs_value % 100));
0772             abs_value /= 100;
0773             *(--buffer_ptr) = digits_to_99[digits_index][1];
0774             *(--buffer_ptr) = digits_to_99[digits_index][0];
0775         }
0776 
0777         if (abs_value >= 10)
0778         {
0779             const auto digits_index = static_cast<unsigned>(abs_value);
0780             *(--buffer_ptr) = digits_to_99[digits_index][1];
0781             *(--buffer_ptr) = digits_to_99[digits_index][0];
0782         }
0783         else
0784         {
0785             *(--buffer_ptr) = static_cast<char>('0' + abs_value);
0786         }
0787 
0788         o->write_characters(number_buffer.data(), n_chars);
0789     }
0790 
0791     /*!
0792     @brief dump a floating-point number
0793 
0794     Dump a given floating-point number to output stream @a o. Works internally
0795     with @a number_buffer.
0796 
0797     @param[in] x  floating-point number to dump
0798     */
0799     void dump_float(number_float_t x)
0800     {
0801         // NaN / inf
0802         if (!std::isfinite(x))
0803         {
0804             o->write_characters("null", 4);
0805             return;
0806         }
0807 
0808         // If number_float_t is an IEEE-754 single or double precision number,
0809         // use the Grisu2 algorithm to produce short numbers which are
0810         // guaranteed to round-trip, using strtof and strtod, resp.
0811         //
0812         // NB: The test below works if <long double> == <double>.
0813         static constexpr bool is_ieee_single_or_double
0814             = (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) ||
0815               (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);
0816 
0817         dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
0818     }
0819 
0820     void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
0821     {
0822         auto* begin = number_buffer.data();
0823         auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
0824 
0825         o->write_characters(begin, static_cast<size_t>(end - begin));
0826     }
0827 
0828     void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
0829     {
0830         // get number of digits for a float -> text -> float round-trip
0831         static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
0832 
0833         // the actual conversion
0834         // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
0835         std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
0836 
0837         // negative value indicates an error
0838         JSON_ASSERT(len > 0);
0839         // check if buffer was large enough
0840         JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
0841 
0842         // erase thousands separator
0843         if (thousands_sep != '\0')
0844         {
0845             // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
0846             const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
0847             std::fill(end, number_buffer.end(), '\0');
0848             JSON_ASSERT((end - number_buffer.begin()) <= len);
0849             len = (end - number_buffer.begin());
0850         }
0851 
0852         // convert decimal point to '.'
0853         if (decimal_point != '\0' && decimal_point != '.')
0854         {
0855             // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
0856             const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
0857             if (dec_pos != number_buffer.end())
0858             {
0859                 *dec_pos = '.';
0860             }
0861         }
0862 
0863         o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
0864 
0865         // determine if we need to append ".0"
0866         const bool value_is_int_like =
0867             std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
0868                          [](char c)
0869         {
0870             return c == '.' || c == 'e';
0871         });
0872 
0873         if (value_is_int_like)
0874         {
0875             o->write_characters(".0", 2);
0876         }
0877     }
0878 
0879     /*!
0880     @brief check whether a string is UTF-8 encoded
0881 
0882     The function checks each byte of a string whether it is UTF-8 encoded. The
0883     result of the check is stored in the @a state parameter. The function must
0884     be called initially with state 0 (accept). State 1 means the string must
0885     be rejected, because the current byte is not allowed. If the string is
0886     completely processed, but the state is non-zero, the string ended
0887     prematurely; that is, the last byte indicated more bytes should have
0888     followed.
0889 
0890     @param[in,out] state  the state of the decoding
0891     @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)
0892     @param[in] byte       next byte to decode
0893     @return               new state
0894 
0895     @note The function has been edited: a std::array is used.
0896 
0897     @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
0898     @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
0899     */
0900     static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
0901     {
0902         static const std::array<std::uint8_t, 400> utf8d =
0903         {
0904             {
0905                 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
0906                 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
0907                 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
0908                 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
0909                 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
0910                 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
0911                 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
0912                 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
0913                 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
0914                 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
0915                 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
0916                 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
0917                 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
0918                 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
0919             }
0920         };
0921 
0922         JSON_ASSERT(byte < utf8d.size());
0923         const std::uint8_t type = utf8d[byte];
0924 
0925         codep = (state != UTF8_ACCEPT)
0926                 ? (byte & 0x3fu) | (codep << 6u)
0927                 : (0xFFu >> type) & (byte);
0928 
0929         std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
0930         JSON_ASSERT(index < 400);
0931         state = utf8d[index];
0932         return state;
0933     }
0934 
0935     /*
0936      * Overload to make the compiler happy while it is instantiating
0937      * dump_integer for number_unsigned_t.
0938      * Must never be called.
0939      */
0940     number_unsigned_t remove_sign(number_unsigned_t x)
0941     {
0942         JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
0943         return x; // LCOV_EXCL_LINE
0944     }
0945 
0946     /*
0947      * Helper function for dump_integer
0948      *
0949      * This function takes a negative signed integer and returns its absolute
0950      * value as unsigned integer. The plus/minus shuffling is necessary as we can
0951      * not directly remove the sign of an arbitrary signed integer as the
0952      * absolute values of INT_MIN and INT_MAX are usually not the same. See
0953      * #1708 for details.
0954      */
0955     inline number_unsigned_t remove_sign(number_integer_t x) noexcept
0956     {
0957         JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)
0958         return static_cast<number_unsigned_t>(-(x + 1)) + 1;
0959     }
0960 
0961   private:
0962     /// the output of the serializer
0963     output_adapter_t<char> o = nullptr;
0964 
0965     /// a (hopefully) large enough character buffer
0966     std::array<char, 64> number_buffer{{}};
0967 
0968     /// the locale
0969     const std::lconv* loc = nullptr;
0970     /// the locale's thousand separator character
0971     const char thousands_sep = '\0';
0972     /// the locale's decimal point character
0973     const char decimal_point = '\0';
0974 
0975     /// string buffer
0976     std::array<char, 512> string_buffer{{}};
0977 
0978     /// the indentation character
0979     const char indent_char;
0980     /// the indentation string
0981     string_t indent_string;
0982 
0983     /// error_handler how to react on decoding errors
0984     const error_handler_t error_handler;
0985 };
0986 
0987 }  // namespace detail
0988 NLOHMANN_JSON_NAMESPACE_END