| ... | @@ -464,34 +464,54 @@ pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void { | ... | @@ -464,34 +464,54 @@ pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void { |
| 464 | | 464 | |
| 465 | /// The `data` parameter is mutable because this function needs to mutate the | 465 | /// The `data` parameter is mutable because this function needs to mutate the |
| 466 | /// fields in order to handle partial writes from `VTable.writeSplat`. | 466 | /// fields in order to handle partial writes from `VTable.writeSplat`. |
| | 467 | /// `data` will be restored to its original state before returning. |
| 467 | pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void { | 468 | pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void { |
| 468 | var index: usize = 0; | 469 | var index: usize = 0; |
| 469 | var truncate: usize = 0; | 470 | var truncate: usize = 0; |
| 470 | var remaining_splat = splat; | | |
| 471 | while (index + 1 < data.len) { | 471 | while (index + 1 < data.len) { |
| 472 | { | 472 | { |
| 473 | const untruncated = data[index]; | 473 | const untruncated = data[index]; |
| 474 | data[index] = untruncated[truncate..]; | 474 | data[index] = untruncated[truncate..]; |
| 475 | defer data[index] = untruncated; | 475 | defer data[index] = untruncated; |
| 476 | truncate += try w.writeSplat(data[index..], remaining_splat); | 476 | truncate += try w.writeSplat(data[index..], splat); |
| 477 | } | 477 | } |
| 478 | while (truncate >= data[index].len) { | 478 | while (truncate >= data[index].len and index + 1 < data.len) { |
| 479 | if (index + 1 < data.len) { | 479 | truncate -= data[index].len; |
| 480 | truncate -= data[index].len; | 480 | index += 1; |
| 481 | index += 1; | 481 | } |
| 482 | } else { | 482 | } |
| 483 | const last = data[data.len - 1]; | 483 | |
| 484 | remaining_splat -= @divExact(truncate, last.len); | 484 | // Deal with any left over splats |
| 485 | while (remaining_splat > 0) { | 485 | if (data.len != 0 and truncate < data[index].len * splat) { |
| 486 | const n = try w.writeSplat(data[data.len - 1 ..][0..1], remaining_splat); | 486 | std.debug.assert(index == data.len - 1); |
| 487 | remaining_splat -= @divExact(n, last.len); | 487 | var remaining_splat = splat; |
| 488 | } | 488 | while (true) { |
| 489 | return; | 489 | remaining_splat -= truncate / data[index].len; |
| 490 | } | 490 | truncate %= data[index].len; |
| | 491 | if (remaining_splat == 0) break; |
| | 492 | truncate += try w.writeSplat(&.{ data[index][truncate..], data[index] }, remaining_splat - 1); |
| 491 | } | 493 | } |
| 492 | } | 494 | } |
| 493 | } | 495 | } |
| 494 | | 496 | |
| | 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 | |
| 495 | pub fn write(w: *Writer, bytes: []const u8) Error!usize { | 515 | pub fn write(w: *Writer, bytes: []const u8) Error!usize { |
| 496 | if (w.end + bytes.len <= w.buffer.len) { | 516 | if (w.end + bytes.len <= w.buffer.len) { |
| 497 | @branchHint(.likely); | 517 | @branchHint(.likely); |
| ... | @@ -763,6 +783,14 @@ pub fn splatByteAll(w: *Writer, byte: u8, n: usize) Error!void { | ... | @@ -763,6 +783,14 @@ pub fn splatByteAll(w: *Writer, byte: u8, n: usize) Error!void { |
| 763 | while (remaining > 0) remaining -= try w.splatByte(byte, remaining); | 783 | while (remaining > 0) remaining -= try w.splatByte(byte, remaining); |
| 764 | } | 784 | } |
| 765 | | 785 | |
| | 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 | |
| 766 | /// Writes the same byte many times, allowing short writes. | 794 | /// Writes the same byte many times, allowing short writes. |
| 767 | /// | 795 | /// |
| 768 | /// Does maximum of one underlying `VTable.drain`. | 796 | /// Does maximum of one underlying `VTable.drain`. |
| ... | @@ -778,13 +806,21 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void { | ... | @@ -778,13 +806,21 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void { |
| 778 | while (remaining_bytes > 0) { | 806 | while (remaining_bytes > 0) { |
| 779 | const leftover = remaining_bytes % bytes.len; | 807 | const leftover = remaining_bytes % bytes.len; |
| 780 | const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes }; | 808 | 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); |
| 782 | } | 810 | } |
| 783 | } | 811 | } |
| 784 | | 812 | |
| | 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 | |
| 785 | /// Writes the same slice many times, allowing short writes. | 821 | /// Writes the same slice many times, allowing short writes. |
| 786 | /// | 822 | /// |
| 787 | /// Does maximum of one underlying `VTable.writeSplat`. | 823 | /// Does maximum of one underlying `VTable.drain`. |
| 788 | pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize { | 824 | pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize { |
| 789 | return writeSplat(w, &.{bytes}, n); | 825 | return writeSplat(w, &.{bytes}, n); |
| 790 | } | 826 | } |