From 016681cd38a12fa4257e1227d247503636cf28d2 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 14 Sep 2018 17:53:49 +0200 Subject: [PATCH] Add support for serialization of bitsets and tuples (#2293) * Add serialization support for dynamic and fixed size bitsets * Support serialization of std::tuple --- src/serialize.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/src/serialize.h b/src/serialize.h index 555c8db59..37ffac5b7 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -357,6 +357,8 @@ I ReadVarInt(Stream& is) } #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +#define FIXEDBITSET(obj, size) REF(CFixedBitSet(REF(obj), (size))) +#define DYNBITSET(obj) REF(CDynamicBitSet(REF(obj))) #define VARINT(obj) REF(WrapVarInt(REF(obj))) #define COMPACTSIZE(obj) REF(CCompactSize(REF(obj))) #define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) @@ -401,6 +403,67 @@ public: } }; +class CFixedBitSet +{ +protected: + std::vector& vec; + size_t size; + +public: + CFixedBitSet(std::vector& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {} + + template + void Serialize(Stream& s) const + { + std::vector vBytes((size + 7) / 8); + size_t ms = std::min(size, vec.size()); + for (size_t p = 0; p < ms; p++) + vBytes[p / 8] |= vec[p] << (p % 8); + s.write((char*)vBytes.data(), vBytes.size()); + } + + template + void Unserialize(Stream& s) + { + vec.resize(size); + + std::vector vBytes((size + 7) / 8); + s.read((char*)vBytes.data(), vBytes.size()); + for (size_t p = 0; p < size; p++) + vec[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0; + if (vBytes.size() * 8 != size) { + size_t rem = vBytes.size() * 8 - size; + uint8_t m = (uint8_t)(0xff << rem); + if (vBytes[vBytes.size() - 1] & m) { + throw std::ios_base::failure("Out-of-range bits set"); + } + } + } +}; + +class CDynamicBitSet +{ +protected: + std::vector& vec; + +public: + explicit CDynamicBitSet(std::vector& vecIn) : vec(vecIn) {} + + template + void Serialize(Stream& s) const + { + WriteCompactSize(s, vec.size()); + CFixedBitSet(REF(vec), vec.size()).Serialize(s); + } + + template + void Unserialize(Stream& s) + { + vec.resize(ReadCompactSize(s)); + CFixedBitSet(vec, vec.size()).Unserialize(s); + } +}; + template class CVarInt { @@ -512,6 +575,12 @@ template inline void Unserialize(Stream template void Serialize(Stream& os, const std::pair& item); template void Unserialize(Stream& is, std::pair& item); +/** + * pair + */ +template void Serialize(Stream& os, const std::tuple& item); +template void Unserialize(Stream& is, std::tuple& item); + /** * map */ @@ -732,6 +801,45 @@ void Unserialize(Stream& is, std::pair& item) Unserialize(is, item.second); } +/** + * tuple + */ +template +struct SerializeDeserializeTuple { + void operator() (Stream&s, std::tuple& t) { + SerializeDeserializeTuple{}(s, t); + if (for_read) { + s >> std::get(t); + } else { + s << std::get(t); + } + } +}; + +template +struct SerializeDeserializeTuple { + void operator() (Stream&s, std::tuple& t) { + if (for_read) { + s >> std::get<0>(t); + } else { + s << std::get<0>(t); + } + } +}; + +template +void Serialize(Stream& os, const std::tuple& item) +{ + const auto size = std::tuple_size>::value; + SerializeDeserializeTuple{}(os, const_cast&>(item)); +} + +template +void Unserialize(Stream& is, std::tuple& item) +{ + const auto size = std::tuple_size>::value; + SerializeDeserializeTuple{}(is, item); +} /**