Make flatten() linear for ordered_json

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-15 08:16:49 +02:00
1 parent 908038c027
commit ad31938c71
4 files changed
+126 -8

No files matched your search

+37 -4
View File
@@ -21562,6 +21562,23 @@ class json_pointer
}
private:
// Add the entry (key, v) to the object `obj`. Flattened paths are pairwise
// distinct, so objects that can append a key known to be absent
// (ordered_map) skip the lookup, which is linear and would make flatten
// quadratic; all other object types use operator[].
template<typename ObjectType, typename ValueType>
static auto add_flattened(ObjectType& obj, const string_t& key, ValueType&& v, int /*unused*/)
-> decltype(obj.emplace_new_key(key, std::forward<ValueType>(v)), void())
{
obj.emplace_new_key(key, std::forward<ValueType>(v));
}
template<typename ObjectType, typename ValueType>
static void add_flattened(ObjectType& obj, const string_t& key, ValueType&& v, ...)
{
obj[key] = std::forward<ValueType>(v);
}
/*!
@param[in] reference_string the reference string to the current value
@param[in] value the value to consider
@@ -21606,7 +21623,8 @@ class json_pointer
// flatten `v`, whose path is `path`: primitives and empty containers
// are added to the result right away; other containers get a frame
const auto enter = [&stack, &path, &result](const BasicJsonType & v)
auto& object = *result.m_data.m_value.object;
const auto enter = [&stack, &path, &object](const BasicJsonType & v)
{
switch (v.type())
{
@@ -21615,7 +21633,7 @@ class json_pointer
if (v.m_data.m_value.array->empty())
{
// flatten empty array as null
result[path] = nullptr;
add_flattened(object, path, nullptr, 0);
}
else
{
@@ -21629,7 +21647,7 @@ class json_pointer
if (v.m_data.m_value.object->empty())
{
// flatten empty object as null
result[path] = nullptr;
add_flattened(object, path, nullptr, 0);
}
else
{
@@ -21649,7 +21667,7 @@ class json_pointer
default:
{
// add a primitive value with its reference string
result[path] = v;
add_flattened(object, path, v, 0);
return;
}
}
@@ -21695,6 +21713,10 @@ class json_pointer
enter(it->second);
}
}
// the entries were added without going through basic_json, so the
// parent pointers (JSON_DIAGNOSTICS) have to be set now
result.set_parents();
}
/*!
@@ -29161,6 +29183,17 @@ public:
return {std::prev(this->end()), true};
}
/// @brief add an element at the end without checking whether the key exists
/// @note The caller must guarantee that @a key is not yet contained, otherwise
/// the container holds duplicate keys. This avoids the linear search of
/// emplace() and operator[] when many keys known to be new are added.
template<class V, detail::enable_if_t<
detail::is_constructible<T, V>::value, int> = 0>
void emplace_new_key(const key_type& key, V && t)
{
append(key, std::forward<V>(t));
}
T& operator[](const key_type& key)
{
return emplace(key, T{}).first->second;