Compare commits

...
Author SHA1 Message Date
Niels LohmannandClaude Opus 4.8 ebb3abba41 Devirtualize binary_writer via a value-type output sink
to_cbor/to_msgpack/to_ubjson/to_bjdata/to_bson wrote every byte through
output_adapter_t, a shared_ptr<output_adapter_protocol> whose
write_character/write_characters are virtual. Unlike the lexer (templated
on a concrete InputAdapterType), the binary writer never got that
treatment, so binary output paid a vtable lookup per byte and a
make_shared per call.

Template binary_writer on an OutputSinkType and give it two concrete,
non-virtual sinks:

- output_vector_sink: appends straight into a std::vector (push_back /
  insert), used by the vector-returning to_* convenience functions. No
  vtable, no shared_ptr; the writes inline.
- output_adapter_sink: forwards to a type-erased output_adapter_t, so the
  existing to_*(j, output_adapter) overloads (streams, strings, custom
  adapters) keep working exactly as before -- one virtual call each,
  unchanged.

binary_writer keeps a convenience constructor taking output_adapter_t
(building the default output_adapter_sink), so the adapter overloads are
untouched; only the convenience functions switch to the vector sink. The
friend declaration and the basic_json binary_writer alias gain the new
(defaulted) template parameter.

Output is byte-for-byte identical: verified across ~3000 randomized
values plus curated edge cases (all scalar widths, strings with invalid
UTF-8, binary, nested arrays/objects) for CBOR, MessagePack, UBJSON (both
size/type settings), BJData, and BSON, plus the output_adapter path, in
C++11/17/20. Warning-clean under clang -Weverything and the gcc pedantic
set; clang-tidy clean on the changed headers; make check-amalgamation
clean.

Throughput (g++ -O3, vs develop): scalar-dense binary output such as
integer arrays ~1.4x; many small to_cbor calls ~1.04x (DOM traversal
bound); string/blob-heavy output unchanged (already bulk-bound). No
workload regressed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAYM1qhSA2FDaDcGfPW3fG
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-20 23:27:51 +00:00
4 changed files with 486 additions and 324 deletions
+168 -155
View File
@@ -42,7 +42,7 @@ enum class bjdata_version_t
/*! /*!
@brief serialization to CBOR and MessagePack values @brief serialization to CBOR and MessagePack values
*/ */
template<typename BasicJsonType, typename CharType> template<typename BasicJsonType, typename CharType, typename OutputSinkType = output_adapter_sink<CharType>>
class binary_writer class binary_writer
{ {
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
@@ -53,12 +53,25 @@ class binary_writer
/*! /*!
@brief create a binary writer @brief create a binary writer
@param[in] sink output sink to write to (a value-type sink such as
output_vector_sink, or output_adapter_sink wrapping a
type-erased output adapter)
*/
explicit binary_writer(OutputSinkType sink) : oa(std::move(sink))
{}
/*!
@brief create a binary writer from a type-erased output adapter
Convenience constructor for the default (output_adapter_sink) sink so the
`output_adapter`-based overloads keep constructing the writer directly from
an adapter. Only participates in overload resolution when the sink can be
built from an adapter.
@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(std::move(adapter)) explicit binary_writer(output_adapter_t<CharType> adapter) : oa(OutputSinkType(std::move(adapter)))
{ {}
JSON_ASSERT(oa);
}
/*! /*!
@param[in] j JSON value to serialize @param[in] j JSON value to serialize
@@ -99,15 +112,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_data.m_value.boolean oa.write_character(j.m_data.m_value.boolean
? to_char_type(0xF5) ? to_char_type(0xF5)
: to_char_type(0xF4)); : to_char_type(0xF4));
break; break;
} }
@@ -124,22 +137,22 @@ class binary_writer
} }
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
} }
} }
@@ -154,22 +167,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));
} }
} }
@@ -184,22 +197,22 @@ class binary_writer
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_data.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_data.m_value.number_unsigned)); write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_data.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_data.m_value.number_unsigned)); write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_data.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_data.m_value.number_unsigned)); write_number(static_cast<std::uint32_t>(j.m_data.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_data.m_value.number_unsigned)); write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));
} }
break; break;
@@ -210,16 +223,16 @@ class binary_writer
if (std::isnan(j.m_data.m_value.number_float)) if (std::isnan(j.m_data.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_data.m_value.number_float)) else if (std::isinf(j.m_data.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_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); oa.write_character(j.m_data.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
{ {
@@ -238,31 +251,31 @@ 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_data.m_value.string->c_str()), reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
j.m_data.m_value.string->size()); j.m_data.m_value.string->size());
break; break;
} }
@@ -276,23 +289,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
@@ -339,31 +352,31 @@ 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_data.m_value.binary->data()), reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
N); N);
break; break;
} }
@@ -378,23 +391,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
@@ -423,15 +436,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_data.m_value.boolean oa.write_character(j.m_data.m_value.boolean
? to_char_type(0xC3) ? to_char_type(0xC3)
: to_char_type(0xC2)); : to_char_type(0xC2));
break; break;
} }
@@ -450,25 +463,25 @@ class binary_writer
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
} }
} }
@@ -483,28 +496,28 @@ class binary_writer
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() && else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() && else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() && else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::int64_t>(j.m_data.m_value.number_integer));
} }
} }
@@ -521,25 +534,25 @@ class binary_writer
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
} }
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) else if (j.m_data.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_data.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
} }
break; break;
@@ -563,26 +576,26 @@ 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_data.m_value.string->c_str()), reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
j.m_data.m_value.string->size()); j.m_data.m_value.string->size());
break; break;
} }
@@ -598,13 +611,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));
} }
@@ -660,7 +673,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 (!fixed) if (!fixed)
{ {
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
@@ -672,7 +685,7 @@ class binary_writer
? 0xC8 // ext 16 ? 0xC8 // ext 16
: 0xC5; // bin 16 : 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)())
@@ -681,7 +694,7 @@ class binary_writer
? 0xC9 // ext 32 ? 0xC9 // ext 32
: 0xC6; // bin 32 : 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));
} }
@@ -692,9 +705,9 @@ 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_data.m_value.binary->data()), reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
N); N);
break; break;
} }
@@ -711,13 +724,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));
} }
@@ -756,7 +769,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;
} }
@@ -765,9 +778,9 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(j.m_data.m_value.boolean oa.write_character(j.m_data.m_value.boolean
? to_char_type('T') ? to_char_type('T')
: to_char_type('F')); : to_char_type('F'));
} }
break; break;
} }
@@ -794,12 +807,12 @@ 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_data.m_value.string->size(), true, use_bjdata); write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()), reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
j.m_data.m_value.string->size()); j.m_data.m_value.string->size());
break; break;
} }
@@ -807,7 +820,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;
@@ -826,14 +839,14 @@ class binary_writer
if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
{ {
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_data.m_value.array->size(), true, use_bjdata); write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata);
} }
@@ -844,7 +857,7 @@ class binary_writer
if (!use_count) if (!use_count)
{ {
oa->write_character(to_char_type(']')); oa.write_character(to_char_type(']'));
} }
break; break;
@@ -854,40 +867,40 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('[')); oa.write_character(to_char_type('['));
} }
if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty())) if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty()))
{ {
JSON_ASSERT(use_count); JSON_ASSERT(use_count);
oa->write_character(to_char_type('$')); oa.write_character(to_char_type('$'));
oa->write_character(bjdata_draft3 ? 'B' : 'U'); oa.write_character(bjdata_draft3 ? 'B' : '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_data.m_value.binary->size(), true, use_bjdata); write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata);
} }
if (use_type) if (use_type)
{ {
oa->write_characters( oa.write_characters(
reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()), reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
j.m_data.m_value.binary->size()); j.m_data.m_value.binary->size());
} }
else else
{ {
for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i) for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)
{ {
oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U')); oa.write_character(to_char_type(bjdata_draft3 ? 'B' : 'U'));
oa->write_character(to_char_type(j.m_data.m_value.binary->data()[i])); oa.write_character(to_char_type(j.m_data.m_value.binary->data()[i]));
} }
} }
if (!use_count) if (!use_count)
{ {
oa->write_character(to_char_type(']')); oa.write_character(to_char_type(']'));
} }
break; break;
@@ -905,7 +918,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;
@@ -924,29 +937,29 @@ class binary_writer
if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
{ {
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_data.m_value.object->size(), true, use_bjdata); write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata);
} }
for (const auto& el : *j.m_data.m_value.object) for (const auto& el : *j.m_data.m_value.object)
{ {
write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata); write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
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, use_bjdata, bjdata_version); write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version);
} }
if (!use_count) if (!use_count)
{ {
oa->write_character(to_char_type('}')); oa.write_character(to_char_type('}'));
} }
break; break;
@@ -985,10 +998,10 @@ 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);
} }
/*! /*!
@@ -998,7 +1011,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));
} }
/*! /*!
@@ -1028,9 +1041,9 @@ class binary_writer
write_bson_entry_header(name, 0x02); write_bson_entry_header(name, 0x02);
write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true); write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true);
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);
} }
/*! /*!
@@ -1151,7 +1164,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));
} }
/*! /*!
@@ -1165,7 +1178,7 @@ class binary_writer
write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true); write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true);
write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00)); write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<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());
} }
/*! /*!
@@ -1291,7 +1304,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));
} }
////////// //////////
@@ -1335,7 +1348,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, use_bjdata); write_number(n, use_bjdata);
} }
@@ -1351,7 +1364,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), use_bjdata); write_number(static_cast<std::uint8_t>(n), use_bjdata);
} }
@@ -1359,7 +1372,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), use_bjdata); write_number(static_cast<std::uint8_t>(n), use_bjdata);
} }
@@ -1367,7 +1380,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), use_bjdata); write_number(static_cast<std::int16_t>(n), use_bjdata);
} }
@@ -1375,7 +1388,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('u')); // uint16 - bjdata only oa.write_character(to_char_type('u')); // uint16 - bjdata only
} }
write_number(static_cast<std::uint16_t>(n), use_bjdata); write_number(static_cast<std::uint16_t>(n), use_bjdata);
} }
@@ -1383,7 +1396,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), use_bjdata); write_number(static_cast<std::int32_t>(n), use_bjdata);
} }
@@ -1391,7 +1404,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('m')); // uint32 - bjdata only oa.write_character(to_char_type('m')); // uint32 - bjdata only
} }
write_number(static_cast<std::uint32_t>(n), use_bjdata); write_number(static_cast<std::uint32_t>(n), use_bjdata);
} }
@@ -1399,7 +1412,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), use_bjdata); write_number(static_cast<std::int64_t>(n), use_bjdata);
} }
@@ -1407,7 +1420,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('M')); // uint64 - bjdata only oa.write_character(to_char_type('M')); // uint64 - bjdata only
} }
write_number(static_cast<std::uint64_t>(n), use_bjdata); write_number(static_cast<std::uint64_t>(n), use_bjdata);
} }
@@ -1415,14 +1428,14 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('H')); // high-precision number oa.write_character(to_char_type('H')); // high-precision number
} }
const auto number = BasicJsonType(n).dump(); const auto number = BasicJsonType(n).dump();
write_number_with_ubjson_prefix(number.size(), true, use_bjdata); write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
for (std::size_t i = 0; i < number.size(); ++i) for (std::size_t i = 0; i < number.size(); ++i)
{ {
oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i]))); oa.write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
} }
} }
} }
@@ -1439,7 +1452,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), use_bjdata); write_number(static_cast<std::int8_t>(n), use_bjdata);
} }
@@ -1447,7 +1460,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), use_bjdata); write_number(static_cast<std::uint8_t>(n), use_bjdata);
} }
@@ -1455,7 +1468,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), use_bjdata); write_number(static_cast<std::int16_t>(n), use_bjdata);
} }
@@ -1463,7 +1476,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('u')); // uint16 - bjdata only oa.write_character(to_char_type('u')); // uint16 - bjdata only
} }
write_number(static_cast<uint16_t>(n), use_bjdata); write_number(static_cast<uint16_t>(n), use_bjdata);
} }
@@ -1471,7 +1484,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), use_bjdata); write_number(static_cast<std::int32_t>(n), use_bjdata);
} }
@@ -1479,7 +1492,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('m')); // uint32 - bjdata only oa.write_character(to_char_type('m')); // uint32 - bjdata only
} }
write_number(static_cast<uint32_t>(n), use_bjdata); write_number(static_cast<uint32_t>(n), use_bjdata);
} }
@@ -1487,7 +1500,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), use_bjdata); write_number(static_cast<std::int64_t>(n), use_bjdata);
} }
@@ -1496,14 +1509,14 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('H')); // high-precision number oa.write_character(to_char_type('H')); // high-precision number
} }
const auto number = BasicJsonType(n).dump(); const auto number = BasicJsonType(n).dump();
write_number_with_ubjson_prefix(number.size(), true, use_bjdata); write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
for (std::size_t i = 0; i < number.size(); ++i) for (std::size_t i = 0; i < number.size(); ++i)
{ {
oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i]))); oa.write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
} }
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@@ -1656,10 +1669,10 @@ class binary_writer
return true; return true;
} }
oa->write_character('['); oa.write_character('[');
oa->write_character('$'); oa.write_character('$');
oa->write_character(dtype); oa.write_character(dtype);
oa->write_character('#'); oa.write_character('#');
key = "_ArraySize_"; key = "_ArraySize_";
write_ubjson(value.at(key), use_count, use_type, true, true, bjdata_version); write_ubjson(value.at(key), use_count, use_type, true, true, bjdata_version);
@@ -1769,7 +1782,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));
} }
void write_compact_float(const number_float_t n, detail::input_format_t format) void write_compact_float(const number_float_t n, detail::input_format_t format)
@@ -1782,16 +1795,16 @@ class binary_writer
static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) && static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(n)) == static_cast<double>(n)))) static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))))
{ {
oa->write_character(format == detail::input_format_t::cbor oa.write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(static_cast<float>(n)) ? get_cbor_float_prefix(static_cast<float>(n))
: get_msgpack_float_prefix(static_cast<float>(n))); : get_msgpack_float_prefix(static_cast<float>(n)));
write_number(static_cast<float>(n)); write_number(static_cast<float>(n));
} }
else else
{ {
oa->write_character(format == detail::input_format_t::cbor oa.write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(n) ? get_cbor_float_prefix(n)
: get_msgpack_float_prefix(n)); : get_msgpack_float_prefix(n));
write_number(n); write_number(n);
} }
#ifdef __GNUC__ #ifdef __GNUC__
@@ -1858,7 +1871,7 @@ class binary_writer
const bool is_little_endian = little_endianness(); const bool is_little_endian = little_endianness();
/// the output /// the output
output_adapter_t<CharType> oa = nullptr; OutputSinkType oa;
}; };
} // namespace detail } // namespace detail
@@ -118,6 +118,68 @@ class output_string_adapter : public output_adapter_protocol<CharType>
StringType& str; StringType& str;
}; };
/// @brief non-virtual output sink writing into a std::vector
///
/// Unlike output_vector_adapter, this sink is not part of the virtual
/// output_adapter_protocol hierarchy: it is passed to binary_writer by value as
/// a template parameter, so write_character()/write_characters() are ordinary
/// (inlinable) calls with no vtable lookup and no shared_ptr. It is used for the
/// common `to_cbor`/`to_msgpack`/... into a std::vector.
template<typename CharType, typename AllocatorType = std::allocator<CharType>>
class output_vector_sink
{
public:
explicit output_vector_sink(std::vector<CharType, AllocatorType>& vec) noexcept
: v(vec)
{}
void write_character(CharType c)
{
v.push_back(c);
}
JSON_HEDLEY_NON_NULL(2)
void write_characters(const CharType* s, std::size_t length)
{
v.insert(v.end(), s, s + length);
}
private:
std::vector<CharType, AllocatorType>& v;
};
/// @brief output sink forwarding to a type-erased output adapter
///
/// Wraps the polymorphic output_adapter_t so the same binary_writer template can
/// also target arbitrary adapters (output streams, strings, user-provided
/// adapters) via the `output_adapter`-based overloads. Each write still goes
/// through one virtual call, exactly as before; only the concrete sinks above
/// avoid it.
template<typename CharType>
class output_adapter_sink
{
public:
explicit output_adapter_sink(output_adapter_t<CharType> adapter)
: oa(std::move(adapter))
{
JSON_ASSERT(oa);
}
void write_character(CharType c)
{
oa->write_character(c);
}
JSON_HEDLEY_NON_NULL(2)
void write_characters(const CharType* s, std::size_t length)
{
oa->write_characters(s, length);
}
private:
output_adapter_t<CharType> oa = nullptr;
};
template<typename CharType, typename StringType = std::basic_string<CharType>> template<typename CharType, typename StringType = std::basic_string<CharType>>
class output_adapter class output_adapter
{ {
+13 -7
View File
@@ -140,7 +140,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
friend ::nlohmann::detail::serializer<basic_json>; friend ::nlohmann::detail::serializer<basic_json>;
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, typename OutputSinkType>
friend class ::nlohmann::detail::binary_writer; friend class ::nlohmann::detail::binary_writer;
template<typename BasicJsonType, typename InputType, typename SAX> template<typename BasicJsonType, typename InputType, typename SAX>
friend class ::nlohmann::detail::binary_reader; friend class ::nlohmann::detail::binary_reader;
@@ -186,7 +186,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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, typename OutputSinkType = ::nlohmann::detail::output_adapter_sink<CharType>>
using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType, OutputSinkType>;
JSON_PRIVATE_UNLESS_TESTED: JSON_PRIVATE_UNLESS_TESTED:
using serializer = ::nlohmann::detail::serializer<basic_json>; using serializer = ::nlohmann::detail::serializer<basic_json>;
@@ -4327,7 +4328,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static std::vector<std::uint8_t> to_cbor(const basic_json& j) static std::vector<std::uint8_t> to_cbor(const basic_json& j)
{ {
std::vector<std::uint8_t> result; std::vector<std::uint8_t> result;
to_cbor(j, result); binary_writer<std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
detail::output_vector_sink<std::uint8_t>(result)).write_cbor(j);
return result; return result;
} }
@@ -4350,7 +4352,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static std::vector<std::uint8_t> to_msgpack(const basic_json& j) static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
{ {
std::vector<std::uint8_t> result; std::vector<std::uint8_t> result;
to_msgpack(j, result); binary_writer<std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
detail::output_vector_sink<std::uint8_t>(result)).write_msgpack(j);
return result; return result;
} }
@@ -4375,7 +4378,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bool use_type = false) const bool use_type = false)
{ {
std::vector<std::uint8_t> result; std::vector<std::uint8_t> result;
to_ubjson(j, result, use_size, use_type); binary_writer<std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
detail::output_vector_sink<std::uint8_t>(result)).write_ubjson(j, use_size, use_type);
return result; return result;
} }
@@ -4403,7 +4407,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const bjdata_version_t version = bjdata_version_t::draft2) const bjdata_version_t version = bjdata_version_t::draft2)
{ {
std::vector<std::uint8_t> result; std::vector<std::uint8_t> result;
to_bjdata(j, result, use_size, use_type, version); binary_writer<std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
detail::output_vector_sink<std::uint8_t>(result)).write_ubjson(j, use_size, use_type, true, true, version);
return result; return result;
} }
@@ -4430,7 +4435,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static std::vector<std::uint8_t> to_bson(const basic_json& j) static std::vector<std::uint8_t> to_bson(const basic_json& j)
{ {
std::vector<std::uint8_t> result; std::vector<std::uint8_t> result;
to_bson(j, result); binary_writer<std::uint8_t, detail::output_vector_sink<std::uint8_t>>(
detail::output_vector_sink<std::uint8_t>(result)).write_bson(j);
return result; return result;
} }
File diff suppressed because it is too large Load Diff