std: update uses of unbuffered_writer

This commit is contained in:
Andrew Kelley 2025-06-03 22:42:53 -07:00
parent 9d163c7ac3
commit b393112674
6 changed files with 39 additions and 90 deletions

View File

@ -608,12 +608,10 @@ pub fn unlockStdErr() void {
}
/// Protected by `stderr_mutex`.
var stderr_buffered_writer: Writer = .{
.unbuffered_writer = stderr_file_writer.interface(),
.buffer = &.{},
};
const stderr_writer: *Writer = &stderr_file_writer.interface;
/// Protected by `stderr_mutex`.
var stderr_file_writer: std.fs.File.Writer = .{
.interface = std.fs.File.Writer.init_interface(&.{}),
.file = if (is_windows) undefined else .stderr(),
.mode = .streaming,
};
@ -628,14 +626,14 @@ pub fn lockStderrWriter(buffer: []u8) *Writer {
stderr_mutex.lock();
clearWrittenWithEscapeCodes() catch {};
if (is_windows) stderr_file_writer.file = .stderr();
stderr_buffered_writer.flush() catch {};
stderr_buffered_writer.buffer = buffer;
return &stderr_buffered_writer;
stderr_writer.flush() catch {};
stderr_writer.buffer = buffer;
return &stderr_writer;
}
pub fn unlockStderrWriter() void {
stderr_buffered_writer.flush() catch {};
stderr_buffered_writer.buffer = &.{};
stderr_writer.flush() catch {};
stderr_writer.buffer = &.{};
stderr_mutex.unlock();
}

View File

@ -197,12 +197,9 @@ pub fn serialize(params: anytype, str: []u8) Error![]const u8 {
/// Compute the number of bytes required to serialize `params`
pub fn calcSize(params: anytype) usize {
var trash: [128]u8 = undefined;
var bw: Writer = .{
.unbuffered_writer = .discarding,
.buffer = &trash,
};
serializeTo(params, &bw) catch unreachable;
return bw.count;
var w: Writer = .discarding(&trash);
serializeTo(params, &w) catch unreachable;
return w.count;
}
fn serializeTo(params: anytype, out: *Writer) !void {

View File

@ -383,22 +383,19 @@ fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {
for (&d.s, v) |*dv, vv| dv.* +%= vv;
}
pub fn writable(this: *@This(), buffer: []u8) Writer {
pub fn writer(this: *@This(), buffer: []u8) Writer {
return .{
.unbuffered_writer = .{
.context = this,
.vtable = &.{
.writeSplat = writeSplat,
.writeFile = Writer.unimplementedWriteFile,
},
},
.context = this,
.vtable = &.{ .drain = drain },
.buffer = buffer,
};
}
fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Writer.Error!usize {
const this: *@This() = @ptrCast(@alignCast(context));
fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {
const this: *@This() = @ptrCast(@alignCast(w.context));
const start_total = this.total_len;
this.update(w.buffered());
w.end = 0;
for (data[0 .. data.len - 1]) |slice| this.update(slice);
for (0..splat) |_| this.update(data[data.len - 1]);
return @intCast(this.total_len - start_total);

View File

@ -845,14 +845,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 bw: Writer = .{
.unbuffered_writer = .discarding,
.buffer = &trash_buffer,
};
bw.print(fmt, args) catch |err| switch (err) {
var w: Writer = .discarding(&trash_buffer);
w.print(fmt, args) catch |err| switch (err) {
error.WriteFailed => unreachable,
};
return bw.count;
return w.count;
}
pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 {

View File

@ -155,11 +155,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(0, data, splat);
if (w.end + count > buffer.len) {
const end = w.end;
const n = try w.vtable.drain(w, data, splat);
return n -| end;
}
if (w.end + count > buffer.len) return w.vtable.drain(w, data, splat);
w.count += count;
for (data) |bytes| {
@memcpy(buffer[w.end..][0..bytes.len], bytes);
@ -168,7 +164,6 @@ pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
const pattern = data[data.len - 1];
if (splat == 0) {
@branchHint(.unlikely);
// It was added in the loop above; undo it here.
w.end -= pattern.len;
return count;
}
@ -245,24 +240,14 @@ pub fn writableSlice(w: *Writer, len: usize) Error![]u8 {
/// If `minimum_length` is zero, this is equivalent to `unusedCapacitySlice`.
pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {
assert(w.buffer.len >= minimum_length);
const cap_slice = w.buffer[w.end..];
if (cap_slice.len >= minimum_length) {
@branchHint(.likely);
return cap_slice;
while (true) {
const cap_slice = w.buffer[w.end..];
if (cap_slice.len >= minimum_length) {
@branchHint(.likely);
return cap_slice;
}
assert(0 == try w.vtable.drain(w, &.{""}, 1));
}
const buffer = w.buffer[0..w.end];
const n = try w.unbuffered_writer.writeVec(&.{buffer});
if (n == buffer.len) {
@branchHint(.likely);
w.end = 0;
return w.buffer;
}
if (n > 0) {
const remainder = buffer[n..];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
w.end = remainder.len;
}
return w.buffer[w.end..];
}
pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
@ -358,39 +343,17 @@ pub fn print(w: *Writer, comptime format: []const u8, args: anytype) Error!void
}
pub fn writeByte(w: *Writer, byte: u8) Error!void {
const buffer = w.buffer[0..w.end];
if (buffer.len < w.buffer.len) {
while (w.buffer.len - w.end == 0) {
const n = try w.vtable.drain(w, &.{&.{byte}}, 1);
if (n > 0) {
w.count += 1;
return;
}
} else {
@branchHint(.likely);
buffer.ptr[buffer.len] = byte;
w.end = buffer.len + 1;
w.buffer[w.end] = byte;
w.end += 1;
w.count += 1;
return;
}
var buffers: [2][]const u8 = .{ buffer, &.{byte} };
while (true) {
const n = try w.unbuffered_writer.writeVec(&buffers);
if (n == 0) {
@branchHint(.unlikely);
continue;
}
w.count += 1;
if (n >= buffer.len) {
@branchHint(.likely);
if (n > buffer.len) {
@branchHint(.likely);
w.end = 0;
return;
} else {
buffer[0] = byte;
w.end = 1;
return;
}
}
const remainder = buffer[n..];
std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
buffer[remainder.len] = byte;
w.end = remainder.len + 1;
return;
}
}

View File

@ -1040,11 +1040,8 @@ pub const Serializer = struct {
};
test Serializer {
var bw: Writer = .{
.unbuffered_writer = .discarding,
.buffer = &.{},
};
var s: Serializer = .{ .writer = &bw };
var w: Writer = .discarding(&.{});
var s: Serializer = .{ .writer = &w };
var vec2 = try s.beginStruct(.{});
try vec2.field("x", 1.5, .{});
try vec2.fieldPrefix("prefix");