From f212e3716b7f687d552fdad5f15cd1f736039910 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Thu, 30 Jul 2026 21:10:50 -0700 Subject: [PATCH] Writer.Allocating.drain: avoid overallocating in certain situations In scenarios where splat=1, `drain` would ensure 2x more unused capacity than necessary for the "pattern" bytes since `bytes.len` and `splat_len` would both be counting the same bytes for the `data[data.len - 1]` element. Now, instead of ensuring `bytes.len + splat_len + 1` unused capacity within the loop, the total amount is calculated upfront and that much unused capacity (+ 1, see 8f4229158be69685b49f4e1ac446cd3677a2e63f) is ensured all at once. --- lib/std/Io/Writer.zig | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index ebfe6cd502f399501eeafdbdf44205ca6636e8d2..7a6f4468964c4b5f8c8a1a6ff86fcd6d7a63a6b4 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -2742,29 +2742,26 @@ pub const Allocating = struct { fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { const a: *Allocating = @fieldParentPtr("writer", w); - const pattern = data[data.len - 1]; - const splat_len = pattern.len * splat; - const start_len = a.writer.end; assert(data.len != 0); - for (data) |bytes| { - a.ensureUnusedCapacity(bytes.len + splat_len + 1) catch return error.WriteFailed; + const count = countSplat(data, splat); + a.ensureUnusedCapacity(count + 1) catch return error.WriteFailed; + for (data[0 .. data.len - 1]) |bytes| { @memcpy(a.writer.buffer[a.writer.end..][0..bytes.len], bytes); a.writer.end += bytes.len; } - if (splat == 0) { - a.writer.end -= pattern.len; - } else switch (pattern.len) { + const pattern = data[data.len - 1]; + switch (pattern.len) { 0 => {}, 1 => { - @memset(a.writer.buffer[a.writer.end..][0 .. splat - 1], pattern[0]); - a.writer.end += splat - 1; + @memset(a.writer.buffer[a.writer.end..][0..splat], pattern[0]); + a.writer.end += splat; }, - else => for (0..splat - 1) |_| { + else => for (0..splat) |_| { @memcpy(a.writer.buffer[a.writer.end..][0..pattern.len], pattern); a.writer.end += pattern.len; }, } - return a.writer.end - start_len; + return count; } fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { -- 2.54.0