From 75226beb400942dc7a54cbb83a92ea3a2972619d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 8 Sep 2026 19:51:33 +0200 Subject: [PATCH] Factor out a reserve-dispatch helper instead of duplicating the object from_json loop Addresses review feedback from @gregmarr on PR #5472: the emplace loop no longer needs to exist twice for the reserve/no-reserve cases. A small from_json_object_reserve() overload pair (SFINAE-dispatched on whether reserve() exists, mirroring the priority_tag technique used elsewhere) either calls reserve() or is a no-op; from_json_object_impl() calls it once. Signed-off-by: Niels Lohmann --- .../nlohmann/detail/conversions/from_json.hpp | 26 ++++++++----------- single_include/nlohmann/json.hpp | 26 ++++++++----------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index fa5eb62b0..75bd019eb 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -398,27 +398,23 @@ inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin) } } -template -auto from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& obj, priority_tag<1> /*unused*/) --> decltype( - obj.reserve(std::declval()), - void()) +template +auto from_json_object_reserve(ConstructibleObjectType& obj, typename ConstructibleObjectType::size_type size, priority_tag<1> /*unused*/) +-> decltype(obj.reserve(size), void()) { - ConstructibleObjectType ret; - const auto* inner_object = j.template get_ptr(); - ret.reserve(inner_object->size()); - for (const auto& p : *inner_object) - { - ret.emplace(p.first, p.second.template get()); - } - obj = std::move(ret); + obj.reserve(size); } +template +inline void from_json_object_reserve(ConstructibleObjectType& /*obj*/, std::size_t /*size*/, priority_tag<0> /*unused*/) +{} + template -inline void from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& obj, priority_tag<0> /*unused*/) +inline void from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& obj) { ConstructibleObjectType ret; const auto* inner_object = j.template get_ptr(); + from_json_object_reserve(ret, inner_object->size(), priority_tag<1> {}); for (const auto& p : *inner_object) { ret.emplace(p.first, p.second.template get()); @@ -435,7 +431,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j)); } - from_json_object_impl(j, obj, priority_tag<1> {}); + from_json_object_impl(j, obj); } // overload for arithmetic types, not chosen for basic_json template arguments diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 4e484d764..79e838322 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5693,27 +5693,23 @@ inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin) } } -template -auto from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& obj, priority_tag<1> /*unused*/) --> decltype( - obj.reserve(std::declval()), - void()) +template +auto from_json_object_reserve(ConstructibleObjectType& obj, typename ConstructibleObjectType::size_type size, priority_tag<1> /*unused*/) +-> decltype(obj.reserve(size), void()) { - ConstructibleObjectType ret; - const auto* inner_object = j.template get_ptr(); - ret.reserve(inner_object->size()); - for (const auto& p : *inner_object) - { - ret.emplace(p.first, p.second.template get()); - } - obj = std::move(ret); + obj.reserve(size); } +template +inline void from_json_object_reserve(ConstructibleObjectType& /*obj*/, std::size_t /*size*/, priority_tag<0> /*unused*/) +{} + template -inline void from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& obj, priority_tag<0> /*unused*/) +inline void from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& obj) { ConstructibleObjectType ret; const auto* inner_object = j.template get_ptr(); + from_json_object_reserve(ret, inner_object->size(), priority_tag<1> {}); for (const auto& p : *inner_object) { ret.emplace(p.first, p.second.template get()); @@ -5730,7 +5726,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j)); } - from_json_object_impl(j, obj, priority_tag<1> {}); + from_json_object_impl(j, obj); } // overload for arithmetic types, not chosen for basic_json template arguments