From 731363a325f095d4f4e4545f21abde9b62ab994f Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 16 Oct 2026 21:35:08 +0200 Subject: [PATCH] Write the usual indentation with four stores instead of memset Every line of a pretty-printed document starts with its indentation, which was written by calling memset with a length known only at run time. An indentation of up to 32 characters, with room in the write buffer, stores four words of the indentation character and claims the part it needs. Wider indentations and a nearly full buffer take the unchanged path. Apple M1, Apple clang, retired instructions per dump(4), on top of the previous changes: canada 50.7M -> 44.4M (-13 %) citm_catalog 8.85M -> 7.48M (-16 %) twitter 5.13M -> 4.71M (-8 %) jeopardy 564M -> 518M (-8 %) a 139-byte object 3277 -> 2924 (-11 %) Linux x86-64 (callgrind), the whole series against develop, gcc 13 / clang 18: canada, indent 4: -13 % / -14 %. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/output/serializer.hpp | 15 +++++++++++++++ single_include/nlohmann/json.hpp | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index e8116a36f..d4f0d863b 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -1325,6 +1325,21 @@ class serializer return; } + // the usual indentation: four words of the indentation character are + // stored unconditionally and only the part wanted is claimed, which + // spares the call of memset + if (JSON_HEDLEY_LIKELY(indent <= 32 && write_buffer_pos + 32 <= write_buffer.size())) + { + const std::uint64_t word = 0x0101010101010101ull * static_cast(indent_char); + char* const d = write_buffer.data() + write_buffer_pos; + std::memcpy(d, &word, sizeof(word)); + std::memcpy(d + 8, &word, sizeof(word)); + std::memcpy(d + 16, &word, sizeof(word)); + std::memcpy(d + 24, &word, sizeof(word)); + write_buffer_pos += indent; + return; + } + const std::size_t capacity = write_buffer.size(); // fill whatever room is left in the buffer; this is the whole job diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 6552900c9..acff3d7b4 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -31469,6 +31469,21 @@ class serializer return; } + // the usual indentation: four words of the indentation character are + // stored unconditionally and only the part wanted is claimed, which + // spares the call of memset + if (JSON_HEDLEY_LIKELY(indent <= 32 && write_buffer_pos + 32 <= write_buffer.size())) + { + const std::uint64_t word = 0x0101010101010101ull * static_cast(indent_char); + char* const d = write_buffer.data() + write_buffer_pos; + std::memcpy(d, &word, sizeof(word)); + std::memcpy(d + 8, &word, sizeof(word)); + std::memcpy(d + 16, &word, sizeof(word)); + std::memcpy(d + 24, &word, sizeof(word)); + write_buffer_pos += indent; + return; + } + const std::size_t capacity = write_buffer.size(); // fill whatever room is left in the buffer; this is the whole job