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 {...@@ -599,11 +599,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
599 return if (alignment) |a| ([:s]align(a.toByteUnits()) T) else [:s]T;599 return if (alignment) |a| ([:s]align(a.toByteUnits()) T) else [:s]T;
600 }600 }
601601
602 /// Initialize with capacity to hold `num` elements.602 /// Initialize with capacity to hold exactly `num` elements.
603 /// The resulting capacity will equal `num` exactly.603 /// Deinitialize with `deinit` or `toOwnedSlice`.
604 /// Deinitialize with `deinit` or use `toOwnedSlice`.
605 pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self {604 pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self {
606 var self = Self{};605 var self: Self = .empty;
607 try self.ensureTotalCapacityPrecise(gpa, num);606 try self.ensureTotalCapacityPrecise(gpa, num);
608 return self;607 return self;
609 }608 }
lib/std/multi_array_list.zig+91-34
...@@ -29,6 +29,14 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -29,6 +29,14 @@ pub fn MultiArrayList(comptime T: type) type {
29 .capacity = 0,29 .capacity = 0,
30 };30 };
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
32 const Elem = switch (@typeInfo(T)) {40 const Elem = switch (@typeInfo(T)) {
33 .@"struct" => T,41 .@"struct" => T,
34 .@"union" => |u| struct {42 .@"union" => |u| struct {
...@@ -253,31 +261,45 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -253,31 +261,45 @@ pub fn MultiArrayList(comptime T: type) type {
253 return self.slice().get(index);261 return self.slice().get(index);
254 }262 }
255263
256 /// Extend the list by 1 element. Allocates more memory as necessary.264 /// Extend the list by 1 element.
257 pub fn append(self: *Self, gpa: Allocator, elem: T) !void {265 ///
266 /// Allocates more memory as necessary.
267 pub fn append(self: *Self, gpa: Allocator, elem: T) Allocator.Error!void {
258 try self.ensureUnusedCapacity(gpa, 1);268 try self.ensureUnusedCapacity(gpa, 1);
259 self.appendAssumeCapacity(elem);269 self.appendAssumeCapacity(elem);
260 }270 }
261271
262 /// Extend the list by 1 element, but asserting `self.capacity`272 /// Extend the list by 1 element.
263 /// is sufficient to hold an additional item.273 ///
274 /// Asserts that capacity is sufficient to hold an additional item.
264 pub fn appendAssumeCapacity(self: *Self, elem: T) void {275 pub fn appendAssumeCapacity(self: *Self, elem: T) void {
265 assert(self.len < self.capacity);276 assert(self.len < self.capacity);
266 self.len += 1;277 self.len += 1;
267 self.set(self.len - 1, elem);278 self.set(self.len - 1, elem);
268 }279 }
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
270 /// Extend the list by 1 element, returning the newly reserved290 /// Extend the list by 1 element, returning the newly reserved
271 /// index with uninitialized data.291 /// index with uninitialized data.
272 /// Allocates more memory as necesasry.292 ///
293 /// Allocates more memory as necessary.
273 pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!usize {294 pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!usize {
274 try self.ensureUnusedCapacity(gpa, 1);295 try self.ensureUnusedCapacity(gpa, 1);
275 return self.addOneAssumeCapacity();296 return self.addOneAssumeCapacity();
276 }297 }
277298
278 /// Extend the list by 1 element, asserting `self.capacity`299 /// Extend the list by 1 element, returning the newly reserved
279 /// is sufficient to hold an additional item. Returns the300 /// index with uninitialized data.
280 /// newly reserved index with uninitialized data.301 ///
302 /// Asserts that capacity is sufficient to hold an additional item.
281 pub fn addOneAssumeCapacity(self: *Self) usize {303 pub fn addOneAssumeCapacity(self: *Self) usize {
282 assert(self.len < self.capacity);304 assert(self.len < self.capacity);
283 const index = self.len;305 const index = self.len;
...@@ -285,6 +307,16 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -285,6 +307,16 @@ pub fn MultiArrayList(comptime T: type) type {
285 return index;307 return index;
286 }308 }
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
288 /// Remove and return the last element from the list, or return `null` if list is empty.320 /// Remove and return the last element from the list, or return `null` if list is empty.
289 /// Invalidates pointers to fields of the removed element.321 /// Invalidates pointers to fields of the removed element.
290 pub fn pop(self: *Self) ?T {322 pub fn pop(self: *Self) ?T {
...@@ -294,19 +326,21 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -294,19 +326,21 @@ pub fn MultiArrayList(comptime T: type) type {
294 return val;326 return val;
295 }327 }
296328
297 /// Inserts an item into an ordered list. Shifts all elements329 /// Inserts an item into the list. Shifts all elements
298 /// after and including the specified index back by one and330 /// after and including the specified index back by one and
299 /// sets the given index to the specified element. May reallocate331 /// sets the given index to the specified element.
300 /// and invalidate iterators.332 ///
333 /// Allocates more memory as necessary.
301 pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: T) !void {334 pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: T) !void {
302 try self.ensureUnusedCapacity(gpa, 1);335 try self.ensureUnusedCapacity(gpa, 1);
303 self.insertAssumeCapacity(index, elem);336 self.insertAssumeCapacity(index, elem);
304 }337 }
305338
306 /// Inserts an item into an ordered list which has room for it.339 /// Inserts an item into the list. Shifts all elements
307 /// Shifts all elements after and including the specified index340 /// after and including the specified index back by one and
308 /// back by one and sets the given index to the specified element.341 /// sets the given index to the specified element.
309 /// Will not reallocate the array, does not invalidate iterators.342 ///
343 /// Asserts that capacity is sufficient to hold an additional item.
310 pub fn insertAssumeCapacity(self: *Self, index: usize, elem: T) void {344 pub fn insertAssumeCapacity(self: *Self, index: usize, elem: T) void {
311 assert(self.len < self.capacity);345 assert(self.len < self.capacity);
312 assert(index <= self.len);346 assert(index <= self.len);
...@@ -327,8 +361,19 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -327,8 +361,19 @@ pub fn MultiArrayList(comptime T: type) type {
327 }361 }
328 }362 }
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
330 /// Remove the specified item from the list, swapping the last375 /// Remove the specified item from the list, swapping the last
331 /// item in the list into its position. Fast, but does not376 /// item in the list into its position. Fast, but does not
332 /// retain list ordering.377 /// retain list ordering.
333 pub fn swapRemove(self: *Self, index: usize) void {378 pub fn swapRemove(self: *Self, index: usize) void {
334 const slices = self.slice();379 const slices = self.slice();
...@@ -393,7 +438,7 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -393,7 +438,7 @@ pub fn MultiArrayList(comptime T: type) type {
393438
394 /// Adjust the list's length to `new_len`.439 /// Adjust the list's length to `new_len`.
395 /// Does not initialize added items, if any.440 /// 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 {
397 try self.ensureTotalCapacity(gpa, new_len);442 try self.ensureTotalCapacity(gpa, new_len);
398 self.len = new_len;443 self.len = new_len;
399 }444 }
...@@ -479,14 +524,14 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -479,14 +524,14 @@ pub fn MultiArrayList(comptime T: type) type {
479524
480 /// Modify the array so that it can hold at least `additional_count` **more** items.525 /// Modify the array so that it can hold at least `additional_count` **more** items.
481 /// Invalidates pointers if additional memory is needed.526 /// 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 {
483 return self.ensureTotalCapacity(gpa, self.len + additional_count);528 return self.ensureTotalCapacity(gpa, self.len + additional_count);
484 }529 }
485530
486 /// Modify the array so that it can hold exactly `new_capacity` items.531 /// Modify the array so that it can hold exactly `new_capacity` items.
487 /// Invalidates pointers if additional memory is needed.532 /// Invalidates pointers if additional memory is needed.
488 /// `new_capacity` must be greater or equal to `len`.533 /// `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 {
490 assert(new_capacity >= self.len);535 assert(new_capacity >= self.len);
491 const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity));536 const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity));
492 if (self.len == 0) {537 if (self.len == 0) {
...@@ -514,7 +559,7 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -514,7 +559,7 @@ pub fn MultiArrayList(comptime T: type) type {
514559
515 /// Create a copy of this list with a new backing store,560 /// Create a copy of this list with a new backing store,
516 /// using the specified allocator.561 /// using the specified allocator.
517 pub fn clone(self: Self, gpa: Allocator) !Self {562 pub fn clone(self: Self, gpa: Allocator) Allocator.Error!Self {
518 var result = Self{};563 var result = Self{};
519 errdefer result.deinit(gpa);564 errdefer result.deinit(gpa);
520 try result.ensureTotalCapacity(gpa, self.len);565 try result.ensureTotalCapacity(gpa, self.len);
...@@ -654,7 +699,7 @@ test "basic usage" {...@@ -654,7 +699,7 @@ test "basic usage" {
654 c: u8,699 c: u8,
655 };700 };
656701
657 var list = MultiArrayList(Foo){};702 var list: MultiArrayList(Foo) = .empty;
658 defer list.deinit(ally);703 defer list.deinit(ally);
659704
660 try testing.expectEqual(@as(usize, 0), list.items(.a).len);705 try testing.expectEqual(@as(usize, 0), list.items(.a).len);
...@@ -667,7 +712,7 @@ test "basic usage" {...@@ -667,7 +712,7 @@ test "basic usage" {
667 .c = 'a',712 .c = 'a',
668 });713 });
669714
670 list.appendAssumeCapacity(.{715 try list.appendBounded(.{
671 .a = 2,716 .a = 2,
672 .b = "zigzag",717 .b = "zigzag",
673 .c = 'b',718 .c = 'b',
...@@ -725,6 +770,8 @@ test "basic usage" {...@@ -725,6 +770,8 @@ test "basic usage" {
725 try testing.expectEqualStrings("zigzag", list.items(.b)[1]);770 try testing.expectEqualStrings("zigzag", list.items(.b)[1]);
726 try testing.expectEqualStrings("fizzbuzz", list.items(.b)[2]);771 try testing.expectEqualStrings("fizzbuzz", list.items(.b)[2]);
727772
773 try testing.expectError(error.OutOfMemory, list.addOneBounded());
774
728 list.set(try list.addOne(ally), .{775 list.set(try list.addOne(ally), .{
729 .a = 4,776 .a = 4,
730 .b = "xnopyt",777 .b = "xnopyt",
...@@ -749,10 +796,10 @@ test "basic usage" {...@@ -749,10 +796,10 @@ test "basic usage" {
749// function used the @reduce code path.796// function used the @reduce code path.
750test "regression test for @reduce bug" {797test "regression test for @reduce bug" {
751 const ally = testing.allocator;798 const ally = testing.allocator;
752 var list = MultiArrayList(struct {799 var list: MultiArrayList(struct {
753 tag: std.zig.Token.Tag,800 tag: std.zig.Token.Tag,
754 start: u32,801 start: u32,
755 }){};802 }) = .empty;
756 defer list.deinit(ally);803 defer list.deinit(ally);
757804
758 try list.ensureTotalCapacity(ally, 20);805 try list.ensureTotalCapacity(ally, 20);
...@@ -832,7 +879,7 @@ test "ensure capacity on empty list" {...@@ -832,7 +879,7 @@ test "ensure capacity on empty list" {
832 b: u8,879 b: u8,
833 };880 };
834881
835 var list = MultiArrayList(Foo){};882 var list: MultiArrayList(Foo) = .empty;
836 defer list.deinit(ally);883 defer list.deinit(ally);
837884
838 try list.ensureTotalCapacity(ally, 2);885 try list.ensureTotalCapacity(ally, 2);
...@@ -867,15 +914,25 @@ test "insert elements" {...@@ -867,15 +914,25 @@ test "insert elements" {
867 b: u32,914 b: u32,
868 };915 };
869916
870 var list = MultiArrayList(Foo){};917 var list = try MultiArrayList(Foo).initCapacity(ally, 2);
871 defer list.deinit(ally);918 defer list.deinit(ally);
872919
873 try list.insert(ally, 0, .{ .a = 1, .b = 2 });920 try list.insertBounded(0, .{ .a = 1, .b = 2 });
874 try list.ensureUnusedCapacity(ally, 1);
875 list.insertAssumeCapacity(1, .{ .a = 2, .b = 3 });921 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));934 try testing.expectEqual(0, list.len);
878 try testing.expectEqualSlices(u32, &[_]u32{ 2, 3 }, list.items(.b));935 try testing.expectEqual(404, list.capacity);
879}936}
880937
881test "union" {938test "union" {
...@@ -886,7 +943,7 @@ test "union" {...@@ -886,7 +943,7 @@ test "union" {
886 b: []const u8,943 b: []const u8,
887 };944 };
888945
889 var list = MultiArrayList(Foo){};946 var list: MultiArrayList(Foo) = .empty;
890 defer list.deinit(ally);947 defer list.deinit(ally);
891948
892 try testing.expectEqual(@as(usize, 0), list.items(.tags).len);949 try testing.expectEqual(@as(usize, 0), list.items(.tags).len);
...@@ -934,7 +991,7 @@ test "union" {...@@ -934,7 +991,7 @@ test "union" {
934}991}
935992
936test "sorting a span" {993test "sorting a span" {
937 var list: MultiArrayList(struct { score: u32, chr: u8 }) = .{};994 var list: MultiArrayList(struct { score: u32, chr: u8 }) = .empty;
938 defer list.deinit(testing.allocator);995 defer list.deinit(testing.allocator);
939996
940 try list.ensureTotalCapacity(testing.allocator, 42);997 try list.ensureTotalCapacity(testing.allocator, 42);
...@@ -981,7 +1038,7 @@ test "0 sized struct field" {...@@ -981,7 +1038,7 @@ test "0 sized struct field" {
981 b: f32,1038 b: f32,
982 };1039 };
9831040
984 var list = MultiArrayList(Foo){};1041 var list: MultiArrayList(Foo) = .empty;
985 defer list.deinit(ally);1042 defer list.deinit(ally);
9861043
987 try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a));1044 try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a));
...@@ -1007,7 +1064,7 @@ test "0 sized struct" {...@@ -1007,7 +1064,7 @@ test "0 sized struct" {
1007 a: u0,1064 a: u0,
1008 };1065 };
10091066
1010 var list = MultiArrayList(Foo){};1067 var list: MultiArrayList(Foo) = .empty;
1011 defer list.deinit(ally);1068 defer list.deinit(ally);
10121069
1013 try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a));1070 try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a));