Add some documentation for standard library things. (#3540)

* Add some documentation for standard library things.

Added a bunch of descriptions for array_list.
Added some usage notes for failing_allocator.
Documented some of mem.Allocator.
master
Nathan Michaels 2019-10-28 03:57:23 -04:00 committed by Andrew Kelley
parent 8af6c7e34c
commit 6fdeaac338
3 changed files with 59 additions and 0 deletions

View File

@ -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);
}
@ -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];
}
@ -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;
}
@ -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;
@ -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;
@ -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();
@ -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;
@ -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);
@ -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();
@ -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,

View File

@ -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,
@ -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,

View File

@ -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);
}
@ -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);