templatized output adapters

This commit is contained in:
Francois Chabot 2020-06-05 16:15:36 -04:00
parent 7444c7fa25
commit bf55a999c5
7 changed files with 651 additions and 608 deletions

View File

@ -23,11 +23,13 @@ namespace detail
/*! /*!
@brief serialization to CBOR and MessagePack values @brief serialization to CBOR and MessagePack values
*/ */
template<typename BasicJsonType, typename CharType> template<typename BasicJsonType, typename OutputAdapterType>
class binary_writer class binary_writer
{ {
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t; using binary_t = typename BasicJsonType::binary_t;
using output_adapter_t = OutputAdapterType;
using CharType = typename OutputAdapterType::char_type;
public: public:
/*! /*!
@ -35,10 +37,8 @@ class binary_writer
@param[in] adapter output adapter to write to @param[in] adapter output adapter to write to
*/ */
explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter) explicit binary_writer(OutputAdapterType adapter) : oa(std::move(adapter))
{ {}
assert(oa);
}
/*! /*!
@param[in] j JSON value to serialize @param[in] j JSON value to serialize
@ -70,15 +70,15 @@ class binary_writer
{ {
case value_t::null: case value_t::null:
{ {
oa->write_character(to_char_type(0xF6)); oa.write_character(to_char_type(0xF6));
break; break;
} }
case value_t::boolean: case value_t::boolean:
{ {
oa->write_character(j.m_value.boolean oa.write_character(j.m_value.boolean
? to_char_type(0xF5) ? to_char_type(0xF5)
: to_char_type(0xF4)); : to_char_type(0xF4));
break; break;
} }
@ -95,22 +95,22 @@ class binary_writer
} }
else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x18)); oa.write_character(to_char_type(0x18));
write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x19)); oa.write_character(to_char_type(0x19));
write_number(static_cast<std::uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x1A)); oa.write_character(to_char_type(0x1A));
write_number(static_cast<std::uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else else
{ {
oa->write_character(to_char_type(0x1B)); oa.write_character(to_char_type(0x1B));
write_number(static_cast<std::uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
} }
@ -125,22 +125,22 @@ class binary_writer
} }
else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x38)); oa.write_character(to_char_type(0x38));
write_number(static_cast<std::uint8_t>(positive_number)); write_number(static_cast<std::uint8_t>(positive_number));
} }
else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x39)); oa.write_character(to_char_type(0x39));
write_number(static_cast<std::uint16_t>(positive_number)); write_number(static_cast<std::uint16_t>(positive_number));
} }
else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x3A)); oa.write_character(to_char_type(0x3A));
write_number(static_cast<std::uint32_t>(positive_number)); write_number(static_cast<std::uint32_t>(positive_number));
} }
else else
{ {
oa->write_character(to_char_type(0x3B)); oa.write_character(to_char_type(0x3B));
write_number(static_cast<std::uint64_t>(positive_number)); write_number(static_cast<std::uint64_t>(positive_number));
} }
} }
@ -155,22 +155,22 @@ class binary_writer
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x18)); oa.write_character(to_char_type(0x18));
write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x19)); oa.write_character(to_char_type(0x19));
write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x1A)); oa.write_character(to_char_type(0x1A));
write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
} }
else else
{ {
oa->write_character(to_char_type(0x1B)); oa.write_character(to_char_type(0x1B));
write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
} }
break; break;
@ -181,16 +181,16 @@ class binary_writer
if (std::isnan(j.m_value.number_float)) if (std::isnan(j.m_value.number_float))
{ {
// NaN is 0xf97e00 in CBOR // NaN is 0xf97e00 in CBOR
oa->write_character(to_char_type(0xF9)); oa.write_character(to_char_type(0xF9));
oa->write_character(to_char_type(0x7E)); oa.write_character(to_char_type(0x7E));
oa->write_character(to_char_type(0x00)); oa.write_character(to_char_type(0x00));
} }
else if (std::isinf(j.m_value.number_float)) else if (std::isinf(j.m_value.number_float))
{ {
// Infinity is 0xf97c00, -Infinity is 0xf9fc00 // Infinity is 0xf97c00, -Infinity is 0xf9fc00
oa->write_character(to_char_type(0xf9)); oa.write_character(to_char_type(0xf9));
oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); oa.write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
oa->write_character(to_char_type(0x00)); oa.write_character(to_char_type(0x00));
} }
else else
{ {
@ -198,12 +198,12 @@ class binary_writer
static_cast<double>(j.m_value.number_float) <= static_cast<double>((std::numeric_limits<float>::max)()) and static_cast<double>(j.m_value.number_float) <= static_cast<double>((std::numeric_limits<float>::max)()) and
static_cast<double>(static_cast<float>(j.m_value.number_float)) == static_cast<double>(j.m_value.number_float)) static_cast<double>(static_cast<float>(j.m_value.number_float)) == static_cast<double>(j.m_value.number_float))
{ {
oa->write_character(get_cbor_float_prefix(static_cast<float>(j.m_value.number_float))); oa.write_character(get_cbor_float_prefix(static_cast<float>(j.m_value.number_float)));
write_number(static_cast<float>(j.m_value.number_float)); write_number(static_cast<float>(j.m_value.number_float));
} }
else else
{ {
oa->write_character(get_cbor_float_prefix(j.m_value.number_float)); oa.write_character(get_cbor_float_prefix(j.m_value.number_float));
write_number(j.m_value.number_float); write_number(j.m_value.number_float);
} }
} }
@ -220,29 +220,29 @@ class binary_writer
} }
else if (N <= (std::numeric_limits<std::uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x78)); oa.write_character(to_char_type(0x78));
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x79)); oa.write_character(to_char_type(0x79));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x7A)); oa.write_character(to_char_type(0x7A));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<std::uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0x7B)); oa.write_character(to_char_type(0x7B));
write_number(static_cast<std::uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
// step 2: write the string // step 2: write the string
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_value.string->c_str()), reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
j.m_value.string->size()); j.m_value.string->size());
break; break;
@ -258,23 +258,23 @@ class binary_writer
} }
else if (N <= (std::numeric_limits<std::uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x98)); oa.write_character(to_char_type(0x98));
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x99)); oa.write_character(to_char_type(0x99));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x9A)); oa.write_character(to_char_type(0x9A));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<std::uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0x9B)); oa.write_character(to_char_type(0x9B));
write_number(static_cast<std::uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -297,29 +297,29 @@ class binary_writer
} }
else if (N <= (std::numeric_limits<std::uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x58)); oa.write_character(to_char_type(0x58));
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x59)); oa.write_character(to_char_type(0x59));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x5A)); oa.write_character(to_char_type(0x5A));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<std::uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0x5B)); oa.write_character(to_char_type(0x5B));
write_number(static_cast<std::uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
// step 2: write each element // step 2: write each element
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_value.binary->data()), reinterpret_cast<const CharType*>(j.m_value.binary->data()),
N); N);
@ -336,23 +336,23 @@ class binary_writer
} }
else if (N <= (std::numeric_limits<std::uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0xB8)); oa.write_character(to_char_type(0xB8));
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0xB9)); oa.write_character(to_char_type(0xB9));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0xBA)); oa.write_character(to_char_type(0xBA));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<std::uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0xBB)); oa.write_character(to_char_type(0xBB));
write_number(static_cast<std::uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -380,15 +380,15 @@ class binary_writer
{ {
case value_t::null: // nil case value_t::null: // nil
{ {
oa->write_character(to_char_type(0xC0)); oa.write_character(to_char_type(0xC0));
break; break;
} }
case value_t::boolean: // true and false case value_t::boolean: // true and false
{ {
oa->write_character(j.m_value.boolean oa.write_character(j.m_value.boolean
? to_char_type(0xC3) ? to_char_type(0xC3)
: to_char_type(0xC2)); : to_char_type(0xC2));
break; break;
} }
@ -407,25 +407,25 @@ class binary_writer
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(to_char_type(0xCC)); oa.write_character(to_char_type(0xCC));
write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(to_char_type(0xCD)); oa.write_character(to_char_type(0xCD));
write_number(static_cast<std::uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(to_char_type(0xCE)); oa.write_character(to_char_type(0xCE));
write_number(static_cast<std::uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(to_char_type(0xCF)); oa.write_character(to_char_type(0xCF));
write_number(static_cast<std::uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
} }
@ -440,28 +440,28 @@ class binary_writer
j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{ {
// int 8 // int 8
oa->write_character(to_char_type(0xD0)); oa.write_character(to_char_type(0xD0));
write_number(static_cast<std::int8_t>(j.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{ {
// int 16 // int 16
oa->write_character(to_char_type(0xD1)); oa.write_character(to_char_type(0xD1));
write_number(static_cast<std::int16_t>(j.m_value.number_integer)); write_number(static_cast<std::int16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{ {
// int 32 // int 32
oa->write_character(to_char_type(0xD2)); oa.write_character(to_char_type(0xD2));
write_number(static_cast<std::int32_t>(j.m_value.number_integer)); write_number(static_cast<std::int32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{ {
// int 64 // int 64
oa->write_character(to_char_type(0xD3)); oa.write_character(to_char_type(0xD3));
write_number(static_cast<std::int64_t>(j.m_value.number_integer)); write_number(static_cast<std::int64_t>(j.m_value.number_integer));
} }
} }
@ -478,25 +478,25 @@ class binary_writer
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(to_char_type(0xCC)); oa.write_character(to_char_type(0xCC));
write_number(static_cast<std::uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(to_char_type(0xCD)); oa.write_character(to_char_type(0xCD));
write_number(static_cast<std::uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(to_char_type(0xCE)); oa.write_character(to_char_type(0xCE));
write_number(static_cast<std::uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(to_char_type(0xCF)); oa.write_character(to_char_type(0xCF));
write_number(static_cast<std::uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
break; break;
@ -504,7 +504,7 @@ class binary_writer
case value_t::number_float: case value_t::number_float:
{ {
oa->write_character(get_msgpack_float_prefix(j.m_value.number_float)); oa.write_character(get_msgpack_float_prefix(j.m_value.number_float));
write_number(j.m_value.number_float); write_number(j.m_value.number_float);
break; break;
} }
@ -521,24 +521,24 @@ class binary_writer
else if (N <= (std::numeric_limits<std::uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// str 8 // str 8
oa->write_character(to_char_type(0xD9)); oa.write_character(to_char_type(0xD9));
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// str 16 // str 16
oa->write_character(to_char_type(0xDA)); oa.write_character(to_char_type(0xDA));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// str 32 // str 32
oa->write_character(to_char_type(0xDB)); oa.write_character(to_char_type(0xDB));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// step 2: write the string // step 2: write the string
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_value.string->c_str()), reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
j.m_value.string->size()); j.m_value.string->size());
break; break;
@ -556,13 +556,13 @@ class binary_writer
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// array 16 // array 16
oa->write_character(to_char_type(0xDC)); oa.write_character(to_char_type(0xDC));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// array 32 // array 32
oa->write_character(to_char_type(0xDD)); oa.write_character(to_char_type(0xDD));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
@ -618,7 +618,7 @@ class binary_writer
fixed = false; fixed = false;
} }
oa->write_character(to_char_type(output_type)); oa.write_character(to_char_type(output_type));
if (not fixed) if (not fixed)
{ {
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
@ -636,7 +636,7 @@ class binary_writer
output_type = 0xC5; // bin 16 output_type = 0xC5; // bin 16
} }
oa->write_character(to_char_type(output_type)); oa.write_character(to_char_type(output_type));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
@ -651,7 +651,7 @@ class binary_writer
output_type = 0xC6; // bin 32 output_type = 0xC6; // bin 32
} }
oa->write_character(to_char_type(output_type)); oa.write_character(to_char_type(output_type));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
@ -662,7 +662,7 @@ class binary_writer
} }
// step 2: write the byte string // step 2: write the byte string
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_value.binary->data()), reinterpret_cast<const CharType*>(j.m_value.binary->data()),
N); N);
@ -681,13 +681,13 @@ class binary_writer
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// map 16 // map 16
oa->write_character(to_char_type(0xDE)); oa.write_character(to_char_type(0xDE));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// map 32 // map 32
oa->write_character(to_char_type(0xDF)); oa.write_character(to_char_type(0xDF));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
@ -720,7 +720,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('Z')); oa.write_character(to_char_type('Z'));
} }
break; break;
} }
@ -729,9 +729,9 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(j.m_value.boolean oa.write_character(j.m_value.boolean
? to_char_type('T') ? to_char_type('T')
: to_char_type('F')); : to_char_type('F'));
} }
break; break;
} }
@ -758,10 +758,10 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('S')); oa.write_character(to_char_type('S'));
} }
write_number_with_ubjson_prefix(j.m_value.string->size(), true); write_number_with_ubjson_prefix(j.m_value.string->size(), true);
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_value.string->c_str()), reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
j.m_value.string->size()); j.m_value.string->size());
break; break;
@ -771,7 +771,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('[')); oa.write_character(to_char_type('['));
} }
bool prefix_required = true; bool prefix_required = true;
@ -788,14 +788,14 @@ class binary_writer
if (same_prefix) if (same_prefix)
{ {
prefix_required = false; prefix_required = false;
oa->write_character(to_char_type('$')); oa.write_character(to_char_type('$'));
oa->write_character(first_prefix); oa.write_character(first_prefix);
} }
} }
if (use_count) if (use_count)
{ {
oa->write_character(to_char_type('#')); oa.write_character(to_char_type('#'));
write_number_with_ubjson_prefix(j.m_value.array->size(), true); write_number_with_ubjson_prefix(j.m_value.array->size(), true);
} }
@ -806,7 +806,7 @@ class binary_writer
if (not use_count) if (not use_count)
{ {
oa->write_character(to_char_type(']')); oa.write_character(to_char_type(']'));
} }
break; break;
@ -816,25 +816,25 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('[')); oa.write_character(to_char_type('['));
} }
if (use_type and not j.m_value.binary->empty()) if (use_type and not j.m_value.binary->empty())
{ {
assert(use_count); assert(use_count);
oa->write_character(to_char_type('$')); oa.write_character(to_char_type('$'));
oa->write_character('U'); oa.write_character('U');
} }
if (use_count) if (use_count)
{ {
oa->write_character(to_char_type('#')); oa.write_character(to_char_type('#'));
write_number_with_ubjson_prefix(j.m_value.binary->size(), true); write_number_with_ubjson_prefix(j.m_value.binary->size(), true);
} }
if (use_type) if (use_type)
{ {
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_value.binary->data()), reinterpret_cast<const CharType*>(j.m_value.binary->data()),
j.m_value.binary->size()); j.m_value.binary->size());
} }
@ -842,14 +842,14 @@ class binary_writer
{ {
for (size_t i = 0; i < j.m_value.binary->size(); ++i) for (size_t i = 0; i < j.m_value.binary->size(); ++i)
{ {
oa->write_character(to_char_type('U')); oa.write_character(to_char_type('U'));
oa->write_character(j.m_value.binary->data()[i]); oa.write_character(j.m_value.binary->data()[i]);
} }
} }
if (not use_count) if (not use_count)
{ {
oa->write_character(to_char_type(']')); oa.write_character(to_char_type(']'));
} }
break; break;
@ -859,7 +859,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('{')); oa.write_character(to_char_type('{'));
} }
bool prefix_required = true; bool prefix_required = true;
@ -876,21 +876,21 @@ class binary_writer
if (same_prefix) if (same_prefix)
{ {
prefix_required = false; prefix_required = false;
oa->write_character(to_char_type('$')); oa.write_character(to_char_type('$'));
oa->write_character(first_prefix); oa.write_character(first_prefix);
} }
} }
if (use_count) if (use_count)
{ {
oa->write_character(to_char_type('#')); oa.write_character(to_char_type('#'));
write_number_with_ubjson_prefix(j.m_value.object->size(), true); write_number_with_ubjson_prefix(j.m_value.object->size(), true);
} }
for (const auto& el : *j.m_value.object) for (const auto& el : *j.m_value.object)
{ {
write_number_with_ubjson_prefix(el.first.size(), true); write_number_with_ubjson_prefix(el.first.size(), true);
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(el.first.c_str()), reinterpret_cast<const CharType*>(el.first.c_str()),
el.first.size()); el.first.size());
write_ubjson(el.second, use_count, use_type, prefix_required); write_ubjson(el.second, use_count, use_type, prefix_required);
@ -898,7 +898,7 @@ class binary_writer
if (not use_count) if (not use_count)
{ {
oa->write_character(to_char_type('}')); oa.write_character(to_char_type('}'));
} }
break; break;
@ -936,8 +936,8 @@ class binary_writer
void write_bson_entry_header(const string_t& name, void write_bson_entry_header(const string_t& name,
const std::uint8_t element_type) const std::uint8_t element_type)
{ {
oa->write_character(to_char_type(element_type)); // boolean oa.write_character(to_char_type(element_type)); // boolean
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(name.c_str()), reinterpret_cast<const CharType*>(name.c_str()),
name.size() + 1u); name.size() + 1u);
} }
@ -949,7 +949,7 @@ class binary_writer
const bool value) const bool value)
{ {
write_bson_entry_header(name, 0x08); write_bson_entry_header(name, 0x08);
oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); oa.write_character(value ? to_char_type(0x01) : to_char_type(0x00));
} }
/*! /*!
@ -979,7 +979,7 @@ class binary_writer
write_bson_entry_header(name, 0x02); write_bson_entry_header(name, 0x02);
write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul)); write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(value.c_str()), reinterpret_cast<const CharType*>(value.c_str()),
value.size() + 1); value.size() + 1);
} }
@ -1101,7 +1101,7 @@ class binary_writer
write_bson_element(std::to_string(array_index++), el); write_bson_element(std::to_string(array_index++), el);
} }
oa->write_character(to_char_type(0x00)); oa.write_character(to_char_type(0x00));
} }
/*! /*!
@ -1115,7 +1115,7 @@ class binary_writer
write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size())); write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size()));
write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00));
oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size()); oa.write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
} }
/*! /*!
@ -1240,7 +1240,7 @@ class binary_writer
write_bson_element(el.first, el.second); write_bson_element(el.first, el.second);
} }
oa->write_character(to_char_type(0x00)); oa.write_character(to_char_type(0x00));
} }
////////// //////////
@ -1283,7 +1283,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(get_ubjson_float_prefix(n)); oa.write_character(get_ubjson_float_prefix(n));
} }
write_number(n); write_number(n);
} }
@ -1298,7 +1298,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('i')); // int8 oa.write_character(to_char_type('i')); // int8
} }
write_number(static_cast<std::uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
@ -1306,7 +1306,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('U')); // uint8 oa.write_character(to_char_type('U')); // uint8
} }
write_number(static_cast<std::uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
@ -1314,7 +1314,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('I')); // int16 oa.write_character(to_char_type('I')); // int16
} }
write_number(static_cast<std::int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
@ -1322,7 +1322,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('l')); // int32 oa.write_character(to_char_type('l')); // int32
} }
write_number(static_cast<std::int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
@ -1330,7 +1330,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('L')); // int64 oa.write_character(to_char_type('L')); // int64
} }
write_number(static_cast<std::int64_t>(n)); write_number(static_cast<std::int64_t>(n));
} }
@ -1351,7 +1351,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('i')); // int8 oa.write_character(to_char_type('i')); // int8
} }
write_number(static_cast<std::int8_t>(n)); write_number(static_cast<std::int8_t>(n));
} }
@ -1359,7 +1359,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('U')); // uint8 oa.write_character(to_char_type('U')); // uint8
} }
write_number(static_cast<std::uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
@ -1367,7 +1367,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('I')); // int16 oa.write_character(to_char_type('I')); // int16
} }
write_number(static_cast<std::int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
@ -1375,7 +1375,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('l')); // int32 oa.write_character(to_char_type('l')); // int32
} }
write_number(static_cast<std::int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
@ -1383,7 +1383,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('L')); // int64 oa.write_character(to_char_type('L')); // int64
} }
write_number(static_cast<std::int64_t>(n)); write_number(static_cast<std::int64_t>(n));
} }
@ -1515,7 +1515,7 @@ class binary_writer
std::reverse(vec.begin(), vec.end()); std::reverse(vec.begin(), vec.end());
} }
oa->write_characters(vec.data(), sizeof(NumberType)); oa.write_characters(vec.data(), sizeof(NumberType));
} }
public: public:
@ -1564,7 +1564,7 @@ class binary_writer
const bool is_little_endian = little_endianess(); const bool is_little_endian = little_endianess();
/// the output /// the output
output_adapter_t<CharType> oa = nullptr; output_adapter_t oa;
}; };
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann

View File

@ -14,110 +14,134 @@ namespace nlohmann
{ {
namespace detail namespace detail
{ {
/// abstract output adapter interface
template<typename CharType> struct output_adapter_protocol
template<typename T>
struct output_adapter_impl;
// Output to a string, append() is faster than insert(str.end(),...) on some compilers,
// so it's worth having a special override for it.
template<typename StringType>
struct string_output_adapter
{ {
virtual void write_character(CharType c) = 0; using char_type = typename StringType::value_type;
virtual void write_characters(const CharType* s, std::size_t length) = 0;
virtual ~output_adapter_protocol() = default;
};
/// a type to simplify interfaces string_output_adapter(StringType& dst) : dst_(dst) {}
template<typename CharType>
using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
/// output adapter for byte vectors void write_character(char_type c)
template<typename CharType>
class output_vector_adapter : public output_adapter_protocol<CharType>
{
public:
explicit output_vector_adapter(std::vector<CharType>& vec) noexcept
: v(vec)
{}
void write_character(CharType c) override
{ {
v.push_back(c); dst_.push_back(c);
} }
JSON_HEDLEY_NON_NULL(2) void write_characters(const char_type* str, std::size_t len)
void write_characters(const CharType* s, std::size_t length) override
{ {
std::copy(s, s + length, std::back_inserter(v)); dst_.append(str, len);
} }
private: private:
std::vector<CharType>& v; StringType& dst_;
}; };
/// output adapter for output streams // Output to an iterator-like object
template<typename CharType> template<class IteratorType>
class output_stream_adapter : public output_adapter_protocol<CharType> struct iterator_output_adapter
{ {
public: using char_type = char; //?????????????????????????
explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
: stream(s)
{}
void write_character(CharType c) override iterator_output_adapter(IteratorType dst) : dst_(dst) {}
void write_character(char_type c)
{ {
stream.put(c); *dst_++ = c;
} }
JSON_HEDLEY_NON_NULL(2) void write_characters(const char_type* str, std::size_t len)
void write_characters(const CharType* s, std::size_t length) override
{ {
stream.write(s, static_cast<std::streamsize>(length)); std::copy(str, str + len, dst_);
} }
private: private:
std::basic_ostream<CharType>& stream; IteratorType dst_;
}; };
/// output adapter for basic_string // Output to a stream-like object
template<typename CharType, typename StringType = std::basic_string<CharType>> template<class StreamType>
class output_string_adapter : public output_adapter_protocol<CharType> struct stream_output_adapter
{ {
public: using char_type = typename StreamType::char_type;
explicit output_string_adapter(StringType& s) noexcept
: str(s)
{}
void write_character(CharType c) override stream_output_adapter(StreamType& dst) : dst_(dst) {}
void write_character(char_type c)
{ {
str.push_back(c); dst_.put(c);
} }
JSON_HEDLEY_NON_NULL(2) void write_characters(const char_type* str, std::size_t len)
void write_characters(const CharType* s, std::size_t length) override
{ {
str.append(s, length); dst_.write(str, len);
} }
private: private:
StringType& str; StreamType& dst_;
}; };
template<typename CharType, typename StringType = std::basic_string<CharType>> template<typename T, typename = void>
class output_adapter struct is_output_iterator : public std::false_type {};
template<typename T>
struct is_output_iterator<T,
typename std::enable_if<
std::is_same<
typename std::iterator_traits<T>::iterator_category,
std::output_iterator_tag>::value
>::type> : public std::true_type {};
template <typename T>
constexpr auto has_push_back (int)
-> decltype( std::declval<T>().push_back('a'),
std::true_type() );
template <typename>
constexpr std::false_type has_push_back (long);
// If the parameter is a basic_string
template<typename CharT, typename Traits, typename Allocator>
string_output_adapter<std::basic_string<CharT, Traits, Allocator>> output_adapter(std::basic_string<CharT, Traits, Allocator>& dst)
{ {
public: return string_output_adapter<std::basic_string<CharT, Traits, Allocator>>(dst);
output_adapter(std::vector<CharType>& vec) }
: oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
output_adapter(std::basic_ostream<CharType>& s) // If the parameter is an output iterator
: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {} template<typename IteratorType,
typename std::enable_if<
is_output_iterator<IteratorType>::value,
int>::type = 0>
auto output_adapter(IteratorType dst) -> iterator_output_adapter<IteratorType>
{
return iterator_output_adapter<IteratorType>(std::move(dst));
}
output_adapter(StringType& s) // Try to extract an output iterator from the parameter
: oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {} template<typename ContainerType,
typename std::enable_if<
decltype(has_push_back<ContainerType>(0))::value,
int>::type = 0>
auto output_adapter(ContainerType& dst) -> decltype(output_adapter(std::back_inserter(dst)))
{
return output_adapter(std::back_inserter(dst));
}
operator output_adapter_t<CharType>()
{
return oa;
}
private: // If all else fails, treat it as a stream
output_adapter_t<CharType> oa = nullptr; template<typename StreamType, typename std::enable_if<
}; not is_output_iterator<StreamType>::value and
not decltype(has_push_back<StreamType>(0))::value,
int>::type = 0>
stream_output_adapter<StreamType> output_adapter(StreamType& dst)
{
return stream_output_adapter<StreamType>(dst);
}
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann

View File

@ -38,7 +38,7 @@ enum class error_handler_t
ignore ///< ignore invalid UTF-8 sequences ignore ///< ignore invalid UTF-8 sequences
}; };
template<typename BasicJsonType> template<typename BasicJsonType, typename OutputAdapterType>
class serializer class serializer
{ {
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
@ -46,16 +46,19 @@ class serializer
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using binary_char_t = typename BasicJsonType::binary_t::value_type; using binary_char_t = typename BasicJsonType::binary_t::value_type;
using output_adapter_t = OutputAdapterType;
static constexpr std::uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_ACCEPT = 0;
static constexpr std::uint8_t UTF8_REJECT = 1; static constexpr std::uint8_t UTF8_REJECT = 1;
static_assert(sizeof(typename output_adapter_t::char_type) == 1, "can only serialize to UTF-8");
public: public:
/*! /*!
@param[in] s output stream to serialize to @param[in] s output stream to serialize to
@param[in] ichar indentation character to use @param[in] ichar indentation character to use
@param[in] error_handler_ how to react on decoding errors @param[in] error_handler_ how to react on decoding errors
*/ */
serializer(output_adapter_t<char> s, const char ichar, serializer(output_adapter_t s, const char ichar,
error_handler_t error_handler_ = error_handler_t::strict) error_handler_t error_handler_ = error_handler_t::strict)
: o(std::move(s)) : o(std::move(s))
, loc(std::localeconv()) , loc(std::localeconv())
@ -107,13 +110,13 @@ class serializer
{ {
if (val.m_value.object->empty()) if (val.m_value.object->empty())
{ {
o->write_characters("{}", 2); o.write_characters("{}", 2);
return; return;
} }
if (pretty_print) if (pretty_print)
{ {
o->write_characters("{\n", 2); o.write_characters("{\n", 2);
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + indent_step;
@ -126,51 +129,51 @@ class serializer
auto i = val.m_value.object->cbegin(); auto i = val.m_value.object->cbegin();
for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
{ {
o->write_characters(indent_string.c_str(), new_indent); o.write_characters(indent_string.c_str(), new_indent);
o->write_character('\"'); o.write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
o->write_characters("\": ", 3); o.write_characters("\": ", 3);
dump(i->second, true, ensure_ascii, indent_step, new_indent); dump(i->second, true, ensure_ascii, indent_step, new_indent);
o->write_characters(",\n", 2); o.write_characters(",\n", 2);
} }
// last element // last element
assert(i != val.m_value.object->cend()); assert(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend()); assert(std::next(i) == val.m_value.object->cend());
o->write_characters(indent_string.c_str(), new_indent); o.write_characters(indent_string.c_str(), new_indent);
o->write_character('\"'); o.write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
o->write_characters("\": ", 3); o.write_characters("\": ", 3);
dump(i->second, true, ensure_ascii, indent_step, new_indent); dump(i->second, true, ensure_ascii, indent_step, new_indent);
o->write_character('\n'); o.write_character('\n');
o->write_characters(indent_string.c_str(), current_indent); o.write_characters(indent_string.c_str(), current_indent);
o->write_character('}'); o.write_character('}');
} }
else else
{ {
o->write_character('{'); o.write_character('{');
// first n-1 elements // first n-1 elements
auto i = val.m_value.object->cbegin(); auto i = val.m_value.object->cbegin();
for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
{ {
o->write_character('\"'); o.write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
o->write_characters("\":", 2); o.write_characters("\":", 2);
dump(i->second, false, ensure_ascii, indent_step, current_indent); dump(i->second, false, ensure_ascii, indent_step, current_indent);
o->write_character(','); o.write_character(',');
} }
// last element // last element
assert(i != val.m_value.object->cend()); assert(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend()); assert(std::next(i) == val.m_value.object->cend());
o->write_character('\"'); o.write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
o->write_characters("\":", 2); o.write_characters("\":", 2);
dump(i->second, false, ensure_ascii, indent_step, current_indent); dump(i->second, false, ensure_ascii, indent_step, current_indent);
o->write_character('}'); o.write_character('}');
} }
return; return;
@ -180,13 +183,13 @@ class serializer
{ {
if (val.m_value.array->empty()) if (val.m_value.array->empty())
{ {
o->write_characters("[]", 2); o.write_characters("[]", 2);
return; return;
} }
if (pretty_print) if (pretty_print)
{ {
o->write_characters("[\n", 2); o.write_characters("[\n", 2);
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + indent_step;
@ -199,37 +202,37 @@ class serializer
for (auto i = val.m_value.array->cbegin(); for (auto i = val.m_value.array->cbegin();
i != val.m_value.array->cend() - 1; ++i) i != val.m_value.array->cend() - 1; ++i)
{ {
o->write_characters(indent_string.c_str(), new_indent); o.write_characters(indent_string.c_str(), new_indent);
dump(*i, true, ensure_ascii, indent_step, new_indent); dump(*i, true, ensure_ascii, indent_step, new_indent);
o->write_characters(",\n", 2); o.write_characters(",\n", 2);
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent); o.write_characters(indent_string.c_str(), new_indent);
dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
o->write_character('\n'); o.write_character('\n');
o->write_characters(indent_string.c_str(), current_indent); o.write_characters(indent_string.c_str(), current_indent);
o->write_character(']'); o.write_character(']');
} }
else else
{ {
o->write_character('['); o.write_character('[');
// first n-1 elements // first n-1 elements
for (auto i = val.m_value.array->cbegin(); for (auto i = val.m_value.array->cbegin();
i != val.m_value.array->cend() - 1; ++i) i != val.m_value.array->cend() - 1; ++i)
{ {
dump(*i, false, ensure_ascii, indent_step, current_indent); dump(*i, false, ensure_ascii, indent_step, current_indent);
o->write_character(','); o.write_character(',');
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
o->write_character(']'); o.write_character(']');
} }
return; return;
@ -237,9 +240,9 @@ class serializer
case value_t::string: case value_t::string:
{ {
o->write_character('\"'); o.write_character('\"');
dump_escaped(*val.m_value.string, ensure_ascii); dump_escaped(*val.m_value.string, ensure_ascii);
o->write_character('\"'); o.write_character('\"');
return; return;
} }
@ -247,7 +250,7 @@ class serializer
{ {
if (pretty_print) if (pretty_print)
{ {
o->write_characters("{\n", 2); o.write_characters("{\n", 2);
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + indent_step;
@ -256,9 +259,9 @@ class serializer
indent_string.resize(indent_string.size() * 2, ' '); indent_string.resize(indent_string.size() * 2, ' ');
} }
o->write_characters(indent_string.c_str(), new_indent); o.write_characters(indent_string.c_str(), new_indent);
o->write_characters("\"bytes\": [", 10); o.write_characters("\"bytes\": [", 10);
if (not val.m_value.binary->empty()) if (not val.m_value.binary->empty())
{ {
@ -266,30 +269,30 @@ class serializer
i != val.m_value.binary->cend() - 1; ++i) i != val.m_value.binary->cend() - 1; ++i)
{ {
dump_integer(*i); dump_integer(*i);
o->write_characters(", ", 2); o.write_characters(", ", 2);
} }
dump_integer(val.m_value.binary->back()); dump_integer(val.m_value.binary->back());
} }
o->write_characters("],\n", 3); o.write_characters("],\n", 3);
o->write_characters(indent_string.c_str(), new_indent); o.write_characters(indent_string.c_str(), new_indent);
o->write_characters("\"subtype\": ", 11); o.write_characters("\"subtype\": ", 11);
if (val.m_value.binary->has_subtype()) if (val.m_value.binary->has_subtype())
{ {
dump_integer(val.m_value.binary->subtype()); dump_integer(val.m_value.binary->subtype());
} }
else else
{ {
o->write_characters("null", 4); o.write_characters("null", 4);
} }
o->write_character('\n'); o.write_character('\n');
o->write_characters(indent_string.c_str(), current_indent); o.write_characters(indent_string.c_str(), current_indent);
o->write_character('}'); o.write_character('}');
} }
else else
{ {
o->write_characters("{\"bytes\":[", 10); o.write_characters("{\"bytes\":[", 10);
if (not val.m_value.binary->empty()) if (not val.m_value.binary->empty())
{ {
@ -297,20 +300,20 @@ class serializer
i != val.m_value.binary->cend() - 1; ++i) i != val.m_value.binary->cend() - 1; ++i)
{ {
dump_integer(*i); dump_integer(*i);
o->write_character(','); o.write_character(',');
} }
dump_integer(val.m_value.binary->back()); dump_integer(val.m_value.binary->back());
} }
o->write_characters("],\"subtype\":", 12); o.write_characters("],\"subtype\":", 12);
if (val.m_value.binary->has_subtype()) if (val.m_value.binary->has_subtype())
{ {
dump_integer(val.m_value.binary->subtype()); dump_integer(val.m_value.binary->subtype());
o->write_character('}'); o.write_character('}');
} }
else else
{ {
o->write_characters("null}", 5); o.write_characters("null}", 5);
} }
} }
return; return;
@ -320,11 +323,11 @@ class serializer
{ {
if (val.m_value.boolean) if (val.m_value.boolean)
{ {
o->write_characters("true", 4); o.write_characters("true", 4);
} }
else else
{ {
o->write_characters("false", 5); o.write_characters("false", 5);
} }
return; return;
} }
@ -349,13 +352,13 @@ class serializer
case value_t::discarded: case value_t::discarded:
{ {
o->write_characters("<discarded>", 11); o.write_characters("<discarded>", 11);
return; return;
} }
case value_t::null: case value_t::null:
{ {
o->write_characters("null", 4); o.write_characters("null", 4);
return; return;
} }
@ -483,7 +486,7 @@ class serializer
// written ("\uxxxx\uxxxx\0") for one code point // written ("\uxxxx\uxxxx\0") for one code point
if (string_buffer.size() - bytes < 13) if (string_buffer.size() - bytes < 13)
{ {
o->write_characters(string_buffer.data(), bytes); o.write_characters(string_buffer.data(), bytes);
bytes = 0; bytes = 0;
} }
@ -534,9 +537,9 @@ class serializer
} }
else else
{ {
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF'); string_buffer[bytes++] = detail::binary_writer<BasicJsonType, output_adapter_t>::to_char_type('\xEF');
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF'); string_buffer[bytes++] = detail::binary_writer<BasicJsonType, output_adapter_t>::to_char_type('\xBF');
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD'); string_buffer[bytes++] = detail::binary_writer<BasicJsonType, output_adapter_t>::to_char_type('\xBD');
} }
// write buffer and reset index; there must be 13 bytes // write buffer and reset index; there must be 13 bytes
@ -544,7 +547,7 @@ class serializer
// written ("\uxxxx\uxxxx\0") for one code point // written ("\uxxxx\uxxxx\0") for one code point
if (string_buffer.size() - bytes < 13) if (string_buffer.size() - bytes < 13)
{ {
o->write_characters(string_buffer.data(), bytes); o.write_characters(string_buffer.data(), bytes);
bytes = 0; bytes = 0;
} }
@ -583,7 +586,7 @@ class serializer
// write buffer // write buffer
if (bytes > 0) if (bytes > 0)
{ {
o->write_characters(string_buffer.data(), bytes); o.write_characters(string_buffer.data(), bytes);
} }
} }
else else
@ -601,22 +604,22 @@ class serializer
case error_handler_t::ignore: case error_handler_t::ignore:
{ {
// write all accepted bytes // write all accepted bytes
o->write_characters(string_buffer.data(), bytes_after_last_accept); o.write_characters(string_buffer.data(), bytes_after_last_accept);
break; break;
} }
case error_handler_t::replace: case error_handler_t::replace:
{ {
// write all accepted bytes // write all accepted bytes
o->write_characters(string_buffer.data(), bytes_after_last_accept); o.write_characters(string_buffer.data(), bytes_after_last_accept);
// add a replacement character // add a replacement character
if (ensure_ascii) if (ensure_ascii)
{ {
o->write_characters("\\ufffd", 6); o.write_characters("\\ufffd", 6);
} }
else else
{ {
o->write_characters("\xEF\xBF\xBD", 3); o.write_characters("\xEF\xBF\xBD", 3);
} }
break; break;
} }
@ -696,7 +699,7 @@ class serializer
// special case for "0" // special case for "0"
if (x == 0) if (x == 0)
{ {
o->write_character('0'); o.write_character('0');
return; return;
} }
@ -750,7 +753,7 @@ class serializer
*(--buffer_ptr) = static_cast<char>('0' + abs_value); *(--buffer_ptr) = static_cast<char>('0' + abs_value);
} }
o->write_characters(number_buffer.data(), n_chars); o.write_characters(number_buffer.data(), n_chars);
} }
/*! /*!
@ -766,7 +769,7 @@ class serializer
// NaN / inf // NaN / inf
if (not std::isfinite(x)) if (not std::isfinite(x))
{ {
o->write_characters("null", 4); o.write_characters("null", 4);
return; return;
} }
@ -787,7 +790,7 @@ class serializer
char* begin = number_buffer.data(); char* begin = number_buffer.data();
char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
o->write_characters(begin, static_cast<size_t>(end - begin)); o.write_characters(begin, static_cast<size_t>(end - begin));
} }
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
@ -823,7 +826,7 @@ class serializer
} }
} }
o->write_characters(number_buffer.data(), static_cast<std::size_t>(len)); o.write_characters(number_buffer.data(), static_cast<std::size_t>(len));
// determine if need to append ".0" // determine if need to append ".0"
const bool value_is_int_like = const bool value_is_int_like =
@ -835,7 +838,7 @@ class serializer
if (value_is_int_like) if (value_is_int_like)
{ {
o->write_characters(".0", 2); o.write_characters(".0", 2);
} }
} }
@ -922,7 +925,7 @@ class serializer
private: private:
/// the output of the serializer /// the output of the serializer
output_adapter_t<char> o = nullptr; output_adapter_t o;
/// a (hopefully) large enough character buffer /// a (hopefully) large enough character buffer
std::array<char, 64> number_buffer{{}}; std::array<char, 64> number_buffer{{}};

View File

@ -174,7 +174,8 @@ class basic_json
template<typename BasicJsonType, typename InputType> template<typename BasicJsonType, typename InputType>
friend class ::nlohmann::detail::parser; friend class ::nlohmann::detail::parser;
friend ::nlohmann::detail::serializer<basic_json>; template<typename BasicJsonType, typename OutputAdapterType>
friend class ::nlohmann::detail::serializer;
template<typename BasicJsonType> template<typename BasicJsonType>
friend class ::nlohmann::detail::iter_impl; friend class ::nlohmann::detail::iter_impl;
template<typename BasicJsonType, typename CharType> template<typename BasicJsonType, typename CharType>
@ -211,14 +212,12 @@ class basic_json
using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>; using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>; template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
template<typename CharType>
using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
template<typename InputType> template<typename InputType>
using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>; using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;
template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>; template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
using serializer = ::nlohmann::detail::serializer<basic_json>; template<typename OutputAdapterType>
using serializer = ::nlohmann::detail::serializer<basic_json, OutputAdapterType>;
public: public:
using value_t = detail::value_t; using value_t = detail::value_t;
@ -2269,7 +2268,23 @@ class basic_json
const error_handler_t error_handler = error_handler_t::strict) const const error_handler_t error_handler = error_handler_t::strict) const
{ {
string_t result; string_t result;
serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
dump_to(result, indent, indent_char, ensure_ascii, error_handler);
return result;
}
template <typename OutputType>
void dump_to(OutputType&& dst,
const int indent = -1,
const char indent_char = ' ',
const bool ensure_ascii = false,
const error_handler_t error_handler = error_handler_t::strict) const
{
auto oa = detail::output_adapter(std::forward<OutputType>(dst));
using serializer_t = serializer<decltype(oa)>;
serializer<decltype(oa)> s(std::move(oa), indent_char, error_handler);
if (indent >= 0) if (indent >= 0)
{ {
@ -2279,10 +2294,7 @@ class basic_json
{ {
s.dump(*this, false, ensure_ascii, 0); s.dump(*this, false, ensure_ascii, 0);
} }
return result;
} }
/*! /*!
@brief return the type of the JSON value (explicit) @brief return the type of the JSON value (explicit)
@ -6516,9 +6528,7 @@ class basic_json
// reset width to 0 for subsequent calls to this stream // reset width to 0 for subsequent calls to this stream
o.width(0); o.width(0);
// do the actual serialization j.dump_to(o, indentation, ' ', false);
serializer s(detail::output_adapter<char>(o), o.fill());
s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
return o; return o;
} }
@ -6976,14 +6986,11 @@ class basic_json
return result; return result;
} }
static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o) template<typename OutputType>
static void to_cbor(const basic_json& j, OutputType&& o)
{ {
binary_writer<uint8_t>(o).write_cbor(j); auto oa = detail::output_adapter(std::forward<OutputType>(o));
} binary_writer<decltype(oa)>(std::move(oa)).write_cbor(j);
static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
{
binary_writer<char>(o).write_cbor(j);
} }
/*! /*!
@ -7073,15 +7080,13 @@ class basic_json
return result; return result;
} }
static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o) template<typename OutputType>
static void to_msgpack(const basic_json& j, OutputType&& o)
{ {
binary_writer<uint8_t>(o).write_msgpack(j); auto oa = detail::output_adapter(std::forward<OutputType>(o));
binary_writer<decltype(oa)>(std::move(oa)).write_msgpack(j);
} }
static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
{
binary_writer<char>(o).write_msgpack(j);
}
/*! /*!
@brief create a UBJSON serialization of a given JSON value @brief create a UBJSON serialization of a given JSON value
@ -7174,23 +7179,18 @@ class basic_json
const bool use_type = false) const bool use_type = false)
{ {
std::vector<uint8_t> result; std::vector<uint8_t> result;
to_ubjson(j, result, use_size, use_type); to_ubjson(j, std::back_inserter(result), use_size, use_type);
return result; return result;
} }
static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o, template<typename OutputType>
static void to_ubjson(const basic_json& j, OutputType&& o,
const bool use_size = false, const bool use_type = false) const bool use_size = false, const bool use_type = false)
{ {
binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type); auto oa = detail::output_adapter(std::forward<OutputType>(o));
binary_writer<decltype(oa)>(std::move(oa)).write_ubjson(j, use_size, use_type);
} }
static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
const bool use_size = false, const bool use_type = false)
{
binary_writer<char>(o).write_ubjson(j, use_size, use_type);
}
/*! /*!
@brief Serializes the given JSON object `j` to BSON and returns a vector @brief Serializes the given JSON object `j` to BSON and returns a vector
containing the corresponding BSON-representation. containing the corresponding BSON-representation.
@ -7262,17 +7262,11 @@ class basic_json
@pre The input `j` shall be an object: `j.is_object() == true` @pre The input `j` shall be an object: `j.is_object() == true`
@sa @ref to_bson(const basic_json&) @sa @ref to_bson(const basic_json&)
*/ */
static void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o) template<typename OutputType>
static void to_bson(const basic_json& j, OutputType&& o)
{ {
binary_writer<uint8_t>(o).write_bson(j); auto oa = detail::output_adapter(std::forward<OutputType>(o));
} binary_writer<decltype(oa)>(std::move(oa)).write_bson(j);
/*!
@copydoc to_bson(const basic_json&, detail::output_adapter<uint8_t>)
*/
static void to_bson(const basic_json& j, detail::output_adapter<char> o)
{
binary_writer<char>(o).write_bson(j);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1587,7 +1587,7 @@ TEST_CASE("parser class")
CHECK (j_filtered1.size() == 2); CHECK (j_filtered1.size() == 2);
CHECK (j_filtered1 == json({1, {{"qux", "baz"}}})); CHECK (j_filtered1 == json({1, {{"qux", "baz"}}}));
json j_filtered2 = json::parse(structured_array, [](int, json::parse_event_t e, const json & /*parsed*/) json j_filtered2 = json::parse(structured_array, [](int, json::parse_event_t e, const json& /*parsed*/)
{ {
if (e == json::parse_event_t::object_end) if (e == json::parse_event_t::object_end)
{ {

View File

@ -42,7 +42,8 @@ void check_escaped(const char* original, const char* escaped = "", const bool en
void check_escaped(const char* original, const char* escaped, const bool ensure_ascii) void check_escaped(const char* original, const char* escaped, const bool ensure_ascii)
{ {
std::stringstream ss; std::stringstream ss;
json::serializer s(nlohmann::detail::output_adapter<char>(ss), ' '); auto oa = nlohmann::detail::output_adapter(ss);
json::serializer<decltype(oa)> s(std::move(oa), ' ');
s.dump_escaped(original, ensure_ascii); s.dump_escaped(original, ensure_ascii);
CHECK(ss.str() == escaped); CHECK(ss.str() == escaped);
} }