feature. See also
. The project being documented here (as the example) is the Zig library itself.
Compress.rebaseInner
fn rebaseInner(
w: *Writer,
preserve: usize,
capacity: usize,
is_flush: bool,
is_finish: bool,
) Writer.Error!void
File
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 {
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;
}
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;
}
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);
break :lazy;
}
var chain = c.opts.chain;
var good = c.opts.good;
if (match.len >= good) {
chain >>= 2;
good = math.maxInt(u8);
}
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],
));
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);
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;
}
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;
}