diff options
| author | tobtoht <tob@featherwallet.org> | 2026-04-27 23:09:10 +0000 |
|---|---|---|
| committer | tobtoht <tob@featherwallet.org> | 2026-04-27 23:09:10 +0000 |
| commit | 586e82bcc0f9491a14bb9b824248925d09f68c75 (patch) | |
| tree | 6a94f6cf2c507aa82c9dc9221fe78dd1196e524d | |
| parent | 64b19b4b9a0004b0e7f8466d77c6597878778ebc (diff) | |
| parent | 54229196bd11913ef0ac2c44b9f090cf619d29d8 (diff) | |
| download | monzero-core-586e82bcc0f9491a14bb9b824248925d09f68c75.tar.gz monzero-core-586e82bcc0f9491a14bb9b824248925d09f68c75.tar.xz monzero-core-586e82bcc0f9491a14bb9b824248925d09f68c75.zip | |
Merge pull request #10367
5422919 Improve unpack reserve handling (Lee Clagett)
| -rw-r--r-- | src/serialization/container.h | 34 | ||||
| -rw-r--r-- | src/serialization/containers.h | 1 | ||||
| -rw-r--r-- | tests/unit_tests/serialization.cpp | 14 |
3 files changed, 45 insertions, 4 deletions
diff --git a/src/serialization/container.h b/src/serialization/container.h index c64549c1e..7ba4d307f 100644 --- a/src/serialization/container.h +++ b/src/serialization/container.h @@ -28,6 +28,12 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include <algorithm> +#include <cstdint> +#include <cstddef> +#include <limits> +#include <type_traits> + namespace serialization { namespace detail @@ -57,8 +63,30 @@ namespace serialization return true; } - template <typename C> - void do_reserve(C &c, size_t N) {} + //! @brief Reserve space for N elements if applicable for container. + template<typename... C> + void do_reserve(const C&...) {} + template<typename C> + 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<T>::type::value ? 1 : + use_container_varint<T>() ? sizeof(T) : + (std::is_same<T, char>::value || std::is_same<T, unsigned char>::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<std::size_t>::max() / max_compression_ratio <= B) + B = std::numeric_limits<std::size_t>::max(); + else + B *= max_compression_ratio; + + return c.reserve(std::min(N, B)); + } } } @@ -77,7 +105,7 @@ bool do_serialize_container(Archive<false> &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/src/serialization/containers.h b/src/serialization/containers.h index dd2de829a..d4c3b6626 100644 --- a/src/serialization/containers.h +++ b/src/serialization/containers.h @@ -87,7 +87,6 @@ namespace serialization { namespace detail { - template <typename T> void do_reserve(std::vector<T> &c, size_t N) { c.reserve(N); } template <typename T> void do_add(std::vector<T> &c, T &&e) { c.emplace_back(std::forward<T>(e)); } template <typename T> void do_add(std::deque<T> &c, T &&e) { c.emplace_back(std::forward<T>(e)); } diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index fdf603272..0cf0275e5 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -304,6 +304,20 @@ TEST(Serialization, serializes_vector_int64_as_fixed_int) ASSERT_EQ(57, blob.size()); } +TEST(Serialization, deserializes_vector_reserve) +{ + std::vector<int64_t> 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<typename T> |
