From a7808892f71d0209a107e8d5e15405ce30f67a1e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 31 Jul 2025 18:05:22 -0700 Subject: [PATCH] std.compress.flate.Decompress: be in indirect or direct mode depending on whether buffered --- lib/std/compress/flate/Decompress.zig | 47 +++++++++++++++++---------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/std/compress/flate/Decompress.zig b/lib/std/compress/flate/Decompress.zig index 05a2354f09..2060f52c02 100644 --- a/lib/std/compress/flate/Decompress.zig +++ b/lib/std/compress/flate/Decompress.zig @@ -53,15 +53,24 @@ pub const Error = Container.Error || error{ EndOfStream, }; +const direct_vtable: Reader.VTable = .{ + .stream = streamDirect, + .rebase = rebaseFallible, + .discard = discard, + .readVec = readVec, +}; + +const indirect_vtable: Reader.VTable = .{ + .stream = streamIndirect, + .rebase = rebaseFallible, + .discard = discard, + .readVec = readVec, +}; + pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress { return .{ .reader = .{ - .vtable = &.{ - .stream = stream, - .rebase = rebaseFallible, - .discard = discard, - .readVec = readVec, - }, + .vtable = if (buffer.len == 0) &direct_vtable else &indirect_vtable, .buffer = buffer, .seek = 0, .end = 0, @@ -79,12 +88,10 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress { } fn rebaseFallible(r: *Reader, capacity: usize) Reader.RebaseError!void { - const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); - rebase(d, capacity); + rebase(r, capacity); } -fn rebase(d: *Decompress, capacity: usize) void { - const r = &d.reader; +fn rebase(r: *Reader, capacity: usize) void { assert(capacity <= r.buffer.len - flate.history_len); assert(r.end + capacity > r.buffer.len); const discard_n = r.end - flate.history_len; @@ -98,7 +105,7 @@ fn rebase(d: *Decompress, capacity: usize) void { /// This could be improved so that when an amount is discarded that includes an /// entire frame, skip decoding that frame. fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize { - r.rebase(flate.history_len) catch unreachable; + if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len); var writer: Writer = .{ .vtable = &.{ .drain = std.Io.Writer.Discarding.drain, @@ -124,12 +131,12 @@ fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize { fn readVec(r: *Reader, data: [][]u8) Reader.Error!usize { _ = data; const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); - return streamIndirect(d); + return streamIndirectInner(d); } -fn streamIndirect(d: *Decompress) Reader.Error!usize { +fn streamIndirectInner(d: *Decompress) Reader.Error!usize { const r = &d.reader; - if (r.end + flate.history_len > r.buffer.len) rebase(d, flate.history_len); + if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len); var writer: Writer = .{ .buffer = r.buffer, .end = r.end, @@ -200,10 +207,16 @@ fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol { return sym; } -pub fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize { +fn streamDirect(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize { const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); - if (w.end >= r.end) return streamFallible(d, w, limit); - return streamIndirect(d); + return streamFallible(d, w, limit); +} + +fn streamIndirect(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize { + const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); + _ = limit; + _ = w; + return streamIndirectInner(d); } fn streamFallible(d: *Decompress, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {