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:
Niels Lohmann committed 2026-10-22 09:29:11 +02:00
1 parent 7241ba94c8
commit ceb3c92709
4 files changed
+54 -18

No files matched your search

@@ -8,7 +8,7 @@
#pragma once
#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
@@ -75,6 +75,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
*/