Skip to content

Commit 7f975bf

Browse files
committed
Merge branch 'daurnimator-less-buffer'
Closes #4405 Closes #4656
2 parents fa46bcb + 231a4b8 commit 7f975bf

File tree

11 files changed

+165
-131
lines changed

11 files changed

+165
-131
lines changed

build.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ const BufMap = std.BufMap;
66
const warn = std.debug.warn;
77
const mem = std.mem;
88
const ArrayList = std.ArrayList;
9-
const Buffer = std.Buffer;
109
const io = std.io;
1110
const fs = std.fs;
1211
const InstallDirectoryOptions = std.build.InstallDirectoryOptions;

lib/std/array_list.zig

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ const testing = std.testing;
55
const mem = std.mem;
66
const Allocator = mem.Allocator;
77

8-
/// List of items.
9-
///
10-
/// This is a wrapper around an array of T values. Initialize with
11-
/// `init`.
8+
/// A contiguous, growable list of items in memory.
9+
/// This is a wrapper around an array of T values. Initialize with `init`.
1210
pub fn ArrayList(comptime T: type) type {
1311
return AlignedArrayList(T, null);
1412
}
@@ -22,7 +20,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
2220
return struct {
2321
const Self = @This();
2422

25-
/// Use toSlice instead of slicing this directly, because if you don't
23+
/// Use `span` instead of slicing this directly, because if you don't
2624
/// specify the end position of the slice, this will potentially give
2725
/// you uninitialized memory.
2826
items: Slice,
@@ -56,34 +54,37 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
5654

5755
/// Return contents as a slice. Only valid while the list
5856
/// doesn't change size.
59-
pub fn toSlice(self: Self) Slice {
57+
pub fn span(self: var) @TypeOf(self.items[0..self.len]) {
6058
return self.items[0..self.len];
6159
}
6260

63-
/// Return list as const slice. Only valid while the list
64-
/// doesn't change size.
61+
/// Deprecated: use `span`.
62+
pub fn toSlice(self: Self) Slice {
63+
return self.span();
64+
}
65+
66+
/// Deprecated: use `span`.
6567
pub fn toSliceConst(self: Self) SliceConst {
66-
return self.items[0..self.len];
68+
return self.span();
6769
}
6870

69-
/// Safely access index i of the list.
71+
/// Deprecated: use `span()[i]`.
7072
pub fn at(self: Self, i: usize) T {
71-
return self.toSliceConst()[i];
73+
return self.span()[i];
7274
}
7375

74-
/// Safely access ptr to index i of the list.
76+
/// Deprecated: use `&span()[i]`.
7577
pub fn ptrAt(self: Self, i: usize) *T {
76-
return &self.toSlice()[i];
78+
return &self.span()[i];
7779
}
7880

79-
/// Sets the value at index `i`, or returns `error.OutOfBounds` if
80-
/// the index is not in range.
81+
/// Deprecated: use `if (i >= list.len) return error.OutOfBounds else span()[i] = item`.
8182
pub fn setOrError(self: Self, i: usize, item: T) !void {
8283
if (i >= self.len) return error.OutOfBounds;
8384
self.items[i] = item;
8485
}
8586

86-
/// Sets the value at index `i`, asserting that the value is in range.
87+
/// Deprecated: use `list.span()[i] = item`.
8788
pub fn set(self: *Self, i: usize, item: T) void {
8889
assert(i < self.len);
8990
self.items[i] = item;
@@ -124,18 +125,18 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
124125
self.items[n] = item;
125126
}
126127

127-
/// Insert slice `items` at index `n`. Moves
128-
/// `list[n .. list.len]` to make room.
129-
pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void {
128+
/// Insert slice `items` at index `i`. Moves
129+
/// `list[i .. list.len]` to make room.
130+
/// This operation is O(N).
131+
pub fn insertSlice(self: *Self, i: usize, items: SliceConst) !void {
130132
try self.ensureCapacity(self.len + items.len);
131133
self.len += items.len;
132134

133-
mem.copyBackwards(T, self.items[n + items.len .. self.len], self.items[n .. self.len - items.len]);
134-
mem.copy(T, self.items[n .. n + items.len], items);
135+
mem.copyBackwards(T, self.items[i + items.len .. self.len], self.items[i .. self.len - items.len]);
136+
mem.copy(T, self.items[i .. i + items.len], items);
135137
}
136138

137-
/// Extend the list by 1 element. Allocates more memory as
138-
/// necessary.
139+
/// Extend the list by 1 element. Allocates more memory as necessary.
139140
pub fn append(self: *Self, item: T) !void {
140141
const new_item_ptr = try self.addOne();
141142
new_item_ptr.* = item;
@@ -148,8 +149,9 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
148149
new_item_ptr.* = item;
149150
}
150151

151-
/// Remove the element at index `i` from the list and return
152-
/// its value. Asserts the array has at least one item.
152+
/// Remove the element at index `i` from the list and return its value.
153+
/// Asserts the array has at least one item.
154+
/// This operation is O(N).
153155
pub fn orderedRemove(self: *Self, i: usize) T {
154156
const newlen = self.len - 1;
155157
if (newlen == i) return self.pop();
@@ -163,18 +165,17 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
163165

164166
/// Removes the element at the specified index and returns it.
165167
/// The empty slot is filled from the end of the list.
168+
/// This operation is O(1).
166169
pub fn swapRemove(self: *Self, i: usize) T {
167170
if (self.len - 1 == i) return self.pop();
168171

169-
const slice = self.toSlice();
172+
const slice = self.span();
170173
const old_item = slice[i];
171174
slice[i] = self.pop();
172175
return old_item;
173176
}
174177

175-
/// Removes the element at the specified index and returns it
176-
/// or an error.OutOfBounds is returned. If no error then
177-
/// the empty slot is filled from the end of the list.
178+
/// Deprecated: use `if (i >= list.len) return error.OutOfBounds else list.swapRemove(i)`.
178179
pub fn swapRemoveOrError(self: *Self, i: usize) !T {
179180
if (i >= self.len) return error.OutOfBounds;
180181
return self.swapRemove(i);
@@ -204,6 +205,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
204205
}
205206

206207
/// Reduce allocated capacity to `new_len`.
208+
/// Invalidates element pointers.
207209
pub fn shrink(self: *Self, new_len: usize) void {
208210
assert(new_len <= self.len);
209211
self.len = new_len;
@@ -222,28 +224,40 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
222224
self.items = try self.allocator.realloc(self.items, better_capacity);
223225
}
224226

227+
/// Increases the array's length to match the full capacity that is already allocated.
228+
/// The new elements have `undefined` values. This operation does not invalidate any
229+
/// element pointers.
230+
pub fn expandToCapacity(self: *Self) void {
231+
self.len = self.items.len;
232+
}
233+
225234
/// Increase length by 1, returning pointer to the new item.
235+
/// The returned pointer becomes invalid when the list is resized.
226236
pub fn addOne(self: *Self) !*T {
227237
const new_length = self.len + 1;
228238
try self.ensureCapacity(new_length);
229239
return self.addOneAssumeCapacity();
230240
}
231241

242+
/// Increase length by 1, returning pointer to the new item.
243+
/// Asserts that there is already space for the new item without allocating more.
244+
/// The returned pointer becomes invalid when the list is resized.
232245
pub fn addOneAssumeCapacity(self: *Self) *T {
233246
assert(self.len < self.capacity());
234247
const result = &self.items[self.len];
235248
self.len += 1;
236249
return result;
237250
}
238251

239-
/// Remove and return the last element from the list. Asserts
240-
/// the list has at least one item.
252+
/// Remove and return the last element from the list.
253+
/// Asserts the list has at least one item.
241254
pub fn pop(self: *Self) T {
242255
self.len -= 1;
243256
return self.items[self.len];
244257
}
245258

246-
/// Like `pop` but returns `null` if empty.
259+
/// Remove and return the last element from the list.
260+
/// If the list is empty, returns `null`.
247261
pub fn popOrNull(self: *Self) ?T {
248262
if (self.len == 0) return null;
249263
return self.pop();
@@ -287,7 +301,7 @@ test "std.ArrayList.basic" {
287301
}
288302
}
289303

290-
for (list.toSlice()) |v, i| {
304+
for (list.span()) |v, i| {
291305
testing.expect(v == @intCast(i32, i + 1));
292306
}
293307

@@ -325,7 +339,7 @@ test "std.ArrayList.appendNTimes" {
325339

326340
try list.appendNTimes(2, 10);
327341
testing.expectEqual(@as(usize, 10), list.len);
328-
for (list.toSlice()) |element| {
342+
for (list.span()) |element| {
329343
testing.expectEqual(@as(i32, 2), element);
330344
}
331345
}

lib/std/buffer.zig

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,18 @@ pub const Buffer = struct {
8181
self.list.deinit();
8282
}
8383

84+
pub fn span(self: var) @TypeOf(self.list.items[0 .. self.list.len - 1 :0]) {
85+
return self.list.span()[0..self.len() :0];
86+
}
87+
88+
/// Deprecated: use `span`
8489
pub fn toSlice(self: Buffer) [:0]u8 {
85-
return self.list.toSlice()[0..self.len() :0];
90+
return self.span();
8691
}
8792

93+
/// Deprecated: use `span`
8894
pub fn toSliceConst(self: Buffer) [:0]const u8 {
89-
return self.list.toSliceConst()[0..self.len() :0];
95+
return self.span();
9096
}
9197

9298
pub fn shrink(self: *Buffer, new_len: usize) void {

lib/std/build.zig

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -926,11 +926,9 @@ pub const Builder = struct {
926926

927927
try child.spawn();
928928

929-
var stdout = std.Buffer.initNull(self.allocator);
930-
defer std.Buffer.deinit(&stdout);
931-
932929
var stdout_file_in_stream = child.stdout.?.inStream();
933-
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
930+
const stdout = try stdout_file_in_stream.stream.readAllAlloc(self.allocator, max_output_size);
931+
errdefer self.allocator.free(stdout);
934932

935933
const term = try child.wait();
936934
switch (term) {
@@ -939,7 +937,7 @@ pub const Builder = struct {
939937
out_code.* = @truncate(u8, code);
940938
return error.ExitCodeFailure;
941939
}
942-
return stdout.toOwnedSlice();
940+
return stdout;
943941
},
944942
.Signal, .Stopped, .Unknown => |code| {
945943
out_code.* = @truncate(u8, code);

lib/std/build/run.zig

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const mem = std.mem;
99
const process = std.process;
1010
const ArrayList = std.ArrayList;
1111
const BufMap = std.BufMap;
12-
const Buffer = std.Buffer;
1312
const warn = std.debug.warn;
1413

1514
const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
@@ -169,23 +168,26 @@ pub const RunStep = struct {
169168
return err;
170169
};
171170

172-
var stdout = Buffer.initNull(self.builder.allocator);
173-
var stderr = Buffer.initNull(self.builder.allocator);
174-
175171
// TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
176172

173+
var stdout: ?[]const u8 = null;
174+
defer if (stdout) |s| self.builder.allocator.free(s);
175+
177176
switch (self.stdout_action) {
178177
.expect_exact, .expect_matches => {
179178
var stdout_file_in_stream = child.stdout.?.inStream();
180-
stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
179+
stdout = stdout_file_in_stream.stream.readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
181180
},
182181
.inherit, .ignore => {},
183182
}
184183

185-
switch (self.stdout_action) {
184+
var stderr: ?[]const u8 = null;
185+
defer if (stderr) |s| self.builder.allocator.free(s);
186+
187+
switch (self.stderr_action) {
186188
.expect_exact, .expect_matches => {
187189
var stderr_file_in_stream = child.stderr.?.inStream();
188-
stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
190+
stderr = stderr_file_in_stream.stream.readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
189191
},
190192
.inherit, .ignore => {},
191193
}
@@ -216,29 +218,29 @@ pub const RunStep = struct {
216218
switch (self.stderr_action) {
217219
.inherit, .ignore => {},
218220
.expect_exact => |expected_bytes| {
219-
if (!mem.eql(u8, expected_bytes, stderr.toSliceConst())) {
221+
if (!mem.eql(u8, expected_bytes, stderr.?)) {
220222
warn(
221223
\\
222224
\\========= Expected this stderr: =========
223225
\\{}
224226
\\========= But found: ====================
225227
\\{}
226228
\\
227-
, .{ expected_bytes, stderr.toSliceConst() });
229+
, .{ expected_bytes, stderr.? });
228230
printCmd(cwd, argv);
229231
return error.TestFailed;
230232
}
231233
},
232234
.expect_matches => |matches| for (matches) |match| {
233-
if (mem.indexOf(u8, stderr.toSliceConst(), match) == null) {
235+
if (mem.indexOf(u8, stderr.?, match) == null) {
234236
warn(
235237
\\
236238
\\========= Expected to find in stderr: =========
237239
\\{}
238240
\\========= But stderr does not contain it: =====
239241
\\{}
240242
\\
241-
, .{ match, stderr.toSliceConst() });
243+
, .{ match, stderr.? });
242244
printCmd(cwd, argv);
243245
return error.TestFailed;
244246
}
@@ -248,29 +250,29 @@ pub const RunStep = struct {
248250
switch (self.stdout_action) {
249251
.inherit, .ignore => {},
250252
.expect_exact => |expected_bytes| {
251-
if (!mem.eql(u8, expected_bytes, stdout.toSliceConst())) {
253+
if (!mem.eql(u8, expected_bytes, stdout.?)) {
252254
warn(
253255
\\
254256
\\========= Expected this stdout: =========
255257
\\{}
256258
\\========= But found: ====================
257259
\\{}
258260
\\
259-
, .{ expected_bytes, stdout.toSliceConst() });
261+
, .{ expected_bytes, stdout.? });
260262
printCmd(cwd, argv);
261263
return error.TestFailed;
262264
}
263265
},
264266
.expect_matches => |matches| for (matches) |match| {
265-
if (mem.indexOf(u8, stdout.toSliceConst(), match) == null) {
267+
if (mem.indexOf(u8, stdout.?, match) == null) {
266268
warn(
267269
\\
268270
\\========= Expected to find in stdout: =========
269271
\\{}
270272
\\========= But stdout does not contain it: =====
271273
\\{}
272274
\\
273-
, .{ match, stdout.toSliceConst() });
275+
, .{ match, stdout.? });
274276
printCmd(cwd, argv);
275277
return error.TestFailed;
276278
}

lib/std/child_process.zig

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,21 +217,19 @@ pub const ChildProcess = struct {
217217

218218
try child.spawn();
219219

220-
var stdout = Buffer.initNull(args.allocator);
221-
var stderr = Buffer.initNull(args.allocator);
222-
defer Buffer.deinit(&stdout);
223-
defer Buffer.deinit(&stderr);
224-
225220
var stdout_file_in_stream = child.stdout.?.inStream();
226221
var stderr_file_in_stream = child.stderr.?.inStream();
227222

228-
try stdout_file_in_stream.stream.readAllBuffer(&stdout, args.max_output_bytes);
229-
try stderr_file_in_stream.stream.readAllBuffer(&stderr, args.max_output_bytes);
223+
// TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
224+
const stdout = try stdout_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);
225+
errdefer args.allocator.free(stdout);
226+
const stderr = try stderr_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);
227+
errdefer args.allocator.free(stderr);
230228

231229
return ExecResult{
232230
.term = try child.wait(),
233-
.stdout = stdout.toOwnedSlice(),
234-
.stderr = stderr.toOwnedSlice(),
231+
.stdout = stdout,
232+
.stderr = stderr,
235233
};
236234
}
237235

0 commit comments

Comments
 (0)