Do not zero the serializer's buffers

Constructing a serializer value-initialized its three buffers (64 + 512
+ 1024 bytes). Each is written before it is read and only the part that
was written is ever read, so the zeroing was never needed, but it took
about 170 instructions per dump(), more than half of the cost of dumping
a small value.

Apple M1, Apple clang, per dump():
  null                325 -> 153 instructions
  [1,2,3]             629 -> 458 instructions
  small object (134 B) 2795 -> 2624 instructions, 190 -> 165 ns (-13 %)
  a 139-byte object, compact: 2763 -> 2596 instructions (-6 %)
Large documents are unchanged. Checked with valgrind memcheck over the
differential corpus (no use of uninitialized values), and with GCC 13
-Wall -Wextra -Wmaybe-uninitialized at -O0 to -O3 and -Os.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-22 09:28:18 +02:00
1 parent 209348c151
commit fdcf3aa390
2 files changed
+16 -8

No files matched your search

@@ -82,7 +82,7 @@ class serializer
being threaded through every call to @ref dump, @ref dump_internal and
@ref dump_iteratively.
*/
serializer(output_adapter_protocol<char>& s, const char ichar,
serializer(output_adapter_protocol<char>& s, const char ichar, // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init): the buffers are written before they are read
const bool pretty_print_ = false,
const bool ensure_ascii_ = false,
const std::size_t indent_step_ = 0,
@@ -2050,11 +2050,15 @@ class serializer
/// the output of the serializer (non-owning; the adapter lives at the call site)
output_adapter_protocol<char>* o = nullptr;
// The three buffers below are left uninitialized: they are written before they
// are read (only the part written is ever read), and zeroing 1.6 KiB took
// more than half of what dumping a small value costs.
/// a (hopefully) large enough character buffer
std::array<char, 64> number_buffer{{}};
std::array<char, 64> number_buffer; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
/// string buffer
std::array<char, 512> string_buffer{{}};
std::array<char, 512> string_buffer; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
/// the indentation character
const char indent_char;
@@ -2074,7 +2078,7 @@ class serializer
/// buffer collecting output before it is flushed to the output adapter, so
/// that the many small structural writes become few bulk writes
static constexpr std::size_t write_buffer_size = 1024;
std::array<char, write_buffer_size> write_buffer{{}};
std::array<char, write_buffer_size> write_buffer; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
/// number of valid bytes currently held in @ref write_buffer
std::size_t write_buffer_pos = 0;
};