Implement CFixedVarIntsBitSet and CAutoBitSet

This commit is contained in:
Alexander Block 2019-01-16 16:24:49 +01:00
parent 76a58f5a48
commit 49de417265

View File

@ -206,6 +206,8 @@ template<typename Stream> inline void Unserialize(Stream& s, double& a ) { a =
template<typename Stream> inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); } template<typename Stream> inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); }
template<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; } template<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; }
template <typename T> size_t GetSerializeSize(const T& t, int nType, int nVersion = 0);
template <typename S, typename T> size_t GetSerializeSize(const S& s, const T& t);
@ -359,6 +361,8 @@ I ReadVarInt(Stream& is)
#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
#define FIXEDBITSET(obj, size) REF(CFixedBitSet(REF(obj), (size))) #define FIXEDBITSET(obj, size) REF(CFixedBitSet(REF(obj), (size)))
#define DYNBITSET(obj) REF(CDynamicBitSet(REF(obj))) #define DYNBITSET(obj) REF(CDynamicBitSet(REF(obj)))
#define FIXEDVARINTSBITSET(obj, size) REF(CFixedVarIntsBitSet(REF(obj), (size)))
#define AUTOBITSET(obj, size) REF(CAutoBitSet(REF(obj), (size)))
#define VARINT(obj) REF(WrapVarInt(REF(obj))) #define VARINT(obj) REF(WrapVarInt(REF(obj)))
#define COMPACTSIZE(obj) REF(CCompactSize(REF(obj))) #define COMPACTSIZE(obj) REF(CCompactSize(REF(obj)))
#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) #define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj)))
@ -464,6 +468,101 @@ public:
} }
}; };
/**
* Stores a fixed size bitset as a series of VarInts. Each VarInt is an offset from the last entry and the sum of the
* last entry and the offset gives an index into the bitset for a set bit. The series of VarInts ends with a 0.
*/
class CFixedVarIntsBitSet
{
protected:
std::vector<bool>& vec;
size_t size;
public:
CFixedVarIntsBitSet(std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream>
void Serialize(Stream& s) const
{
int32_t last = -1;
for (int32_t i = 0; i < (int32_t)vec.size(); i++) {
if (vec[i]) {
WriteVarInt<Stream, uint32_t>(s, (uint32_t)(i - last));
last = i;
}
}
WriteVarInt(s, 0); // stopper
}
template<typename Stream>
void Unserialize(Stream& s)
{
vec.assign(size, false);
int32_t last = -1;
while(true) {
uint32_t offset = ReadVarInt<Stream, uint32_t>(s);
if (offset == 0) {
break;
}
int32_t idx = last + offset;
if (idx >= size) {
throw std::ios_base::failure("out of bounds index");
}
if (last != -1 && idx <= last) {
throw std::ios_base::failure("offset overflow");
}
vec[idx] = true;
last = idx;
}
}
};
/**
* Serializes either as a CFixedBitSet or CFixedVarIntsBitSet, depending on which would give a smaller size
*/
class CAutoBitSet
{
protected:
std::vector<bool>& vec;
size_t size;
public:
explicit CAutoBitSet(std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream>
void Serialize(Stream& s) const
{
assert(vec.size() == size);
size_t size1 = ::GetSerializeSize(s, CFixedBitSet(vec, size));
size_t size2 = ::GetSerializeSize(s, CFixedVarIntsBitSet(vec, size));
if (size1 < size2) {
ser_writedata8(s, 0);
s << FIXEDBITSET(vec, vec.size());
} else {
ser_writedata8(s, 1);
s << FIXEDVARINTSBITSET(vec, vec.size());
}
}
template<typename Stream>
void Unserialize(Stream& s)
{
uint8_t isVarInts = ser_readdata8(s);
if (isVarInts != 0 && isVarInts != 1) {
throw std::ios_base::failure("invalid value for isVarInts byte");
}
if (!isVarInts) {
s >> FIXEDBITSET(vec, size);
} else {
s >> FIXEDVARINTSBITSET(vec, size);
}
}
};
template<typename I> template<typename I>
class CVarInt class CVarInt
{ {
@ -1093,7 +1192,7 @@ inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)
} }
template <typename T> template <typename T>
size_t GetSerializeSize(const T& t, int nType, int nVersion = 0) size_t GetSerializeSize(const T& t, int nType, int nVersion)
{ {
return (CSizeComputer(nType, nVersion) << t).size(); return (CSizeComputer(nType, nVersion) << t).size();
} }