From 42bd27824ee6fff25088a7f4ac5a55f8cdb78d78 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 16 Oct 2026 21:49:28 +0200 Subject: [PATCH] Reserve room for two elements in the arrays unflatten() creates An array that unflatten() creates grows by one element at a time, so an array of two elements (a coordinate pair, a range) was allocated, grown and freed once more than needed. New arrays get room for two elements first, for array types that have reserve(). Arrays of two or more elements need no more memory than before; an array of one element has room for one more. unflatten() (instructions on macOS, Linux Ir GCC 13 / Clang 18): canada 161.9M -> 141.2M, 128.3M -> 117.9M / 138.0M -> 128.6M; citm_catalog 43.5M -> 42.8M, 37.0M -> 36.8M / 37.5M -> 37.3M; twitter unchanged. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/json_pointer.hpp | 14 ++++++++++++++ single_include/nlohmann/json.hpp | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 9d87d4f92..af10a4aa5 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -481,6 +481,18 @@ class json_pointer return pos == size; } + /// reserve room for @a n elements of an array type that has reserve() + template + static auto reserve_elements(ArrayType& array, const std::size_t n, detail::priority_tag<1> /*unused*/) + -> decltype(array.reserve(n), void()) + { + array.reserve(n); + } + + template + static void reserve_elements(ArrayType& /*array*/, const std::size_t /*n*/, detail::priority_tag<0> /*unused*/) + {} + /// @brief object member access with a key that is only copied if it is inserted /// /// Objects that can find the position of a key and insert there @@ -1717,6 +1729,8 @@ class json_pointer { // some reference token below this position is 0, so the // value is an array + *current = BasicJsonType(detail::value_t::array); + reserve_elements(*current->m_data.m_value.array, 2, detail::priority_tag<1> {}); current = ¤t->operator[](array_index(token)); } else diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0fd6ebb1b..45c474078 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -22831,6 +22831,18 @@ class json_pointer return pos == size; } + /// reserve room for @a n elements of an array type that has reserve() + template + static auto reserve_elements(ArrayType& array, const std::size_t n, detail::priority_tag<1> /*unused*/) + -> decltype(array.reserve(n), void()) + { + array.reserve(n); + } + + template + static void reserve_elements(ArrayType& /*array*/, const std::size_t /*n*/, detail::priority_tag<0> /*unused*/) + {} + /// @brief object member access with a key that is only copied if it is inserted /// /// Objects that can find the position of a key and insert there @@ -24067,6 +24079,8 @@ class json_pointer { // some reference token below this position is 0, so the // value is an array + *current = BasicJsonType(detail::value_t::array); + reserve_elements(*current->m_data.m_value.array, 2, detail::priority_tag<1> {}); current = ¤t->operator[](array_index(token)); } else