Make serializer's indent_string lazily allocated

The serializer constructor unconditionally allocated a 512-byte
indent_string, even though it is only ever read inside the
pretty_print branches of dump(). This wasted a heap allocation (and
its matching deallocation) on every compact (i.e. default, non-pretty)
dump() call.

indent_string is now default-constructed empty and lazily grown to
512 bytes, filled with indent_char, the first time a pretty-print
branch actually needs it. The existing doubling/growth logic for
larger indents is otherwise untouched, so output remains byte-identical
to before -- including in the pre-existing edge case where growth
beyond the initial buffer fills with ' ' instead of indent_char
(tracked separately by open PR #5186, which is left alone here).

The second, larger optimization mentioned in #5413 (removing the
shared_ptr-based output adapter) is intentionally out of scope, as it
overlaps open PR #5285.

Fixes #5413

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-05 20:59:58 +02:00
parent 09b6b6b5ba
commit d027f06a42
3 changed files with 135 additions and 4 deletions
+14 -2
View File
@@ -20150,7 +20150,7 @@ class serializer
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
, decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
, indent_char(ichar)
, indent_string(512, indent_char)
, indent_string()
, error_handler(error_handler_)
{}
@@ -20205,6 +20205,10 @@ class serializer
// variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step;
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
{
indent_string.resize(512, indent_char);
}
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
{
indent_string.resize(indent_string.size() * 2, ' ');
@@ -20278,6 +20282,10 @@ class serializer
// variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step;
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
{
indent_string.resize(512, indent_char);
}
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
{
indent_string.resize(indent_string.size() * 2, ' ');
@@ -20339,6 +20347,10 @@ class serializer
// variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step;
if (JSON_HEDLEY_UNLIKELY(indent_string.empty()))
{
indent_string.resize(512, indent_char);
}
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
{
indent_string.resize(indent_string.size() * 2, ' ');
@@ -21089,7 +21101,7 @@ class serializer
/// the indentation character
const char indent_char;
/// the indentation string
/// the indentation string (lazily allocated on first use by a pretty-print branch)
string_t indent_string;
/// error_handler how to react on decoding errors