Skip to content

Commit b8b636c

Browse files
committed
Compact serialization for variable-length integers
Variable-length integers: bytes are a MSB base-128 encoding of the number. The high bit in each byte signifies whether another digit follows. To make the encoding is one-to-one, one is subtracted from all but the last digit. Thus, the byte sequence a[] with length len, where all but the last byte has bit 128 set, encodes the number: (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) Properties: * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) * Every integer has exactly one encoding * Encoding does not depend on size of original integer type
1 parent bafc8da commit b8b636c

File tree

2 files changed

+95
-1
lines changed

2 files changed

+95
-1
lines changed

src/checkpoints.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "net.h"
99
#include "util.h"
1010

11-
#define CHECKPOINT_MAX_SPAN (60 * 60) // max 1 hour before latest block
11+
#define CHECKPOINT_MAX_SPAN (60 * 60) // max 60 minutes before latest block
1212

1313
#ifdef WIN32
1414
#undef STRICT

src/serialize.h

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,76 @@ uint64 ReadCompactSize(Stream& is)
244244
}
245245

246246

247+
// Variable-length integers: bytes are a MSB base-128 encoding of the number.
248+
// The high bit in each byte signifies whether another digit follows. To make
249+
// the encoding is one-to-one, one is subtracted from all but the last digit.
250+
// Thus, the byte sequence a[] with length len, where all but the last byte
251+
// has bit 128 set, encodes the number:
252+
//
253+
// (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1))
254+
//
255+
// Properties:
256+
// * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes)
257+
// * Every integer has exactly one encoding
258+
// * Encoding does not depend on size of original integer type
259+
// * No redundancy: every (infinite) byte sequence corresponds to a list
260+
// of encoded integers.
261+
//
262+
// 0: [0x00] 256: [0x81 0x00]
263+
// 1: [0x01] 16383: [0xFE 0x7F]
264+
// 127: [0x7F] 16384: [0xFF 0x00]
265+
// 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F]
266+
// 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F]
267+
// 2^32: [0x8E 0xFE 0xFE 0xFF 0x00]
268+
269+
template<typename I>
270+
inline unsigned int GetSizeOfVarInt(I n)
271+
{
272+
int nRet = 0;
273+
while(true) {
274+
nRet++;
275+
if (n <= 0x7F)
276+
break;
277+
n = (n >> 7) - 1;
278+
}
279+
return nRet;
280+
}
281+
282+
template<typename Stream, typename I>
283+
void WriteVarInt(Stream& os, I n)
284+
{
285+
unsigned char tmp[(sizeof(n)*8+6)/7];
286+
int len=0;
287+
while(true) {
288+
tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00);
289+
if (n <= 0x7F)
290+
break;
291+
n = (n >> 7) - 1;
292+
len++;
293+
}
294+
do {
295+
WRITEDATA(os, tmp[len]);
296+
} while(len--);
297+
}
298+
299+
template<typename Stream, typename I>
300+
I ReadVarInt(Stream& is)
301+
{
302+
I n = 0;
303+
while(true) {
304+
unsigned char chData;
305+
READDATA(is, chData);
306+
n = (n << 7) | (chData & 0x7F);
307+
if (chData & 0x80)
308+
n++;
309+
else
310+
return n;
311+
}
312+
}
313+
247314

248315
#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
316+
#define VARINT(obj) REF(WrapVarInt(REF(obj)))
249317

250318
/** Wrapper for serializing arrays and POD.
251319
*/
@@ -279,6 +347,32 @@ class CFlatData
279347
}
280348
};
281349

350+
template<typename I>
351+
class CVarInt
352+
{
353+
protected:
354+
I &n;
355+
public:
356+
CVarInt(I& nIn) : n(nIn) { }
357+
358+
unsigned int GetSerializeSize(int, int) const {
359+
return GetSizeOfVarInt<I>(n);
360+
}
361+
362+
template<typename Stream>
363+
void Serialize(Stream &s, int, int) const {
364+
WriteVarInt<Stream,I>(s, n);
365+
}
366+
367+
template<typename Stream>
368+
void Unserialize(Stream& s, int, int) {
369+
n = ReadVarInt<Stream,I>(s);
370+
}
371+
};
372+
373+
template<typename I>
374+
CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); }
375+
282376
//
283377
// Forward declarations
284378
//

0 commit comments

Comments
 (0)