mirror of
https://github.com/nlohmann/json.git
synced 2026-10-22 14:08:13 +00:00
Write a line break and the indentation of the next line together
A pretty-printed array or object wrote ",\n", checked the room for the indentation, and stored it, for every element. The line break and the usual indentation (up to 32 characters, with room in the write buffer) are now written with one check and one run of stores, also after the opening bracket and in front of the closing one. Other indentations take the unchanged path. Apple M1, Apple clang, retired instructions per dump(4), on top of the previous changes: citm_catalog 7.28M -> 7.06M (-3 %) canada 44.4M -> 43.3M (-3 %) twitter 3.91M -> 3.78M (-3 %) jeopardy -1 % Linux x86-64 (callgrind), gcc 13 / clang 18, dump(4) / dump(1, '\t'): citm_catalog dump(4) -3 % / -4 %, tab -4 % / -5 %, with the function inlined (without that GCC wrote the combined step out of line and was 5 % slower than before the change). Compact output is unchanged. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
2 files changed
+68
-28
No files matched your search
@@ -167,30 +167,27 @@ class serializer
|
||||
|
||||
if (pretty_print)
|
||||
{
|
||||
put_literal("{\n");
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = next_indent(current_indent, indent_step);
|
||||
|
||||
put_literal_indent("{\n", new_indent);
|
||||
|
||||
// first n-1 elements
|
||||
auto i = val.m_data.m_value.object->cbegin();
|
||||
for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
|
||||
{
|
||||
put_indent(new_indent);
|
||||
put_quoted(i->first, "\": ");
|
||||
dump_element(i->second, new_indent, depth + 1);
|
||||
put_literal(",\n");
|
||||
put_literal_indent(",\n", new_indent);
|
||||
}
|
||||
|
||||
// last element
|
||||
JSON_ASSERT(i != val.m_data.m_value.object->cend());
|
||||
JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
|
||||
put_indent(new_indent);
|
||||
put_quoted(i->first, "\": ");
|
||||
dump_element(i->second, new_indent, depth + 1);
|
||||
|
||||
put_char('\n');
|
||||
put_indent(current_indent);
|
||||
put_literal_indent("\n", current_indent);
|
||||
put_char('}');
|
||||
}
|
||||
else
|
||||
@@ -234,27 +231,24 @@ class serializer
|
||||
|
||||
if (pretty_print)
|
||||
{
|
||||
put_literal("[\n");
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = next_indent(current_indent, indent_step);
|
||||
|
||||
put_literal_indent("[\n", new_indent);
|
||||
|
||||
// first n-1 elements
|
||||
for (auto i = val.m_data.m_value.array->cbegin();
|
||||
i != val.m_data.m_value.array->cend() - 1; ++i)
|
||||
{
|
||||
put_indent(new_indent);
|
||||
dump_element(*i, new_indent, depth + 1);
|
||||
put_literal(",\n");
|
||||
put_literal_indent(",\n", new_indent);
|
||||
}
|
||||
|
||||
// last element
|
||||
JSON_ASSERT(!val.m_data.m_value.array->empty());
|
||||
put_indent(new_indent);
|
||||
dump_element(val.m_data.m_value.array->back(), new_indent, depth + 1);
|
||||
|
||||
put_char('\n');
|
||||
put_indent(current_indent);
|
||||
put_literal_indent("\n", current_indent);
|
||||
put_char(']');
|
||||
}
|
||||
else
|
||||
@@ -1430,6 +1424,32 @@ class serializer
|
||||
write_buffer_pos = indent;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief append a string literal and then @a indent indentation characters
|
||||
|
||||
The usual line break and indentation go into the buffer with one check of
|
||||
its room and four stores of the indentation, see @ref put_indent.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
JSON_HEDLEY_ALWAYS_INLINE void put_literal_indent(const char (&s)[N], const std::size_t indent) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
{
|
||||
constexpr std::size_t length = N - 1;
|
||||
if (JSON_HEDLEY_LIKELY(indent <= 32 && write_buffer_pos + length + 32 <= write_buffer.size()))
|
||||
{
|
||||
const std::uint64_t word = 0x0101010101010101ull * static_cast<unsigned char>(indent_char);
|
||||
char* const d = write_buffer.data() + write_buffer_pos;
|
||||
std::memcpy(d, s, length);
|
||||
std::memcpy(d + length, &word, sizeof(word));
|
||||
std::memcpy(d + length + 8, &word, sizeof(word));
|
||||
std::memcpy(d + length + 16, &word, sizeof(word));
|
||||
std::memcpy(d + length + 24, &word, sizeof(word));
|
||||
write_buffer_pos += length + indent;
|
||||
return;
|
||||
}
|
||||
put_literal(s);
|
||||
put_indent(indent);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief append a string literal to the write buffer
|
||||
|
||||
|
||||
Generated
+34
-14
@@ -30311,30 +30311,27 @@ class serializer
|
||||
|
||||
if (pretty_print)
|
||||
{
|
||||
put_literal("{\n");
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = next_indent(current_indent, indent_step);
|
||||
|
||||
put_literal_indent("{\n", new_indent);
|
||||
|
||||
// first n-1 elements
|
||||
auto i = val.m_data.m_value.object->cbegin();
|
||||
for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
|
||||
{
|
||||
put_indent(new_indent);
|
||||
put_quoted(i->first, "\": ");
|
||||
dump_element(i->second, new_indent, depth + 1);
|
||||
put_literal(",\n");
|
||||
put_literal_indent(",\n", new_indent);
|
||||
}
|
||||
|
||||
// last element
|
||||
JSON_ASSERT(i != val.m_data.m_value.object->cend());
|
||||
JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
|
||||
put_indent(new_indent);
|
||||
put_quoted(i->first, "\": ");
|
||||
dump_element(i->second, new_indent, depth + 1);
|
||||
|
||||
put_char('\n');
|
||||
put_indent(current_indent);
|
||||
put_literal_indent("\n", current_indent);
|
||||
put_char('}');
|
||||
}
|
||||
else
|
||||
@@ -30378,27 +30375,24 @@ class serializer
|
||||
|
||||
if (pretty_print)
|
||||
{
|
||||
put_literal("[\n");
|
||||
|
||||
// variable to hold indentation for recursive calls
|
||||
const auto new_indent = next_indent(current_indent, indent_step);
|
||||
|
||||
put_literal_indent("[\n", new_indent);
|
||||
|
||||
// first n-1 elements
|
||||
for (auto i = val.m_data.m_value.array->cbegin();
|
||||
i != val.m_data.m_value.array->cend() - 1; ++i)
|
||||
{
|
||||
put_indent(new_indent);
|
||||
dump_element(*i, new_indent, depth + 1);
|
||||
put_literal(",\n");
|
||||
put_literal_indent(",\n", new_indent);
|
||||
}
|
||||
|
||||
// last element
|
||||
JSON_ASSERT(!val.m_data.m_value.array->empty());
|
||||
put_indent(new_indent);
|
||||
dump_element(val.m_data.m_value.array->back(), new_indent, depth + 1);
|
||||
|
||||
put_char('\n');
|
||||
put_indent(current_indent);
|
||||
put_literal_indent("\n", current_indent);
|
||||
put_char(']');
|
||||
}
|
||||
else
|
||||
@@ -31574,6 +31568,32 @@ class serializer
|
||||
write_buffer_pos = indent;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief append a string literal and then @a indent indentation characters
|
||||
|
||||
The usual line break and indentation go into the buffer with one check of
|
||||
its room and four stores of the indentation, see @ref put_indent.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
JSON_HEDLEY_ALWAYS_INLINE void put_literal_indent(const char (&s)[N], const std::size_t indent) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
{
|
||||
constexpr std::size_t length = N - 1;
|
||||
if (JSON_HEDLEY_LIKELY(indent <= 32 && write_buffer_pos + length + 32 <= write_buffer.size()))
|
||||
{
|
||||
const std::uint64_t word = 0x0101010101010101ull * static_cast<unsigned char>(indent_char);
|
||||
char* const d = write_buffer.data() + write_buffer_pos;
|
||||
std::memcpy(d, s, length);
|
||||
std::memcpy(d + length, &word, sizeof(word));
|
||||
std::memcpy(d + length + 8, &word, sizeof(word));
|
||||
std::memcpy(d + length + 16, &word, sizeof(word));
|
||||
std::memcpy(d + length + 24, &word, sizeof(word));
|
||||
write_buffer_pos += length + indent;
|
||||
return;
|
||||
}
|
||||
put_literal(s);
|
||||
put_indent(indent);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief append a string literal to the write buffer
|
||||
|
||||
|
||||
Reference in new issue
Block a user