86 lines
2.2 KiB
D
86 lines
2.2 KiB
D
import std.stdio, std.string, std.file, std.algorithm;
|
|
|
|
/// Variable length quantity (unsigned long, max 63-bit).
|
|
struct VLQ {
|
|
ulong value;
|
|
|
|
// This allows VLQ to work like an ulong.
|
|
alias value this;
|
|
|
|
uint extract(in ubyte[] v) pure
|
|
in {
|
|
assert(v.length > 0);
|
|
} body {
|
|
immutable limit = min(v.length - 1, 8);
|
|
ulong t = 0;
|
|
size_t idx = 0;
|
|
while ((idx < limit) && ((v[idx] & 0x80) > 0))
|
|
t = (t << 7) | (0x7f & v[idx++]);
|
|
if (idx > limit)
|
|
throw new Exception(
|
|
"Too large for ulong or invalid format.");
|
|
else
|
|
value = (t << 7) | v[idx];
|
|
return idx + 1;
|
|
}
|
|
|
|
VLQ from(in ubyte[] v) pure {
|
|
extract(v);
|
|
return this;
|
|
}
|
|
|
|
@property ubyte[] toVLQ() const pure {
|
|
ubyte[] v = [0x7f & value];
|
|
for (ulong k = value >>> 7; k > 0; k >>>= 7)
|
|
v ~= (k & 0x7f) | 0x80;
|
|
if (v.length > 9)
|
|
throw new Exception("Too large value.");
|
|
v.reverse();
|
|
return v;
|
|
}
|
|
|
|
static ulong[] split(in ubyte[] b) pure {
|
|
ulong[] res;
|
|
VLQ v;
|
|
for (size_t i = 0; i < b.length; ) {
|
|
i += v.extract(b[i .. $]);
|
|
res ~= v.value;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
string toString() const pure /*nothrow*/ {
|
|
return format("(%(%02X:%))", this.toVLQ);
|
|
}
|
|
}
|
|
|
|
|
|
void main() { // VLQ demo code.
|
|
VLQ a = VLQ(0x7f),
|
|
b = VLQ(0x4000),
|
|
c;
|
|
writefln("a:%8x = %s\nb:%8x = %s\nc:%8x = %s",
|
|
a.value, a, b.value, b, c.value, c);
|
|
|
|
// Some operations.
|
|
c = (a + 1) * b;
|
|
a = c - 1;
|
|
b = VLQ().from(a.toVLQ);
|
|
a <<= 1;
|
|
|
|
// Convert ulong to octet sequence.
|
|
writefln("\na:%8x = %s\nb:%8x = %s\nc:%8x = %s",
|
|
a.value, a, b.value, b, c.value, c);
|
|
|
|
// Write them to a binary file.
|
|
std.file.write("vlqtest.bin", a.toVLQ ~ b.toVLQ ~ c.toVLQ);
|
|
|
|
// Read them back.
|
|
const buf = cast(ubyte[])std.file.read("vlqtest.bin");
|
|
writefln("\nFile length: %d bytes.", buf.length);
|
|
|
|
// Convert octet sequence to ulongs.
|
|
foreach (immutable i, immutable v; VLQ.split(buf))
|
|
writefln("%d:%8x = %s", i + 1, v, VLQ(v));
|
|
}
|