Keep the target values of a diffed object of up to 16 members on the stack

diff_unequal() allocated a vector with the values in target of the members
of every object it diffed member by member. Objects with up to 16 members,
which are most of them, now use space in the stack frame, and larger ones
a vector as before. The storage is chosen once, when its size is reserved,
so that adding and reading a value needs no check of which one is in use.

diff() over the previous commit (instructions on macOS, Linux Ir GCC 13 / Clang
18): citm_catalog 21.5M -> 20.0M, 14.2M -> 13.5M / 14.2M -> 13.7M; twitter
12.0M -> 11.7M, 7.5M -> 7.3M / 7.5M -> 7.4M; canada 82.0M -> 81.5M.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-22 09:29:54 +02:00
1 parent 39ae5bc7be
commit 7521d0436b
2 files changed
+94 -4

No files matched your search

+47 -2
View File
@@ -39932,6 +39932,50 @@ public:
diff_operation(result, "add", path, &value);
}
/// @brief the values in the target of the members of a source object, for the
/// objects of up to 16 members without allocating
///
/// reserve() must be called with the number of values that are added.
class diff_target_values
{
public:
diff_target_values() = default;
diff_target_values(const diff_target_values&) = delete;
diff_target_values& operator=(const diff_target_values&) = delete;
~diff_target_values() = default;
void reserve(const std::size_t n)
{
if (n > inline_size)
{
large.resize(n);
items = large.data();
}
}
void push_back(const basic_json* value)
{
items[count++] = value;
}
std::size_t size() const noexcept
{
return count;
}
const basic_json* operator[](const std::size_t i) const noexcept
{
return items[i];
}
private:
static constexpr std::size_t inline_size = 16;
std::size_t count = 0;
const basic_json** items = small;
std::vector<const basic_json*> large{}; // NOLINT(readability-redundant-member-init)
const basic_json* small[inline_size]; // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
};
/// @brief append "/" and the decimal representation of @a index to @a path
static void diff_append_index(string_t& path, std::size_t index)
{
@@ -40012,8 +40056,9 @@ public:
operations that remove every member of @a source and add every member of
@a target to @a result, and returns false.
*/
template<typename TargetValues>
static bool diff_object_keys(basic_json& result, const basic_json& source, const basic_json& target,
const string_t& path, std::vector<const basic_json*>& target_values,
const string_t& path, TargetValues& target_values,
std::vector<const_iterator>& added)
{
// first pass: one lookup per source key
@@ -40227,7 +40272,7 @@ public:
case value_t::object:
{
std::vector<const basic_json*> target_values;
diff_target_values target_values;
std::vector<const_iterator> added;
if (diff_object_keys(result, source, target, path, target_values, added))
{