Write the digits of a high-precision UBJSON number without basic_json

An unsigned integer above the int64 range is a high-precision number in
UBJSON: its decimal digits as a string. They were found by building a
basic_json from the integer and calling dump() on it, an allocation and a
serializer for 20 digits.

An unsigned integer of at most 64 bits now writes its digits from a small
buffer. Other integer types (wider than 64 bits) keep dump().

Instructions per call, 3000 integers above the int64 range (Linux, GCC 13, thousands): to_ubjson 3968 -> 1825, to_bjdata 180 -> 180. (to_bjdata writes these as uint64 and is unchanged.)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-22 09:29:31 +02:00
1 parent bc94203dbc
commit 7717853976
2 files changed
+60

No files matched your search

@@ -3754,6 +3754,36 @@ class binary_writer
template<typename NumberType>
JSON_HEDLEY_NEVER_INLINE
void write_ubjson_high_precision(const NumberType n, const bool use_bjdata)
{
write_ubjson_high_precision(n, use_bjdata, std::integral_constant < bool, std::is_unsigned<NumberType>::value && sizeof(NumberType) <= sizeof(std::uint64_t) > ());
}
/// an unsigned integer of at most 64 bits: its decimal digits are written directly
template<typename NumberType>
void write_ubjson_high_precision(const NumberType n, const bool use_bjdata, std::true_type /*is_unsigned_64_bits*/)
{
std::array<char, 20> digits; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init): written before read
std::size_t first = digits.size();
auto value = static_cast<std::uint64_t>(n);
do
{
digits[--first] = static_cast<char>('0' + (value % 10));
value /= 10;
}
while (value != 0);
const std::size_t length = digits.size() - first;
write_number_with_ubjson_prefix(length, true, use_bjdata);
CharType* const out = oa.reserve(digits.size());
for (std::size_t i = 0; i < length; ++i)
{
out[i] = to_char_type(static_cast<std::uint8_t>(digits[first + i]));
}
oa.commit(length);
}
/// any other integer: its decimal digits from basic_json::dump()
template<typename NumberType>
void write_ubjson_high_precision(const NumberType n, const bool use_bjdata, std::false_type /*is_unsigned_64_bits*/)
{
const auto number = BasicJsonType(n).dump();
write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
+30
View File
@@ -28604,6 +28604,36 @@ class binary_writer
template<typename NumberType>
JSON_HEDLEY_NEVER_INLINE
void write_ubjson_high_precision(const NumberType n, const bool use_bjdata)
{
write_ubjson_high_precision(n, use_bjdata, std::integral_constant < bool, std::is_unsigned<NumberType>::value && sizeof(NumberType) <= sizeof(std::uint64_t) > ());
}
/// an unsigned integer of at most 64 bits: its decimal digits are written directly
template<typename NumberType>
void write_ubjson_high_precision(const NumberType n, const bool use_bjdata, std::true_type /*is_unsigned_64_bits*/)
{
std::array<char, 20> digits; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init): written before read
std::size_t first = digits.size();
auto value = static_cast<std::uint64_t>(n);
do
{
digits[--first] = static_cast<char>('0' + (value % 10));
value /= 10;
}
while (value != 0);
const std::size_t length = digits.size() - first;
write_number_with_ubjson_prefix(length, true, use_bjdata);
CharType* const out = oa.reserve(digits.size());
for (std::size_t i = 0; i < length; ++i)
{
out[i] = to_char_type(static_cast<std::uint8_t>(digits[first + i]));
}
oa.commit(length);
}
/// any other integer: its decimal digits from basic_json::dump()
template<typename NumberType>
void write_ubjson_high_precision(const NumberType n, const bool use_bjdata, std::false_type /*is_unsigned_64_bits*/)
{
const auto number = BasicJsonType(n).dump();
write_number_with_ubjson_prefix(number.size(), true, use_bjdata);