Changeset View
Changeset View
Standalone View
Standalone View
src/serialize.h
Show First 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* 0: [0x00] 256: [0x81 0x00] | * 0: [0x00] 256: [0x81 0x00] | ||||
* 1: [0x01] 16383: [0xFE 0x7F] | * 1: [0x01] 16383: [0xFE 0x7F] | ||||
* 127: [0x7F] 16384: [0xFF 0x00] | * 127: [0x7F] 16384: [0xFF 0x00] | ||||
* 128: [0x80 0x00] 16511: [0xFF 0x7F] | * 128: [0x80 0x00] 16511: [0xFF 0x7F] | ||||
* 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F] | * 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F] | ||||
* 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] | * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] | ||||
*/ | */ | ||||
template <typename I> inline unsigned int GetSizeOfVarInt(I n) { | |||||
/** | |||||
* Mode for encoding VarInts. | |||||
* | |||||
* Currently there is no support for signed encodings. The default mode will not | |||||
* compile with signed values, and the legacy "nonnegative signed" mode will | |||||
* accept signed values, but improperly encode and decode them if they are | |||||
* negative. In the future, the DEFAULT mode could be extended to support | |||||
* negative numbers in a backwards compatible way, and additional modes could be | |||||
* added to support different varint formats (e.g. zigzag encoding). | |||||
*/ | |||||
enum class VarIntMode { DEFAULT, NONNEGATIVE_SIGNED }; | |||||
template <VarIntMode Mode, typename I> struct CheckVarIntMode { | |||||
constexpr CheckVarIntMode() { | |||||
static_assert(Mode != VarIntMode::DEFAULT || std::is_unsigned<I>::value, | |||||
"Unsigned type required with mode DEFAULT."); | |||||
static_assert(Mode != VarIntMode::NONNEGATIVE_SIGNED || | |||||
std::is_signed<I>::value, | |||||
"Signed type required with mode NONNEGATIVE_SIGNED."); | |||||
} | |||||
}; | |||||
template <VarIntMode Mode, typename I> | |||||
inline unsigned int GetSizeOfVarInt(I n) { | |||||
CheckVarIntMode<Mode, I>(); | |||||
int nRet = 0; | int nRet = 0; | ||||
while (true) { | while (true) { | ||||
nRet++; | nRet++; | ||||
if (n <= 0x7F) { | if (n <= 0x7F) { | ||||
return nRet; | return nRet; | ||||
} | } | ||||
n = (n >> 7) - 1; | n = (n >> 7) - 1; | ||||
} | } | ||||
} | } | ||||
template <typename I> inline void WriteVarInt(CSizeComputer &os, I n); | template <typename I> inline void WriteVarInt(CSizeComputer &os, I n); | ||||
template <typename Stream, typename I> void WriteVarInt(Stream &os, I n) { | template <typename Stream, VarIntMode Mode, typename I> | ||||
void WriteVarInt(Stream &os, I n) { | |||||
CheckVarIntMode<Mode, I>(); | |||||
uint8_t tmp[(sizeof(n) * 8 + 6) / 7]; | uint8_t tmp[(sizeof(n) * 8 + 6) / 7]; | ||||
int len = 0; | int len = 0; | ||||
while (true) { | while (true) { | ||||
tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00); | tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00); | ||||
if (n <= 0x7F) { | if (n <= 0x7F) { | ||||
break; | break; | ||||
} | } | ||||
n = (n >> 7) - 1; | n = (n >> 7) - 1; | ||||
len++; | len++; | ||||
} | } | ||||
do { | do { | ||||
ser_writedata8(os, tmp[len]); | ser_writedata8(os, tmp[len]); | ||||
} while (len--); | } while (len--); | ||||
} | } | ||||
template <typename Stream, typename I> I ReadVarInt(Stream &is) { | template <typename Stream, VarIntMode Mode, typename I> | ||||
I ReadVarInt(Stream &is) { | |||||
CheckVarIntMode<Mode, I>(); | |||||
I n = 0; | I n = 0; | ||||
while (true) { | while (true) { | ||||
uint8_t chData = ser_readdata8(is); | uint8_t chData = ser_readdata8(is); | ||||
if (n > (std::numeric_limits<I>::max() >> 7)) { | if (n > (std::numeric_limits<I>::max() >> 7)) { | ||||
throw std::ios_base::failure("ReadVarInt(): size too large"); | throw std::ios_base::failure("ReadVarInt(): size too large"); | ||||
} | } | ||||
n = (n << 7) | (chData & 0x7F); | n = (n << 7) | (chData & 0x7F); | ||||
if ((chData & 0x80) == 0) { | if ((chData & 0x80) == 0) { | ||||
return n; | return n; | ||||
} | } | ||||
if (n == std::numeric_limits<I>::max()) { | if (n == std::numeric_limits<I>::max()) { | ||||
throw std::ios_base::failure("ReadVarInt(): size too large"); | throw std::ios_base::failure("ReadVarInt(): size too large"); | ||||
} | } | ||||
n++; | n++; | ||||
} | } | ||||
} | } | ||||
#define FLATDATA(obj) CFlatData((char *)&(obj), (char *)&(obj) + sizeof(obj)) | #define FLATDATA(obj) CFlatData((char *)&(obj), (char *)&(obj) + sizeof(obj)) | ||||
#define VARINT(obj) WrapVarInt(REF(obj)) | #define VARINT(obj, ...) WrapVarInt<__VA_ARGS__>(REF(obj)) | ||||
#define COMPACTSIZE(obj) CCompactSize(REF(obj)) | #define COMPACTSIZE(obj) CCompactSize(REF(obj)) | ||||
#define LIMITED_STRING(obj, n) LimitedString<n>(REF(obj)) | #define LIMITED_STRING(obj, n) LimitedString<n>(REF(obj)) | ||||
/** | /** | ||||
* Wrapper for serializing arrays and POD. | * Wrapper for serializing arrays and POD. | ||||
*/ | */ | ||||
class CFlatData { | class CFlatData { | ||||
protected: | protected: | ||||
Show All 21 Lines | template <typename Stream> void Serialize(Stream &s) const { | ||||
s.write(pbegin, pend - pbegin); | s.write(pbegin, pend - pbegin); | ||||
} | } | ||||
template <typename Stream> void Unserialize(Stream &s) { | template <typename Stream> void Unserialize(Stream &s) { | ||||
s.read(pbegin, pend - pbegin); | s.read(pbegin, pend - pbegin); | ||||
} | } | ||||
}; | }; | ||||
template <typename I> class CVarInt { | template <VarIntMode Mode, typename I> class CVarInt { | ||||
protected: | protected: | ||||
I &n; | I &n; | ||||
public: | public: | ||||
explicit CVarInt(I &nIn) : n(nIn) {} | explicit CVarInt(I &nIn) : n(nIn) {} | ||||
template <typename Stream> void Serialize(Stream &s) const { | template <typename Stream> void Serialize(Stream &s) const { | ||||
WriteVarInt<Stream, I>(s, n); | WriteVarInt<Stream, Mode, I>(s, n); | ||||
} | } | ||||
template <typename Stream> void Unserialize(Stream &s) { | template <typename Stream> void Unserialize(Stream &s) { | ||||
n = ReadVarInt<Stream, I>(s); | n = ReadVarInt<Stream, Mode, I>(s); | ||||
} | } | ||||
}; | }; | ||||
class CCompactSize { | class CCompactSize { | ||||
protected: | protected: | ||||
uint64_t &n; | uint64_t &n; | ||||
public: | public: | ||||
Show All 29 Lines | public: | ||||
template <typename Stream> void Serialize(Stream &s) const { | template <typename Stream> void Serialize(Stream &s) const { | ||||
WriteCompactSize(s, string.size()); | WriteCompactSize(s, string.size()); | ||||
if (!string.empty()) { | if (!string.empty()) { | ||||
s.write((char *)string.data(), string.size()); | s.write((char *)string.data(), string.size()); | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
template <typename I> CVarInt<I> WrapVarInt(I &n) { | template <VarIntMode Mode = VarIntMode::DEFAULT, typename I> | ||||
return CVarInt<I>(n); | CVarInt<Mode, I> WrapVarInt(I &n) { | ||||
return CVarInt<Mode, I>{n}; | |||||
} | } | ||||
/** | /** | ||||
* Forward declarations | * Forward declarations | ||||
*/ | */ | ||||
/** | /** | ||||
* string | * string | ||||
▲ Show 20 Lines • Show All 421 Lines • Show Last 20 Lines |