-
Notifications
You must be signed in to change notification settings - Fork 5
Packed
Packed integers are a special data type used to represent integers with widely varying size. They are used to save space as they only take up as much bytes as it requires, and no more.
The first bit of each byte represents whether or not the reader should read the next byte. The rest of the bits act as a 7 bit integer unsigned or a 6 bit integer signed. The maximum values that can be represented for the first byte of a signed packed integer is 64.
An unsigned packed integer in memory may look like the following:
fb ff 0d
0xfb = 0b11111011
This tells us that the first byte is equal to 123. The bits do not need to be shifted as it's the first byte in the sequence. The first bit is omitted since it only tells us to read the next byte in the sequence.
0xff = 0b11111111
This next byte is equal to 127, as again, the first bit only tells us to read the next byte. Remember to shift the bits in the byte 7 places to the left, or 16256 to add to the accumulator, as you would do with a normal integer. This leaves us with 16379
0x0d = 0b00001101
This byte is equal to 13, this time the first bit is telling us to stop and to not read the next byte. The value must be shifted 14 places to the left this time, as it it's offset is 2 from the base, or 212992. This leaves us with 229371 if you add this to the accumulated value.
Note how using normal integers, any value from 0 to 4,294,967,295 would take up 4 bytes in a uint32 type, while using packed integers, it would only take as much as absolutely needed.
function readPacked(buffer) {
let output = 0;
for (let shift = 0;; shift+=7) {
const byte = buffer.readUInt8(shift / 7);
const read = (byte >> 7) & 1;
const val = read ? byte ^ 0b10000000 : byte;
output |= val << shift;
if (!read) {
break;
}
}
return output;
}
function writePacked(val) {
do {
let b = val & 0b11111111;
if (val >= 0b10000000) {
b |= 0b10000000;
}
val >>= 7;
} while (val > 0);
return val;
}