mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-22 15:04:44 +01:00
Add custom vector-element formatter
This allows a very compact notation for serialization of vectors whose elements are not serialized using their default encoding.
This commit is contained in:
parent
37d800bea0
commit
abf8624356
1 changed files with 47 additions and 0 deletions
|
@ -596,6 +596,53 @@ public:
|
||||||
template<typename I>
|
template<typename I>
|
||||||
BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
|
BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
|
||||||
|
|
||||||
|
/** Formatter to serialize/deserialize vector elements using another formatter
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* struct X {
|
||||||
|
* std::vector<uint64_t> v;
|
||||||
|
* SERIALIZE_METHODS(X, obj) { READWRITE(Using<VectorFormatter<VarInt>>(obj.v)); }
|
||||||
|
* };
|
||||||
|
* will define a struct that contains a vector of uint64_t, which is serialized
|
||||||
|
* as a vector of VarInt-encoded integers.
|
||||||
|
*
|
||||||
|
* V is not required to be an std::vector type. It works for any class that
|
||||||
|
* exposes a value_type, size, reserve, push_back, and const iterators.
|
||||||
|
*/
|
||||||
|
template<class Formatter>
|
||||||
|
struct VectorFormatter
|
||||||
|
{
|
||||||
|
template<typename Stream, typename V>
|
||||||
|
void Ser(Stream& s, const V& v)
|
||||||
|
{
|
||||||
|
WriteCompactSize(s, v.size());
|
||||||
|
for (const typename V::value_type& elem : v) {
|
||||||
|
s << Using<Formatter>(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Stream, typename V>
|
||||||
|
void Unser(Stream& s, V& v)
|
||||||
|
{
|
||||||
|
v.clear();
|
||||||
|
size_t size = ReadCompactSize(s);
|
||||||
|
size_t allocated = 0;
|
||||||
|
while (allocated < size) {
|
||||||
|
// For DoS prevention, do not blindly allocate as much as the stream claims to contain.
|
||||||
|
// Instead, allocate in 5MiB batches, so that an attacker actually needs to provide
|
||||||
|
// X MiB of data to make us allocate X+5 Mib.
|
||||||
|
static_assert(sizeof(typename V::value_type) <= MAX_VECTOR_ALLOCATE, "Vector element size too large");
|
||||||
|
allocated = std::min(size, allocated + MAX_VECTOR_ALLOCATE / sizeof(typename V::value_type));
|
||||||
|
v.reserve(allocated);
|
||||||
|
while (v.size() < allocated) {
|
||||||
|
typename V::value_type val;
|
||||||
|
s >> Using<Formatter>(val);
|
||||||
|
v.push_back(std::move(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward declarations
|
* Forward declarations
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue