From 7717853976e250a255916e7893e24c84dc96a8f2 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 17 Oct 2026 00:53:32 +0200 Subject: [PATCH] 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 --- .../nlohmann/detail/output/binary_writer.hpp | 30 +++++++++++++++++++ single_include/nlohmann/json.hpp | 30 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 8915a4c7d..f2734f4fa 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -3754,6 +3754,36 @@ class binary_writer template 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::value && sizeof(NumberType) <= sizeof(std::uint64_t) > ()); + } + + /// an unsigned integer of at most 64 bits: its decimal digits are written directly + template + void write_ubjson_high_precision(const NumberType n, const bool use_bjdata, std::true_type /*is_unsigned_64_bits*/) + { + std::array digits; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init): written before read + std::size_t first = digits.size(); + auto value = static_cast(n); + do + { + digits[--first] = static_cast('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(digits[first + i])); + } + oa.commit(length); + } + + /// any other integer: its decimal digits from basic_json::dump() + template + 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); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index bd77bf628..9707fcc96 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -28604,6 +28604,36 @@ class binary_writer template 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::value && sizeof(NumberType) <= sizeof(std::uint64_t) > ()); + } + + /// an unsigned integer of at most 64 bits: its decimal digits are written directly + template + void write_ubjson_high_precision(const NumberType n, const bool use_bjdata, std::true_type /*is_unsigned_64_bits*/) + { + std::array digits; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init): written before read + std::size_t first = digits.size(); + auto value = static_cast(n); + do + { + digits[--first] = static_cast('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(digits[first + i])); + } + oa.commit(length); + } + + /// any other integer: its decimal digits from basic_json::dump() + template + 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);