mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
migrate some std lib
This commit is contained in:
parent
c2fc6b0b6c
commit
5356f3a307
@ -2766,8 +2766,9 @@ fn dumpBadDirnameHelp(
|
||||
comptime msg: []const u8,
|
||||
args: anytype,
|
||||
) anyerror!void {
|
||||
var w = debug.lockStdErr2();
|
||||
var buffered_writer = debug.lockStdErr2();
|
||||
defer debug.unlockStdErr();
|
||||
const w = &buffered_writer;
|
||||
|
||||
const stderr = io.getStdErr();
|
||||
try w.print(msg, args);
|
||||
@ -2784,7 +2785,7 @@ fn dumpBadDirnameHelp(
|
||||
|
||||
if (asking_step) |as| {
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.writer().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
|
||||
as.dump(stderr);
|
||||
@ -2802,7 +2803,8 @@ pub fn dumpBadGetPathHelp(
|
||||
src_builder: *Build,
|
||||
asking_step: ?*Step,
|
||||
) anyerror!void {
|
||||
var w = stderr.unbufferedWriter();
|
||||
var buffered_writer = stderr.unbufferedWriter();
|
||||
const w = &buffered_writer;
|
||||
try w.print(
|
||||
\\getPath() was called on a GeneratedFile that wasn't built yet.
|
||||
\\ source package path: {s}
|
||||
@ -2821,7 +2823,7 @@ pub fn dumpBadGetPathHelp(
|
||||
s.dump(stderr);
|
||||
if (asking_step) |as| {
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.writer().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
|
||||
as.dump(stderr);
|
||||
|
||||
@ -1061,14 +1061,17 @@ pub const Manifest = struct {
|
||||
}
|
||||
|
||||
fn addDepFileMaybePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void {
|
||||
const dep_file_contents = try dir.readFileAlloc(self.cache.gpa, dep_file_basename, manifest_file_size_max);
|
||||
defer self.cache.gpa.free(dep_file_contents);
|
||||
const gpa = self.cache.gpa;
|
||||
const dep_file_contents = try dir.readFileAlloc(gpa, dep_file_basename, manifest_file_size_max);
|
||||
defer gpa.free(dep_file_contents);
|
||||
|
||||
var error_buf = std.ArrayList(u8).init(self.cache.gpa);
|
||||
defer error_buf.deinit();
|
||||
var error_buf: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer error_buf.deinit(gpa);
|
||||
|
||||
var resolve_buf: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer resolve_buf.deinit(gpa);
|
||||
|
||||
var it: DepTokenizer = .{ .bytes = dep_file_contents };
|
||||
|
||||
while (it.next()) |token| {
|
||||
switch (token) {
|
||||
// We don't care about targets, we only want the prereqs
|
||||
@ -1078,16 +1081,14 @@ pub const Manifest = struct {
|
||||
_ = try self.addFile(file_path, null);
|
||||
} else try self.addFilePost(file_path),
|
||||
.prereq_must_resolve => {
|
||||
var resolve_buf = std.ArrayList(u8).init(self.cache.gpa);
|
||||
defer resolve_buf.deinit();
|
||||
|
||||
try token.resolve(resolve_buf.writer());
|
||||
resolve_buf.clearRetainingCapacity();
|
||||
try token.resolve(gpa, &resolve_buf);
|
||||
if (self.manifest_file == null) {
|
||||
_ = try self.addFile(resolve_buf.items, null);
|
||||
} else try self.addFilePost(resolve_buf.items);
|
||||
},
|
||||
else => |err| {
|
||||
try err.printError(error_buf.writer());
|
||||
try err.printError(gpa, &error_buf);
|
||||
log.err("failed parsing {s}: {s}", .{ dep_file_basename, error_buf.items });
|
||||
return error.InvalidDepFile;
|
||||
},
|
||||
@ -1125,13 +1126,13 @@ pub const Manifest = struct {
|
||||
if (self.manifest_dirty) {
|
||||
self.manifest_dirty = false;
|
||||
|
||||
var contents = std.ArrayList(u8).init(self.cache.gpa);
|
||||
defer contents.deinit();
|
||||
const gpa = self.cache.gpa;
|
||||
var contents: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer contents.deinit(gpa);
|
||||
|
||||
const writer = contents.writer();
|
||||
try writer.writeAll(manifest_header ++ "\n");
|
||||
try contents.appendSlice(gpa, manifest_header ++ "\n");
|
||||
for (self.files.keys()) |file| {
|
||||
try writer.print("{d} {d} {d} {x} {d} {s}\n", .{
|
||||
try contents.print(gpa, "{d} {d} {d} {x} {d} {s}\n", .{
|
||||
file.stat.size,
|
||||
file.stat.inode,
|
||||
file.stat.mtime,
|
||||
|
||||
@ -7,6 +7,7 @@ state: State = .lhs,
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub fn next(self: *Tokenizer) ?Token {
|
||||
var start = self.index;
|
||||
@ -362,7 +363,7 @@ pub const Token = union(enum) {
|
||||
};
|
||||
|
||||
/// Resolve escapes in target or prereq. Only valid with .target_must_resolve or .prereq_must_resolve.
|
||||
pub fn resolve(self: Token, writer: anytype) @TypeOf(writer).Error!void {
|
||||
pub fn resolve(self: Token, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!void {
|
||||
switch (self) {
|
||||
.target_must_resolve => |bytes| {
|
||||
var state: enum { start, escape, dollar } = .start;
|
||||
@ -372,27 +373,27 @@ pub const Token = union(enum) {
|
||||
switch (c) {
|
||||
'\\' => state = .escape,
|
||||
'$' => state = .dollar,
|
||||
else => try writer.writeByte(c),
|
||||
else => try list.append(gpa, c),
|
||||
}
|
||||
},
|
||||
.escape => {
|
||||
switch (c) {
|
||||
' ', '#', '\\' => {},
|
||||
'$' => {
|
||||
try writer.writeByte('\\');
|
||||
try list.append(gpa, '\\');
|
||||
state = .dollar;
|
||||
continue;
|
||||
},
|
||||
else => try writer.writeByte('\\'),
|
||||
else => try list.append(gpa, '\\'),
|
||||
}
|
||||
try writer.writeByte(c);
|
||||
try list.append(gpa, c);
|
||||
state = .start;
|
||||
},
|
||||
.dollar => {
|
||||
try writer.writeByte('$');
|
||||
try list.append(gpa, '$');
|
||||
switch (c) {
|
||||
'$' => {},
|
||||
else => try writer.writeByte(c),
|
||||
else => try list.append(gpa, c),
|
||||
}
|
||||
state = .start;
|
||||
},
|
||||
@ -406,19 +407,19 @@ pub const Token = union(enum) {
|
||||
.start => {
|
||||
switch (c) {
|
||||
'\\' => state = .escape,
|
||||
else => try writer.writeByte(c),
|
||||
else => try list.append(gpa, c),
|
||||
}
|
||||
},
|
||||
.escape => {
|
||||
switch (c) {
|
||||
' ' => {},
|
||||
'\\' => {
|
||||
try writer.writeByte(c);
|
||||
try list.append(gpa, c);
|
||||
continue;
|
||||
},
|
||||
else => try writer.writeByte('\\'),
|
||||
else => try list.append(gpa, '\\'),
|
||||
}
|
||||
try writer.writeByte(c);
|
||||
try list.append(gpa, c);
|
||||
state = .start;
|
||||
},
|
||||
}
|
||||
@ -428,20 +429,20 @@ pub const Token = union(enum) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn printError(self: Token, writer: anytype) @TypeOf(writer).Error!void {
|
||||
pub fn printError(self: Token, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!void {
|
||||
switch (self) {
|
||||
.target, .target_must_resolve, .prereq, .prereq_must_resolve => unreachable, // not an error
|
||||
.incomplete_quoted_prerequisite,
|
||||
.incomplete_target,
|
||||
=> |index_and_bytes| {
|
||||
try writer.print("{s} '", .{self.errStr()});
|
||||
try list.print("{s} '", .{self.errStr()});
|
||||
if (self == .incomplete_target) {
|
||||
const tmp = Token{ .target_must_resolve = index_and_bytes.bytes };
|
||||
try tmp.resolve(writer);
|
||||
try tmp.resolve(gpa, list);
|
||||
} else {
|
||||
try printCharValues(writer, index_and_bytes.bytes);
|
||||
try printCharValues(gpa, list, index_and_bytes.bytes);
|
||||
}
|
||||
try writer.print("' at position {d}", .{index_and_bytes.index});
|
||||
try list.print(gpa, "' at position {d}", .{index_and_bytes.index});
|
||||
},
|
||||
.invalid_target,
|
||||
.bad_target_escape,
|
||||
@ -450,9 +451,9 @@ pub const Token = union(enum) {
|
||||
.incomplete_escape,
|
||||
.expected_colon,
|
||||
=> |index_and_char| {
|
||||
try writer.writeAll("illegal char ");
|
||||
try printUnderstandableChar(writer, index_and_char.char);
|
||||
try writer.print(" at position {d}: {s}", .{ index_and_char.index, self.errStr() });
|
||||
try list.appendSlice("illegal char ");
|
||||
try printUnderstandableChar(gpa, list, index_and_char.char);
|
||||
try list.print(gpa, " at position {d}: {s}", .{ index_and_char.index, self.errStr() });
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1026,41 +1027,41 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void {
|
||||
defer arena_allocator.deinit();
|
||||
|
||||
var it: Tokenizer = .{ .bytes = input };
|
||||
var buffer = std.ArrayList(u8).init(arena);
|
||||
var resolve_buf = std.ArrayList(u8).init(arena);
|
||||
var buffer: std.ArrayListUnmanaged(u8) = .empty;
|
||||
var resolve_buf: std.ArrayListUnmanaged(u8) = .empty;
|
||||
var i: usize = 0;
|
||||
while (it.next()) |token| {
|
||||
if (i != 0) try buffer.appendSlice("\n");
|
||||
if (i != 0) try buffer.appendSlice(arena, "\n");
|
||||
switch (token) {
|
||||
.target, .prereq => |bytes| {
|
||||
try buffer.appendSlice(@tagName(token));
|
||||
try buffer.appendSlice(" = {");
|
||||
try buffer.appendSlice(arena, @tagName(token));
|
||||
try buffer.appendSlice(arena, " = {");
|
||||
for (bytes) |b| {
|
||||
try buffer.append(printable_char_tab[b]);
|
||||
try buffer.append(arena, printable_char_tab[b]);
|
||||
}
|
||||
try buffer.appendSlice("}");
|
||||
try buffer.appendSlice(arena, "}");
|
||||
},
|
||||
.target_must_resolve => {
|
||||
try buffer.appendSlice("target = {");
|
||||
try token.resolve(resolve_buf.writer());
|
||||
try buffer.appendSlice(arena, "target = {");
|
||||
try token.resolve(arena, &resolve_buf);
|
||||
for (resolve_buf.items) |b| {
|
||||
try buffer.append(printable_char_tab[b]);
|
||||
try buffer.append(arena, printable_char_tab[b]);
|
||||
}
|
||||
resolve_buf.items.len = 0;
|
||||
try buffer.appendSlice("}");
|
||||
try buffer.appendSlice(arena, "}");
|
||||
},
|
||||
.prereq_must_resolve => {
|
||||
try buffer.appendSlice("prereq = {");
|
||||
try token.resolve(resolve_buf.writer());
|
||||
try buffer.appendSlice(arena, "prereq = {");
|
||||
try token.resolve(arena, &resolve_buf);
|
||||
for (resolve_buf.items) |b| {
|
||||
try buffer.append(printable_char_tab[b]);
|
||||
try buffer.append(arena, printable_char_tab[b]);
|
||||
}
|
||||
resolve_buf.items.len = 0;
|
||||
try buffer.appendSlice("}");
|
||||
try buffer.appendSlice(arena, "}");
|
||||
},
|
||||
else => {
|
||||
try buffer.appendSlice("ERROR: ");
|
||||
try token.printError(buffer.writer());
|
||||
try buffer.appendSlice(arena, "ERROR: ");
|
||||
try token.printError(arena, &buffer);
|
||||
break;
|
||||
},
|
||||
}
|
||||
@ -1072,121 +1073,7 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void {
|
||||
return;
|
||||
}
|
||||
|
||||
const out = std.io.getStdErr().writer();
|
||||
|
||||
try out.writeAll("\n");
|
||||
try printSection(out, "<<<< input", input);
|
||||
try printSection(out, "==== expect", expect);
|
||||
try printSection(out, ">>>> got", buffer.items);
|
||||
try printRuler(out);
|
||||
|
||||
try testing.expect(false);
|
||||
}
|
||||
|
||||
fn printSection(out: anytype, label: []const u8, bytes: []const u8) !void {
|
||||
try printLabel(out, label, bytes);
|
||||
try hexDump(out, bytes);
|
||||
try printRuler(out);
|
||||
try out.writeAll(bytes);
|
||||
try out.writeAll("\n");
|
||||
}
|
||||
|
||||
fn printLabel(out: anytype, label: []const u8, bytes: []const u8) !void {
|
||||
var buf: [80]u8 = undefined;
|
||||
const text = try std.fmt.bufPrint(buf[0..], "{s} {d} bytes ", .{ label, bytes.len });
|
||||
try out.writeAll(text);
|
||||
var i: usize = text.len;
|
||||
const end = 79;
|
||||
while (i < end) : (i += 1) {
|
||||
try out.writeAll(&[_]u8{label[0]});
|
||||
}
|
||||
try out.writeAll("\n");
|
||||
}
|
||||
|
||||
fn printRuler(out: anytype) !void {
|
||||
var i: usize = 0;
|
||||
const end = 79;
|
||||
while (i < end) : (i += 1) {
|
||||
try out.writeAll("-");
|
||||
}
|
||||
try out.writeAll("\n");
|
||||
}
|
||||
|
||||
fn hexDump(out: anytype, bytes: []const u8) !void {
|
||||
const n16 = bytes.len >> 4;
|
||||
var line: usize = 0;
|
||||
var offset: usize = 0;
|
||||
while (line < n16) : (line += 1) {
|
||||
try hexDump16(out, offset, bytes[offset..][0..16]);
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
const n = bytes.len & 0x0f;
|
||||
if (n > 0) {
|
||||
try printDecValue(out, offset, 8);
|
||||
try out.writeAll(":");
|
||||
try out.writeAll(" ");
|
||||
const end1 = @min(offset + n, offset + 8);
|
||||
for (bytes[offset..end1]) |b| {
|
||||
try out.writeAll(" ");
|
||||
try printHexValue(out, b, 2);
|
||||
}
|
||||
const end2 = offset + n;
|
||||
if (end2 > end1) {
|
||||
try out.writeAll(" ");
|
||||
for (bytes[end1..end2]) |b| {
|
||||
try out.writeAll(" ");
|
||||
try printHexValue(out, b, 2);
|
||||
}
|
||||
}
|
||||
const short = 16 - n;
|
||||
var i: usize = 0;
|
||||
while (i < short) : (i += 1) {
|
||||
try out.writeAll(" ");
|
||||
}
|
||||
if (end2 > end1) {
|
||||
try out.writeAll(" |");
|
||||
} else {
|
||||
try out.writeAll(" |");
|
||||
}
|
||||
try printCharValues(out, bytes[offset..end2]);
|
||||
try out.writeAll("|\n");
|
||||
offset += n;
|
||||
}
|
||||
|
||||
try printDecValue(out, offset, 8);
|
||||
try out.writeAll(":");
|
||||
try out.writeAll("\n");
|
||||
}
|
||||
|
||||
fn hexDump16(out: anytype, offset: usize, bytes: []const u8) !void {
|
||||
try printDecValue(out, offset, 8);
|
||||
try out.writeAll(":");
|
||||
try out.writeAll(" ");
|
||||
for (bytes[0..8]) |b| {
|
||||
try out.writeAll(" ");
|
||||
try printHexValue(out, b, 2);
|
||||
}
|
||||
try out.writeAll(" ");
|
||||
for (bytes[8..16]) |b| {
|
||||
try out.writeAll(" ");
|
||||
try printHexValue(out, b, 2);
|
||||
}
|
||||
try out.writeAll(" |");
|
||||
try printCharValues(out, bytes);
|
||||
try out.writeAll("|\n");
|
||||
}
|
||||
|
||||
fn printDecValue(out: anytype, value: u64, width: u8) !void {
|
||||
var buffer: [20]u8 = undefined;
|
||||
const len = std.fmt.formatIntBuf(buffer[0..], value, 10, .lower, .{ .width = width, .fill = '0' });
|
||||
try out.writeAll(buffer[0..len]);
|
||||
}
|
||||
|
||||
fn printHexValue(out: anytype, value: u64, width: u8) !void {
|
||||
var buffer: [16]u8 = undefined;
|
||||
const len = std.fmt.formatIntBuf(buffer[0..], value, 16, .lower, .{ .width = width, .fill = '0' });
|
||||
try out.writeAll(buffer[0..len]);
|
||||
try testing.expectEqualStrings(expect, buffer.items);
|
||||
}
|
||||
|
||||
fn printCharValues(out: anytype, bytes: []const u8) !void {
|
||||
|
||||
@ -976,37 +976,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig
|
||||
@memcpy(self.items[old_len..][0..items.len], items);
|
||||
}
|
||||
|
||||
pub const WriterContext = struct {
|
||||
self: *Self,
|
||||
allocator: Allocator,
|
||||
};
|
||||
|
||||
pub const Writer = if (T != u8)
|
||||
@compileError("The Writer interface is only defined for ArrayList(u8) " ++
|
||||
"but the given type is ArrayList(" ++ @typeName(T) ++ ")")
|
||||
else
|
||||
std.io.Writer(WriterContext, Allocator.Error, appendWrite);
|
||||
|
||||
/// Initializes a Writer which will append to the list.
|
||||
pub fn writer(self: *Self, gpa: Allocator) Writer {
|
||||
return .{ .context = .{ .self = self, .allocator = gpa } };
|
||||
}
|
||||
|
||||
/// Same as `append` except it returns the number of bytes written,
|
||||
/// which is always the same as `m.len`. The purpose of this function
|
||||
/// existing is to match `std.io.Writer` API.
|
||||
/// Invalidates element pointers if additional memory is needed.
|
||||
fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
|
||||
try context.self.appendSlice(context.allocator, m);
|
||||
return m.len;
|
||||
}
|
||||
|
||||
pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
|
||||
comptime assert(T == u8);
|
||||
try self.ensureUnusedCapacity(gpa, fmt.len);
|
||||
var alw: std.io.ArrayListWriter = undefined;
|
||||
const bw = alw.fromOwned(gpa, self);
|
||||
defer self.* = alw.toOwned();
|
||||
var aw: std.io.AllocatingWriter = undefined;
|
||||
const bw = aw.fromArrayList(gpa, self);
|
||||
defer self.* = aw.toArrayList();
|
||||
bw.print(fmt, args) catch return error.OutOfMemory;
|
||||
}
|
||||
|
||||
|
||||
@ -301,7 +301,7 @@ pub const AnyWriter = Writer;
|
||||
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
|
||||
|
||||
pub const BufferedWriter = @import("io/BufferedWriter.zig");
|
||||
pub const ArrayListWriter = @import("io/ArrayListWriter.zig");
|
||||
pub const AllocatingWriter = @import("io/AllocatingWriter.zig");
|
||||
|
||||
pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader;
|
||||
pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader;
|
||||
@ -784,7 +784,7 @@ test {
|
||||
_ = Writer;
|
||||
_ = CountingWriter;
|
||||
_ = FixedBufferStream;
|
||||
_ = ArrayListWriter;
|
||||
_ = AllocatingWriter;
|
||||
_ = @import("io/bit_reader.zig");
|
||||
_ = @import("io/bit_writer.zig");
|
||||
_ = @import("io/buffered_atomic_file.zig");
|
||||
|
||||
@ -1,73 +1,119 @@
|
||||
//! The straightforward way to use `std.ArrayList` as the underlying writer
|
||||
//! when using `std.io.BufferedWriter` is to populate the `std.io.Writer`
|
||||
//! interface and then use an empty buffer. However, this means that every use
|
||||
//! of `std.io.BufferedWriter` will go through the vtable, including for
|
||||
//! TODO rename to AllocatingWriter.
|
||||
//! While it is possible to use `std.ArrayList` as the underlying writer when
|
||||
//! using `std.io.BufferedWriter` by populating the `std.io.Writer` interface
|
||||
//! and then using an empty buffer, it means that every use of
|
||||
//! `std.io.BufferedWriter` will go through the vtable, including for
|
||||
//! functions such as `writeByte`. This API instead maintains
|
||||
//! `std.io.BufferedWriter` state such that it writes to the unused capacity of
|
||||
//! the array list, filling it up completely before making a call through the
|
||||
//! an array list, filling it up completely before making a call through the
|
||||
//! vtable, causing a resize. Consequently, the same, optimized, non-generic
|
||||
//! machine code that uses `std.io.BufferedReader`, such as formatted printing,
|
||||
//! is also used when the underlying writer is backed by `std.ArrayList`.
|
||||
//! takes the hot paths when using this API.
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const ArrayListWriter = @This();
|
||||
const AllocatingWriter = @This();
|
||||
const assert = std.debug.assert;
|
||||
|
||||
items: []u8,
|
||||
/// This is missing the data stored in `buffered_writer`. See `getWritten` for
|
||||
/// returning a slice that includes both.
|
||||
written: []u8,
|
||||
allocator: std.mem.Allocator,
|
||||
buffered_writer: std.io.BufferedWriter,
|
||||
|
||||
/// Replaces `array_list` with empty, taking ownership of the memory.
|
||||
pub fn fromOwned(
|
||||
alw: *ArrayListWriter,
|
||||
allocator: std.mem.Allocator,
|
||||
array_list: *std.ArrayListUnmanaged(u8),
|
||||
) *std.io.BufferedWriter {
|
||||
alw.* = .{
|
||||
.allocated_slice = array_list.items,
|
||||
const vtable: std.io.Writer.VTable = .{
|
||||
.writev = writev,
|
||||
.writeFile = writeFile,
|
||||
};
|
||||
|
||||
/// Sets the `AllocatingWriter` to an empty state.
|
||||
pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) *std.io.BufferedWriter {
|
||||
aw.* = .{
|
||||
.written = &.{},
|
||||
.allocator = allocator,
|
||||
.buffered_writer = .{
|
||||
.unbuffered_writer = .{
|
||||
.context = alw,
|
||||
.vtable = &.{
|
||||
.writev = writev,
|
||||
.writeFile = writeFile,
|
||||
},
|
||||
.context = aw,
|
||||
.vtable = &vtable,
|
||||
},
|
||||
.buffer = &.{},
|
||||
},
|
||||
};
|
||||
return &aw.buffered_writer;
|
||||
}
|
||||
|
||||
/// Replaces `array_list` with empty, taking ownership of the memory.
|
||||
pub fn fromArrayList(
|
||||
aw: *AllocatingWriter,
|
||||
allocator: std.mem.Allocator,
|
||||
array_list: *std.ArrayListUnmanaged(u8),
|
||||
) *std.io.BufferedWriter {
|
||||
aw.* = .{
|
||||
.written = array_list.items,
|
||||
.allocator = allocator,
|
||||
.buffered_writer = .{
|
||||
.unbuffered_writer = .{
|
||||
.context = aw,
|
||||
.vtable = &vtable,
|
||||
},
|
||||
.buffer = array_list.unusedCapacitySlice(),
|
||||
},
|
||||
};
|
||||
array_list.* = .empty;
|
||||
return &alw.buffered_writer;
|
||||
return &aw.buffered_writer;
|
||||
}
|
||||
|
||||
/// Returns the memory back that was borrowed with `fromOwned`.
|
||||
pub fn toOwned(alw: *ArrayListWriter) std.ArrayListUnmanaged(u8) {
|
||||
const end = alw.buffered_writer.end;
|
||||
/// Returns an array list that takes ownership of the allocated memory.
|
||||
/// Resets the `AllocatingWriter` to an empty state.
|
||||
pub fn toArrayList(aw: *AllocatingWriter) std.ArrayListUnmanaged(u8) {
|
||||
const bw = &aw.buffered_writer;
|
||||
const written = aw.written;
|
||||
const result: std.ArrayListUnmanaged(u8) = .{
|
||||
.items = alw.items.ptr[0 .. alw.items.len + end],
|
||||
.capacity = alw.buffered_writer.buffer.len - end,
|
||||
.items = written.ptr[0 .. written.len + bw.end],
|
||||
.capacity = written.len + bw.buffer.len,
|
||||
};
|
||||
alw.* = undefined;
|
||||
aw.written = &.{};
|
||||
bw.buffer = &.{};
|
||||
bw.end = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn setArrayList(aw: *AllocatingWriter, list: std.ArrayListUnmanaged(u8)) void {
|
||||
aw.written = list.items;
|
||||
aw.buffered_writer.buffer = list.unusedCapacitySlice();
|
||||
}
|
||||
|
||||
pub fn getWritten(aw: *AllocatingWriter) []u8 {
|
||||
const bw = &aw.buffered_writer;
|
||||
const end = aw.buffered_writer.end;
|
||||
const result = aw.written.ptr[0 .. aw.written.len + end];
|
||||
bw.buffer = bw.buffer[end..];
|
||||
bw.end = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn clearRetainingCapacity(aw: *AllocatingWriter) void {
|
||||
const bw = &aw.buffered_writer;
|
||||
bw.buffer = aw.written.ptr[0 .. aw.written.len + bw.buffer.len];
|
||||
bw.end = 0;
|
||||
aw.written.len = 0;
|
||||
}
|
||||
|
||||
fn writev(context: *anyopaque, data: []const []const u8) anyerror!usize {
|
||||
const alw: *ArrayListWriter = @alignCast(@ptrCast(context));
|
||||
const start_len = alw.items.len;
|
||||
const bw = &alw.buffered_writer;
|
||||
assert(data[0].ptr == alw.items.ptr + start_len);
|
||||
const bw_end = data[0].len;
|
||||
const aw: *AllocatingWriter = @alignCast(@ptrCast(context));
|
||||
const start_len = aw.written.len;
|
||||
const bw = &aw.buffered_writer;
|
||||
assert(data[0].ptr == aw.written.ptr + start_len);
|
||||
var list: std.ArrayListUnmanaged(u8) = .{
|
||||
.items = alw.items.ptr[0 .. start_len + bw_end],
|
||||
.capacity = bw.buffer.len - bw_end,
|
||||
.items = aw.written.ptr[0 .. start_len + data[0].len],
|
||||
.capacity = start_len + bw.buffer.len,
|
||||
};
|
||||
defer setArrayList(aw, list);
|
||||
const rest = data[1..];
|
||||
var new_capacity: usize = list.capacity;
|
||||
for (rest) |bytes| new_capacity += bytes.len;
|
||||
try list.ensureTotalCapacity(alw.allocator, new_capacity + 1);
|
||||
try list.ensureTotalCapacity(aw.allocator, new_capacity + 1);
|
||||
for (rest) |bytes| list.appendSliceAssumeCapacity(bytes);
|
||||
alw.items = list.items;
|
||||
aw.written = list.items;
|
||||
bw.buffer = list.unusedCapacitySlice();
|
||||
return list.items.len - start_len;
|
||||
}
|
||||
@ -80,16 +126,16 @@ fn writeFile(
|
||||
headers_and_trailers_full: []const []const u8,
|
||||
headers_len_full: usize,
|
||||
) anyerror!usize {
|
||||
const alw: *ArrayListWriter = @alignCast(@ptrCast(context));
|
||||
const list = alw.array_list;
|
||||
const bw = &alw.buffered_writer;
|
||||
const aw: *AllocatingWriter = @alignCast(@ptrCast(context));
|
||||
const gpa = aw.allocator;
|
||||
var list = aw.toArrayList();
|
||||
defer setArrayList(aw, list);
|
||||
const start_len = list.items.len;
|
||||
const headers_and_trailers, const headers_len = if (headers_len_full >= 1) b: {
|
||||
assert(headers_and_trailers_full[0].ptr == list.items.ptr + start_len);
|
||||
list.items.len += headers_and_trailers_full[0].len;
|
||||
break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 };
|
||||
} else .{ headers_and_trailers_full, headers_len_full };
|
||||
const gpa = alw.allocator;
|
||||
const trailers = headers_and_trailers[headers_len..];
|
||||
if (len == .entire_file) {
|
||||
var new_capacity: usize = list.capacity + std.atomic.cache_line;
|
||||
@ -103,11 +149,9 @@ fn writeFile(
|
||||
for (trailers) |bytes| new_capacity += bytes.len;
|
||||
try list.ensureTotalCapacity(gpa, new_capacity);
|
||||
for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes);
|
||||
bw.buffer = list.unusedCapacitySlice();
|
||||
return list.items.len - start_len;
|
||||
}
|
||||
list.items.len += n;
|
||||
bw.buffer = list.unusedCapacitySlice();
|
||||
return list.items.len - start_len;
|
||||
}
|
||||
var new_capacity: usize = list.capacity + len.int();
|
||||
@ -118,10 +162,8 @@ fn writeFile(
|
||||
const n = try file.pread(dest, offset);
|
||||
list.items.len += n;
|
||||
if (n < dest.len) {
|
||||
bw.buffer = list.unusedCapacitySlice();
|
||||
return list.items.len - start_len;
|
||||
}
|
||||
for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes);
|
||||
bw.buffer = list.unusedCapacitySlice();
|
||||
return list.items.len - start_len;
|
||||
}
|
||||
@ -19,6 +19,9 @@ end: usize = 0,
|
||||
/// vectors through the underlying write calls as possible.
|
||||
pub const max_buffers_len = 8;
|
||||
|
||||
/// Although `BufferedWriter` can easily satisfy the `Writer` interface, it's
|
||||
/// generally more practical to pass a `BufferedWriter` instance itself around,
|
||||
/// since it will result in fewer calls across vtable boundaries.
|
||||
pub fn writer(bw: *BufferedWriter) Writer {
|
||||
return .{
|
||||
.context = bw,
|
||||
@ -212,6 +215,7 @@ pub fn splatByte(bw: *BufferedWriter, byte: u8, n: usize) anyerror!usize {
|
||||
|
||||
const new_end = end + n;
|
||||
if (new_end <= buffer.len) {
|
||||
@branchHint(.likely);
|
||||
@memset(buffer[end..][0..n], byte);
|
||||
bw.end = new_end;
|
||||
return n;
|
||||
@ -226,6 +230,7 @@ pub fn splatByte(bw: *BufferedWriter, byte: u8, n: usize) anyerror!usize {
|
||||
bw.end = remainder.len;
|
||||
return 0;
|
||||
}
|
||||
assert(bw.buffer.ptr == buffer.ptr); // TODO this is not a valid assertion
|
||||
@memset(buffer[0..n], byte);
|
||||
bw.end = n;
|
||||
return n;
|
||||
|
||||
@ -71,12 +71,7 @@ pub const Config = union(enum) {
|
||||
reset_attributes: u16,
|
||||
};
|
||||
|
||||
pub fn setColor(
|
||||
conf: Config,
|
||||
writer: anytype,
|
||||
color: Color,
|
||||
) (@typeInfo(@TypeOf(writer.writeAll(""))).error_union.error_set ||
|
||||
windows.SetConsoleTextAttributeError)!void {
|
||||
pub fn setColor(conf: Config, bw: *std.io.BufferedWriter, color: Color) anyerror!void {
|
||||
nosuspend switch (conf) {
|
||||
.no_color => return,
|
||||
.escape_codes => {
|
||||
@ -101,7 +96,7 @@ pub const Config = union(enum) {
|
||||
.dim => "\x1b[2m",
|
||||
.reset => "\x1b[0m",
|
||||
};
|
||||
try writer.writeAll(color_string);
|
||||
try bw.writeAll(color_string);
|
||||
},
|
||||
.windows_api => |ctx| if (native_os == .windows) {
|
||||
const attributes = switch (color) {
|
||||
|
||||
@ -1004,7 +1004,8 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
|
||||
|
||||
fn writeIntFd(fd: i32, value: ErrInt) !void {
|
||||
const file: File = .{ .handle = fd };
|
||||
file.writer().writeInt(u64, @intCast(value), .little) catch return error.SystemResources;
|
||||
var bw = file.unbufferedWriter();
|
||||
bw.writeInt(u64, @intCast(value), .little) catch return error.SystemResources;
|
||||
}
|
||||
|
||||
fn readIntFd(fd: i32) !ErrInt {
|
||||
|
||||
@ -475,37 +475,37 @@ pub fn stringEscape(
|
||||
bytes: []const u8,
|
||||
comptime f: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
bw: *std.io.BufferedWriter,
|
||||
) !void {
|
||||
_ = options;
|
||||
for (bytes) |byte| switch (byte) {
|
||||
'\n' => try writer.writeAll("\\n"),
|
||||
'\r' => try writer.writeAll("\\r"),
|
||||
'\t' => try writer.writeAll("\\t"),
|
||||
'\\' => try writer.writeAll("\\\\"),
|
||||
'\n' => try bw.writeAll("\\n"),
|
||||
'\r' => try bw.writeAll("\\r"),
|
||||
'\t' => try bw.writeAll("\\t"),
|
||||
'\\' => try bw.writeAll("\\\\"),
|
||||
'"' => {
|
||||
if (f.len == 1 and f[0] == '\'') {
|
||||
try writer.writeByte('"');
|
||||
try bw.writeByte('"');
|
||||
} else if (f.len == 0) {
|
||||
try writer.writeAll("\\\"");
|
||||
try bw.writeAll("\\\"");
|
||||
} else {
|
||||
@compileError("expected {} or {'}, found {" ++ f ++ "}");
|
||||
}
|
||||
},
|
||||
'\'' => {
|
||||
if (f.len == 1 and f[0] == '\'') {
|
||||
try writer.writeAll("\\'");
|
||||
try bw.writeAll("\\'");
|
||||
} else if (f.len == 0) {
|
||||
try writer.writeByte('\'');
|
||||
try bw.writeByte('\'');
|
||||
} else {
|
||||
@compileError("expected {} or {'}, found {" ++ f ++ "}");
|
||||
}
|
||||
},
|
||||
' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
|
||||
' ', '!', '#'...'&', '('...'[', ']'...'~' => try bw.writeByte(byte),
|
||||
// Use hex escapes for rest any unprintable characters.
|
||||
else => {
|
||||
try writer.writeAll("\\x");
|
||||
try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
|
||||
try bw.writeAll("\\x");
|
||||
try bw.printIntOptions(byte, 16, .lower, .{ .width = 2, .fill = '0' });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user