mirror of
https://github.com/nlohmann/json.git
synced 2026-10-15 18:57:13 +00:00
Speed up JSON pointer parsing, formatting, comparison and lookup (#5836)
* Speed up JSON pointer parsing, formatting, comparison and lookup Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Restore unflatten() speed after the linear-time rewrite The prefix tree introduced for linear unflatten() kept a std::map per prefix, copied each token into it and looked every token up a second time while creating the values. Replace the per-prefix maps by one open-addressing table keyed by (parent, token) that refers to the parsed tokens, skip the lookups for the prefix shared with the previous key (flattened objects are mostly sorted), and derive the prefix numbers of the second pass from parent links instead of lookups. Time and memory stay linear in the pointer depth, and the result is still independent of the iteration order of the flattened object. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Put [[noreturn]] before __attribute__ on the JSON pointer throw helpers Clang 18 on Linux rejects a C++11 attribute list after a GNU __attribute__ ("an attribute list cannot appear here"). Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
0c4e7c103c
commit
0a4b3a84ee
6 files changed
+939
-273
No files matched your search
+20
-26
@@ -6562,24 +6562,18 @@ public:
|
||||
};
|
||||
|
||||
// wrapper for "add" operation; add value at ptr
|
||||
const auto operation_add = [&result](json_pointer & ptr, const basic_json & val)
|
||||
const auto operation_add = [&result](json_pointer & ptr, basic_json val)
|
||||
{
|
||||
// adding to the root of the target document means replacing it
|
||||
if (ptr.empty())
|
||||
{
|
||||
result = val;
|
||||
result = std::move(val);
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure the top element of the pointer exists
|
||||
json_pointer const top_pointer = ptr.top();
|
||||
if (top_pointer != ptr)
|
||||
{
|
||||
result.at(top_pointer);
|
||||
}
|
||||
|
||||
// get reference to the parent of the JSON pointer ptr
|
||||
const auto last_path = ptr.back();
|
||||
// get reference to the parent of the JSON pointer ptr; a missing
|
||||
// parent (or one of its ancestors) is reported by at()
|
||||
auto last_path = std::move(ptr.reference_tokens.back());
|
||||
ptr.pop_back();
|
||||
// parent must exist when performing patch add per RFC6902 specs
|
||||
basic_json& parent = result.at(ptr);
|
||||
@@ -6590,7 +6584,7 @@ public:
|
||||
case value_t::object:
|
||||
{
|
||||
// use operator[] to add value
|
||||
parent[last_path] = val;
|
||||
parent[std::move(last_path)] = std::move(val);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6599,7 +6593,7 @@ public:
|
||||
if (last_path == "-")
|
||||
{
|
||||
// special case: append to back
|
||||
parent.push_back(val);
|
||||
parent.push_back(std::move(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -6611,7 +6605,7 @@ public:
|
||||
}
|
||||
|
||||
// default case: insert add offset
|
||||
parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
|
||||
parent.insert(parent.begin() + static_cast<difference_type>(idx), std::move(val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -6634,7 +6628,8 @@ public:
|
||||
const auto operation_remove = [this, & result](json_pointer & ptr)
|
||||
{
|
||||
// get reference to the parent of the JSON pointer ptr
|
||||
const auto last_path = ptr.back();
|
||||
static_cast<void>(ptr.back()); // throws out_of_range.405 if ptr is the root
|
||||
const auto last_path = std::move(ptr.reference_tokens.back());
|
||||
ptr.pop_back();
|
||||
basic_json& parent = result.at(ptr);
|
||||
|
||||
@@ -6734,8 +6729,8 @@ public:
|
||||
}
|
||||
|
||||
// collect mandatory members
|
||||
const auto op = get_value("op", "op", true).template get<string_t>();
|
||||
const auto path = get_value(op, "path", true).template get<string_t>();
|
||||
const string_t& op = *get_value("op", "op", true).m_data.m_value.string;
|
||||
const string_t& path = *get_value(op, "path", true).m_data.m_value.string;
|
||||
json_pointer ptr(path);
|
||||
|
||||
switch (get_op(op))
|
||||
@@ -6761,7 +6756,7 @@ public:
|
||||
|
||||
case patch_operations::move:
|
||||
{
|
||||
const auto from_path = get_value("move", "from", true).template get<string_t>();
|
||||
const string_t& from_path = *get_value("move", "from", true).m_data.m_value.string;
|
||||
json_pointer from_ptr(from_path);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr)))
|
||||
@@ -6770,29 +6765,28 @@ public:
|
||||
}
|
||||
|
||||
// the "from" location must exist - use at()
|
||||
basic_json const v = result.at(from_ptr);
|
||||
// a root "from" is rejected by operation_remove below, which must leave result intact
|
||||
basic_json v = from_ptr.empty() ? basic_json(result) : std::move(result.at(from_ptr));
|
||||
|
||||
// The move operation is functionally identical to a
|
||||
// "remove" operation on the "from" location, followed
|
||||
// immediately by an "add" operation at the target
|
||||
// location with the value that was just removed.
|
||||
operation_remove(from_ptr);
|
||||
operation_add(ptr, v);
|
||||
operation_add(ptr, std::move(v));
|
||||
break;
|
||||
}
|
||||
|
||||
case patch_operations::copy:
|
||||
{
|
||||
const auto from_path = get_value("copy", "from", true).template get<string_t>();
|
||||
const string_t& from_path = *get_value("copy", "from", true).m_data.m_value.string;
|
||||
const json_pointer from_ptr(from_path);
|
||||
|
||||
// the "from" location must exist - use at()
|
||||
basic_json const v = result.at(from_ptr);
|
||||
|
||||
// The copy is functionally identical to an "add"
|
||||
// operation at the target location using the value
|
||||
// specified in the "from" member.
|
||||
operation_add(ptr, v);
|
||||
// specified in the "from" member; the "from" location
|
||||
// must exist - use at()
|
||||
operation_add(ptr, result.at(from_ptr));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user