Skip to content

Allocate the deep copy's key scratch space with the provided allocator - #5573

Merged
nlohmann merged 5 commits into
developfrom
copy-scratch-allocator
Sep 25, 2026
Merged

nlohmann merged 5 commits into
developfrom
copy-scratch-allocator

Conversation

@nlohmann

Copy link
Copy Markdown
Owner

Summary

Follow-up to @gregmarr's question in #4843: should the temporary vectors added by the recent non-recursive rewrites also use the provided allocator?

Most of them hold only pointers, iterators and counters: the copy worklist and the stacks for merging (#5547), hashing (#5546), dump() (#5285) and the binary readers (#5505). That matches the parser's ref_stack, the lexer's token_string and the other internal bookkeeping, which have always used std::allocator.

The exception is copy_scratch_t (from #5389). The iterative deep copy uses it to build an object's keys as std::pair<key_type, basic_json> values before passing them to the object's range constructor. It holds JSON values, so this PR allocates it with AllocatorType, the same way #4843 does for the destructor's stack.

Changes

  • copy_scratch_t now uses AllocatorType<std::pair<typename object_t::key_type, basic_json>>.
  • New test in unit-allocator.cpp: "deep copy uses the provided allocator". It deep-copies an object nested 300 levels deep with an allocator that counts allocations of std::pair<Key, T> with a non-const key. The object types only store std::pair<const Key, T>, so the only such allocations come from the scratch space. The test fails without the change and passes with it under C++11 and C++20, and with JSON_NO_THREAD_LOCAL.
  • template_parameters.md: adds the new AllocatorType instantiation to the list, and states that AllocatorType allocates the JSON values, while most temporary storage uses std::allocator.

One more candidate is left: json_sax_dom_callback_parser::duplicate_key_stash holds values as well but still uses std::allocator. It's only used by the callback parser when there are duplicate keys, and it lives in a class templated on BasicJsonType, so switching it would need rebind_alloc. I left it out.

Breaking changes

No breaking changes to the public API. AllocatorType is now also instantiated with std::pair<StringType, basic_json>. This only affects deep copies of values nested deeper than 128 levels, or any depth when JSON_NO_THREAD_LOCAL is defined. Any allocator template usable as AllocatorType today already has to accept arbitrary single type arguments.

🤖 Generated with Claude Code

The iterative deep copy builds each object's keys in a temporary vector of
key/value pairs before handing them to the object's range constructor. That
vector holds basic_json values, so like the values themselves it now uses
AllocatorType instead of std::allocator.

Also document that AllocatorType covers the JSON values, while most
temporary storage still uses std::allocator.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
@nlohmann nlohmann added the review needed It would be great if someone could review the proposed changes. label Sep 24, 2026
From C++23 on, libc++'s containers allocate through allocate_at_least when
the allocator has one. The test allocator inherited it from std::allocator,
so the scratch allocations were not counted and the test failed on Xcode.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
@nlohmann nlohmann removed the review needed It would be great if someone could review the proposed changes. label Sep 25, 2026
@nlohmann nlohmann added this to the Release 3.13.0 milestone Sep 25, 2026
@nlohmann
nlohmann merged commit c60a0bc into develop Sep 25, 2026
159 of 160 checks passed
@nlohmann
nlohmann deleted the copy-scratch-allocator branch September 25, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants