authorgravatar for iokg04@gmail.comRue04 <iokg04@gmail.com> 2026-01-03 20:32:07+01:00
committergravatar for iokg04@gmail.comRue04 <iokg04@gmail.com> 2026-01-04 03:05:34+01:00
log86a9a9048e28efc8b49d42db12db123822c3450b
tree5b1190726ce64d5f019d0dd732deaa334d398062
parent0cbaaa5eb9434eb9484bae95949a4086eb472c6a

`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

2 files changed, 94 insertions(+), 38 deletions(-)

lib/std/array_list.zig+3-4
......@@ -599,11 +599,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
599599 return if (alignment) |a| ([:s]align(a.toByteUnits()) T) else [:s]T;
600600 }
601601
602 /// Initialize with capacity to hold `num` elements.
603 /// The resulting capacity will equal `num` exactly.
604 /// Deinitialize with `deinit` or use `toOwnedSlice`.
602 /// Initialize with capacity to hold exactly `num` elements.
603 /// Deinitialize with `deinit` or `toOwnedSlice`.
605604 pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self {
606 var self = Self{};
605 var self: Self = .empty;
607606 try self.ensureTotalCapacityPrecise(gpa, num);
608607 return self;
609608 }
lib/std/multi_array_list.zig+91-34
......@@ -29,6 +29,14 @@ pub fn MultiArrayList(comptime T: type) type {
2929 .capacity = 0,
3030 };
3131
32 /// Initialize with capacity to hold exactly `num` elements.
33 /// Deinitialize with `deinit` or `toOwnedSlice`.
34 pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self {
35 var self: Self = .empty;
36 try self.setCapacity(gpa, num);
37 return self;
38 }
39
3240 const Elem = switch (@typeInfo(T)) {
3341 .@"struct" => T,
3442 .@"union" => |u| struct {
......@@ -253,31 +261,45 @@ pub fn MultiArrayList(comptime T: type) type {
253261 return self.slice().get(index);
254262 }
255263
256 /// Extend the list by 1 element. Allocates more memory as necessary.
257 pub fn append(self: *Self, gpa: Allocator, elem: T) !void {
264 /// Extend the list by 1 element.
265 ///
266 /// Allocates more memory as necessary.
267 pub fn append(self: *Self, gpa: Allocator, elem: T) Allocator.Error!void {
258268 try self.ensureUnusedCapacity(gpa, 1);
259269 self.appendAssumeCapacity(elem);
260270 }
261271
262 /// Extend the list by 1 element, but asserting `self.capacity`
263 /// is sufficient to hold an additional item.
272 /// Extend the list by 1 element.
273 ///
274 /// Asserts that capacity is sufficient to hold an additional item.
264275 pub fn appendAssumeCapacity(self: *Self, elem: T) void {
265276 assert(self.len < self.capacity);
266277 self.len += 1;
267278 self.set(self.len - 1, elem);
268279 }
269280
281 /// Extend the list by 1 element.
282 ///
283 /// If capacity is not sufficient to hold an additional
284 /// item, returns `error.OutOfMemory`.
285 pub fn appendBounded(self: *Self, elem: T) error{OutOfMemory}!void {
286 if (self.capacity - self.len < 1) return error.OutOfMemory;
287 return appendAssumeCapacity(self, elem);
288 }
289
270290 /// Extend the list by 1 element, returning the newly reserved
271291 /// index with uninitialized data.
272 /// Allocates more memory as necesasry.
292 ///
293 /// Allocates more memory as necessary.
273294 pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!usize {
274295 try self.ensureUnusedCapacity(gpa, 1);
275296 return self.addOneAssumeCapacity();
276297 }
277298
278 /// Extend the list by 1 element, asserting `self.capacity`
279 /// is sufficient to hold an additional item. Returns the
280 /// newly reserved index with uninitialized data.
299 /// Extend the list by 1 element, returning the newly reserved
300 /// index with uninitialized data.
301 ///
302 /// Asserts that capacity is sufficient to hold an additional item.
281303 pub fn addOneAssumeCapacity(self: *Self) usize {
282304 assert(self.len < self.capacity);
283305 const index = self.len;
......@@ -285,6 +307,16 @@ pub fn MultiArrayList(comptime T: type) type {
285307 return index;
286308 }
287309
310 /// Extend the list by 1 element, returning the newly reserved
311 /// index with uninitialized data.
312 ///
313 /// If capacity is not sufficient to hold an additional
314 /// item, returns `error.OutOfMemory`.
315 pub fn addOneBounded(self: *Self) error{OutOfMemory}!usize {
316 if (self.capacity - self.len < 1) return error.OutOfMemory;
317 return addOneAssumeCapacity(self);
318 }
319
288320 /// Remove and return the last element from the list, or return `null` if list is empty.
289321 /// Invalidates pointers to fields of the removed element.
290322 pub fn pop(self: *Self) ?T {
......@@ -294,19 +326,21 @@ pub fn MultiArrayList(comptime T: type) type {
294326 return val;
295327 }
296328
297 /// Inserts an item into an ordered list. Shifts all elements
329 /// Inserts an item into the list. Shifts all elements
298330 /// after and including the specified index back by one and
299 /// sets the given index to the specified element. May reallocate
300 /// and invalidate iterators.
331 /// sets the given index to the specified element.
332 ///
333 /// Allocates more memory as necessary.
301334 pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: T) !void {
302335 try self.ensureUnusedCapacity(gpa, 1);
303336 self.insertAssumeCapacity(index, elem);
304337 }
305338
306 /// Inserts an item into an ordered list which has room for it.
307 /// Shifts all elements after and including the specified index
308 /// back by one and sets the given index to the specified element.
309 /// Will not reallocate the array, does not invalidate iterators.
339 /// Inserts an item into the list. Shifts all elements
340 /// after and including the specified index back by one and
341 /// sets the given index to the specified element.
342 ///
343 /// Asserts that capacity is sufficient to hold an additional item.
310344 pub fn insertAssumeCapacity(self: *Self, index: usize, elem: T) void {
311345 assert(self.len < self.capacity);
312346 assert(index <= self.len);
......@@ -327,8 +361,19 @@ pub fn MultiArrayList(comptime T: type) type {
327361 }
328362 }
329363
364 /// Inserts an item into the list. Shifts all elements
365 /// after and including the specified index back by one and
366 /// sets the given index to the specified element.
367 ///
368 /// If capacity is not sufficient to hold an additional
369 /// item, returns `error.OutOfMemory`.
370 pub fn insertBounded(self: *Self, index: usize, elem: T) error{OutOfMemory}!void {
371 if (self.capacity - self.len < 1) return error.OutOfMemory;
372 return insertAssumeCapacity(self, index, elem);
373 }
374
330375 /// Remove the specified item from the list, swapping the last
331 /// item in the list into its position. Fast, but does not
376 /// item in the list into its position. Fast, but does not
332377 /// retain list ordering.
333378 pub fn swapRemove(self: *Self, index: usize) void {
334379 const slices = self.slice();
......@@ -393,7 +438,7 @@ pub fn MultiArrayList(comptime T: type) type {
393438
394439 /// Adjust the list's length to `new_len`.
395440 /// Does not initialize added items, if any.
396 pub fn resize(self: *Self, gpa: Allocator, new_len: usize) !void {
441 pub fn resize(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void {
397442 try self.ensureTotalCapacity(gpa, new_len);
398443 self.len = new_len;
399444 }
......@@ -479,14 +524,14 @@ pub fn MultiArrayList(comptime T: type) type {
479524
480525 /// Modify the array so that it can hold at least `additional_count` **more** items.
481526 /// Invalidates pointers if additional memory is needed.
482 pub fn ensureUnusedCapacity(self: *Self, gpa: Allocator, additional_count: usize) !void {
527 pub fn ensureUnusedCapacity(self: *Self, gpa: Allocator, additional_count: usize) Allocator.Error!void {
483528 return self.ensureTotalCapacity(gpa, self.len + additional_count);
484529 }
485530
486531 /// Modify the array so that it can hold exactly `new_capacity` items.
487532 /// Invalidates pointers if additional memory is needed.
488533 /// `new_capacity` must be greater or equal to `len`.
489 pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) !void {
534 pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {
490535 assert(new_capacity >= self.len);
491536 const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity));
492537 if (self.len == 0) {
......@@ -514,7 +559,7 @@ pub fn MultiArrayList(comptime T: type) type {
514559
515560 /// Create a copy of this list with a new backing store,
516561 /// using the specified allocator.
517 pub fn clone(self: Self, gpa: Allocator) !Self {
562 pub fn clone(self: Self, gpa: Allocator) Allocator.Error!Self {
518563 var result = Self{};
519564 errdefer result.deinit(gpa);
520565 try result.ensureTotalCapacity(gpa, self.len);
......@@ -654,7 +699,7 @@ test "basic usage" {
654699 c: u8,
655700 };
656701
657 var list = MultiArrayList(Foo){};
702 var list: MultiArrayList(Foo) = .empty;
658703 defer list.deinit(ally);
659704
660705 try testing.expectEqual(@as(usize, 0), list.items(.a).len);
......@@ -667,7 +712,7 @@ test "basic usage" {
667712 .c = 'a',
668713 });
669714
670 list.appendAssumeCapacity(.{
715 try list.appendBounded(.{
671716 .a = 2,
672717 .b = "zigzag",
673718 .c = 'b',
......@@ -725,6 +770,8 @@ test "basic usage" {
725770 try testing.expectEqualStrings("zigzag", list.items(.b)[1]);
726771 try testing.expectEqualStrings("fizzbuzz", list.items(.b)[2]);
727772
773 try testing.expectError(error.OutOfMemory, list.addOneBounded());
774
728775 list.set(try list.addOne(ally), .{
729776 .a = 4,
730777 .b = "xnopyt",
......@@ -749,10 +796,10 @@ test "basic usage" {
749796// function used the @reduce code path.
750797test "regression test for @reduce bug" {
751798 const ally = testing.allocator;
752 var list = MultiArrayList(struct {
799 var list: MultiArrayList(struct {
753800 tag: std.zig.Token.Tag,
754801 start: u32,
755 }){};
802 }) = .empty;
756803 defer list.deinit(ally);
757804
758805 try list.ensureTotalCapacity(ally, 20);
......@@ -832,7 +879,7 @@ test "ensure capacity on empty list" {
832879 b: u8,
833880 };
834881
835 var list = MultiArrayList(Foo){};
882 var list: MultiArrayList(Foo) = .empty;
836883 defer list.deinit(ally);
837884
838885 try list.ensureTotalCapacity(ally, 2);
......@@ -867,15 +914,25 @@ test "insert elements" {
867914 b: u32,
868915 };
869916
870 var list = MultiArrayList(Foo){};
917 var list = try MultiArrayList(Foo).initCapacity(ally, 2);
871918 defer list.deinit(ally);
872919
873 try list.insert(ally, 0, .{ .a = 1, .b = 2 });
874 try list.ensureUnusedCapacity(ally, 1);
920 try list.insertBounded(0, .{ .a = 1, .b = 2 });
875921 list.insertAssumeCapacity(1, .{ .a = 2, .b = 3 });
922 try list.insert(ally, 0, .{ .a = 3, .b = 4 });
923
924 try testing.expectEqualSlices(u8, &[_]u8{ 3, 1, 2 }, list.items(.a));
925 try testing.expectEqualSlices(u32, &[_]u32{ 4, 2, 3 }, list.items(.b));
926}
927
928test "initCapacity" {
929 const gpa = testing.allocator;
930
931 var list = try MultiArrayList(struct { a: u8, b: u32 }).initCapacity(gpa, 404);
932 defer list.deinit(gpa);
876933
877 try testing.expectEqualSlices(u8, &[_]u8{ 1, 2 }, list.items(.a));
878 try testing.expectEqualSlices(u32, &[_]u32{ 2, 3 }, list.items(.b));
934 try testing.expectEqual(0, list.len);
935 try testing.expectEqual(404, list.capacity);
879936}
880937
881938test "union" {
......@@ -886,7 +943,7 @@ test "union" {
886943 b: []const u8,
887944 };
888945
889 var list = MultiArrayList(Foo){};
946 var list: MultiArrayList(Foo) = .empty;
890947 defer list.deinit(ally);
891948
892949 try testing.expectEqual(@as(usize, 0), list.items(.tags).len);
......@@ -934,7 +991,7 @@ test "union" {
934991}
935992
936993test "sorting a span" {
937 var list: MultiArrayList(struct { score: u32, chr: u8 }) = .{};
994 var list: MultiArrayList(struct { score: u32, chr: u8 }) = .empty;
938995 defer list.deinit(testing.allocator);
939996
940997 try list.ensureTotalCapacity(testing.allocator, 42);
......@@ -981,7 +1038,7 @@ test "0 sized struct field" {
9811038 b: f32,
9821039 };
9831040
984 var list = MultiArrayList(Foo){};
1041 var list: MultiArrayList(Foo) = .empty;
9851042 defer list.deinit(ally);
9861043
9871044 try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a));
......@@ -1007,7 +1064,7 @@ test "0 sized struct" {
10071064 a: u0,
10081065 };
10091066
1010 var list = MultiArrayList(Foo){};
1067 var list: MultiArrayList(Foo) = .empty;
10111068 defer list.deinit(ally);
10121069
10131070 try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a));