#!/usr/bin/perl
# Author: Trizen
# Date: 23 March 2023
# https://github.com/trizen
# Encode and decode a random list of integers into a binary string, using increasing fixed-width segments.
use 5.036;
sub read_bits ($fh, $bits_len) {
my $data = '';
read($fh, $data, $bits_len >> 3);
$data = unpack('B*', $data);
while (length($data) < $bits_len) {
$data .= unpack('B*', getc($fh) // return undef);
}
if (length($data) > $bits_len) {
$data = substr($data, 0, $bits_len);
}
return $data;
}
sub encode_integers ($integers) {
my @counts;
my $count = 0;
my $bits_width = 1;
my $bits_max_symbol = 1 = $bits_max_symbol) {
if ($count > 0) {
push @counts, [$bits_width, $count];
$processed_len += $count;
}
$count = 0;
$bits_max_symbol *= 2;
$bits_width += 1;
}
++$count;
}
push @counts, grep { $_->[1] > 0 } [$bits_width, scalar(@$integers) - $processed_len];
my $compressed = chr(scalar @counts);
foreach my $pair (@counts) {
my ($blen, $len) = @$pair;
$compressed .= chr($blen);
$compressed .= pack('N', $len);
}
my $bits = '';
foreach my $pair (@counts) {
my ($blen, $len) = @$pair;
foreach my $symbol (splice(@$integers, 0, $len)) {
$bits .= sprintf("%0*b", $blen, $symbol);
}
}
$compressed .= pack('B*', $bits);
return $compressed;
}
sub decode_integers ($str) {
open my $fh, '