mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
eliminate all uses of std.io.Writer.count except for CBE
This commit is contained in:
parent
d345a10054
commit
bc2cf0c173
8 changed files with 81 additions and 94 deletions
|
|
@ -1603,10 +1603,10 @@ test "manage resources correctly" {
|
|||
// self-hosted debug info is still too buggy
|
||||
if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
|
||||
|
||||
var writer: std.io.Writer = .discarding(&.{});
|
||||
var discarding: std.io.Writer.Discarding = .init(&.{});
|
||||
var di = try SelfInfo.open(testing.allocator);
|
||||
defer di.deinit();
|
||||
try printSourceAtAddress(&di, &writer, showMyTrace(), io.tty.detectConfig(.stderr()));
|
||||
try printSourceAtAddress(&di, &discarding.writer, showMyTrace(), io.tty.detectConfig(.stderr()));
|
||||
}
|
||||
|
||||
noinline fn showMyTrace() usize {
|
||||
|
|
|
|||
|
|
@ -772,11 +772,11 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr
|
|||
/// Count the characters needed for format.
|
||||
pub fn count(comptime fmt: []const u8, args: anytype) usize {
|
||||
var trash_buffer: [64]u8 = undefined;
|
||||
var w: Writer = .discarding(&trash_buffer);
|
||||
w.print(fmt, args) catch |err| switch (err) {
|
||||
var dw: Writer.Discarding = .init(&trash_buffer);
|
||||
dw.writer.print(fmt, args) catch |err| switch (err) {
|
||||
error.WriteFailed => unreachable,
|
||||
};
|
||||
return w.count;
|
||||
return @intCast(dw.count + dw.writer.end);
|
||||
}
|
||||
|
||||
pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 {
|
||||
|
|
|
|||
|
|
@ -1293,13 +1293,14 @@ pub const basic_authorization = struct {
|
|||
const user: Uri.Component = uri.user orelse .empty;
|
||||
const password: Uri.Component = uri.password orelse .empty;
|
||||
|
||||
var w: std.io.Writer = .discarding(&.{});
|
||||
user.formatUser(&w) catch unreachable; // discarding
|
||||
const user_len = w.count;
|
||||
var dw: std.io.Writer.Discarding = .init(&.{});
|
||||
user.formatUser(&dw.writer) catch unreachable; // discarding
|
||||
const user_len = dw.count + dw.writer.end;
|
||||
|
||||
w.count = 0;
|
||||
password.formatPassword(&w) catch unreachable; // discarding
|
||||
const password_len = w.count;
|
||||
dw.count = 0;
|
||||
dw.writer.end = 0;
|
||||
password.formatPassword(&dw.writer) catch unreachable; // discarding
|
||||
const password_len = dw.count + dw.writer.end;
|
||||
|
||||
return valueLength(@intCast(user_len), @intCast(password_len));
|
||||
}
|
||||
|
|
@ -1311,7 +1312,6 @@ pub const basic_authorization = struct {
|
|||
var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
|
||||
var w: std.io.Writer = .fixed(&buf);
|
||||
user.formatUser(&w) catch unreachable; // fixed
|
||||
assert(w.count <= max_user_len);
|
||||
password.formatPassword(&w) catch unreachable; // fixed
|
||||
|
||||
@memcpy(out[0..prefix.len], prefix);
|
||||
|
|
|
|||
|
|
@ -132,10 +132,8 @@ pub fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
|
|||
r.seek += n;
|
||||
return n;
|
||||
}
|
||||
const before = w.count;
|
||||
const n = try r.vtable.stream(r, w, limit);
|
||||
assert(n <= @intFromEnum(limit));
|
||||
assert(w.count == before + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
@ -158,17 +156,17 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize {
|
|||
pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
|
||||
assert(r.seek == 0);
|
||||
assert(r.end == 0);
|
||||
var w: Writer = .discarding(r.buffer);
|
||||
const n = r.stream(&w, limit) catch |err| switch (err) {
|
||||
var dw: Writer.Discarding = .init(r.buffer);
|
||||
const n = r.stream(&dw.writer, limit) catch |err| switch (err) {
|
||||
error.WriteFailed => unreachable,
|
||||
error.ReadFailed => return error.ReadFailed,
|
||||
error.EndOfStream => return error.EndOfStream,
|
||||
};
|
||||
if (n > @intFromEnum(limit)) {
|
||||
const over_amt = n - @intFromEnum(limit);
|
||||
r.seek = w.end - over_amt;
|
||||
r.end = w.end;
|
||||
assert(r.end <= w.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
|
||||
r.seek = dw.writer.end - over_amt;
|
||||
r.end = dw.writer.end;
|
||||
assert(r.end <= dw.writer.buffer.len); // limit may be exceeded only by an amount within buffer capacity.
|
||||
return @intFromEnum(limit);
|
||||
}
|
||||
return n;
|
||||
|
|
|
|||
|
|
@ -14,12 +14,6 @@ vtable: *const VTable,
|
|||
buffer: []u8,
|
||||
/// In `buffer` before this are buffered bytes, after this is `undefined`.
|
||||
end: usize = 0,
|
||||
/// Tracks total number of bytes written to this `Writer`. This value
|
||||
/// only increases. In the case of fixed mode, this value always equals `end`.
|
||||
///
|
||||
/// This value is maintained by the interface; `VTable` function
|
||||
/// implementations need not modify it.
|
||||
count: usize = 0,
|
||||
|
||||
pub const VTable = struct {
|
||||
/// Sends bytes to the logical sink. A write will only be sent here if it
|
||||
|
|
@ -117,8 +111,7 @@ pub const FileError = error{
|
|||
Unimplemented,
|
||||
};
|
||||
|
||||
/// Writes to `buffer` and returns `error.WriteFailed` when it is full. Unless
|
||||
/// modified externally, `count` will always equal `end`.
|
||||
/// Writes to `buffer` and returns `error.WriteFailed` when it is full.
|
||||
pub fn fixed(buffer: []u8) Writer {
|
||||
return .{
|
||||
.vtable = &.{ .drain = fixedDrain },
|
||||
|
|
@ -137,16 +130,6 @@ pub const failing: Writer = .{
|
|||
},
|
||||
};
|
||||
|
||||
pub fn discarding(buffer: []u8) Writer {
|
||||
return .{
|
||||
.vtable = &.{
|
||||
.drain = discardingDrain,
|
||||
.sendFile = discardingSendFile,
|
||||
},
|
||||
.buffer = buffer,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the contents not yet drained.
|
||||
pub fn buffered(w: *const Writer) []u8 {
|
||||
return w.buffer[0..w.end];
|
||||
|
|
@ -178,12 +161,7 @@ pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
|
|||
assert(data.len > 0);
|
||||
const buffer = w.buffer;
|
||||
const count = countSplat(data, splat);
|
||||
if (w.end + count > buffer.len) {
|
||||
const n = try w.vtable.drain(w, data, splat);
|
||||
w.count += n;
|
||||
return n;
|
||||
}
|
||||
w.count += count;
|
||||
if (w.end + count > buffer.len) return w.vtable.drain(w, data, splat);
|
||||
for (data) |bytes| {
|
||||
@memcpy(buffer[w.end..][0..bytes.len], bytes);
|
||||
w.end += bytes.len;
|
||||
|
|
@ -236,7 +214,6 @@ pub fn writeSplatHeader(
|
|||
if (new_end <= w.buffer.len) {
|
||||
@memcpy(w.buffer[w.end..][0..header.len], header);
|
||||
w.end = new_end;
|
||||
w.count += header.len;
|
||||
return header.len + try writeSplat(w, data, splat);
|
||||
}
|
||||
var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size.
|
||||
|
|
@ -249,9 +226,7 @@ pub fn writeSplatHeader(
|
|||
if (vecs.len - i == 0) break;
|
||||
}
|
||||
const new_splat = if (vecs[i - 1].ptr == data[data.len - 1].ptr) splat else 1;
|
||||
const n = try w.vtable.drain(w, vecs[0..i], new_splat);
|
||||
w.count += n;
|
||||
return n;
|
||||
return w.vtable.drain(w, vecs[0..i], new_splat);
|
||||
}
|
||||
|
||||
/// Equivalent to `writeSplatHeader` but writes at most `limit` bytes.
|
||||
|
|
@ -429,7 +404,6 @@ pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
|
|||
|
||||
pub fn undo(w: *Writer, n: usize) void {
|
||||
w.end -= n;
|
||||
w.count -= n;
|
||||
}
|
||||
|
||||
/// After calling `writableSliceGreedy`, this function tracks how many bytes
|
||||
|
|
@ -440,13 +414,11 @@ pub fn advance(w: *Writer, n: usize) void {
|
|||
const new_end = w.end + n;
|
||||
assert(new_end <= w.buffer.len);
|
||||
w.end = new_end;
|
||||
w.count += n;
|
||||
}
|
||||
|
||||
/// After calling `writableVector`, this function tracks how many bytes were
|
||||
/// written to it.
|
||||
pub fn advanceVector(w: *Writer, n: usize) usize {
|
||||
w.count += n;
|
||||
return consume(w, n);
|
||||
}
|
||||
|
||||
|
|
@ -504,12 +476,9 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {
|
|||
@branchHint(.likely);
|
||||
@memcpy(w.buffer[w.end..][0..bytes.len], bytes);
|
||||
w.end += bytes.len;
|
||||
w.count += bytes.len;
|
||||
return bytes.len;
|
||||
}
|
||||
const n = try w.vtable.drain(w, &.{bytes}, 1);
|
||||
w.count += n;
|
||||
return n;
|
||||
return w.vtable.drain(w, &.{bytes}, 1);
|
||||
}
|
||||
|
||||
/// Asserts `buffer` capacity exceeds `preserve_length`.
|
||||
|
|
@ -519,7 +488,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro
|
|||
@branchHint(.likely);
|
||||
@memcpy(w.buffer[w.end..][0..bytes.len], bytes);
|
||||
w.end += bytes.len;
|
||||
w.count += bytes.len;
|
||||
return bytes.len;
|
||||
}
|
||||
const temp_end = w.end -| preserve_length;
|
||||
|
|
@ -527,7 +495,6 @@ pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Erro
|
|||
w.end = temp_end;
|
||||
defer w.end += preserved.len;
|
||||
const n = try w.vtable.drain(w, &.{bytes}, 1);
|
||||
w.count += n;
|
||||
assert(w.end <= temp_end + preserved.len);
|
||||
@memmove(w.buffer[w.end..][0..preserved.len], preserved);
|
||||
return n;
|
||||
|
|
@ -560,15 +527,11 @@ pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void
|
|||
pub fn writeByte(w: *Writer, byte: u8) Error!void {
|
||||
while (w.buffer.len - w.end == 0) {
|
||||
const n = try w.vtable.drain(w, &.{&.{byte}}, 1);
|
||||
if (n > 0) {
|
||||
w.count += 1;
|
||||
return;
|
||||
}
|
||||
if (n > 0) return;
|
||||
} else {
|
||||
@branchHint(.likely);
|
||||
w.buffer[w.end] = byte;
|
||||
w.end += 1;
|
||||
w.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -581,7 +544,6 @@ pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!voi
|
|||
@branchHint(.likely);
|
||||
w.buffer[w.end] = byte;
|
||||
w.end += 1;
|
||||
w.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -690,12 +652,10 @@ pub fn sendFileHeader(
|
|||
if (new_end <= w.buffer.len) {
|
||||
@memcpy(w.buffer[w.end..][0..header.len], header);
|
||||
w.end = new_end;
|
||||
w.count += header.len;
|
||||
return header.len + try w.vtable.sendFile(w, file_reader, limit);
|
||||
}
|
||||
const buffered_contents = limit.slice(file_reader.interface.buffered());
|
||||
const n = try w.vtable.drain(w, &.{ header, buffered_contents }, 1);
|
||||
w.count += n;
|
||||
file_reader.interface.toss(n - header.len);
|
||||
return n;
|
||||
}
|
||||
|
|
@ -1950,29 +1910,52 @@ pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) File
|
|||
return error.WriteFailed;
|
||||
}
|
||||
|
||||
pub fn discardingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
|
||||
pub const Discarding = struct {
|
||||
count: u64,
|
||||
writer: Writer,
|
||||
|
||||
pub fn init(buffer: []u8) Discarding {
|
||||
return .{
|
||||
.count = 0,
|
||||
.writer = .{
|
||||
.vtable = &.{
|
||||
.drain = Discarding.drain,
|
||||
.sendFile = Discarding.sendFile,
|
||||
},
|
||||
.buffer = buffer,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
|
||||
const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
|
||||
const slice = data[0 .. data.len - 1];
|
||||
const pattern = data[slice.len..];
|
||||
var written: usize = pattern.len * splat;
|
||||
for (slice) |bytes| written += bytes.len;
|
||||
d.count += w.end + written;
|
||||
w.end = 0;
|
||||
return written;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn discardingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
|
||||
pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
|
||||
if (File.Handle == void) return error.Unimplemented;
|
||||
const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
|
||||
d.count += w.end;
|
||||
w.end = 0;
|
||||
if (file_reader.getSize()) |size| {
|
||||
const n = limit.minInt64(size - file_reader.pos);
|
||||
file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;
|
||||
w.end = 0;
|
||||
d.count += n;
|
||||
return n;
|
||||
} else |_| {
|
||||
// Error is observable on `file_reader` instance, and it is better to
|
||||
// treat the file as a pipe.
|
||||
return error.Unimplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Removes the first `n` bytes from `buffer` by shifting buffer contents,
|
||||
/// returning how many bytes are left after consuming the entire buffer, or
|
||||
|
|
@ -2219,9 +2202,7 @@ pub const Allocating = struct {
|
|||
}
|
||||
|
||||
pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void {
|
||||
const shrink_by = a.writer.end - new_len;
|
||||
a.writer.end = new_len;
|
||||
a.writer.count -= shrink_by;
|
||||
}
|
||||
|
||||
pub fn clearRetainingCapacity(a: *Allocating) void {
|
||||
|
|
|
|||
|
|
@ -195,22 +195,30 @@ fn renderErrorMessageToWriter(
|
|||
) (Writer.Error || std.posix.UnexpectedError)!void {
|
||||
const ttyconf = options.ttyconf;
|
||||
const err_msg = eb.getErrorMessage(err_msg_index);
|
||||
const prefix_start = w.count;
|
||||
if (err_msg.src_loc != .none) {
|
||||
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
|
||||
var prefix: std.io.Writer.Discarding = .init(&.{});
|
||||
try w.splatByteAll(' ', indent);
|
||||
prefix.count += indent;
|
||||
try ttyconf.setColor(w, .bold);
|
||||
try w.print("{s}:{d}:{d}: ", .{
|
||||
eb.nullTerminatedString(src.data.src_path),
|
||||
src.data.line + 1,
|
||||
src.data.column + 1,
|
||||
});
|
||||
try prefix.writer.print("{s}:{d}:{d}: ", .{
|
||||
eb.nullTerminatedString(src.data.src_path),
|
||||
src.data.line + 1,
|
||||
src.data.column + 1,
|
||||
});
|
||||
try ttyconf.setColor(w, color);
|
||||
try w.writeAll(kind);
|
||||
prefix.count += kind.len;
|
||||
try w.writeAll(": ");
|
||||
prefix.count += 2;
|
||||
// This is the length of the part before the error message:
|
||||
// e.g. "file.zig:4:5: error: "
|
||||
const prefix_len = w.count - prefix_start;
|
||||
const prefix_len: usize = @intCast(prefix.count);
|
||||
try ttyconf.setColor(w, .reset);
|
||||
try ttyconf.setColor(w, .bold);
|
||||
if (err_msg.count == 1) {
|
||||
|
|
|
|||
|
|
@ -1016,8 +1016,8 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
|
|||
// By using a buffer with maximum length of encoded instruction, we can use
|
||||
// the `end` field of the Writer for the count.
|
||||
var buf: [16]u8 = undefined;
|
||||
var trash = std.io.Writer.discarding(&buf);
|
||||
inst.encode(&trash, .{
|
||||
var trash: std.io.Writer.Discarding = .init(&buf);
|
||||
inst.encode(&trash.writer, .{
|
||||
.allow_frame_locs = true,
|
||||
.allow_symbols = true,
|
||||
}) catch {
|
||||
|
|
@ -1027,7 +1027,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
|
|||
// (`estimateInstructionLength`) has the wrong function signature.
|
||||
@panic("unexpected failure to encode");
|
||||
};
|
||||
return @intCast(trash.end);
|
||||
return trash.writer.end;
|
||||
}
|
||||
|
||||
const mnemonic_to_encodings_map = init: {
|
||||
|
|
|
|||
|
|
@ -1390,8 +1390,8 @@ const x86_64 = struct {
|
|||
// TODO: hack to force imm32s in the assembler
|
||||
.{ .imm = .s(-129) },
|
||||
}, t) catch return false;
|
||||
var trash = std.io.Writer.discarding(&.{});
|
||||
inst.encode(&trash, .{}) catch return false;
|
||||
var trash: std.io.Writer.Discarding = .init(&.{});
|
||||
inst.encode(&trash.writer, .{}) catch return false;
|
||||
return true;
|
||||
},
|
||||
else => return false,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue