feature. See also
. The project being documented here (as the example) is the Zig library itself.
Decompress.BitReader
const BitReader = struct
File
Code
const BitReader = struct {
bytes: []const u8,
index: usize = 0,
bits: u8 = 0,
count: u4 = 0,
fn initBits(comptime T: type, out: anytype, num: u16) Bits(T) {
const UT = @Int(.unsigned, @bitSizeOf(T));
return .{
@bitCast(@as(UT, @intCast(out))),
num,
};
}
fn readBitsNoEof(self: *@This(), comptime T: type, num: u16) !T {
const b, const c = try self.readBitsTuple(T, num);
if (c < num) return error.EndOfStream;
return b;
}
fn readBits(self: *@This(), comptime T: type, num: u16, out_bits: *u16) !T {
const b, const c = try self.readBitsTuple(T, num);
out_bits.* = c;
return b;
}
fn readBitsTuple(self: *@This(), comptime T: type, num: u16) !Bits(T) {
const UT = @Int(.unsigned, @bitSizeOf(T));
const U = if (@bitSizeOf(T) < 8) u8 else UT;
if (num <= self.count) return initBits(T, self.removeBits(@intCast(num)), num);
var out_count: u16 = self.count;
var out: U = self.removeBits(self.count);
const full_bytes_left = (num - out_count) / 8;
for (0..full_bytes_left) |_| {
const byte = takeByte(self) catch |err| switch (err) {
error.EndOfStream => return initBits(T, out, out_count),
};
const pos = @as(U, byte) << @intCast(out_count);
out |= pos;
out_count += 8;
}
const bits_left = num - out_count;
const keep = 8 - bits_left;
if (bits_left == 0) return initBits(T, out, out_count);
const final_byte = takeByte(self) catch |err| switch (err) {
error.EndOfStream => return initBits(T, out, out_count),
};
const pos = @as(U, final_byte & low_bit_mask[bits_left]) << @intCast(out_count);
out |= pos;
self.bits = final_byte >> @intCast(bits_left);
self.count = @intCast(keep);
return initBits(T, out, num);
}
fn takeByte(br: *BitReader) error{EndOfStream}!u8 {
if (br.bytes.len - br.index == 0) return error.EndOfStream;
const result = br.bytes[br.index];
br.index += 1;
return result;
}
fn removeBits(self: *@This(), num: u4) u8 {
if (num == 8) {
self.count = 0;
return self.bits;
}
const keep = self.count - num;
const bits = self.bits & low_bit_mask[num];
self.bits >>= @intCast(num);
self.count = keep;
return bits;
}
fn alignToByte(self: *@This()) void {
self.bits = 0;
self.count = 0;
}
}