Skip to content

Commit 04fe1bf

Browse files
committed
std.Io.Reader: use readVec for fill functions
readVec has two updated responsibilities: 1. it must respect any existing already buffered data. 2. it must write to the buffer if data is empty
1 parent e17a050 commit 04fe1bf

File tree

2 files changed

+120
-62
lines changed

2 files changed

+120
-62
lines changed

lib/std/Io/Reader.zig

Lines changed: 100 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,14 @@ pub const VTable = struct {
7070

7171
/// Returns number of bytes written to `data`.
7272
///
73-
/// `data` may not have nonzero length.
73+
/// `data` must have nonzero length. `data[0]` may have zero length, in
74+
/// which case the implementation must write to `Reader.buffer`.
7475
///
7576
/// `data` may not contain an alias to `Reader.buffer`.
7677
///
77-
/// `data` is mutable because the implementation may to temporarily modify
78-
/// the fields in order to handle partial reads. Implementations must
79-
/// restore the original value before returning.
78+
/// `data` is mutable because the implementation may temporarily modify the
79+
/// fields in order to handle partial reads. Implementations must restore
80+
/// the original value before returning.
8081
///
8182
/// Implementations may ignore `data`, writing directly to `Reader.buffer`,
8283
/// modifying `seek` and `end` accordingly, and returning 0 from this
@@ -421,23 +422,29 @@ pub fn readVec(r: *Reader, data: [][]u8) Error!usize {
421422

422423
/// Writes to `Reader.buffer` or `data`, whichever has larger capacity.
423424
pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize {
424-
assert(r.seek == r.end);
425-
r.seek = 0;
426-
r.end = 0;
427425
const first = data[0];
428-
const direct = first.len >= r.buffer.len;
426+
if (r.seek == r.end and first.len >= r.buffer.len) {
427+
var writer: Writer = .{
428+
.buffer = first,
429+
.end = 0,
430+
.vtable = &.{ .drain = Writer.fixedDrain },
431+
};
432+
const limit: Limit = .limited(writer.buffer.len - writer.end);
433+
return r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
434+
error.WriteFailed => unreachable,
435+
else => |e| return e,
436+
};
437+
}
429438
var writer: Writer = .{
430-
.buffer = if (direct) first else r.buffer,
431-
.end = 0,
439+
.buffer = r.buffer,
440+
.end = r.end,
432441
.vtable = &.{ .drain = Writer.fixedDrain },
433442
};
434443
const limit: Limit = .limited(writer.buffer.len - writer.end);
435-
const n = r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
444+
r.end += r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
436445
error.WriteFailed => unreachable,
437446
else => |e| return e,
438447
};
439-
if (direct) return n;
440-
r.end += n;
441448
return 0;
442449
}
443450

@@ -1059,17 +1066,8 @@ pub fn fill(r: *Reader, n: usize) Error!void {
10591066
/// increasing by a factor of 5 or more.
10601067
fn fillUnbuffered(r: *Reader, n: usize) Error!void {
10611068
try rebase(r, n);
1062-
var writer: Writer = .{
1063-
.buffer = r.buffer,
1064-
.vtable = &.{ .drain = Writer.fixedDrain },
1065-
};
1066-
while (r.end < r.seek + n) {
1067-
writer.end = r.end;
1068-
r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
1069-
error.WriteFailed => unreachable,
1070-
error.ReadFailed, error.EndOfStream => |e| return e,
1071-
};
1072-
}
1069+
var bufs: [1][]u8 = .{""};
1070+
while (r.end < r.seek + n) _ = try r.vtable.readVec(r, &bufs);
10731071
}
10741072

10751073
/// Without advancing the seek position, does exactly one underlying read, filling the buffer as
@@ -1079,15 +1077,8 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
10791077
/// Asserts buffer capacity is at least 1.
10801078
pub fn fillMore(r: *Reader) Error!void {
10811079
try rebase(r, 1);
1082-
var writer: Writer = .{
1083-
.buffer = r.buffer,
1084-
.end = r.end,
1085-
.vtable = &.{ .drain = Writer.fixedDrain },
1086-
};
1087-
r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
1088-
error.WriteFailed => unreachable,
1089-
else => |e| return e,
1090-
};
1080+
var bufs: [1][]u8 = .{""};
1081+
_ = try r.vtable.readVec(r, &bufs);
10911082
}
10921083

10931084
/// Returns the next byte from the stream or returns `error.EndOfStream`.
@@ -1796,18 +1787,26 @@ pub fn Hashed(comptime Hasher: type) type {
17961787

17971788
fn readVec(r: *Reader, data: [][]u8) Error!usize {
17981789
const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1799-
const n = try this.in.readVec(data);
1790+
var vecs: [8][]u8 = undefined; // Arbitrarily chosen amount.
1791+
const dest_n, const data_size = try r.writableVector(&vecs, data);
1792+
const dest = vecs[0..dest_n];
1793+
const n = try this.in.readVec(dest);
18001794
var remaining: usize = n;
1801-
for (data) |slice| {
1795+
for (dest) |slice| {
18021796
if (remaining < slice.len) {
18031797
this.hasher.update(slice[0..remaining]);
1804-
return n;
1798+
remaining = 0;
1799+
break;
18051800
} else {
18061801
remaining -= slice.len;
18071802
this.hasher.update(slice);
18081803
}
18091804
}
18101805
assert(remaining == 0);
1806+
if (n > data_size) {
1807+
r.end += n - data_size;
1808+
return data_size;
1809+
}
18111810
return n;
18121811
}
18131812

@@ -1824,17 +1823,24 @@ pub fn Hashed(comptime Hasher: type) type {
18241823
pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const []u8) Error!struct { usize, usize } {
18251824
var i: usize = 0;
18261825
var n: usize = 0;
1827-
for (data) |buf| {
1828-
if (buffer.len - i == 0) return .{ i, n };
1826+
if (r.seek == r.end) {
1827+
for (data) |buf| {
1828+
if (buffer.len - i == 0) return .{ i, n };
1829+
if (buf.len != 0) {
1830+
buffer[i] = .{ .base = buf.ptr, .len = buf.len };
1831+
i += 1;
1832+
n += buf.len;
1833+
}
1834+
}
1835+
const buf = r.buffer;
18291836
if (buf.len != 0) {
1837+
r.seek = 0;
1838+
r.end = 0;
18301839
buffer[i] = .{ .base = buf.ptr, .len = buf.len };
18311840
i += 1;
1832-
n += buf.len;
18331841
}
1834-
}
1835-
assert(r.seek == r.end);
1836-
const buf = r.buffer;
1837-
if (buf.len != 0) {
1842+
} else {
1843+
const buf = r.buffer[r.end..];
18381844
buffer[i] = .{ .base = buf.ptr, .len = buf.len };
18391845
i += 1;
18401846
}
@@ -1848,28 +1854,62 @@ pub fn writableVectorWsa(
18481854
) Error!struct { usize, usize } {
18491855
var i: usize = 0;
18501856
var n: usize = 0;
1851-
for (data) |buf| {
1852-
if (buffer.len - i == 0) return .{ i, n };
1853-
if (buf.len == 0) continue;
1854-
if (std.math.cast(u32, buf.len)) |len| {
1855-
buffer[i] = .{ .buf = buf.ptr, .len = len };
1857+
if (r.seek == r.end) {
1858+
for (data) |buf| {
1859+
if (buffer.len - i == 0) return .{ i, n };
1860+
if (buf.len == 0) continue;
1861+
if (std.math.cast(u32, buf.len)) |len| {
1862+
buffer[i] = .{ .buf = buf.ptr, .len = len };
1863+
i += 1;
1864+
n += len;
1865+
continue;
1866+
}
1867+
buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
1868+
i += 1;
1869+
n += std.math.maxInt(u32);
1870+
return .{ i, n };
1871+
}
1872+
const buf = r.buffer;
1873+
if (buf.len != 0) {
1874+
r.seek = 0;
1875+
r.end = 0;
1876+
if (std.math.cast(u32, buf.len)) |len| {
1877+
buffer[i] = .{ .buf = buf.ptr, .len = len };
1878+
} else {
1879+
buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
1880+
}
18561881
i += 1;
1857-
n += len;
1858-
continue;
18591882
}
1860-
buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
1883+
} else {
1884+
buffer[i] = .{
1885+
.buf = r.buffer.ptr + r.end,
1886+
.len = @min(std.math.maxInt(u32), r.buffer.len - r.end),
1887+
};
18611888
i += 1;
1862-
n += std.math.maxInt(u32);
1863-
return .{ i, n };
18641889
}
1865-
assert(r.seek == r.end);
1866-
const buf = r.buffer;
1867-
if (buf.len != 0) {
1868-
if (std.math.cast(u32, buf.len)) |len| {
1869-
buffer[i] = .{ .buf = buf.ptr, .len = len };
1870-
} else {
1871-
buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
1890+
return .{ i, n };
1891+
}
1892+
1893+
pub fn writableVector(r: *Reader, buffer: [][]u8, data: []const []u8) Error!struct { usize, usize } {
1894+
var i: usize = 0;
1895+
var n: usize = 0;
1896+
if (r.seek == r.end) {
1897+
for (data) |buf| {
1898+
if (buffer.len - i == 0) return .{ i, n };
1899+
if (buf.len != 0) {
1900+
buffer[i] = buf;
1901+
i += 1;
1902+
n += buf.len;
1903+
}
1904+
}
1905+
if (r.buffer.len != 0) {
1906+
r.seek = 0;
1907+
r.end = 0;
1908+
buffer[i] = r.buffer;
1909+
i += 1;
18721910
}
1911+
} else {
1912+
buffer[i] = r.buffer[r.end..];
18731913
i += 1;
18741914
}
18751915
return .{ i, n };

lib/std/fs/File.zig

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,7 +1312,16 @@ pub const Reader = struct {
13121312
if (is_windows) {
13131313
// Unfortunately, `ReadFileScatter` cannot be used since it
13141314
// requires page alignment.
1315-
return readPositional(r, data[0]);
1315+
assert(io_reader.seek == io_reader.end);
1316+
io_reader.seek = 0;
1317+
io_reader.end = 0;
1318+
const first = data[0];
1319+
if (first.len >= io_reader.buffer.len) {
1320+
return readPositional(r, first);
1321+
} else {
1322+
io_reader.end += try readPositional(r, io_reader.buffer);
1323+
return 0;
1324+
}
13161325
}
13171326
var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
13181327
const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);
@@ -1352,7 +1361,16 @@ pub const Reader = struct {
13521361
if (is_windows) {
13531362
// Unfortunately, `ReadFileScatter` cannot be used since it
13541363
// requires page alignment.
1355-
return readStreaming(r, data[0]);
1364+
assert(io_reader.seek == io_reader.end);
1365+
io_reader.seek = 0;
1366+
io_reader.end = 0;
1367+
const first = data[0];
1368+
if (first.len >= io_reader.buffer.len) {
1369+
return readStreaming(r, first);
1370+
} else {
1371+
io_reader.end += try readStreaming(r, io_reader.buffer);
1372+
return 0;
1373+
}
13561374
}
13571375
var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
13581376
const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);

0 commit comments

Comments
 (0)