17 #include <type_traits>
19 #include <nlohmann/detail/exceptions.hpp>
20 #include <nlohmann/detail/conversions/to_chars.hpp>
21 #include <nlohmann/detail/macro_scope.hpp>
22 #include <nlohmann/detail/meta.hpp>
23 #include <nlohmann/detail/output/output_adapters.hpp>
24 #include <nlohmann/detail/value_t.hpp>
34 template<
typename BasicJsonType>
37 using string_t =
typename BasicJsonType::string_t;
38 using number_float_t =
typename BasicJsonType::number_float_t;
39 using number_integer_t =
typename BasicJsonType::number_integer_t;
40 using number_unsigned_t =
typename BasicJsonType::number_unsigned_t;
41 static constexpr
uint8_t UTF8_ACCEPT = 0;
42 static constexpr
uint8_t UTF8_REJECT = 1;
50 : o(std::move(s)), loc(std::localeconv()),
51 thousands_sep(loc->thousands_sep == nullptr ?
'\0' : * (loc->thousands_sep)),
52 decimal_point(loc->decimal_point == nullptr ?
'\0' : * (loc->decimal_point)),
53 indent_char(ichar), indent_string(512, indent_char)
77 void dump(
const BasicJsonType& val,
const bool pretty_print,
78 const bool ensure_ascii,
79 const unsigned int indent_step,
80 const unsigned int current_indent = 0)
86 if (val.m_value.object->empty())
88 o->write_characters(
"{}", 2);
94 o->write_characters(
"{\n", 2);
97 const auto new_indent = current_indent + indent_step;
98 if (JSON_UNLIKELY(indent_string.size() < new_indent))
100 indent_string.resize(indent_string.size() * 2,
' ');
104 auto i = val.m_value.object->cbegin();
105 for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
107 o->write_characters(indent_string.c_str(), new_indent);
108 o->write_character(
'\"');
109 dump_escaped(i->first, ensure_ascii);
110 o->write_characters(
"\": ", 3);
111 dump(i->second,
true, ensure_ascii, indent_step, new_indent);
112 o->write_characters(
",\n", 2);
116 assert(i != val.m_value.object->cend());
117 assert(std::next(i) == val.m_value.object->cend());
118 o->write_characters(indent_string.c_str(), new_indent);
119 o->write_character(
'\"');
120 dump_escaped(i->first, ensure_ascii);
121 o->write_characters(
"\": ", 3);
122 dump(i->second,
true, ensure_ascii, indent_step, new_indent);
124 o->write_character(
'\n');
125 o->write_characters(indent_string.c_str(), current_indent);
126 o->write_character(
'}');
130 o->write_character(
'{');
133 auto i = val.m_value.object->cbegin();
134 for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
136 o->write_character(
'\"');
137 dump_escaped(i->first, ensure_ascii);
138 o->write_characters(
"\":", 2);
139 dump(i->second,
false, ensure_ascii, indent_step, current_indent);
140 o->write_character(
',');
144 assert(i != val.m_value.object->cend());
145 assert(std::next(i) == val.m_value.object->cend());
146 o->write_character(
'\"');
147 dump_escaped(i->first, ensure_ascii);
148 o->write_characters(
"\":", 2);
149 dump(i->second,
false, ensure_ascii, indent_step, current_indent);
151 o->write_character(
'}');
159 if (val.m_value.array->empty())
161 o->write_characters(
"[]", 2);
167 o->write_characters(
"[\n", 2);
170 const auto new_indent = current_indent + indent_step;
171 if (JSON_UNLIKELY(indent_string.size() < new_indent))
173 indent_string.resize(indent_string.size() * 2,
' ');
177 for (
auto i = val.m_value.array->cbegin();
178 i != val.m_value.array->cend() - 1; ++i)
180 o->write_characters(indent_string.c_str(), new_indent);
181 dump(*i,
true, ensure_ascii, indent_step, new_indent);
182 o->write_characters(
",\n", 2);
186 assert(not val.m_value.array->empty());
187 o->write_characters(indent_string.c_str(), new_indent);
188 dump(val.m_value.array->back(),
true, ensure_ascii, indent_step, new_indent);
190 o->write_character(
'\n');
191 o->write_characters(indent_string.c_str(), current_indent);
192 o->write_character(
']');
196 o->write_character(
'[');
199 for (
auto i = val.m_value.array->cbegin();
200 i != val.m_value.array->cend() - 1; ++i)
202 dump(*i,
false, ensure_ascii, indent_step, current_indent);
203 o->write_character(
',');
207 assert(not val.m_value.array->empty());
208 dump(val.m_value.array->back(),
false, ensure_ascii, indent_step, current_indent);
210 o->write_character(
']');
218 o->write_character(
'\"');
219 dump_escaped(*val.m_value.string, ensure_ascii);
220 o->write_character(
'\"');
226 if (val.m_value.boolean)
228 o->write_characters(
"true", 4);
232 o->write_characters(
"false", 5);
239 dump_integer(val.m_value.number_integer);
245 dump_integer(val.m_value.number_unsigned);
251 dump_float(val.m_value.number_float);
257 o->write_characters(
"<discarded>", 11);
263 o->write_characters(
"null", 4);
284 void dump_escaped(
const string_t& s,
const bool ensure_ascii)
288 std::size_t bytes = 0;
290 for (std::size_t i = 0; i < s.size(); ++i)
292 const auto byte = static_cast<uint8_t>(s[i]);
294 switch (decode(state, codepoint,
byte))
302 string_buffer[bytes++] =
'\\';
303 string_buffer[bytes++] =
'b';
309 string_buffer[bytes++] =
'\\';
310 string_buffer[bytes++] =
't';
316 string_buffer[bytes++] =
'\\';
317 string_buffer[bytes++] =
'n';
323 string_buffer[bytes++] =
'\\';
324 string_buffer[bytes++] =
'f';
330 string_buffer[bytes++] =
'\\';
331 string_buffer[bytes++] =
'r';
337 string_buffer[bytes++] =
'\\';
338 string_buffer[bytes++] =
'\"';
344 string_buffer[bytes++] =
'\\';
345 string_buffer[bytes++] =
'\\';
353 if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))
355 if (codepoint <= 0xFFFF)
357 std::snprintf(string_buffer.data() + bytes, 7,
"\\u%04x",
358 static_cast<uint16_t>(codepoint));
363 std::snprintf(string_buffer.data() + bytes, 13,
"\\u%04x\\u%04x",
364 static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),
365 static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));
373 string_buffer[bytes++] = s[i];
382 if (string_buffer.size() - bytes < 13)
384 o->write_characters(string_buffer.data(), bytes);
392 std::stringstream ss;
393 ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(
byte);
394 JSON_THROW(type_error::create(316,
"invalid UTF-8 byte at index " + std::to_string(i) +
": 0x" + ss.str()));
399 if (not ensure_ascii)
402 string_buffer[bytes++] = s[i];
409 if (JSON_LIKELY(state == UTF8_ACCEPT))
414 o->write_characters(string_buffer.data(), bytes);
420 std::stringstream ss;
421 ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(static_cast<uint8_t>(s.back()));
422 JSON_THROW(type_error::create(316,
"incomplete UTF-8 string; last byte: 0x" + ss.str()));
435 template<
typename NumberType, detail::enable_if_t<
436 std::is_same<NumberType, number_unsigned_t>::value or
437 std::is_same<NumberType, number_integer_t>::value,
439 void dump_integer(NumberType x)
444 o->write_character(
'0');
448 const bool is_negative = (x <= 0) and (x != 0);
454 assert(i < number_buffer.size() - 1);
456 const auto digit = std::labs(static_cast<long>(x % 10));
457 number_buffer[i++] = static_cast<char>(
'0' + digit);
464 assert(i < number_buffer.size() - 2);
465 number_buffer[i++] =
'-';
468 std::reverse(number_buffer.begin(), number_buffer.begin() + i);
469 o->write_characters(number_buffer.data(), i);
480 void dump_float(number_float_t x)
483 if (not std::isfinite(x))
485 o->write_characters(
"null", 4);
494 static constexpr
bool is_ieee_single_or_double
495 = (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or
496 (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);
498 dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
501 void dump_float(number_float_t x, std::true_type )
503 char* begin = number_buffer.data();
504 char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
506 o->write_characters(begin, static_cast<size_t>(end - begin));
509 void dump_float(number_float_t x, std::false_type )
512 static constexpr
auto d = std::numeric_limits<number_float_t>::max_digits10;
515 std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(),
"%.*g", d, x);
520 assert(static_cast<std::size_t>(len) < number_buffer.size());
523 if (thousands_sep !=
'\0')
525 const auto end = std::remove(number_buffer.begin(),
526 number_buffer.begin() + len, thousands_sep);
527 std::fill(end, number_buffer.end(),
'\0');
528 assert((end - number_buffer.begin()) <= len);
529 len = (end - number_buffer.begin());
533 if (decimal_point !=
'\0' and decimal_point !=
'.')
535 const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
536 if (dec_pos != number_buffer.end())
542 o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
545 const bool value_is_int_like =
546 std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
549 return (c ==
'.' or c ==
'e');
552 if (value_is_int_like)
554 o->write_characters(
".0", 2);
581 static const std::array<uint8_t, 400> utf8d =
584 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,
585 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,
586 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,
587 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,
588 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,
589 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,
590 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,
591 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3,
592 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,
593 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1,
594 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,
595 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,
596 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,
597 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
601 const uint8_t type = utf8d[byte];
603 codep = (state != UTF8_ACCEPT)
604 ? (
byte & 0x3fu) | (codep << 6)
605 : static_cast<uint32_t>(0xff >> type) & (byte);
607 state = utf8d[256u + state * 16u + type];
613 output_adapter_t<char> o =
nullptr;
616 std::array<char, 64> number_buffer{{}};
619 const std::lconv* loc =
nullptr;
621 const char thousands_sep =
'\0';
623 const char decimal_point =
'\0';
626 std::array<char, 512> string_buffer{{}};
629 const char indent_char;
631 string_t indent_string;