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