From baa631ff7567f61651079854f90fce95e42b49e3 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Sat, 14 Mar 2026 12:24:55 -0400 Subject: [PATCH] Improve unpack reserve handling --- src/serialization/container.h | 27 +++++++++++++++++++++++++-- tests/unit_tests/serialization.cpp | 14 ++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/serialization/container.h b/src/serialization/container.h index 508b50992..5d2ac0052 100644 --- a/src/serialization/container.h +++ b/src/serialization/container.h @@ -30,11 +30,15 @@ #pragma once +#include #include #include +#include #include #include +#include "serialization/serialization.h" + namespace serialization { namespace detail @@ -76,7 +80,26 @@ namespace serialization template void do_reserve(const C&...) {} template - auto do_reserve(C &c, std::size_t N) -> decltype(c.reserve(N)) { return c.reserve(N); } + auto do_reserve(C &c, std::size_t N, std::size_t B) -> decltype(c.reserve(N)) + { + using T = typename C::value_type; + + static constexpr std::size_t max_compression_ratio = + is_blob_type::type::value ? 1 : + use_container_varint() ? sizeof(T) : + (std::is_same::value || std::is_same::value) ? 1: + 4; // default + + // max compression ratio for upfront memory usage + B /= sizeof(T); + B = std::max(std::size_t(1), B); + if (std::numeric_limits::max() / max_compression_ratio <= B) + B = std::numeric_limits::max(); + else + B *= max_compression_ratio; + + return c.reserve(std::min(N, B)); + } // The value_type of STL map-like containers come in the form std::pair. // Since we can't {de}serialize const types in this lib, we must convert this to std::pair @@ -104,7 +127,7 @@ bool do_serialize_container(Archive &ar, C &v) return false; } - ::serialization::detail::do_reserve(v, cnt); + ::serialization::detail::do_reserve(v, cnt, ar.remaining_bytes()); for (size_t i = 0; i < cnt; i++) { if (i > 0) diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 6cf9be8bd..893d4933d 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -372,6 +372,20 @@ TEST(Serialization, serializes_vector_int64_as_fixed_int) ASSERT_EQ(57, blob.size()); } +TEST(Serialization, deserializes_vector_reserve) +{ + std::vector v; + string blob; + + tools::write_varint(std::back_inserter(blob), unsigned(100)); + blob.append(std::string(100, 0)); + + ASSERT_LT(v.capacity(), 20); + ASSERT_FALSE(serialization::parse_binary(blob, v)); + ASSERT_LT(v.capacity(), 100); // could fail if lib allocates more in reserve call +} + + namespace { template