serialize: add LimitedVectorFormatter

This commit is contained in:
Anthony Towns
2026-05-07 02:56:18 +10:00
parent 1b3f776ebb
commit 94ed45427c
2 changed files with 55 additions and 0 deletions

View File

@@ -494,6 +494,7 @@ static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&
#define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
#define COMPACTSIZE(obj) Using<CompactSizeFormatter<true>>(obj)
#define LIMITED_STRING(obj,n) Using<LimitedStringFormatter<n>>(obj)
#define LIMITED_VECTOR(obj,n) Using<LimitedVectorFormatter<n>>(obj)
/** Serialization wrapper class for integers in VarInt format. */
template<VarIntMode Mode>
@@ -790,6 +791,35 @@ struct DefaultFormatter
static void Unser(Stream& s, T& t) { Unserialize(s, t); }
};
/**
* Limited vector formatter. Throws an error if a vector is oversized.
*/
template<size_t Limit, class Formatter = DefaultFormatter>
struct LimitedVectorFormatter
{
template<typename Stream, typename V>
void Unser(Stream& s, V& v)
{
Formatter formatter;
v.clear();
size_t size = ReadCompactSize(s);
if (size > Limit) {
throw std::ios_base::failure("Vector length limit exceeded");
}
v.reserve(size);
for (size_t i = 0; i < size; ++i) {
v.emplace_back();
formatter.Unser(s, v.back());
}
}
template<typename Stream, typename V>
void Ser(Stream& s, const V& v)
{
VectorFormatter<Formatter>{}.Ser(s, v);
}
};

View File

@@ -9,6 +9,7 @@
#include <test/util/setup_common.h>
#include <util/strencodings.h>
#include <algorithm>
#include <cstdint>
#include <string>
@@ -251,6 +252,30 @@ BOOST_AUTO_TEST_CASE(string_view)
BOOST_CHECK_EQUAL(sv, s);
}
BOOST_AUTO_TEST_CASE(limited_vector)
{
const std::vector<int> v = {1,2,3,4,-5,-6,-7,-8,-9,-10,10000,20000,-30000};
auto check = [&]<size_t N>() {
DataStream ss;
ss << v;
try {
std::vector<int> r;
ss >> LIMITED_VECTOR(r, N);
BOOST_CHECK_LE(r.size(), N);
BOOST_CHECK(std::ranges::equal(r, v));
} catch (const std::ios_base::failure&) {
BOOST_CHECK_GT(v.size(), N);
}
};
check.operator()<0>();
check.operator()<10>();
check.operator()<12>();
check.operator()<13>();
check.operator()<14>();
check.operator()<100>();
}
BOOST_AUTO_TEST_CASE(class_methods)
{
int intval(100);