mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 00:35:10 +00:00
fixups & make some API decisions
Removed: std.io.InStream.readUntilDelimiterBuffer Deprecated: std.ArrayList.toSlice std.ArrayList.toSliceConst std.ArrayList.at std.ArrayList.ptrAt std.ArrayList.setOrError std.ArrayList.set std.ArrayList.swapRemoveOrError std.Buffer.toSlice std.Buffer.toSliceConst std.io.InStream.readFull => std.io.InStream.readAll std.io.InStream.readAllBuffer New: std.ArrayList.span std.ArrayList.expandToCapacity std.Buffer.span std.io.InStream.readUntilDelimiterArrayList
This commit is contained in:
parent
4114b63d75
commit
231a4b8fde
@ -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,33 +249,19 @@ 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();
|
||||
}
|
||||
|
||||
pub fn eql(self: Self, m: []const T) bool {
|
||||
return mem.eql(T, self.toSliceConst(), m);
|
||||
}
|
||||
|
||||
pub fn startsWith(self: Self, m: []const T) bool {
|
||||
if (self.len < m.len) return false;
|
||||
return mem.eql(T, self.items[0..m.len], m);
|
||||
}
|
||||
|
||||
pub fn endsWith(self: Self, m: []const T) bool {
|
||||
if (self.len < m.len) return false;
|
||||
const start = self.len - m.len;
|
||||
return mem.eql(T, self.items[start..self.len], m);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -302,7 +301,7 @@ test "std.ArrayList.basic" {
|
||||
}
|
||||
}
|
||||
|
||||
for (list.toSlice()) |v, i| {
|
||||
for (list.span()) |v, i| {
|
||||
testing.expect(v == @intCast(i32, i + 1));
|
||||
}
|
||||
|
||||
@ -340,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
@ -133,7 +139,7 @@ pub const Buffer = struct {
|
||||
|
||||
pub fn startsWith(self: Buffer, m: []const u8) bool {
|
||||
if (self.len() < m.len) return false;
|
||||
return self.list.startsWith(m);
|
||||
return mem.eql(u8, self.list.items[0..m.len], m);
|
||||
}
|
||||
|
||||
pub fn endsWith(self: Buffer, m: []const u8) bool {
|
||||
|
||||
@ -170,7 +170,9 @@ pub const RunStep = struct {
|
||||
|
||||
// TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
|
||||
|
||||
var stdout: []const u8 = undefined;
|
||||
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();
|
||||
@ -178,12 +180,10 @@ pub const RunStep = struct {
|
||||
},
|
||||
.inherit, .ignore => {},
|
||||
}
|
||||
defer switch (self.stdout_action) {
|
||||
.expect_exact, .expect_matches => self.builder.allocator.free(stdout),
|
||||
.inherit, .ignore => {},
|
||||
};
|
||||
|
||||
var stderr: []const u8 = undefined;
|
||||
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();
|
||||
@ -191,10 +191,6 @@ pub const RunStep = struct {
|
||||
},
|
||||
.inherit, .ignore => {},
|
||||
}
|
||||
defer switch (self.stderr_action) {
|
||||
.expect_exact, .expect_matches => self.builder.allocator.free(stderr),
|
||||
.inherit, .ignore => {},
|
||||
};
|
||||
|
||||
const term = child.wait() catch |err| {
|
||||
warn("Unable to spawn {}: {}\n", .{ argv[0], @errorName(err) });
|
||||
@ -222,7 +218,7 @@ pub const RunStep = struct {
|
||||
switch (self.stderr_action) {
|
||||
.inherit, .ignore => {},
|
||||
.expect_exact => |expected_bytes| {
|
||||
if (!mem.eql(u8, expected_bytes, stderr)) {
|
||||
if (!mem.eql(u8, expected_bytes, stderr.?)) {
|
||||
warn(
|
||||
\\
|
||||
\\========= Expected this stderr: =========
|
||||
@ -230,13 +226,13 @@ pub const RunStep = struct {
|
||||
\\========= But found: ====================
|
||||
\\{}
|
||||
\\
|
||||
, .{ expected_bytes, stderr });
|
||||
, .{ expected_bytes, stderr.? });
|
||||
printCmd(cwd, argv);
|
||||
return error.TestFailed;
|
||||
}
|
||||
},
|
||||
.expect_matches => |matches| for (matches) |match| {
|
||||
if (mem.indexOf(u8, stderr, match) == null) {
|
||||
if (mem.indexOf(u8, stderr.?, match) == null) {
|
||||
warn(
|
||||
\\
|
||||
\\========= Expected to find in stderr: =========
|
||||
@ -244,7 +240,7 @@ pub const RunStep = struct {
|
||||
\\========= But stderr does not contain it: =====
|
||||
\\{}
|
||||
\\
|
||||
, .{ match, stderr });
|
||||
, .{ match, stderr.? });
|
||||
printCmd(cwd, argv);
|
||||
return error.TestFailed;
|
||||
}
|
||||
@ -254,7 +250,7 @@ pub const RunStep = struct {
|
||||
switch (self.stdout_action) {
|
||||
.inherit, .ignore => {},
|
||||
.expect_exact => |expected_bytes| {
|
||||
if (!mem.eql(u8, expected_bytes, stdout)) {
|
||||
if (!mem.eql(u8, expected_bytes, stdout.?)) {
|
||||
warn(
|
||||
\\
|
||||
\\========= Expected this stdout: =========
|
||||
@ -262,13 +258,13 @@ pub const RunStep = struct {
|
||||
\\========= But found: ====================
|
||||
\\{}
|
||||
\\
|
||||
, .{ expected_bytes, stdout });
|
||||
, .{ expected_bytes, stdout.? });
|
||||
printCmd(cwd, argv);
|
||||
return error.TestFailed;
|
||||
}
|
||||
},
|
||||
.expect_matches => |matches| for (matches) |match| {
|
||||
if (mem.indexOf(u8, stdout, match) == null) {
|
||||
if (mem.indexOf(u8, stdout.?, match) == null) {
|
||||
warn(
|
||||
\\
|
||||
\\========= Expected to find in stdout: =========
|
||||
@ -276,7 +272,7 @@ pub const RunStep = struct {
|
||||
\\========= But stdout does not contain it: =====
|
||||
\\{}
|
||||
\\
|
||||
, .{ match, stdout });
|
||||
, .{ match, stdout.? });
|
||||
printCmd(cwd, argv);
|
||||
return error.TestFailed;
|
||||
}
|
||||
|
||||
@ -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,39 +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.list.ensureCapacity(1);
|
||||
buffer.list.len = 0;
|
||||
errdefer buffer.resize(0) catch unreachable; // make sure we leave buffer in a valid state on error
|
||||
buffer.list.shrink(0);
|
||||
try self.readAllArrayList(&buffer.list, max_size);
|
||||
errdefer buffer.shrink(0);
|
||||
try buffer.list.append(0);
|
||||
}
|
||||
|
||||
/// Appends to the ArrayList contents by reading from the stream until end of stream is found.
|
||||
/// If the ArrayList length would exceed `max_size`, `error.StreamTooLong` is returned and the contents
|
||||
/// read from the stream so far are lost.
|
||||
pub fn readAllArrayList(self: *Self, array_list: *std.ArrayList(u8), max_size: usize) !void {
|
||||
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 = array_list.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) {
|
||||
array_list.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 array_list.resize(new_buf_size);
|
||||
// This will trigger ArrayList to expand superlinearly at whatever its growth rate is.
|
||||
try array_list.ensureCapacity(start_index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,23 +111,17 @@ pub fn InStream(comptime ReadError: type) type {
|
||||
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.list.ensureCapacity(1);
|
||||
buffer.list.len = 0;
|
||||
errdefer buffer.resize(0) catch unreachable; // make sure we leave buffer in a valid state on error
|
||||
try self.readUntilDelimiterArrayList(&buffer.list, delimiter, max_size);
|
||||
try buffer.list.append(0);
|
||||
}
|
||||
|
||||
/// Appends to the ArrayList contents by reading from the stream until `delimiter` is found.
|
||||
/// Does not include the delimiter in the result.
|
||||
/// If the ArrayList length would exceed `max_size`, `error.StreamTooLong` is returned and the contents
|
||||
/// read from the stream so far are lost.
|
||||
pub fn readUntilDelimiterArrayList(self: *Self, array_list: *std.ArrayList(u8), delimiter: u8, max_size: usize) !void {
|
||||
/// 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();
|
||||
|
||||
@ -140,7 +141,12 @@ 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 {
|
||||
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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user