Merge branch 'daurnimator-less-buffer'

Closes #4405
Closes #4656
This commit is contained in:
Andrew Kelley 2020-03-06 18:49:26 -05:00
commit 7f975bf09f
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
11 changed files with 166 additions and 132 deletions

View File

@ -6,7 +6,6 @@ const BufMap = std.BufMap;
const warn = std.debug.warn;
const mem = std.mem;
const ArrayList = std.ArrayList;
const Buffer = std.Buffer;
const io = std.io;
const fs = std.fs;
const InstallDirectoryOptions = std.build.InstallDirectoryOptions;

View File

@ -5,10 +5,8 @@ const testing = std.testing;
const mem = std.mem;
const Allocator = mem.Allocator;
/// List of items.
///
/// This is a wrapper around an array of T values. Initialize with
/// `init`.
/// A contiguous, growable list of items in memory.
/// This is a wrapper around an array of T values. Initialize with `init`.
pub fn ArrayList(comptime T: type) type {
return AlignedArrayList(T, null);
}
@ -22,7 +20,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
return struct {
const Self = @This();
/// Use toSlice instead of slicing this directly, because if you don't
/// Use `span` instead of slicing this directly, because if you don't
/// specify the end position of the slice, this will potentially give
/// you uninitialized memory.
items: Slice,
@ -56,34 +54,37 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
/// Return contents as a slice. Only valid while the list
/// doesn't change size.
pub fn span(self: var) @TypeOf(self.items[0..self.len]) {
return self.items[0..self.len];
}
/// Deprecated: use `span`.
pub fn toSlice(self: Self) Slice {
return self.items[0..self.len];
return self.span();
}
/// Return list as const slice. Only valid while the list
/// doesn't change size.
/// Deprecated: use `span`.
pub fn toSliceConst(self: Self) SliceConst {
return self.items[0..self.len];
return self.span();
}
/// Safely access index i of the list.
/// Deprecated: use `span()[i]`.
pub fn at(self: Self, i: usize) T {
return self.toSliceConst()[i];
return self.span()[i];
}
/// Safely access ptr to index i of the list.
/// Deprecated: use `&span()[i]`.
pub fn ptrAt(self: Self, i: usize) *T {
return &self.toSlice()[i];
return &self.span()[i];
}
/// Sets the value at index `i`, or returns `error.OutOfBounds` if
/// the index is not in range.
/// Deprecated: use `if (i >= list.len) return error.OutOfBounds else span()[i] = item`.
pub fn setOrError(self: Self, i: usize, item: T) !void {
if (i >= self.len) return error.OutOfBounds;
self.items[i] = item;
}
/// Sets the value at index `i`, asserting that the value is in range.
/// Deprecated: use `list.span()[i] = item`.
pub fn set(self: *Self, i: usize, item: T) void {
assert(i < self.len);
self.items[i] = item;
@ -124,18 +125,18 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
self.items[n] = item;
}
/// Insert slice `items` at index `n`. Moves
/// `list[n .. list.len]` to make room.
pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void {
/// Insert slice `items` at index `i`. Moves
/// `list[i .. list.len]` to make room.
/// This operation is O(N).
pub fn insertSlice(self: *Self, i: usize, items: SliceConst) !void {
try self.ensureCapacity(self.len + items.len);
self.len += items.len;
mem.copyBackwards(T, self.items[n + items.len .. self.len], self.items[n .. self.len - items.len]);
mem.copy(T, self.items[n .. n + items.len], items);
mem.copyBackwards(T, self.items[i + items.len .. self.len], self.items[i .. self.len - items.len]);
mem.copy(T, self.items[i .. i + items.len], items);
}
/// Extend the list by 1 element. Allocates more memory as
/// necessary.
/// Extend the list by 1 element. Allocates more memory as necessary.
pub fn append(self: *Self, item: T) !void {
const new_item_ptr = try self.addOne();
new_item_ptr.* = item;
@ -148,8 +149,9 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
new_item_ptr.* = item;
}
/// Remove the element at index `i` from the list and return
/// its value. Asserts the array has at least one item.
/// Remove the element at index `i` from the list and return its value.
/// Asserts the array has at least one item.
/// This operation is O(N).
pub fn orderedRemove(self: *Self, i: usize) T {
const newlen = self.len - 1;
if (newlen == i) return self.pop();
@ -163,18 +165,17 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
/// Removes the element at the specified index and returns it.
/// The empty slot is filled from the end of the list.
/// This operation is O(1).
pub fn swapRemove(self: *Self, i: usize) T {
if (self.len - 1 == i) return self.pop();
const slice = self.toSlice();
const slice = self.span();
const old_item = slice[i];
slice[i] = self.pop();
return old_item;
}
/// Removes the element at the specified index and returns it
/// or an error.OutOfBounds is returned. If no error then
/// the empty slot is filled from the end of the list.
/// Deprecated: use `if (i >= list.len) return error.OutOfBounds else list.swapRemove(i)`.
pub fn swapRemoveOrError(self: *Self, i: usize) !T {
if (i >= self.len) return error.OutOfBounds;
return self.swapRemove(i);
@ -204,6 +205,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
}
/// Reduce allocated capacity to `new_len`.
/// Invalidates element pointers.
pub fn shrink(self: *Self, new_len: usize) void {
assert(new_len <= self.len);
self.len = new_len;
@ -222,13 +224,24 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
self.items = try self.allocator.realloc(self.items, better_capacity);
}
/// Increases the array's length to match the full capacity that is already allocated.
/// The new elements have `undefined` values. This operation does not invalidate any
/// element pointers.
pub fn expandToCapacity(self: *Self) void {
self.len = self.items.len;
}
/// Increase length by 1, returning pointer to the new item.
/// The returned pointer becomes invalid when the list is resized.
pub fn addOne(self: *Self) !*T {
const new_length = self.len + 1;
try self.ensureCapacity(new_length);
return self.addOneAssumeCapacity();
}
/// Increase length by 1, returning pointer to the new item.
/// Asserts that there is already space for the new item without allocating more.
/// The returned pointer becomes invalid when the list is resized.
pub fn addOneAssumeCapacity(self: *Self) *T {
assert(self.len < self.capacity());
const result = &self.items[self.len];
@ -236,14 +249,15 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
return result;
}
/// Remove and return the last element from the list. Asserts
/// the list has at least one item.
/// Remove and return the last element from the list.
/// Asserts the list has at least one item.
pub fn pop(self: *Self) T {
self.len -= 1;
return self.items[self.len];
}
/// Like `pop` but returns `null` if empty.
/// Remove and return the last element from the list.
/// If the list is empty, returns `null`.
pub fn popOrNull(self: *Self) ?T {
if (self.len == 0) return null;
return self.pop();
@ -287,7 +301,7 @@ test "std.ArrayList.basic" {
}
}
for (list.toSlice()) |v, i| {
for (list.span()) |v, i| {
testing.expect(v == @intCast(i32, i + 1));
}
@ -325,7 +339,7 @@ test "std.ArrayList.appendNTimes" {
try list.appendNTimes(2, 10);
testing.expectEqual(@as(usize, 10), list.len);
for (list.toSlice()) |element| {
for (list.span()) |element| {
testing.expectEqual(@as(i32, 2), element);
}
}

View File

@ -81,12 +81,18 @@ pub const Buffer = struct {
self.list.deinit();
}
pub fn toSlice(self: Buffer) [:0]u8 {
return self.list.toSlice()[0..self.len() :0];
pub fn span(self: var) @TypeOf(self.list.items[0 .. self.list.len - 1 :0]) {
return self.list.span()[0..self.len() :0];
}
/// Deprecated: use `span`
pub fn toSlice(self: Buffer) [:0]u8 {
return self.span();
}
/// Deprecated: use `span`
pub fn toSliceConst(self: Buffer) [:0]const u8 {
return self.list.toSliceConst()[0..self.len() :0];
return self.span();
}
pub fn shrink(self: *Buffer, new_len: usize) void {

View File

@ -926,11 +926,9 @@ pub const Builder = struct {
try child.spawn();
var stdout = std.Buffer.initNull(self.allocator);
defer std.Buffer.deinit(&stdout);
var stdout_file_in_stream = child.stdout.?.inStream();
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
const stdout = try stdout_file_in_stream.stream.readAllAlloc(self.allocator, max_output_size);
errdefer self.allocator.free(stdout);
const term = try child.wait();
switch (term) {
@ -939,7 +937,7 @@ pub const Builder = struct {
out_code.* = @truncate(u8, code);
return error.ExitCodeFailure;
}
return stdout.toOwnedSlice();
return stdout;
},
.Signal, .Stopped, .Unknown => |code| {
out_code.* = @truncate(u8, code);

View File

@ -9,7 +9,6 @@ const mem = std.mem;
const process = std.process;
const ArrayList = std.ArrayList;
const BufMap = std.BufMap;
const Buffer = std.Buffer;
const warn = std.debug.warn;
const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
@ -169,23 +168,26 @@ pub const RunStep = struct {
return err;
};
var stdout = Buffer.initNull(self.builder.allocator);
var stderr = Buffer.initNull(self.builder.allocator);
// TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
var stdout: ?[]const u8 = null;
defer if (stdout) |s| self.builder.allocator.free(s);
switch (self.stdout_action) {
.expect_exact, .expect_matches => {
var stdout_file_in_stream = child.stdout.?.inStream();
stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
stdout = stdout_file_in_stream.stream.readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
},
.inherit, .ignore => {},
}
switch (self.stdout_action) {
var stderr: ?[]const u8 = null;
defer if (stderr) |s| self.builder.allocator.free(s);
switch (self.stderr_action) {
.expect_exact, .expect_matches => {
var stderr_file_in_stream = child.stderr.?.inStream();
stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
stderr = stderr_file_in_stream.stream.readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
},
.inherit, .ignore => {},
}
@ -216,7 +218,7 @@ pub const RunStep = struct {
switch (self.stderr_action) {
.inherit, .ignore => {},
.expect_exact => |expected_bytes| {
if (!mem.eql(u8, expected_bytes, stderr.toSliceConst())) {
if (!mem.eql(u8, expected_bytes, stderr.?)) {
warn(
\\
\\========= Expected this stderr: =========
@ -224,13 +226,13 @@ pub const RunStep = struct {
\\========= But found: ====================
\\{}
\\
, .{ expected_bytes, stderr.toSliceConst() });
, .{ expected_bytes, stderr.? });
printCmd(cwd, argv);
return error.TestFailed;
}
},
.expect_matches => |matches| for (matches) |match| {
if (mem.indexOf(u8, stderr.toSliceConst(), match) == null) {
if (mem.indexOf(u8, stderr.?, match) == null) {
warn(
\\
\\========= Expected to find in stderr: =========
@ -238,7 +240,7 @@ pub const RunStep = struct {
\\========= But stderr does not contain it: =====
\\{}
\\
, .{ match, stderr.toSliceConst() });
, .{ match, stderr.? });
printCmd(cwd, argv);
return error.TestFailed;
}
@ -248,7 +250,7 @@ pub const RunStep = struct {
switch (self.stdout_action) {
.inherit, .ignore => {},
.expect_exact => |expected_bytes| {
if (!mem.eql(u8, expected_bytes, stdout.toSliceConst())) {
if (!mem.eql(u8, expected_bytes, stdout.?)) {
warn(
\\
\\========= Expected this stdout: =========
@ -256,13 +258,13 @@ pub const RunStep = struct {
\\========= But found: ====================
\\{}
\\
, .{ expected_bytes, stdout.toSliceConst() });
, .{ expected_bytes, stdout.? });
printCmd(cwd, argv);
return error.TestFailed;
}
},
.expect_matches => |matches| for (matches) |match| {
if (mem.indexOf(u8, stdout.toSliceConst(), match) == null) {
if (mem.indexOf(u8, stdout.?, match) == null) {
warn(
\\
\\========= Expected to find in stdout: =========
@ -270,7 +272,7 @@ pub const RunStep = struct {
\\========= But stdout does not contain it: =====
\\{}
\\
, .{ match, stdout.toSliceConst() });
, .{ match, stdout.? });
printCmd(cwd, argv);
return error.TestFailed;
}

View File

@ -217,21 +217,19 @@ pub const ChildProcess = struct {
try child.spawn();
var stdout = Buffer.initNull(args.allocator);
var stderr = Buffer.initNull(args.allocator);
defer Buffer.deinit(&stdout);
defer Buffer.deinit(&stderr);
var stdout_file_in_stream = child.stdout.?.inStream();
var stderr_file_in_stream = child.stderr.?.inStream();
try stdout_file_in_stream.stream.readAllBuffer(&stdout, args.max_output_bytes);
try stderr_file_in_stream.stream.readAllBuffer(&stderr, args.max_output_bytes);
// TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
const stdout = try stdout_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);
errdefer args.allocator.free(stdout);
const stderr = try stderr_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);
errdefer args.allocator.free(stderr);
return ExecResult{
.term = try child.wait(),
.stdout = stdout.toOwnedSlice(),
.stderr = stderr.toOwnedSlice(),
.stdout = stdout,
.stderr = stderr,
};
}

View File

@ -1643,10 +1643,10 @@ test "hexToBytes" {
test "formatIntValue with comptime_int" {
const value: comptime_int = 123456789123456789;
var buf = try std.Buffer.init(std.testing.allocator, "");
var buf = std.ArrayList(u8).init(std.testing.allocator);
defer buf.deinit();
try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append);
std.testing.expect(mem.eql(u8, buf.toSlice(), "123456789123456789"));
try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
}
test "formatType max_depth" {
@ -1698,24 +1698,24 @@ test "formatType max_depth" {
inst.a = &inst;
inst.tu.ptr = &inst.tu;
var buf0 = try std.Buffer.init(std.testing.allocator, "");
var buf0 = std.ArrayList(u8).init(std.testing.allocator);
defer buf0.deinit();
try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0);
try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
var buf1 = try std.Buffer.init(std.testing.allocator, "");
var buf1 = std.ArrayList(u8).init(std.testing.allocator);
defer buf1.deinit();
try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1);
try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
var buf2 = try std.Buffer.init(std.testing.allocator, "");
var buf2 = std.ArrayList(u8).init(std.testing.allocator);
defer buf2.deinit();
try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2);
try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
var buf3 = try std.Buffer.init(std.testing.allocator, "");
var buf3 = std.ArrayList(u8).init(std.testing.allocator);
defer buf3.deinit();
try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3);
try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
}

View File

@ -41,10 +41,13 @@ pub fn InStream(comptime ReadError: type) type {
}
}
/// Deprecated: use `readAll`.
pub const readFull = readAll;
/// Returns the number of bytes read. If the number read is smaller than buf.len, it
/// means the stream reached the end. Reaching the end of a stream is not an error
/// condition.
pub fn readFull(self: *Self, buffer: []u8) Error!usize {
pub fn readAll(self: *Self, buffer: []u8) Error!usize {
var index: usize = 0;
while (index != buffer.len) {
const amt = try self.read(buffer[index..]);
@ -57,30 +60,43 @@ pub fn InStream(comptime ReadError: type) type {
/// Returns the number of bytes read. If the number read would be smaller than buf.len,
/// error.EndOfStream is returned instead.
pub fn readNoEof(self: *Self, buf: []u8) !void {
const amt_read = try self.readFull(buf);
const amt_read = try self.readAll(buf);
if (amt_read < buf.len) return error.EndOfStream;
}
/// Replaces `buffer` contents by reading from the stream until it is finished.
/// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
/// the contents read from the stream are lost.
/// Deprecated: use `readAllArrayList`.
pub fn readAllBuffer(self: *Self, buffer: *Buffer, max_size: usize) !void {
try buffer.resize(0);
buffer.list.shrink(0);
try self.readAllArrayList(&buffer.list, max_size);
errdefer buffer.shrink(0);
try buffer.list.append(0);
}
var actual_buf_len: usize = 0;
/// Appends to the `std.ArrayList` contents by reading from the stream until end of stream is found.
/// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned
/// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
pub fn readAllArrayList(self: *Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {
try array_list.ensureCapacity(math.min(max_append_size, 4096));
const original_len = array_list.len;
var start_index: usize = original_len;
while (true) {
const dest_slice = buffer.toSlice()[actual_buf_len..];
const bytes_read = try self.readFull(dest_slice);
actual_buf_len += bytes_read;
array_list.expandToCapacity();
const dest_slice = array_list.span()[start_index..];
const bytes_read = try self.readAll(dest_slice);
start_index += bytes_read;
if (start_index - original_len > max_append_size) {
array_list.shrink(original_len + max_append_size);
return error.StreamTooLong;
}
if (bytes_read != dest_slice.len) {
buffer.shrink(actual_buf_len);
array_list.shrink(start_index);
return;
}
const new_buf_size = math.min(max_size, actual_buf_len + mem.page_size);
if (new_buf_size == actual_buf_len) return error.StreamTooLong;
try buffer.resize(new_buf_size);
// This will trigger ArrayList to expand superlinearly at whatever its growth rate is.
try array_list.ensureCapacity(start_index + 1);
}
}
@ -89,20 +105,23 @@ pub fn InStream(comptime ReadError: type) type {
/// Caller owns returned memory.
/// If this function returns an error, the contents from the stream read so far are lost.
pub fn readAllAlloc(self: *Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {
var buf = Buffer.initNull(allocator);
defer buf.deinit();
try self.readAllBuffer(&buf, max_size);
return buf.toOwnedSlice();
var array_list = std.ArrayList(u8).init(allocator);
defer array_list.deinit();
try self.readAllArrayList(&array_list, max_size);
return array_list.toOwnedSlice();
}
/// Replaces `buffer` contents by reading from the stream until `delimiter` is found.
/// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found.
/// Does not include the delimiter in the result.
/// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
/// read from the stream so far are lost.
pub fn readUntilDelimiterBuffer(self: *Self, buffer: *Buffer, delimiter: u8, max_size: usize) !void {
try buffer.resize(0);
/// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
/// `std.ArrayList` is populated with `max_size` bytes from the stream.
pub fn readUntilDelimiterArrayList(
self: *Self,
array_list: *std.ArrayList(u8),
delimiter: u8,
max_size: usize,
) !void {
array_list.shrink(0);
while (true) {
var byte: u8 = try self.readByte();
@ -110,11 +129,11 @@ pub fn InStream(comptime ReadError: type) type {
return;
}
if (buffer.len() == max_size) {
if (array_list.len == max_size) {
return error.StreamTooLong;
}
try buffer.appendByte(byte);
try array_list.append(byte);
}
}
@ -122,12 +141,16 @@ pub fn InStream(comptime ReadError: type) type {
/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
/// Caller owns returned memory.
/// If this function returns an error, the contents from the stream read so far are lost.
pub fn readUntilDelimiterAlloc(self: *Self, allocator: *mem.Allocator, delimiter: u8, max_size: usize) ![]u8 {
var buf = Buffer.initNull(allocator);
defer buf.deinit();
try self.readUntilDelimiterBuffer(&buf, delimiter, max_size);
return buf.toOwnedSlice();
pub fn readUntilDelimiterAlloc(
self: *Self,
allocator: *mem.Allocator,
delimiter: u8,
max_size: usize,
) ![]u8 {
var array_list = std.ArrayList(u8).init(allocator);
defer array_list.deinit();
try self.readUntilDelimiterArrayList(&array_list, delimiter, max_size);
return array_list.toOwnedSlice();
}
/// Reads from the stream until specified byte is found. If the buffer is not

View File

@ -3,7 +3,6 @@ const builtin = std.builtin;
const os = std.os;
const fs = std.fs;
const BufMap = std.BufMap;
const Buffer = std.Buffer;
const mem = std.mem;
const math = std.math;
const Allocator = mem.Allocator;
@ -266,7 +265,7 @@ pub const ArgIteratorWindows = struct {
}
fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
var buf = try Buffer.initSize(allocator, 0);
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
var backslash_count: usize = 0;
@ -282,10 +281,10 @@ pub const ArgIteratorWindows = struct {
if (quote_is_real) {
self.seen_quote_count += 1;
if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
try buf.appendByte('"');
try buf.append('"');
}
} else {
try buf.appendByte('"');
try buf.append('"');
}
},
'\\' => {
@ -295,7 +294,7 @@ pub const ArgIteratorWindows = struct {
try self.emitBackslashes(&buf, backslash_count);
backslash_count = 0;
if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
try buf.appendByte(byte);
try buf.append(byte);
} else {
return buf.toOwnedSlice();
}
@ -303,16 +302,16 @@ pub const ArgIteratorWindows = struct {
else => {
try self.emitBackslashes(&buf, backslash_count);
backslash_count = 0;
try buf.appendByte(byte);
try buf.append(byte);
},
}
}
}
fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
fn emitBackslashes(self: *ArgIteratorWindows, buf: *std.ArrayList(u8), emit_count: usize) !void {
var i: usize = 0;
while (i < emit_count) : (i += 1) {
try buf.appendByte('\\');
try buf.append('\\');
}
}
@ -410,7 +409,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
// TODO refactor to only make 1 allocation.
var it = args();
var contents = try Buffer.initSize(allocator, 0);
var contents = std.ArrayList(u8).init(allocator);
defer contents.deinit();
var slice_list = std.ArrayList(usize).init(allocator);
@ -419,7 +418,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
while (it.next(allocator)) |arg_or_err| {
const arg = try arg_or_err;
defer allocator.free(arg);
try contents.append(arg);
try contents.appendSlice(arg);
try slice_list.append(arg.len);
}

View File

@ -9,7 +9,6 @@ const mem = std.mem;
const process = std.process;
const Allocator = mem.Allocator;
const ArrayList = std.ArrayList;
const Buffer = std.Buffer;
const c = @import("c.zig");
const introspect = @import("introspect.zig");

View File

@ -566,14 +566,13 @@ pub const StackTracesContext = struct {
}
child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", .{ full_exe_path, @errorName(err) });
var stdout = Buffer.initNull(b.allocator);
var stderr = Buffer.initNull(b.allocator);
var stdout_file_in_stream = child.stdout.?.inStream();
var stderr_file_in_stream = child.stderr.?.inStream();
stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
const stdout = stdout_file_in_stream.stream.readAllAlloc(b.allocator, max_stdout_size) catch unreachable;
defer b.allocator.free(stdout);
const stderr = stderr_file_in_stream.stream.readAllAlloc(b.allocator, max_stdout_size) catch unreachable;
defer b.allocator.free(stderr);
const term = child.wait() catch |err| {
debug.panic("Unable to spawn {}: {}\n", .{ full_exe_path, @errorName(err) });
@ -616,11 +615,8 @@ pub const StackTracesContext = struct {
const got: []const u8 = got_result: {
var buf = try Buffer.initSize(b.allocator, 0);
defer buf.deinit();
const bytes = if (stderr.endsWith("\n"))
stderr.toSliceConst()[0 .. stderr.len() - 1]
else
stderr.toSliceConst()[0..stderr.len()];
var it = mem.separate(bytes, "\n");
if (stderr.len != 0 and stderr[stderr.len - 1] == '\n') stderr = stderr[0 .. stderr.len - 1];
var it = mem.separate(stderr, "\n");
process_lines: while (it.next()) |line| {
if (line.len == 0) continue;
const delims = [_][]const u8{ ":", ":", ":", " in " };