Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

BitWriter

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,
        };
    }

    /// Asserts `bits` is zero-extended
    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); // n may be 56 so u57 is needed
        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));
    }

    /// Asserts one byte can be written to `b.output` without rebasing.
    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;
    }

    /// Byte align using only empty flate blocks
    pub fn byteAlignBlocks(b: *BitWriter) Writer.Error!void {
        if (b.buffered_n == 0) return;

        // There are two methods to do this:
        // 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;
            // fixed eos code is 0, so the only bits are for the block header
            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 {
        // Write the first four clen entries seperately since they are always present,
        // 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,
                }),
            );
        }
    }
}