Given an IO
, I want to read N bits into each index of an Array{UInt64}
and vice-versa: For example, the data [0b0_101_100_011_010_001_000_111_110_101_100_011_010_001_000_111_110_101_100_011_010_001, 0b00_010_001_000_111_110_101_100_011_010_001_000_111_110_101_100_011_010_001_000_111_11]
becomes UInt64[1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2]
. Here are my current functions:
function unpack(compressed::IO, bits::Int64, size::Int64)
data = zeros(UInt, size)
shift = 0
mask = 2^bits - 1
current = read(compressed, UInt64)
for i in 1:length(data)
data[i] += (current >>> shift) & mask
if shift + bits > 64
current = read(compressed, UInt64)
data[i] += (current >>> (shift - 64)) & mask
shift = shift + bits - 64
elseif shift + bits == 64
current = read(compressed, UInt64)
shift = 0
else
shift += bits
end
end
return data
end
function pack(io::IO, uncompressed::Array{UInt64}, bits::Int64)
write(io, BitArray(n >>> i & 1 == 1 for n in uncompressed for i in 0:bits - 1).chunks)
end
B = rand(UInt64, 256^3); path, io = mktemp(cleanup=true);
@btime pack($io, $B, 3) # 135.244 ms (28 allocations: 17.76 MiB)
A1 = pack(B, 3); L = length(A1); A = IOBuffer(reinterpret(UInt8, A1));
@btime (seek($A, 0); unpack($A, 3, L Ă· 3)) # 1.278 ms (4 allocations: 2.00 MiB)
Can anyone think of a faster way of doing this? I was thinking there may be some way to use reinterpret
but couldn’t get anything to work. Any help would be appreciated!