From fdcf3aa3901fef591f91f4258baf69e675618785 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 16 Oct 2026 21:33:38 +0200 Subject: [PATCH] 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 --- include/nlohmann/detail/output/serializer.hpp | 12 ++++++++---- single_include/nlohmann/json.hpp | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 8c16bc5f1..e8116a36f 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -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& s, const char ichar, + serializer(output_adapter_protocol& 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* 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 number_buffer{{}}; + std::array number_buffer; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) /// string buffer - std::array string_buffer{{}}; + std::array 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 write_buffer{{}}; + std::array 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; }; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 80690adc0..6552900c9 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -30226,7 +30226,7 @@ class serializer being threaded through every call to @ref dump, @ref dump_internal and @ref dump_iteratively. */ - serializer(output_adapter_protocol& s, const char ichar, + serializer(output_adapter_protocol& 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, @@ -32194,11 +32194,15 @@ class serializer /// the output of the serializer (non-owning; the adapter lives at the call site) output_adapter_protocol* 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 number_buffer{{}}; + std::array number_buffer; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) /// string buffer - std::array string_buffer{{}}; + std::array string_buffer; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) /// the indentation character const char indent_char; @@ -32218,7 +32222,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 write_buffer{{}}; + std::array 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; };