mirror of
https://github.com/nlohmann/json.git
synced 2026-09-13 19:57:58 +00:00
Only reserve array capacity if the array type supports it
PR #5476 added an unconditional `reserve()` call to the `start_array()` implementations of both `json_sax_dom_parser` and `json_sax_dom_callback_parser`. `ArrayType` is a template parameter of `basic_json`, however, and is not required to have a `reserve()` member function: instantiating either parser for, e.g., `basic_json<std::map, std::deque>` fails to compile, which breaks every use of `parse()` and the binary readers for such a type. Move the capped reservation into a `reserve_array()` helper that selects a no-op overload through `priority_tag` when `ArrayType` has no `reserve()`, mirroring `from_json_object_reserve()`. `std::vector` array types keep reserving as before, and the 16384-element cap is unchanged. Signed-off-by: Niels Lohmann <mail@nlohmann.me> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c0b2878a44
commit
ee211df64a
@@ -18,6 +18,7 @@
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
#include <nlohmann/detail/input/lexer.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
@@ -151,6 +152,29 @@ constexpr std::size_t unknown_size()
|
||||
return (std::numeric_limits<std::size_t>::max)();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reserve capacity for @a len elements in array @a arr
|
||||
|
||||
Reserving upfront avoids repeated reallocations while the elements are added,
|
||||
but the reservation is capped so a bogus/hostile length (which is not bounded
|
||||
by max_size(), unlike e.g. std::vector) cannot trigger an oversized allocation
|
||||
for a small or truncated input.
|
||||
|
||||
The overload below is selected for array types without reserve() (e.g.,
|
||||
std::deque), which are then left untouched.
|
||||
*/
|
||||
template<typename ArrayType>
|
||||
auto reserve_array(ArrayType& arr, std::size_t len, priority_tag<1> /*unused*/)
|
||||
-> decltype(arr.reserve(len), void())
|
||||
{
|
||||
constexpr std::size_t reserve_cap = 16384;
|
||||
arr.reserve((std::min)(len, reserve_cap));
|
||||
}
|
||||
|
||||
template<typename ArrayType>
|
||||
inline void reserve_array(ArrayType& /*arr*/, std::size_t /*len*/, priority_tag<0> /*unused*/)
|
||||
{}
|
||||
|
||||
/*!
|
||||
@brief SAX implementation to create a JSON value from SAX events
|
||||
|
||||
@@ -308,12 +332,7 @@ class json_sax_dom_parser
|
||||
|
||||
if (len != detail::unknown_size())
|
||||
{
|
||||
// reserve upfront to avoid repeated reallocations while adding elements,
|
||||
// but cap the reservation so a bogus/hostile length (which is not bounded
|
||||
// by max_size(), unlike e.g. std::vector) cannot trigger an oversized
|
||||
// allocation for a small or truncated input
|
||||
constexpr std::size_t reserve_cap = 16384;
|
||||
ref_stack.back()->m_data.m_value.array->reserve((std::min)(len, reserve_cap));
|
||||
reserve_array(*ref_stack.back()->m_data.m_value.array, len, priority_tag<1> {});
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -697,12 +716,7 @@ class json_sax_dom_callback_parser
|
||||
|
||||
if (len != detail::unknown_size())
|
||||
{
|
||||
// reserve upfront to avoid repeated reallocations while adding elements,
|
||||
// but cap the reservation so a bogus/hostile length (which is not bounded
|
||||
// by max_size(), unlike e.g. std::vector) cannot trigger an oversized
|
||||
// allocation for a small or truncated input
|
||||
constexpr std::size_t reserve_cap = 16384;
|
||||
ref_stack.back()->m_data.m_value.array->reserve((std::min)(len, reserve_cap));
|
||||
reserve_array(*ref_stack.back()->m_data.m_value.array, len, priority_tag<1> {});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user