Skip to content

Commit

Permalink
Implement CFixedVarIntsBitSet and CAutoBitSet
Browse files Browse the repository at this point in the history
  • Loading branch information
codablock committed Jan 17, 2019
1 parent 76a58f5 commit 49de417
Showing 1 changed file with 100 additions and 1 deletion.
101 changes: 100 additions & 1 deletion src/serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 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);



Expand Down Expand Up @@ -359,6 +361,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 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 COMPACTSIZE(obj) REF(CCompactSize(REF(obj)))
#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj)))
Expand Down Expand Up @@ -464,6 +468,101 @@ class CDynamicBitSet
}
};

/**
* 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>
class CVarInt
{
Expand Down Expand Up @@ -1093,7 +1192,7 @@ inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)
}

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();
}
Expand Down

0 comments on commit 49de417

Please sign in to comment.