mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
fix splatBytesAll and writeSplatAll
This commit is contained in:
parent
c7bcdb4802
commit
d772c06272
@ -464,32 +464,52 @@ pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void {
|
|||||||
|
|
||||||
/// The `data` parameter is mutable because this function needs to mutate the
|
/// The `data` parameter is mutable because this function needs to mutate the
|
||||||
/// fields in order to handle partial writes from `VTable.writeSplat`.
|
/// fields in order to handle partial writes from `VTable.writeSplat`.
|
||||||
|
/// `data` will be restored to its original state before returning.
|
||||||
pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void {
|
pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void {
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
var truncate: usize = 0;
|
var truncate: usize = 0;
|
||||||
var remaining_splat = splat;
|
|
||||||
while (index + 1 < data.len) {
|
while (index + 1 < data.len) {
|
||||||
{
|
{
|
||||||
const untruncated = data[index];
|
const untruncated = data[index];
|
||||||
data[index] = untruncated[truncate..];
|
data[index] = untruncated[truncate..];
|
||||||
defer data[index] = untruncated;
|
defer data[index] = untruncated;
|
||||||
truncate += try w.writeSplat(data[index..], remaining_splat);
|
truncate += try w.writeSplat(data[index..], splat);
|
||||||
}
|
}
|
||||||
while (truncate >= data[index].len) {
|
while (truncate >= data[index].len and index + 1 < data.len) {
|
||||||
if (index + 1 < data.len) {
|
|
||||||
truncate -= data[index].len;
|
truncate -= data[index].len;
|
||||||
index += 1;
|
index += 1;
|
||||||
} else {
|
|
||||||
const last = data[data.len - 1];
|
|
||||||
remaining_splat -= @divExact(truncate, last.len);
|
|
||||||
while (remaining_splat > 0) {
|
|
||||||
const n = try w.writeSplat(data[data.len - 1 ..][0..1], remaining_splat);
|
|
||||||
remaining_splat -= @divExact(n, last.len);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deal with any left over splats
|
||||||
|
if (data.len != 0 and truncate < data[index].len * splat) {
|
||||||
|
std.debug.assert(index == data.len - 1);
|
||||||
|
var remaining_splat = splat;
|
||||||
|
while (true) {
|
||||||
|
remaining_splat -= truncate / data[index].len;
|
||||||
|
truncate %= data[index].len;
|
||||||
|
if (remaining_splat == 0) break;
|
||||||
|
truncate += try w.writeSplat(&.{ data[index][truncate..], data[index] }, remaining_splat - 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test writeSplatAll {
|
||||||
|
var aw: Writer.Allocating = .init(testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
|
||||||
|
var buffers = [_][]const u8{ "ba", "na" };
|
||||||
|
try aw.writer.writeSplatAll(&buffers, 2);
|
||||||
|
try testing.expectEqualStrings("banana", aw.writer.buffered());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "writeSplatAll works with a single buffer" {
|
||||||
|
var aw: Writer.Allocating = .init(testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
|
||||||
|
var message: [1][]const u8 = .{"hello"};
|
||||||
|
try aw.writer.writeSplatAll(&message, 3);
|
||||||
|
try testing.expectEqualStrings("hellohellohello", aw.writer.buffered());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(w: *Writer, bytes: []const u8) Error!usize {
|
pub fn write(w: *Writer, bytes: []const u8) Error!usize {
|
||||||
@ -763,6 +783,14 @@ pub fn splatByteAll(w: *Writer, byte: u8, n: usize) Error!void {
|
|||||||
while (remaining > 0) remaining -= try w.splatByte(byte, remaining);
|
while (remaining > 0) remaining -= try w.splatByte(byte, remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test splatByteAll {
|
||||||
|
var aw: Writer.Allocating = .init(testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
|
||||||
|
try aw.writer.splatByteAll('7', 45);
|
||||||
|
try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes the same byte many times, allowing short writes.
|
/// Writes the same byte many times, allowing short writes.
|
||||||
///
|
///
|
||||||
/// Does maximum of one underlying `VTable.drain`.
|
/// Does maximum of one underlying `VTable.drain`.
|
||||||
@ -778,13 +806,21 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {
|
|||||||
while (remaining_bytes > 0) {
|
while (remaining_bytes > 0) {
|
||||||
const leftover = remaining_bytes % bytes.len;
|
const leftover = remaining_bytes % bytes.len;
|
||||||
const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };
|
const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };
|
||||||
remaining_bytes -= try w.splatBytes(&buffers, splat);
|
remaining_bytes -= try w.writeSplat(&buffers, splat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test splatBytesAll {
|
||||||
|
var aw: Writer.Allocating = .init(testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
|
||||||
|
try aw.writer.splatBytesAll("hello", 3);
|
||||||
|
try testing.expectEqualStrings("hellohellohello", aw.writer.buffered());
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes the same slice many times, allowing short writes.
|
/// Writes the same slice many times, allowing short writes.
|
||||||
///
|
///
|
||||||
/// Does maximum of one underlying `VTable.writeSplat`.
|
/// Does maximum of one underlying `VTable.drain`.
|
||||||
pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize {
|
pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize {
|
||||||
return writeSplat(w, &.{bytes}, n);
|
return writeSplat(w, &.{bytes}, n);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user