Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some documentation for standard library things. #3540

Merged
merged 2 commits into from Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions lib/std/array_list.zig
Expand Up @@ -5,6 +5,10 @@ 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`.
pub fn ArrayList(comptime T: type) type {
return AlignedArrayList(T, null);
}
Expand Down Expand Up @@ -37,18 +41,24 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
};
}

/// Release all allocated memory.
pub fn deinit(self: Self) void {
self.allocator.free(self.items);
}

/// Return contents as a slice. Only valid while the list
/// doesn't change size.
pub fn toSlice(self: Self) Slice {
return self.items[0..self.len];
}

/// Return list as const slice. Only valid while the list
/// doesn't change size.
pub fn toSliceConst(self: Self) SliceConst {
return self.items[0..self.len];
}

/// Safely access index i of the list.
pub fn at(self: Self, i: usize) T {
return self.toSliceConst()[i];
}
Expand All @@ -66,10 +76,13 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
self.items[i] = item;
}

/// Return length of the list.
pub fn count(self: Self) usize {
return self.len;
}

/// Return the maximum number of items the list can hold
/// without allocating more memory.
pub fn capacity(self: Self) usize {
return self.items.len;
}
Expand All @@ -93,6 +106,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
return result;
}

/// Insert `item` at index `n`. Moves `list[n .. list.count()]`
/// to make room.
pub fn insert(self: *Self, n: usize, item: T) !void {
try self.ensureCapacity(self.len + 1);
self.len += 1;
Expand All @@ -101,6 +116,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
self.items[n] = item;
}

/// Insert slice `items` at index `n`. Moves
/// `list[n .. list.count()]` to make room.
pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void {
try self.ensureCapacity(self.len + items.len);
self.len += items.len;
Expand All @@ -109,16 +126,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
mem.copy(T, self.items[n .. n + items.len], items);
}

/// 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;
}

/// Extend the list by 1 element, but asserting `self.capacity`
/// is sufficient to hold an additional item.
pub fn appendAssumeCapacity(self: *Self, item: T) void {
const new_item_ptr = self.addOneAssumeCapacity();
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.
pub fn orderedRemove(self: *Self, i: usize) T {
const newlen = self.len - 1;
if (newlen == i) return self.pop();
Expand Down Expand Up @@ -149,17 +172,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
return self.swapRemove(i);
}

/// Append the slice of items to the list. Allocates more
/// memory as necessary.
pub fn appendSlice(self: *Self, items: SliceConst) !void {
try self.ensureCapacity(self.len + items.len);
mem.copy(T, self.items[self.len..], items);
self.len += items.len;
}

/// Adjust the list's length to `new_len`. Doesn't initialize
/// added items if any.
pub fn resize(self: *Self, new_len: usize) !void {
try self.ensureCapacity(new_len);
self.len = new_len;
}

/// Reduce allocated capacity to `new_len`.
pub fn shrink(self: *Self, new_len: usize) void {
assert(new_len <= self.len);
self.len = new_len;
Expand All @@ -178,6 +206,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
self.items = try self.allocator.realloc(self.items, better_capacity);
}

/// Increase length by 1, returning pointer to the new item.
pub fn addOne(self: *Self) !*T {
const new_length = self.len + 1;
try self.ensureCapacity(new_length);
Expand All @@ -191,11 +220,14 @@ 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.
pub fn pop(self: *Self) T {
self.len -= 1;
return self.items[self.len];
}

/// Like `pop` but returns `null` if empty.
pub fn popOrNull(self: *Self) ?T {
if (self.len == 0) return null;
return self.pop();
Expand All @@ -218,6 +250,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
}
};

/// Return an iterator over the list.
pub fn iterator(self: *const Self) Iterator {
return Iterator{
.list = self,
Expand Down
16 changes: 16 additions & 0 deletions lib/std/debug/failing_allocator.zig
Expand Up @@ -3,6 +3,14 @@ const mem = std.mem;

/// Allocator that fails after N allocations, useful for making sure out of
/// memory conditions are handled correctly.
///
/// To use this, first initialize it and get an allocator with
///
/// `const failing_allocator = &FailingAllocator.init(<allocator>,
/// <fail_index>).allocator;`
///
/// Then use `failing_allocator` anywhere you would have used a
/// different allocator.
pub const FailingAllocator = struct {
allocator: mem.Allocator,
index: usize,
Expand All @@ -13,6 +21,14 @@ pub const FailingAllocator = struct {
allocations: usize,
deallocations: usize,

/// `fail_index` is the number of successful allocations you can
/// expect from this allocator. The next allocation will fail.
/// For example, if this is called with `fail_index` equal to 2,
/// the following test will pass:
///
/// var a = try failing_alloc.create(i32);
/// var b = try failing_alloc.create(i32);
/// testing.expectError(error.OutOfMemory, failing_alloc.create(i32));
pub fn init(allocator: *mem.Allocator, fail_index: usize) FailingAllocator {
return FailingAllocator{
.internal_allocator = allocator,
Expand Down
10 changes: 10 additions & 0 deletions lib/std/mem.zig
Expand Up @@ -93,6 +93,14 @@ pub const Allocator = struct {
assert(shrink_result.len == 0);
}

/// Allocates an array of `n` items of type `T` and sets all the
/// items to `undefined`. Depending on the Allocator
/// implementation, it may be required to call `free` once the
/// memory is no longer needed, to avoid a resource leak. If the
/// `Allocator` implementation is unknown, then correct code will
/// call `free` when done.
///
/// For allocating a single item, see `create`.
pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
return self.alignedAlloc(T, null, n);
}
Expand Down Expand Up @@ -218,6 +226,8 @@ pub const Allocator = struct {
return @bytesToSlice(T, @alignCast(new_alignment, byte_slice));
}

/// Free an array allocated with `alloc`. To free a single item,
/// see `destroy`.
pub fn free(self: *Allocator, memory: var) void {
const Slice = @typeInfo(@typeOf(memory)).Pointer;
const bytes = @sliceToBytes(memory);
Expand Down