Variable-length quantity
vlq_encode() returns a string of characters whose ordinals are the encoded octets. vlq_decode() takes a string and returns a decimal number.
sub vlq_encode ($number is copy) {
my $string = '';
my $t = 0x7F +& $number;
$number +>= 7;
$string = $t.chr ~ $string;
while ($number) {
$t = 0x7F +& $number;
$string = (0x80 +| $t).chr ~ $string;
$number +>= 7;
}
return $string;
}
sub vlq_decode ($string is copy) {
my $number = '0b';
for $string.ords -> $oct {
$number ~= ($oct +& 0x7F).fmt("%07b");
}
return :2($number);
}
#test encoding and decoding
for (
0, 0xa, 123, 254, 255, 256,
257, 65534, 65535, 65536, 65537, 0x1fffff,
0x200000
) -> $testcase {
my $encoded = vlq_encode($testcase);
printf "%8s %12s %8s\n", $testcase,
( join ':', $encoded.ords>>.fmt("%02X") ),
vlq_decode($encoded);
}
Output:
Output:
0 00 0
10 0A 10
123 7B 123
254 81:7E 254
255 81:7F 255
256 82:00 256
257 82:01 257
65534 83:FF:7E 65534
65535 83:FF:7F 65535
65536 84:80:00 65536
65537 84:80:01 65537
2097151 FF:FF:7F 2097151
2097152 81:80:80:00 2097152