12 #include <type_traits>
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>
39 template<
typename BasicJsonType>
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;
59 ,
loc(std::localeconv())
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)
106 if (val.m_value.object->empty())
108 o->write_characters(
"{}", 2);
114 o->write_characters(
"{\n", 2);
117 const auto new_indent = current_indent + indent_step;
124 auto i = val.m_value.object->cbegin();
125 for (
std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
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);
136 JSON_ASSERT(i != val.m_value.object->cend());
137 JSON_ASSERT(std::next(i) == val.m_value.object->cend());
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);
144 o->write_character(
'\n');
146 o->write_character(
'}');
150 o->write_character(
'{');
153 auto i = val.m_value.object->cbegin();
154 for (
std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
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(
',');
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);
171 o->write_character(
'}');
179 if (val.m_value.array->empty())
181 o->write_characters(
"[]", 2);
187 o->write_characters(
"[\n", 2);
190 const auto new_indent = current_indent + indent_step;
197 for (
auto i = val.m_value.array->cbegin();
198 i != val.m_value.array->cend() - 1; ++i)
201 dump(*i,
true, ensure_ascii, indent_step, new_indent);
202 o->write_characters(
",\n", 2);
206 JSON_ASSERT(!val.m_value.array->empty());
208 dump(val.m_value.array->back(),
true, ensure_ascii, indent_step, new_indent);
210 o->write_character(
'\n');
212 o->write_character(
']');
216 o->write_character(
'[');
219 for (
auto i = val.m_value.array->cbegin();
220 i != val.m_value.array->cend() - 1; ++i)
222 dump(*i,
false, ensure_ascii, indent_step, current_indent);
223 o->write_character(
',');
227 JSON_ASSERT(!val.m_value.array->empty());
228 dump(val.m_value.array->back(),
false, ensure_ascii, indent_step, current_indent);
230 o->write_character(
']');
238 o->write_character(
'\"');
239 dump_escaped(*val.m_value.string, ensure_ascii);
240 o->write_character(
'\"');
248 o->write_characters(
"{\n", 2);
251 const auto new_indent = current_indent + indent_step;
259 o->write_characters(
"\"bytes\": [", 10);
261 if (!val.m_value.binary->empty())
263 for (
auto i = val.m_value.binary->cbegin();
264 i != val.m_value.binary->cend() - 1; ++i)
267 o->write_characters(
", ", 2);
269 dump_integer(val.m_value.binary->back());
272 o->write_characters(
"],\n", 3);
275 o->write_characters(
"\"subtype\": ", 11);
276 if (val.m_value.binary->has_subtype())
278 dump_integer(val.m_value.binary->subtype());
282 o->write_characters(
"null", 4);
284 o->write_character(
'\n');
286 o->write_character(
'}');
290 o->write_characters(
"{\"bytes\":[", 10);
292 if (!val.m_value.binary->empty())
294 for (
auto i = val.m_value.binary->cbegin();
295 i != val.m_value.binary->cend() - 1; ++i)
298 o->write_character(
',');
300 dump_integer(val.m_value.binary->back());
303 o->write_characters(
"],\"subtype\":", 12);
304 if (val.m_value.binary->has_subtype())
306 dump_integer(val.m_value.binary->subtype());
307 o->write_character(
'}');
311 o->write_characters(
"null}", 5);
319 if (val.m_value.boolean)
321 o->write_characters(
"true", 4);
325 o->write_characters(
"false", 5);
332 dump_integer(val.m_value.number_integer);
338 dump_integer(val.m_value.number_unsigned);
344 dump_float(val.m_value.number_float);
350 o->write_characters(
"<discarded>", 11);
356 o->write_characters(
"null", 4);
365 JSON_PRIVATE_UNLESS_TESTED:
380 void dump_escaped(
const string_t& s,
const bool ensure_ascii)
382 std::uint32_t codepoint{};
383 std::uint8_t state = UTF8_ACCEPT;
392 const auto byte =
static_cast<std::uint8_t
>(s[i]);
394 switch (decode(state, codepoint,
byte))
453 if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
455 if (codepoint <= 0xFFFF)
459 static_cast<std::uint16_t
>(codepoint));
465 (std::snprintf)(
string_buffer.data() + bytes, 13,
"\\u%04x\\u%04x",
466 static_cast<std::uint16_t
>(0xD7C0u + (codepoint >> 10u)),
467 static_cast<std::uint16_t
>(0xDC00u + (codepoint & 0x3FFu)));
491 bytes_after_last_accept = bytes;
502 std::string sn(9,
'\0');
504 (std::snprintf)(&sn[0], sn.size(),
"%.2X", byte);
505 JSON_THROW(type_error::create(316,
"invalid UTF-8 byte at index " + std::to_string(i) +
": 0x" + sn, BasicJsonType()));
515 if (undumped_chars > 0)
522 bytes = bytes_after_last_accept;
538 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type(
'\xEF');
539 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type(
'\xBF');
540 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type(
'\xBD');
552 bytes_after_last_accept = bytes;
582 if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
597 std::string sn(9,
'\0');
599 (std::snprintf)(&sn[0], sn.size(),
"%.2X",
static_cast<std::uint8_t
>(s.back()));
600 JSON_THROW(type_error::create(316,
"incomplete UTF-8 string; last byte: 0x" + sn, BasicJsonType()));
606 o->write_characters(
string_buffer.data(), bytes_after_last_accept);
613 o->write_characters(
string_buffer.data(), bytes_after_last_accept);
617 o->write_characters(
"\\ufffd", 6);
621 o->write_characters(
"\xEF\xBF\xBD", 3);
641 inline unsigned int count_digits(number_unsigned_t x) noexcept
643 unsigned int n_digits = 1;
676 template <
typename NumberType, detail::enable_if_t <
677 std::is_integral<NumberType>::value ||
678 std::is_same<NumberType, number_unsigned_t>::value ||
679 std::is_same<NumberType, number_integer_t>::value ||
680 std::is_same<NumberType, binary_char_t>::value,
682 void dump_integer(NumberType x)
684 static constexpr std::array<std::array<char, 2>, 100> digits_to_99
687 {{
'0',
'0'}}, {{
'0',
'1'}}, {{
'0',
'2'}}, {{
'0',
'3'}}, {{
'0',
'4'}}, {{
'0',
'5'}}, {{
'0',
'6'}}, {{
'0',
'7'}}, {{
'0',
'8'}}, {{
'0',
'9'}},
688 {{
'1',
'0'}}, {{
'1',
'1'}}, {{
'1',
'2'}}, {{
'1',
'3'}}, {{
'1',
'4'}}, {{
'1',
'5'}}, {{
'1',
'6'}}, {{
'1',
'7'}}, {{
'1',
'8'}}, {{
'1',
'9'}},
689 {{
'2',
'0'}}, {{
'2',
'1'}}, {{
'2',
'2'}}, {{
'2',
'3'}}, {{
'2',
'4'}}, {{
'2',
'5'}}, {{
'2',
'6'}}, {{
'2',
'7'}}, {{
'2',
'8'}}, {{
'2',
'9'}},
690 {{
'3',
'0'}}, {{
'3',
'1'}}, {{
'3',
'2'}}, {{
'3',
'3'}}, {{
'3',
'4'}}, {{
'3',
'5'}}, {{
'3',
'6'}}, {{
'3',
'7'}}, {{
'3',
'8'}}, {{
'3',
'9'}},
691 {{
'4',
'0'}}, {{
'4',
'1'}}, {{
'4',
'2'}}, {{
'4',
'3'}}, {{
'4',
'4'}}, {{
'4',
'5'}}, {{
'4',
'6'}}, {{
'4',
'7'}}, {{
'4',
'8'}}, {{
'4',
'9'}},
692 {{
'5',
'0'}}, {{
'5',
'1'}}, {{
'5',
'2'}}, {{
'5',
'3'}}, {{
'5',
'4'}}, {{
'5',
'5'}}, {{
'5',
'6'}}, {{
'5',
'7'}}, {{
'5',
'8'}}, {{
'5',
'9'}},
693 {{
'6',
'0'}}, {{
'6',
'1'}}, {{
'6',
'2'}}, {{
'6',
'3'}}, {{
'6',
'4'}}, {{
'6',
'5'}}, {{
'6',
'6'}}, {{
'6',
'7'}}, {{
'6',
'8'}}, {{
'6',
'9'}},
694 {{
'7',
'0'}}, {{
'7',
'1'}}, {{
'7',
'2'}}, {{
'7',
'3'}}, {{
'7',
'4'}}, {{
'7',
'5'}}, {{
'7',
'6'}}, {{
'7',
'7'}}, {{
'7',
'8'}}, {{
'7',
'9'}},
695 {{
'8',
'0'}}, {{
'8',
'1'}}, {{
'8',
'2'}}, {{
'8',
'3'}}, {{
'8',
'4'}}, {{
'8',
'5'}}, {{
'8',
'6'}}, {{
'8',
'7'}}, {{
'8',
'8'}}, {{
'8',
'9'}},
696 {{
'9',
'0'}}, {{
'9',
'1'}}, {{
'9',
'2'}}, {{
'9',
'3'}}, {{
'9',
'4'}}, {{
'9',
'5'}}, {{
'9',
'6'}}, {{
'9',
'7'}}, {{
'9',
'8'}}, {{
'9',
'9'}},
703 o->write_character(
'0');
710 const bool is_negative = std::is_signed<NumberType>::value && !(x >= 0);
711 number_unsigned_t abs_value;
713 unsigned int n_chars{};
718 abs_value = remove_sign(
static_cast<number_integer_t
>(x));
721 n_chars = 1 + count_digits(abs_value);
725 abs_value =
static_cast<number_unsigned_t
>(x);
726 n_chars = count_digits(abs_value);
734 buffer_ptr += n_chars;
738 while (abs_value >= 100)
740 const auto digits_index =
static_cast<unsigned>((abs_value % 100));
742 *(--buffer_ptr) = digits_to_99[digits_index][1];
743 *(--buffer_ptr) = digits_to_99[digits_index][0];
748 const auto digits_index =
static_cast<unsigned>(abs_value);
749 *(--buffer_ptr) = digits_to_99[digits_index][1];
750 *(--buffer_ptr) = digits_to_99[digits_index][0];
754 *(--buffer_ptr) =
static_cast<char>(
'0' + abs_value);
768 void dump_float(number_float_t x)
771 if (!std::isfinite(x))
773 o->write_characters(
"null", 4);
782 static constexpr
bool is_ieee_single_or_double
783 = (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) ||
784 (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);
786 dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
789 void dump_float(number_float_t x, std::true_type )
792 auto* end = ::nlohmann::detail::to_chars(begin, begin +
number_buffer.size(), x);
794 o->write_characters(begin,
static_cast<size_t>(end - begin));
797 void dump_float(number_float_t x, std::false_type )
800 static constexpr
auto d = std::numeric_limits<number_float_t>::max_digits10;
807 JSON_ASSERT(len > 0);
834 const bool value_is_int_like =
838 return c ==
'.' || c ==
'e';
841 if (value_is_int_like)
843 o->write_characters(
".0", 2);
868 static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep,
const std::uint8_t
byte) noexcept
870 static const std::array<std::uint8_t, 400> utf8d =
873 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,
874 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,
875 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,
876 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,
877 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,
878 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,
879 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,
880 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3,
881 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,
882 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1,
883 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,
884 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,
885 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,
886 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
890 JSON_ASSERT(
byte < utf8d.size());
891 const std::uint8_t
type = utf8d[byte];
893 codep = (state != UTF8_ACCEPT)
894 ? (
byte & 0x3fu) | (codep << 6u)
895 : (0xFFu >> type) & (byte);
897 std::size_t index = 256u +
static_cast<size_t>(state) * 16u +
static_cast<size_t>(type);
898 JSON_ASSERT(index < 400);
899 state = utf8d[index];
908 number_unsigned_t remove_sign(number_unsigned_t x)
923 inline number_unsigned_t remove_sign(number_integer_t x) noexcept
925 JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());
926 return static_cast<number_unsigned_t
>(-(x + 1)) + 1;
931 output_adapter_t<char> o =
nullptr;
937 const std::lconv*
loc =
nullptr;
Definition: serializer.hpp:41
const error_handler_t error_handler
error_handler how to react on decoding errors
Definition: serializer.hpp:952
const std::lconv * loc
the locale
Definition: serializer.hpp:937
std::array< char, 64 > number_buffer
a (hopefully) large enough character buffer
Definition: serializer.hpp:934
const char decimal_point
the locale's decimal point character
Definition: serializer.hpp:941
const char thousands_sep
the locale's thousand separator character
Definition: serializer.hpp:939
void dump(const BasicJsonType &val, const bool pretty_print, const bool ensure_ascii, const unsigned int indent_step, const unsigned int current_indent=0)
internal implementation of the serialization function
Definition: serializer.hpp:96
const char indent_char
the indentation character
Definition: serializer.hpp:947
std::array< char, 512 > string_buffer
string buffer
Definition: serializer.hpp:944
serializer(output_adapter_t< char > s, const char ichar, error_handler_t error_handler_=error_handler_t::strict)
Definition: serializer.hpp:56
string_t indent_string
the indentation string
Definition: serializer.hpp:949
CPP_concept type
\concept type
Definition: concepts.hpp:838
std::integral_constant< std::size_t, N > size_t
An integral constant wrapper for std::size_t.
Definition: meta.hpp:163
empty< find_if< L, Fn > > none_of
A Boolean integral constant wrapper around true if invoke<Fn, A>::value is false for all elements A i...
Definition: meta.hpp:3063
drop< L, min< find_index< L, T >, size< L > >> find
Return the tail of the list L starting at the first occurrence of T, if any such element exists; the ...
Definition: meta.hpp:2388
@ number_integer
number value (signed integer)
@ discarded
discarded by the parser callback function
@ binary
binary array (ordered collection of bytes)
@ object
object (unordered set of name/value pairs)
@ number_float
number value (floating-point)
@ number_unsigned
number value (unsigned integer)
@ array
array (ordered collection of values)
error_handler_t
how to treat decoding errors
Definition: serializer.hpp:33
@ strict
throw a type_error exception in case of invalid UTF-8
@ ignore
ignore invalid UTF-8 sequences
@ replace
replace invalid UTF-8 sequences with U+FFFD
std::shared_ptr< output_adapter_protocol< CharType > > output_adapter_t
a type to simplify interfaces
Definition: output_adapters.hpp:37
namespace for Niels Lohmann
Definition: adl_serializer.hpp:12