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.

rebaseInner

Compress.rebaseInner
fn rebaseInner(
    w: *Writer,
    preserve: usize,
    capacity: usize,
    is_flush: bool,
    is_finish: bool,
) Writer.Error!void

File

lib/std/compress/flate/Compress.zig:379

Code

fn rebaseInner(
    w: *Writer,
    preserve: usize,
    capacity: usize,
    is_flush: bool,
    is_finish: bool,
) Writer.Error!void {
    if (!is_flush) {
        assert(@max(preserve, rebase_min_preserve) + (capacity + rebase_reserved_capacity) <= w.buffer.len);
    } else {
        // Preverse is not considered for `matching_end`
        assert(preserve == 0 and capacity == w.buffer.len - flate.history_len);
    }
    if (is_finish) assert(is_flush);

    const c: *Compress = @fieldParentPtr("writer", w);
    const buffered = w.buffered();

    const start: usize = c.history_len;
    const hashable_len = buffered.len -| (seq_bytes - 1);
    const matching_end: usize = if (!is_flush)
        buffered.len - rebase_reserved_capacity - (preserve -| flate.history_len)
    else
        hashable_len;

    var i = start;
    var last_unmatched = i;
    var seq: Seq = start_seq: {
        if (c.history_end_unhashed) {
            @branchHint(.unlikely);

            assert(i != 0);
            i -|= seq_bytes - 1;
            var seq: Seq = mem.readInt(
                @Int(.unsigned, (seq_bytes - 1) * 8),
                w.buffer[i..][0 .. seq_bytes - 1],
                .big,
            );

            while (i < @min(start, hashable_len)) {
                seq <<= 8;
                seq |= buffered[i + (seq_bytes - 1)];
                c.addHash(i, hash(seq));
                i += 1;
            }

            if (i < start) {
                @branchHint(.unlikely);
                i = start;
                assert(i >= hashable_len);
                assert(i >= matching_end);
                assert(is_flush);
                break :start_seq undefined; // Unused
            }

            c.history_end_unhashed = false;
            break :start_seq seq;
        }

        if (i >= hashable_len) {
            @branchHint(.unlikely);
            assert(i >= matching_end);
            assert(is_flush);
            break :start_seq undefined; // Unused
        }

        break :start_seq mem.readInt(
            @Int(.unsigned, (seq_bytes - 1) * 8),
            buffered[i..][0 .. seq_bytes - 1],
            .big,
        );
    };

    while (i < matching_end) {
        var match_start = i;
        seq <<= 8;
        seq |= buffered[i + (seq_bytes - 1)];
        var match = c.matchAndAddHash(i, hash(seq), token.min_length - 1, c.opts.chain, c.opts.good);
        i += 1;
        if (match.len < token.min_length) continue;

        var match_unadded = match.len - 1;
        lazy: {
            if (match.len >= c.opts.lazy) break :lazy;
            if (match.len >= c.writer.buffered()[i..].len) {
                @branchHint(.unlikely); // Only end of stream
                break :lazy;
            }

            var chain = c.opts.chain;
            var good = c.opts.good;
            if (match.len >= good) {
                chain >>= 2;
                good = math.maxInt(u8); // Reduce only once
            }

            seq <<= 8;
            seq |= buffered[i + (seq_bytes - 1)];
            const lazy = c.matchAndAddHash(i, hash(seq), match.len, chain, good);
            match_unadded -= 1;
            i += 1;

            if (lazy.len > match.len) {
                match_start += 1;
                match = lazy;
                match_unadded = match.len - 1;
            }
        }

        assert(i + match_unadded == match_start + match.len);
        assert(mem.eql(
            u8,
            buffered[match_start..][0..match.len],
            buffered[match_start - 1 - match.dist ..][0..match.len],
        )); // This assert also seems to help codegen.

        try c.outputBytes(buffered[last_unmatched..match_start]);
        try c.outputMatch(@intCast(match.dist), @intCast(match.len - 3));
        last_unmatched = match_start + match.len;

        while (i < hashable_len) {
            seq <<= 8;
            seq |= buffered[i + (seq_bytes - 1)];
            c.addHash(i, hash(seq));
            i += 1;

            match_unadded -= 1;
            if (match_unadded == 0) break;
        } else {
            @branchHint(.unlikely);
            assert(is_flush);
            // `c.history_end_unhashed` is set down below
            break;
        }
        assert(i == match_start + match.len);
    }

    if (is_flush) {
        try c.outputBytes(buffered[last_unmatched..]);
        c.hasher.update(buffered[start..]);

        if (is_finish) {
            try c.writeBlock(true);
            return; // Other state does not need updated since the writer transitions to `.failing`
        }

        i = buffered.len;
        c.history_end_unhashed = i != 0;

        if (c.buffered_tokens.n != 0) {
            try c.writeBlock(false);
        }
    } else {
        try c.outputBytes(buffered[last_unmatched..i]);
        c.hasher.update(buffered[start..i]);
    }

    c.history_len = @min(i, flate.history_len);
    const preserved = buffered[i - c.history_len ..];
    if (!is_flush) assert(preserved.len >= @max(rebase_min_preserve, preserve));
    @memmove(w.buffer[0..preserved.len], preserved);
    w.end = preserved.len;
}