Write the members of an object with scalar values without a call each
Every member of an object was a call of write_cbor()/write_msgpack()/ write_ubjson() for its value, however simple: a function with a large frame that saves and restores many registers around a single sink write. Objects are now written by a function of their own, like arrays, in which members with a null, boolean, integer, or string value (and a float, in UBJSON and BJData) are written in place; anything else is passed on to the general function. The depth limit and the recursion for nested values are unchanged. Instructions per call (Linux, GCC 13, thousands), to_ubjson: 20000 small objects 17861 -> 14661, twitter 3271 -> 2798; to_bjdata: 20000 small objects 17881 -> 14681, twitter 3277 -> 2804; to_msgpack: twitter 2948 -> 2646. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
2 files changed
+326
-52
No files matched your search
@@ -305,16 +305,7 @@ class binary_writer
|
||||
|
||||
case value_t::object:
|
||||
{
|
||||
// step 1: write control byte and the object size
|
||||
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// el.first is written directly (not via a temporary
|
||||
// basic_json), with the object as diagnostics context
|
||||
write_cbor_key(el.first, j);
|
||||
write_cbor(el.second, depth + 1);
|
||||
}
|
||||
write_cbor_object(j, depth);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -530,15 +521,7 @@ class binary_writer
|
||||
case value_t::object:
|
||||
{
|
||||
// step 1: write control byte and the object size
|
||||
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// as in write_cbor, el.first is written directly with the
|
||||
// object as diagnostics context
|
||||
write_msgpack_key(el.first, j);
|
||||
write_msgpack(el.second, depth + 1);
|
||||
}
|
||||
write_msgpack_object(j, depth);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -708,13 +691,7 @@ class binary_writer
|
||||
bool prefix_required = true;
|
||||
const bool write_closer = write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// a converted key must outlive the reference returned by sanitize_utf8_for_write
|
||||
const object_key_string_t key_string = el.first;
|
||||
write_ubjson_text(key_string, j, false, use_bjdata);
|
||||
write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1);
|
||||
}
|
||||
write_ubjson_members(j, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth);
|
||||
|
||||
if (write_closer)
|
||||
{
|
||||
@@ -2579,6 +2556,56 @@ class binary_writer
|
||||
return encode_first_byte_and_tail(out, first_byte, size_class, argument);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an object value (head and members) as CBOR
|
||||
|
||||
A member whose value is null, a boolean, an integer, or a string is written
|
||||
without a call of @ref write_cbor. Kept out of line, like @ref write_cbor_array.
|
||||
*/
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
void write_cbor_object(const BasicJsonType& j, const std::size_t depth)
|
||||
{
|
||||
// step 1: write control byte and the object size
|
||||
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// el.first is written directly (not via a temporary
|
||||
// basic_json), with the object as diagnostics context
|
||||
write_cbor_key(el.first, j);
|
||||
|
||||
const BasicJsonType& value = el.second;
|
||||
switch (value.type())
|
||||
{
|
||||
case value_t::null:
|
||||
oa.write_character(to_char_type(0xF6));
|
||||
break;
|
||||
|
||||
case value_t::boolean:
|
||||
oa.write_character(value.m_data.m_value.boolean ? to_char_type(0xF5) : to_char_type(0xF4));
|
||||
break;
|
||||
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
write_cbor_integer(value, std::integral_constant<bool, integers_fit_64_bits()>());
|
||||
break;
|
||||
|
||||
case value_t::string:
|
||||
write_cbor_string(*value.m_data.m_value.string, value);
|
||||
break;
|
||||
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
case value_t::binary:
|
||||
case value_t::number_float:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
write_cbor(value, depth + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an array value (head and elements) as CBOR
|
||||
|
||||
@@ -2857,6 +2884,54 @@ class binary_writer
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an object value (head and members) as MessagePack
|
||||
|
||||
See @ref write_cbor_object.
|
||||
*/
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
void write_msgpack_object(const BasicJsonType& j, const std::size_t depth)
|
||||
{
|
||||
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// as in write_cbor, el.first is written directly with the
|
||||
// object as diagnostics context
|
||||
write_msgpack_key(el.first, j);
|
||||
|
||||
const BasicJsonType& value = el.second;
|
||||
switch (value.type())
|
||||
{
|
||||
case value_t::null:
|
||||
oa.write_character(to_char_type(0xC0));
|
||||
break;
|
||||
|
||||
case value_t::boolean:
|
||||
oa.write_character(value.m_data.m_value.boolean ? to_char_type(0xC3) : to_char_type(0xC2));
|
||||
break;
|
||||
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
write_msgpack_integer(value, std::integral_constant<bool, integers_fit_64_bits()>());
|
||||
break;
|
||||
|
||||
case value_t::string:
|
||||
write_msgpack_string(*value.m_data.m_value.string, value);
|
||||
break;
|
||||
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
case value_t::binary:
|
||||
case value_t::number_float:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
write_msgpack(value, depth + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an array value (head and elements) as MessagePack
|
||||
|
||||
@@ -3248,6 +3323,68 @@ class binary_writer
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write the members of the object @a j of a UBJSON/BJData container
|
||||
|
||||
A member whose value is null, a boolean, an integer, a float, or a string is
|
||||
written without a call of @ref write_ubjson. Kept out of line, like
|
||||
@ref write_cbor_object.
|
||||
*/
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
void write_ubjson_members(const BasicJsonType& j, const bool use_count, const bool use_type,
|
||||
const bool prefix_required, const bool use_bjdata, const bjdata_version_t bjdata_version,
|
||||
const std::size_t depth)
|
||||
{
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// a converted key must outlive the reference returned by sanitize_utf8_for_write
|
||||
const object_key_string_t key_string = el.first;
|
||||
write_ubjson_text(key_string, j, false, use_bjdata);
|
||||
|
||||
const BasicJsonType& value = el.second;
|
||||
switch (value.type())
|
||||
{
|
||||
case value_t::null:
|
||||
if (prefix_required)
|
||||
{
|
||||
oa.write_character(to_char_type('Z'));
|
||||
}
|
||||
break;
|
||||
|
||||
case value_t::boolean:
|
||||
if (prefix_required)
|
||||
{
|
||||
oa.write_character(value.m_data.m_value.boolean ? to_char_type('T') : to_char_type('F'));
|
||||
}
|
||||
break;
|
||||
|
||||
case value_t::number_integer:
|
||||
write_number_with_ubjson_prefix(value.m_data.m_value.number_integer, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::number_unsigned:
|
||||
write_number_with_ubjson_prefix(value.m_data.m_value.number_unsigned, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::number_float:
|
||||
write_number_with_ubjson_prefix(value.m_data.m_value.number_float, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::string:
|
||||
write_ubjson_text(*value.m_data.m_value.string, value, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
case value_t::binary:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
write_ubjson(value, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write a UBJSON/BJData string or object key: the optional string
|
||||
marker `S`, the length as an integer with its marker, and the characters
|
||||
|
||||
Generated
+163
-26
@@ -25133,16 +25133,7 @@ class binary_writer
|
||||
|
||||
case value_t::object:
|
||||
{
|
||||
// step 1: write control byte and the object size
|
||||
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// el.first is written directly (not via a temporary
|
||||
// basic_json), with the object as diagnostics context
|
||||
write_cbor_key(el.first, j);
|
||||
write_cbor(el.second, depth + 1);
|
||||
}
|
||||
write_cbor_object(j, depth);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -25358,15 +25349,7 @@ class binary_writer
|
||||
case value_t::object:
|
||||
{
|
||||
// step 1: write control byte and the object size
|
||||
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// as in write_cbor, el.first is written directly with the
|
||||
// object as diagnostics context
|
||||
write_msgpack_key(el.first, j);
|
||||
write_msgpack(el.second, depth + 1);
|
||||
}
|
||||
write_msgpack_object(j, depth);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -25536,13 +25519,7 @@ class binary_writer
|
||||
bool prefix_required = true;
|
||||
const bool write_closer = write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// a converted key must outlive the reference returned by sanitize_utf8_for_write
|
||||
const object_key_string_t key_string = el.first;
|
||||
write_ubjson_text(key_string, j, false, use_bjdata);
|
||||
write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1);
|
||||
}
|
||||
write_ubjson_members(j, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth);
|
||||
|
||||
if (write_closer)
|
||||
{
|
||||
@@ -27407,6 +27384,56 @@ class binary_writer
|
||||
return encode_first_byte_and_tail(out, first_byte, size_class, argument);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an object value (head and members) as CBOR
|
||||
|
||||
A member whose value is null, a boolean, an integer, or a string is written
|
||||
without a call of @ref write_cbor. Kept out of line, like @ref write_cbor_array.
|
||||
*/
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
void write_cbor_object(const BasicJsonType& j, const std::size_t depth)
|
||||
{
|
||||
// step 1: write control byte and the object size
|
||||
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// el.first is written directly (not via a temporary
|
||||
// basic_json), with the object as diagnostics context
|
||||
write_cbor_key(el.first, j);
|
||||
|
||||
const BasicJsonType& value = el.second;
|
||||
switch (value.type())
|
||||
{
|
||||
case value_t::null:
|
||||
oa.write_character(to_char_type(0xF6));
|
||||
break;
|
||||
|
||||
case value_t::boolean:
|
||||
oa.write_character(value.m_data.m_value.boolean ? to_char_type(0xF5) : to_char_type(0xF4));
|
||||
break;
|
||||
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
write_cbor_integer(value, std::integral_constant<bool, integers_fit_64_bits()>());
|
||||
break;
|
||||
|
||||
case value_t::string:
|
||||
write_cbor_string(*value.m_data.m_value.string, value);
|
||||
break;
|
||||
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
case value_t::binary:
|
||||
case value_t::number_float:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
write_cbor(value, depth + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an array value (head and elements) as CBOR
|
||||
|
||||
@@ -27685,6 +27712,54 @@ class binary_writer
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an object value (head and members) as MessagePack
|
||||
|
||||
See @ref write_cbor_object.
|
||||
*/
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
void write_msgpack_object(const BasicJsonType& j, const std::size_t depth)
|
||||
{
|
||||
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
||||
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// as in write_cbor, el.first is written directly with the
|
||||
// object as diagnostics context
|
||||
write_msgpack_key(el.first, j);
|
||||
|
||||
const BasicJsonType& value = el.second;
|
||||
switch (value.type())
|
||||
{
|
||||
case value_t::null:
|
||||
oa.write_character(to_char_type(0xC0));
|
||||
break;
|
||||
|
||||
case value_t::boolean:
|
||||
oa.write_character(value.m_data.m_value.boolean ? to_char_type(0xC3) : to_char_type(0xC2));
|
||||
break;
|
||||
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
write_msgpack_integer(value, std::integral_constant<bool, integers_fit_64_bits()>());
|
||||
break;
|
||||
|
||||
case value_t::string:
|
||||
write_msgpack_string(*value.m_data.m_value.string, value);
|
||||
break;
|
||||
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
case value_t::binary:
|
||||
case value_t::number_float:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
write_msgpack(value, depth + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write an array value (head and elements) as MessagePack
|
||||
|
||||
@@ -28076,6 +28151,68 @@ class binary_writer
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write the members of the object @a j of a UBJSON/BJData container
|
||||
|
||||
A member whose value is null, a boolean, an integer, a float, or a string is
|
||||
written without a call of @ref write_ubjson. Kept out of line, like
|
||||
@ref write_cbor_object.
|
||||
*/
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
void write_ubjson_members(const BasicJsonType& j, const bool use_count, const bool use_type,
|
||||
const bool prefix_required, const bool use_bjdata, const bjdata_version_t bjdata_version,
|
||||
const std::size_t depth)
|
||||
{
|
||||
for (const auto& el : *j.m_data.m_value.object)
|
||||
{
|
||||
// a converted key must outlive the reference returned by sanitize_utf8_for_write
|
||||
const object_key_string_t key_string = el.first;
|
||||
write_ubjson_text(key_string, j, false, use_bjdata);
|
||||
|
||||
const BasicJsonType& value = el.second;
|
||||
switch (value.type())
|
||||
{
|
||||
case value_t::null:
|
||||
if (prefix_required)
|
||||
{
|
||||
oa.write_character(to_char_type('Z'));
|
||||
}
|
||||
break;
|
||||
|
||||
case value_t::boolean:
|
||||
if (prefix_required)
|
||||
{
|
||||
oa.write_character(value.m_data.m_value.boolean ? to_char_type('T') : to_char_type('F'));
|
||||
}
|
||||
break;
|
||||
|
||||
case value_t::number_integer:
|
||||
write_number_with_ubjson_prefix(value.m_data.m_value.number_integer, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::number_unsigned:
|
||||
write_number_with_ubjson_prefix(value.m_data.m_value.number_unsigned, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::number_float:
|
||||
write_number_with_ubjson_prefix(value.m_data.m_value.number_float, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::string:
|
||||
write_ubjson_text(*value.m_data.m_value.string, value, prefix_required, use_bjdata);
|
||||
break;
|
||||
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
case value_t::binary:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
write_ubjson(value, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief write a UBJSON/BJData string or object key: the optional string
|
||||
marker `S`, the length as an integer with its marker, and the characters
|
||||
|
||||
Reference in new issue
Block a user