Skip to content

Commit baa631f

Browse files
committed
Improve unpack reserve handling
1 parent b9998fc commit baa631f

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/serialization/container.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,15 @@
3030

3131
#pragma once
3232

33+
#include <algorithm>
3334
#include <cstdint>
3435
#include <cstddef>
36+
#include <limits>
3537
#include <string>
3638
#include <type_traits>
3739

40+
#include "serialization/serialization.h"
41+
3842
namespace serialization
3943
{
4044
namespace detail
@@ -76,7 +80,26 @@ namespace serialization
7680
template<typename... C>
7781
void do_reserve(const C&...) {}
7882
template<typename C>
79-
auto do_reserve(C &c, std::size_t N) -> decltype(c.reserve(N)) { return c.reserve(N); }
83+
auto do_reserve(C &c, std::size_t N, std::size_t B) -> decltype(c.reserve(N))
84+
{
85+
using T = typename C::value_type;
86+
87+
static constexpr std::size_t max_compression_ratio =
88+
is_blob_type<T>::type::value ? 1 :
89+
use_container_varint<T>() ? sizeof(T) :
90+
(std::is_same<T, char>::value || std::is_same<T, unsigned char>::value) ? 1:
91+
4; // default
92+
93+
// max compression ratio for upfront memory usage
94+
B /= sizeof(T);
95+
B = std::max(std::size_t(1), B);
96+
if (std::numeric_limits<std::size_t>::max() / max_compression_ratio <= B)
97+
B = std::numeric_limits<std::size_t>::max();
98+
else
99+
B *= max_compression_ratio;
100+
101+
return c.reserve(std::min(N, B));
102+
}
80103

81104
// The value_type of STL map-like containers come in the form std::pair<const K, V>.
82105
// Since we can't {de}serialize const types in this lib, we must convert this to std::pair<K, V>
@@ -104,7 +127,7 @@ bool do_serialize_container(Archive<false> &ar, C &v)
104127
return false;
105128
}
106129

107-
::serialization::detail::do_reserve(v, cnt);
130+
::serialization::detail::do_reserve(v, cnt, ar.remaining_bytes());
108131

109132
for (size_t i = 0; i < cnt; i++) {
110133
if (i > 0)

tests/unit_tests/serialization.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,20 @@ TEST(Serialization, serializes_vector_int64_as_fixed_int)
372372
ASSERT_EQ(57, blob.size());
373373
}
374374

375+
TEST(Serialization, deserializes_vector_reserve)
376+
{
377+
std::vector<int64_t> v;
378+
string blob;
379+
380+
tools::write_varint(std::back_inserter(blob), unsigned(100));
381+
blob.append(std::string(100, 0));
382+
383+
ASSERT_LT(v.capacity(), 20);
384+
ASSERT_FALSE(serialization::parse_binary(blob, v));
385+
ASSERT_LT(v.capacity(), 100); // could fail if lib allocates more in reserve call
386+
}
387+
388+
375389
namespace
376390
{
377391
template<typename T>

0 commit comments

Comments
 (0)