mirror of
https://github.com/nlohmann/json.git
synced 2026-10-22 22:08:55 +00:00
Reserve at least 64 bytes for the result of a binary serialization
The result of to_cbor() and its siblings reserved the lower bound of binary_reserve_hint(), for a small object a few bytes, and the first write of the sink replaced it by an allocation of 64 bytes, as an empty or too small vector is grown to at least that. A small document therefore cost two allocations and a free. The result now reserves at least min_vector_sink_capacity (64) characters at once. binary_reserve_hint() itself, a lower bound that is tested as such, is unchanged. Instructions to serialize a small object (six members, a nested array and object), Linux, GCC 13: to_cbor 1700 -> 1500, to_msgpack 1800 -> 1600, to_ubjson 1800 -> 1700, to_bson 2700 -> 2500. Documents larger than 64 bytes of hint are unchanged. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
4 files changed
+54
-18
No files matched your search
Generated
+27
-9
@@ -24241,7 +24241,7 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
|
||||
|
||||
#include <algorithm> // min, reverse
|
||||
#include <algorithm> // max, min, reverse
|
||||
#include <array> // array
|
||||
#include <cmath> // isnan, isinf
|
||||
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
|
||||
@@ -24378,6 +24378,9 @@ inline void copy_short(CharType* dst, const CharType* src, const std::size_t len
|
||||
std::memcpy(dst, src, length * sizeof(CharType));
|
||||
}
|
||||
|
||||
/// the number of characters an empty vector is grown to by output_vector_sink
|
||||
constexpr std::size_t min_vector_sink_capacity = 64;
|
||||
|
||||
/// @brief non-virtual output sink writing into a std::vector
|
||||
///
|
||||
/// This sink is not part of the virtual output_adapter_protocol hierarchy: it is
|
||||
@@ -24498,10 +24501,10 @@ class output_vector_sink
|
||||
void grow(const std::size_t length)
|
||||
{
|
||||
// use the capacity the vector already has, else at least double it;
|
||||
// never less than 64 characters, so that a small value does not
|
||||
// never less than min_vector_sink_capacity, so that a small value does not
|
||||
// reallocate for every few bytes
|
||||
const std::size_t needed = position + length;
|
||||
v->resize((std::max)(std::size_t{64}, needed <= v->capacity()
|
||||
v->resize((std::max)(min_vector_sink_capacity, needed <= v->capacity()
|
||||
? v->capacity()
|
||||
: (std::max)(needed, v->capacity() * 2)));
|
||||
}
|
||||
@@ -24903,6 +24906,21 @@ std::size_t binary_reserve_hint(const BasicJsonType& j)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief the capacity to reserve for the result of a binary serialization into a
|
||||
std::vector
|
||||
|
||||
The hint of @ref binary_reserve_hint, but not less than the 64 characters that
|
||||
output_vector_sink grows an empty vector to on its first write anyway. A small
|
||||
document then costs one allocation, instead of an allocation of a few bytes that
|
||||
the first write replaces with one of 64.
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
std::size_t binary_initial_capacity(const BasicJsonType& j)
|
||||
{
|
||||
return (std::max)(binary_reserve_hint(j), min_vector_sink_capacity);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief serialization to BJData, BON8, BSON, CBOR, MessagePack, and UBJSON values
|
||||
*/
|
||||
@@ -40035,7 +40053,7 @@ public:
|
||||
const error_handler_t error_handler = detail::binary_writer_default_error_handler())
|
||||
{
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve(detail::binary_reserve_hint(j));
|
||||
result.reserve(detail::binary_initial_capacity(j));
|
||||
vector_writer(result, error_handler).write_cbor(j);
|
||||
return result;
|
||||
}
|
||||
@@ -40066,7 +40084,7 @@ public:
|
||||
const error_handler_t error_handler = error_handler_t::keep)
|
||||
{
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve(detail::binary_reserve_hint(j));
|
||||
result.reserve(detail::binary_initial_capacity(j));
|
||||
vector_writer(result, error_handler).write_msgpack(j);
|
||||
return result;
|
||||
}
|
||||
@@ -40099,7 +40117,7 @@ public:
|
||||
const error_handler_t error_handler = detail::binary_writer_default_error_handler())
|
||||
{
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve(detail::binary_reserve_hint(j));
|
||||
result.reserve(detail::binary_initial_capacity(j));
|
||||
vector_writer(result, error_handler).write_ubjson(j, use_size, use_type);
|
||||
return result;
|
||||
}
|
||||
@@ -40135,7 +40153,7 @@ public:
|
||||
const error_handler_t error_handler = detail::binary_writer_default_error_handler())
|
||||
{
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve(detail::binary_reserve_hint(j));
|
||||
result.reserve(detail::binary_initial_capacity(j));
|
||||
vector_writer(result, error_handler).write_ubjson(j, use_size, use_type, true, true, version);
|
||||
return result;
|
||||
}
|
||||
@@ -40170,7 +40188,7 @@ public:
|
||||
const error_handler_t error_handler = detail::binary_writer_default_error_handler())
|
||||
{
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve(detail::binary_reserve_hint(j));
|
||||
result.reserve(detail::binary_initial_capacity(j));
|
||||
vector_writer(result, error_handler).write_bson(j);
|
||||
return result;
|
||||
}
|
||||
@@ -40200,7 +40218,7 @@ public:
|
||||
static std::vector<std::uint8_t> to_bon8(const basic_json& j)
|
||||
{
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve(detail::binary_reserve_hint(j));
|
||||
result.reserve(detail::binary_initial_capacity(j));
|
||||
vector_writer(result).write_bon8(j);
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user