feature. See also
. The project being documented here (as the example) is the Zig library itself.
Compress.BitWriter
const BitWriter = struct
File
Code
const BitWriter = struct {
output: *Writer,
buffered: u7,
buffered_n: u3,
pub fn init(w: *Writer) BitWriter {
return .{
.output = w,
.buffered = 0,
.buffered_n = 0,
};
}
pub fn write(b: *BitWriter, bits: u56, n: u6) Writer.Error!void {
assert(@as(u8, b.buffered) >> b.buffered_n == 0);
assert(@as(u57, bits) >> n == 0);
const combined = @shlExact(@as(u64, bits), b.buffered_n) | b.buffered;
const combined_bits = @as(u6, b.buffered_n) + n;
const out = try b.output.writableSliceGreedy(8);
mem.writeInt(u64, out[0..8], combined, .little);
b.output.advance(combined_bits / 8);
b.buffered_n = @truncate(combined_bits);
b.buffered = @intCast(combined >> (combined_bits - b.buffered_n));
}
pub fn byteAlign(b: *BitWriter) void {
b.output.unusedCapacitySlice()[0] = b.buffered;
b.output.advance(@intFromBool(b.buffered_n != 0));
b.buffered = 0;
b.buffered_n = 0;
}
pub fn byteAlignBlocks(b: *BitWriter) Writer.Error!void {
if (b.buffered_n == 0) return;
// 1. A store block (5 or 6 bytes)
// 2. Outputting empty 10-bit fixed blocks until aligned
//
// Fixed blocks advance the bit alignment by two, and so can only used for even numbers
// requiring a maximum of four bytes (three blocks = 30 bits) to which is always more
// efficient than store blocks.
if (b.buffered_n & 1 == 0) {
const splat = (8 - @as(u5, b.buffered_n)) >> 1;
const bits = splat * 10;
const pattern: u32 = BlockHeader.int(.{ .kind = .fixed, .final = false });
const splatted = ((pattern << 20) | (pattern << 10) | pattern) >> (30 - bits);
try b.write(splatted, bits);
} else {
try b.write(BlockHeader.int(.{ .kind = .stored, .final = false }), 3);
try b.output.rebase(0, 5);
b.byteAlign();
b.output.writeInt(u16, 0x0000, .little) catch unreachable;
b.output.writeInt(u16, 0xffff, .little) catch unreachable;
}
assert(b.buffered_n == 0);
}
pub fn writeClen(
b: *BitWriter,
hclen: u4,
clen_values: []u8,
clen_extra: []u8,
clen_codes: [19]u16,
clen_bits: [19]u4,
) Writer.Error!void {
// and writing them all at once takes too many bits.
try b.write(clen_bits[token.codegen_order[0]] |
@shlExact(@as(u6, clen_bits[token.codegen_order[1]]), 3) |
@shlExact(@as(u9, clen_bits[token.codegen_order[2]]), 6) |
@shlExact(@as(u12, clen_bits[token.codegen_order[3]]), 9), 12);
var i = hclen;
var clen_bits_table: u45 = 0;
while (i != 0) {
i -= 1;
clen_bits_table <<= 3;
clen_bits_table |= clen_bits[token.codegen_order[4..][i]];
}
try b.write(clen_bits_table, @as(u6, hclen) * 3);
for (clen_values, clen_extra) |value, extra| {
try b.write(
clen_codes[value] | @shlExact(@as(u16, extra), clen_bits[value]),
clen_bits[value] + @as(u3, switch (value) {
0...15 => 0,
16 => 2,
17 => 3,
18 => 7,
else => unreachable,
}),
);
}
}
}