zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 86a9a9048e28efc8b49d42db12db123822c3450b (tree)
parent 0cbaaa5eb9434eb9484bae95949a4086eb472c6a
Author: Rue04 <iokg04@gmail.com>
Date:   Sat,  3 Jan 2026 20:32:07 +0100

`std.MultiArrayList`: add `*Bounded` variants and `initCapacity`

Because I accidentially squished two commit and can't figure out how to separate them
again, this also
- standardizes some doc-comments
- makes a slight change to `std.ArrayList`'s `initCapacity`'s doc-comment

Diffstat:
Mlib/std/array_list.zig | 7+++----
Mlib/std/multi_array_list.zig | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
2 files changed, 94 insertions(+), 38 deletions(-)

diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig @@ -599,11 +599,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { return if (alignment) |a| ([:s]align(a.toByteUnits()) T) else [:s]T; } - /// Initialize with capacity to hold `num` elements. - /// The resulting capacity will equal `num` exactly. - /// Deinitialize with `deinit` or use `toOwnedSlice`. + /// Initialize with capacity to hold exactly `num` elements. + /// Deinitialize with `deinit` or `toOwnedSlice`. pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self { - var self = Self{}; + var self: Self = .empty; try self.ensureTotalCapacityPrecise(gpa, num); return self; } diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig @@ -29,6 +29,14 @@ pub fn MultiArrayList(comptime T: type) type { .capacity = 0, }; + /// Initialize with capacity to hold exactly `num` elements. + /// Deinitialize with `deinit` or `toOwnedSlice`. + pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self { + var self: Self = .empty; + try self.setCapacity(gpa, num); + return self; + } + const Elem = switch (@typeInfo(T)) { .@"struct" => T, .@"union" => |u| struct { @@ -253,31 +261,45 @@ pub fn MultiArrayList(comptime T: type) type { return self.slice().get(index); } - /// Extend the list by 1 element. Allocates more memory as necessary. - pub fn append(self: *Self, gpa: Allocator, elem: T) !void { + /// Extend the list by 1 element. + /// + /// Allocates more memory as necessary. + pub fn append(self: *Self, gpa: Allocator, elem: T) Allocator.Error!void { try self.ensureUnusedCapacity(gpa, 1); self.appendAssumeCapacity(elem); } - /// Extend the list by 1 element, but asserting `self.capacity` - /// is sufficient to hold an additional item. + /// Extend the list by 1 element. + /// + /// Asserts that capacity is sufficient to hold an additional item. pub fn appendAssumeCapacity(self: *Self, elem: T) void { assert(self.len < self.capacity); self.len += 1; self.set(self.len - 1, elem); } + /// Extend the list by 1 element. + /// + /// If capacity is not sufficient to hold an additional + /// item, returns `error.OutOfMemory`. + pub fn appendBounded(self: *Self, elem: T) error{OutOfMemory}!void { + if (self.capacity - self.len < 1) return error.OutOfMemory; + return appendAssumeCapacity(self, elem); + } + /// Extend the list by 1 element, returning the newly reserved /// index with uninitialized data. - /// Allocates more memory as necesasry. + /// + /// Allocates more memory as necessary. pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!usize { try self.ensureUnusedCapacity(gpa, 1); return self.addOneAssumeCapacity(); } - /// Extend the list by 1 element, asserting `self.capacity` - /// is sufficient to hold an additional item. Returns the - /// newly reserved index with uninitialized data. + /// Extend the list by 1 element, returning the newly reserved + /// index with uninitialized data. + /// + /// Asserts that capacity is sufficient to hold an additional item. pub fn addOneAssumeCapacity(self: *Self) usize { assert(self.len < self.capacity); const index = self.len; @@ -285,6 +307,16 @@ pub fn MultiArrayList(comptime T: type) type { return index; } + /// Extend the list by 1 element, returning the newly reserved + /// index with uninitialized data. + /// + /// If capacity is not sufficient to hold an additional + /// item, returns `error.OutOfMemory`. + pub fn addOneBounded(self: *Self) error{OutOfMemory}!usize { + if (self.capacity - self.len < 1) return error.OutOfMemory; + return addOneAssumeCapacity(self); + } + /// Remove and return the last element from the list, or return `null` if list is empty. /// Invalidates pointers to fields of the removed element. pub fn pop(self: *Self) ?T { @@ -294,19 +326,21 @@ pub fn MultiArrayList(comptime T: type) type { return val; } - /// Inserts an item into an ordered list. Shifts all elements + /// Inserts an item into the list. Shifts all elements /// after and including the specified index back by one and - /// sets the given index to the specified element. May reallocate - /// and invalidate iterators. + /// sets the given index to the specified element. + /// + /// Allocates more memory as necessary. pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: T) !void { try self.ensureUnusedCapacity(gpa, 1); self.insertAssumeCapacity(index, elem); } - /// Inserts an item into an ordered list which has room for it. - /// Shifts all elements after and including the specified index - /// back by one and sets the given index to the specified element. - /// Will not reallocate the array, does not invalidate iterators. + /// Inserts an item into the list. Shifts all elements + /// after and including the specified index back by one and + /// sets the given index to the specified element. + /// + /// Asserts that capacity is sufficient to hold an additional item. pub fn insertAssumeCapacity(self: *Self, index: usize, elem: T) void { assert(self.len < self.capacity); assert(index <= self.len); @@ -327,8 +361,19 @@ pub fn MultiArrayList(comptime T: type) type { } } + /// Inserts an item into the list. Shifts all elements + /// after and including the specified index back by one and + /// sets the given index to the specified element. + /// + /// If capacity is not sufficient to hold an additional + /// item, returns `error.OutOfMemory`. + pub fn insertBounded(self: *Self, index: usize, elem: T) error{OutOfMemory}!void { + if (self.capacity - self.len < 1) return error.OutOfMemory; + return insertAssumeCapacity(self, index, elem); + } + /// Remove the specified item from the list, swapping the last - /// item in the list into its position. Fast, but does not + /// item in the list into its position. Fast, but does not /// retain list ordering. pub fn swapRemove(self: *Self, index: usize) void { const slices = self.slice(); @@ -393,7 +438,7 @@ pub fn MultiArrayList(comptime T: type) type { /// Adjust the list's length to `new_len`. /// Does not initialize added items, if any. - pub fn resize(self: *Self, gpa: Allocator, new_len: usize) !void { + pub fn resize(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void { try self.ensureTotalCapacity(gpa, new_len); self.len = new_len; } @@ -479,14 +524,14 @@ pub fn MultiArrayList(comptime T: type) type { /// Modify the array so that it can hold at least `additional_count` **more** items. /// Invalidates pointers if additional memory is needed. - pub fn ensureUnusedCapacity(self: *Self, gpa: Allocator, additional_count: usize) !void { + pub fn ensureUnusedCapacity(self: *Self, gpa: Allocator, additional_count: usize) Allocator.Error!void { return self.ensureTotalCapacity(gpa, self.len + additional_count); } /// Modify the array so that it can hold exactly `new_capacity` items. /// Invalidates pointers if additional memory is needed. /// `new_capacity` must be greater or equal to `len`. - pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) !void { + pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { assert(new_capacity >= self.len); const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity)); if (self.len == 0) { @@ -514,7 +559,7 @@ pub fn MultiArrayList(comptime T: type) type { /// Create a copy of this list with a new backing store, /// using the specified allocator. - pub fn clone(self: Self, gpa: Allocator) !Self { + pub fn clone(self: Self, gpa: Allocator) Allocator.Error!Self { var result = Self{}; errdefer result.deinit(gpa); try result.ensureTotalCapacity(gpa, self.len); @@ -654,7 +699,7 @@ test "basic usage" { c: u8, }; - var list = MultiArrayList(Foo){}; + var list: MultiArrayList(Foo) = .empty; defer list.deinit(ally); try testing.expectEqual(@as(usize, 0), list.items(.a).len); @@ -667,7 +712,7 @@ test "basic usage" { .c = 'a', }); - list.appendAssumeCapacity(.{ + try list.appendBounded(.{ .a = 2, .b = "zigzag", .c = 'b', @@ -725,6 +770,8 @@ test "basic usage" { try testing.expectEqualStrings("zigzag", list.items(.b)[1]); try testing.expectEqualStrings("fizzbuzz", list.items(.b)[2]); + try testing.expectError(error.OutOfMemory, list.addOneBounded()); + list.set(try list.addOne(ally), .{ .a = 4, .b = "xnopyt", @@ -749,10 +796,10 @@ test "basic usage" { // function used the @reduce code path. test "regression test for @reduce bug" { const ally = testing.allocator; - var list = MultiArrayList(struct { + var list: MultiArrayList(struct { tag: std.zig.Token.Tag, start: u32, - }){}; + }) = .empty; defer list.deinit(ally); try list.ensureTotalCapacity(ally, 20); @@ -832,7 +879,7 @@ test "ensure capacity on empty list" { b: u8, }; - var list = MultiArrayList(Foo){}; + var list: MultiArrayList(Foo) = .empty; defer list.deinit(ally); try list.ensureTotalCapacity(ally, 2); @@ -867,15 +914,25 @@ test "insert elements" { b: u32, }; - var list = MultiArrayList(Foo){}; + var list = try MultiArrayList(Foo).initCapacity(ally, 2); defer list.deinit(ally); - try list.insert(ally, 0, .{ .a = 1, .b = 2 }); - try list.ensureUnusedCapacity(ally, 1); + try list.insertBounded(0, .{ .a = 1, .b = 2 }); list.insertAssumeCapacity(1, .{ .a = 2, .b = 3 }); + try list.insert(ally, 0, .{ .a = 3, .b = 4 }); + + try testing.expectEqualSlices(u8, &[_]u8{ 3, 1, 2 }, list.items(.a)); + try testing.expectEqualSlices(u32, &[_]u32{ 4, 2, 3 }, list.items(.b)); +} + +test "initCapacity" { + const gpa = testing.allocator; + + var list = try MultiArrayList(struct { a: u8, b: u32 }).initCapacity(gpa, 404); + defer list.deinit(gpa); - try testing.expectEqualSlices(u8, &[_]u8{ 1, 2 }, list.items(.a)); - try testing.expectEqualSlices(u32, &[_]u32{ 2, 3 }, list.items(.b)); + try testing.expectEqual(0, list.len); + try testing.expectEqual(404, list.capacity); } test "union" { @@ -886,7 +943,7 @@ test "union" { b: []const u8, }; - var list = MultiArrayList(Foo){}; + var list: MultiArrayList(Foo) = .empty; defer list.deinit(ally); try testing.expectEqual(@as(usize, 0), list.items(.tags).len); @@ -934,7 +991,7 @@ test "union" { } test "sorting a span" { - var list: MultiArrayList(struct { score: u32, chr: u8 }) = .{}; + var list: MultiArrayList(struct { score: u32, chr: u8 }) = .empty; defer list.deinit(testing.allocator); try list.ensureTotalCapacity(testing.allocator, 42); @@ -981,7 +1038,7 @@ test "0 sized struct field" { b: f32, }; - var list = MultiArrayList(Foo){}; + var list: MultiArrayList(Foo) = .empty; defer list.deinit(ally); try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a)); @@ -1007,7 +1064,7 @@ test "0 sized struct" { a: u0, }; - var list = MultiArrayList(Foo){}; + var list: MultiArrayList(Foo) = .empty; defer list.deinit(ally); try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a));