Reserve the storage of an ordered_json in flatten() once

flatten() appended the entries to an ordered_map one by one, so its vector
grew by doubling and moved every entry about once in total. The number of
entries is known after a walk over the value that only counts (it needs no
path strings), so objects with a reserve() are given that capacity first.
std::map has no reserve() and is unchanged.

flatten() of an ordered_json (instructions on macOS, Linux Ir GCC 13 / Clang 18):
citm_catalog 36.8M -> 23.1M, 32.7M -> 17.1M / 31.7M -> 16.8M; twitter 20.5M ->
13.6M, 17.6M -> 10.0M / 17.0M -> 9.8M. Output is identical.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-22 09:29:49 +02:00
1 parent f2c0e8b6f9
commit ba25f96169
2 files changed
+94

No files matched your search

+47
View File
@@ -23704,6 +23704,52 @@ class json_pointer
obj[key] = std::forward<ValueType>(v);
}
/// the number of entries that flattening @a value adds: its primitive
/// values and empty containers
template<typename BasicJsonType>
static std::size_t count_flattened(const BasicJsonType& value)
{
std::size_t count = 0;
std::vector<const BasicJsonType*> pending(1, &value);
while (!pending.empty())
{
const BasicJsonType* const v = pending.back();
pending.pop_back();
if (v->is_array() && !v->m_data.m_value.array->empty())
{
for (const auto& element : *v->m_data.m_value.array)
{
pending.push_back(&element);
}
}
else if (v->is_object() && !v->m_data.m_value.object->empty())
{
for (const auto& member : *v->m_data.m_value.object)
{
pending.push_back(&member.second);
}
}
else
{
++count;
}
}
return count;
}
// Reserve the storage for @a value of objects that have a reserve(), so
// that it does not have to be moved while it grows
template<typename ObjectType, typename BasicJsonType>
static auto reserve_flattened(ObjectType& obj, const BasicJsonType& value, detail::priority_tag<1> /*unused*/)
-> decltype(obj.reserve(std::size_t {}), void())
{
obj.reserve(count_flattened(value));
}
template<typename ObjectType, typename BasicJsonType>
static void reserve_flattened(ObjectType& /*obj*/, const BasicJsonType& /*value*/, detail::priority_tag<0> /*unused*/)
{}
/// append the decimal representation of @a i to @a out
static void append_index(string_t& out, std::size_t i)
{
@@ -23813,6 +23859,7 @@ class json_pointer
}
};
reserve_flattened(object, value, detail::priority_tag<1> {});
enter(value);
while (!stack.empty())
{