Skip to content

Commit d772c06

Browse files
silversquirlandrewrk
authored andcommitted
fix splatBytesAll and writeSplatAll
1 parent c7bcdb4 commit d772c06

File tree

1 file changed

+53
-17
lines changed

1 file changed

+53
-17
lines changed

lib/std/Io/Writer.zig

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -464,34 +464,54 @@ pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void {
464464

465465
/// The `data` parameter is mutable because this function needs to mutate the
466466
/// fields in order to handle partial writes from `VTable.writeSplat`.
467+
/// `data` will be restored to its original state before returning.
467468
pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void {
468469
var index: usize = 0;
469470
var truncate: usize = 0;
470-
var remaining_splat = splat;
471471
while (index + 1 < data.len) {
472472
{
473473
const untruncated = data[index];
474474
data[index] = untruncated[truncate..];
475475
defer data[index] = untruncated;
476-
truncate += try w.writeSplat(data[index..], remaining_splat);
476+
truncate += try w.writeSplat(data[index..], splat);
477477
}
478-
while (truncate >= data[index].len) {
479-
if (index + 1 < data.len) {
480-
truncate -= data[index].len;
481-
index += 1;
482-
} else {
483-
const last = data[data.len - 1];
484-
remaining_splat -= @divExact(truncate, last.len);
485-
while (remaining_splat > 0) {
486-
const n = try w.writeSplat(data[data.len - 1 ..][0..1], remaining_splat);
487-
remaining_splat -= @divExact(n, last.len);
488-
}
489-
return;
490-
}
478+
while (truncate >= data[index].len and index + 1 < data.len) {
479+
truncate -= data[index].len;
480+
index += 1;
481+
}
482+
}
483+
484+
// Deal with any left over splats
485+
if (data.len != 0 and truncate < data[index].len * splat) {
486+
std.debug.assert(index == data.len - 1);
487+
var remaining_splat = splat;
488+
while (true) {
489+
remaining_splat -= truncate / data[index].len;
490+
truncate %= data[index].len;
491+
if (remaining_splat == 0) break;
492+
truncate += try w.writeSplat(&.{ data[index][truncate..], data[index] }, remaining_splat - 1);
491493
}
492494
}
493495
}
494496

497+
test writeSplatAll {
498+
var aw: Writer.Allocating = .init(testing.allocator);
499+
defer aw.deinit();
500+
501+
var buffers = [_][]const u8{ "ba", "na" };
502+
try aw.writer.writeSplatAll(&buffers, 2);
503+
try testing.expectEqualStrings("banana", aw.writer.buffered());
504+
}
505+
506+
test "writeSplatAll works with a single buffer" {
507+
var aw: Writer.Allocating = .init(testing.allocator);
508+
defer aw.deinit();
509+
510+
var message: [1][]const u8 = .{"hello"};
511+
try aw.writer.writeSplatAll(&message, 3);
512+
try testing.expectEqualStrings("hellohellohello", aw.writer.buffered());
513+
}
514+
495515
pub fn write(w: *Writer, bytes: []const u8) Error!usize {
496516
if (w.end + bytes.len <= w.buffer.len) {
497517
@branchHint(.likely);
@@ -763,6 +783,14 @@ pub fn splatByteAll(w: *Writer, byte: u8, n: usize) Error!void {
763783
while (remaining > 0) remaining -= try w.splatByte(byte, remaining);
764784
}
765785

786+
test splatByteAll {
787+
var aw: Writer.Allocating = .init(testing.allocator);
788+
defer aw.deinit();
789+
790+
try aw.writer.splatByteAll('7', 45);
791+
try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());
792+
}
793+
766794
/// Writes the same byte many times, allowing short writes.
767795
///
768796
/// Does maximum of one underlying `VTable.drain`.
@@ -778,13 +806,21 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {
778806
while (remaining_bytes > 0) {
779807
const leftover = remaining_bytes % bytes.len;
780808
const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };
781-
remaining_bytes -= try w.splatBytes(&buffers, splat);
809+
remaining_bytes -= try w.writeSplat(&buffers, splat);
782810
}
783811
}
784812

813+
test splatBytesAll {
814+
var aw: Writer.Allocating = .init(testing.allocator);
815+
defer aw.deinit();
816+
817+
try aw.writer.splatBytesAll("hello", 3);
818+
try testing.expectEqualStrings("hellohellohello", aw.writer.buffered());
819+
}
820+
785821
/// Writes the same slice many times, allowing short writes.
786822
///
787-
/// Does maximum of one underlying `VTable.writeSplat`.
823+
/// Does maximum of one underlying `VTable.drain`.
788824
pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize {
789825
return writeSplat(w, &.{bytes}, n);
790826
}

0 commit comments

Comments
 (0)