authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-15 22:46:27-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-15 22:46:27-08:00
logfcc94f54317f12fadffb7822cb4478f49e4045a1
treee085a7c2ce4a0af4077448e0a4bbc2b984f0a367
parent32e88251e48d9f4a412b08acbd04d5694ec91e19
parentf2721a4cbc45cf4a7ef22800ed69550c3c5dd97d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #18468 from notcancername/legalize-arraylist

std.array_list: Document and reduce illegal behavior in ArrayLists

1 files changed, 221 insertions(+), 138 deletions(-)

lib/std/array_list.zig+221-138
......@@ -10,7 +10,7 @@ const Allocator = mem.Allocator;
1010/// This is a wrapper around an array of T values. Initialize with `init`.
1111///
1212/// This struct internally stores a `std.mem.Allocator` for memory management.
13/// To manually specify an allocator with each method call see `ArrayListUnmanaged`.
13/// To manually specify an allocator with each function call see `ArrayListUnmanaged`.
1414pub fn ArrayList(comptime T: type) type {
1515 return ArrayListAligned(T, null);
1616}
......@@ -21,7 +21,7 @@ pub fn ArrayList(comptime T: type) type {
2121/// Initialize with `init`.
2222///
2323/// This struct internally stores a `std.mem.Allocator` for memory management.
24/// To manually specify an allocator with each method call see `ArrayListAlignedUnmanaged`.
24/// To manually specify an allocator with each function call see `ArrayListAlignedUnmanaged`.
2525pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
2626 if (alignment) |a| {
2727 if (a == @alignOf(T)) {
......@@ -30,15 +30,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
3030 }
3131 return struct {
3232 const Self = @This();
33 /// Contents of the list. Pointers to elements in this slice are
34 /// **invalid after resizing operations** on the ArrayList unless the
35 /// operation explicitly either: (1) states otherwise or (2) lists the
36 /// invalidated pointers.
33 /// Contents of the list. This field is intended to be accessed
34 /// directly.
3735 ///
38 /// The allocator used determines how element pointers are
39 /// invalidated, so the behavior may vary between lists. To avoid
40 /// illegal behavior, take into account the above paragraph plus the
41 /// explicit statements given in each method.
36 /// Pointers to elements in this slice are invalidated by various
37 /// functions of this ArrayList in accordance with the respective
38 /// documentation. In all cases, "invalidated" means that the memory
39 /// has been passed to this allocator's resize or free function.
4240 items: Slice,
4341 /// How many T values this list can hold without allocating
4442 /// additional memory.
......@@ -128,7 +126,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
128126
129127 /// The caller owns the returned memory. Empties this ArrayList.
130128 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
131 try self.ensureTotalCapacityPrecise(self.items.len + 1);
129 try self.ensureTotalCapacityPrecise(try addOrOom(self.items.len, 1));
132130 self.appendAssumeCapacity(sentinel);
133131 const result = try self.toOwnedSlice();
134132 return result[0 .. result.len - 1 :sentinel];
......@@ -141,25 +139,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
141139 return cloned;
142140 }
143141
144 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.
145 /// If `n` is equal to the length of the list this operation is equivalent to append.
142 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
143 /// If `i` is equal to the length of the list this operation is equivalent to append.
146144 /// This operation is O(N).
147 /// Invalidates pointers if additional memory is needed.
148 pub fn insert(self: *Self, n: usize, item: T) Allocator.Error!void {
149 const dst = try self.addManyAt(n, 1);
145 /// Invalidates element pointers if additional memory is needed.
146 /// Asserts that the index is in bounds or equal to the length.
147 pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void {
148 const dst = try self.addManyAt(i, 1);
150149 dst[0] = item;
151150 }
152151
153 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.
154 /// If `n` is equal to the length of the list this operation is equivalent to append.
152 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
153 /// If `i` is equal to the length of the list this operation is
154 /// equivalent to appendAssumeCapacity.
155155 /// This operation is O(N).
156156 /// Asserts that there is enough capacity for the new item.
157 pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void {
157 /// Asserts that the index is in bounds or equal to the length.
158 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
158159 assert(self.items.len < self.capacity);
159160 self.items.len += 1;
160161
161 mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]);
162 self.items[n] = item;
162 mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
163 self.items[i] = item;
163164 }
164165
165166 /// Add `count` new elements at position `index`, which have
......@@ -169,8 +170,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
169170 /// Invalidates pre-existing pointers to elements at and after `index`.
170171 /// Invalidates all pre-existing element pointers if capacity must be
171172 /// increased to accomodate the new elements.
173 /// Asserts that the index is in bounds or equal to the length.
172174 pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {
173 const new_len = self.items.len + count;
175 const new_len = try addOrOom(self.items.len, count);
174176
175177 if (self.capacity >= new_len)
176178 return addManyAtAssumeCapacity(self, index, count);
......@@ -208,6 +210,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
208210 /// Asserts that there is enough capacity for the new elements.
209211 /// Invalidates pre-existing pointers to elements at and after `index`, but
210212 /// does not invalidate any before that.
213 /// Asserts that the index is in bounds or equal to the length.
211214 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
212215 const new_len = self.items.len + count;
213216 assert(self.capacity >= new_len);
......@@ -224,6 +227,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
224227 /// Invalidates pre-existing pointers to elements at and after `index`.
225228 /// Invalidates all pre-existing element pointers if capacity must be
226229 /// increased to accomodate the new elements.
230 /// Asserts that the index is in bounds or equal to the length.
227231 pub fn insertSlice(
228232 self: *Self,
229233 index: usize,
......@@ -236,9 +240,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
236240 /// Replace range of elements `list[start..][0..len]` with `new_items`.
237241 /// Grows list if `len < new_items.len`.
238242 /// Shrinks list if `len > new_items.len`.
239 /// Invalidates pointers if this ArrayList is resized.
243 /// Invalidates element pointers if this ArrayList is resized.
244 /// Asserts that the start index is in bounds or equal to the length.
240245 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {
241 const after_range = start + len;
246 const after_range = try addOrOom(start, len);
242247 const range = self.items[start..after_range];
243248
244249 if (range.len == new_items.len)
......@@ -251,7 +256,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
251256 try self.insertSlice(after_range, rest);
252257 } else {
253258 @memcpy(range[0..new_items.len], new_items);
254 const after_subrange = start + new_items.len;
259 const after_subrange = try addOrOom(start, new_items.len);
255260
256261 for (self.items[after_range..], 0..) |item, i| {
257262 self.items[after_subrange..][i] = item;
......@@ -261,16 +266,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
261266 }
262267 }
263268
264 /// Extend the list by 1 element. Allocates more memory as necessary.
265 /// Invalidates pointers if additional memory is needed.
269 /// Extends the list by 1 element. Allocates more memory as necessary.
270 /// Invalidates element pointers if additional memory is needed.
266271 pub fn append(self: *Self, item: T) Allocator.Error!void {
267272 const new_item_ptr = try self.addOne();
268273 new_item_ptr.* = item;
269274 }
270275
271 /// Extend the list by 1 element, but assert `self.capacity`
272 /// is sufficient to hold an additional item. **Does not**
273 /// invalidate pointers.
276 /// Extends the list by 1 element.
277 /// Never invalidates element pointers.
278 /// Asserts that the list can hold one additional item.
274279 pub fn appendAssumeCapacity(self: *Self, item: T) void {
275280 const new_item_ptr = self.addOneAssumeCapacity();
276281 new_item_ptr.* = item;
......@@ -278,10 +283,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
278283
279284 /// Remove the element at index `i`, shift elements after index
280285 /// `i` forward, and return the removed element.
281 /// Asserts the array has at least one item.
282 /// Invalidates pointers to end of list.
286 /// Invalidates element pointers to end of list.
283287 /// This operation is O(N).
284288 /// This preserves item order. Use `swapRemove` if order preservation is not important.
289 /// Asserts that the index is in bounds.
290 /// Asserts that the list is not empty.
285291 pub fn orderedRemove(self: *Self, i: usize) T {
286292 const newlen = self.items.len - 1;
287293 if (newlen == i) return self.pop();
......@@ -297,6 +303,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
297303 /// The empty slot is filled from the end of the list.
298304 /// This operation is O(1).
299305 /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.
306 /// Asserts that the list is not empty.
307 /// Asserts that the index is in bounds.
300308 pub fn swapRemove(self: *Self, i: usize) T {
301309 if (self.items.len - 1 == i) return self.pop();
302310
......@@ -307,14 +315,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
307315
308316 /// Append the slice of items to the list. Allocates more
309317 /// memory as necessary.
310 /// Invalidates pointers if additional memory is needed.
318 /// Invalidates element pointers if additional memory is needed.
311319 pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void {
312320 try self.ensureUnusedCapacity(items.len);
313321 self.appendSliceAssumeCapacity(items);
314322 }
315323
316 /// Append the slice of items to the list, asserting the capacity is already
317 /// enough to store the new items. **Does not** invalidate pointers.
324 /// Append the slice of items to the list.
325 /// Never invalidates element pointers.
326 /// Asserts that the list can hold the additional items.
318327 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
319328 const old_len = self.items.len;
320329 const new_len = old_len + items.len;
......@@ -326,16 +335,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
326335 /// Append an unaligned slice of items to the list. Allocates more
327336 /// memory as necessary. Only call this function if calling
328337 /// `appendSlice` instead would be a compile error.
329 /// Invalidates pointers if additional memory is needed.
338 /// Invalidates element pointers if additional memory is needed.
330339 pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void {
331340 try self.ensureUnusedCapacity(items.len);
332341 self.appendUnalignedSliceAssumeCapacity(items);
333342 }
334343
335 /// Append the slice of items to the list, asserting the capacity is already
336 /// enough to store the new items. **Does not** invalidate pointers.
337 /// Only call this function if calling `appendSliceAssumeCapacity` instead
338 /// would be a compile error.
344 /// Append the slice of items to the list.
345 /// Never invalidates element pointers.
346 /// This function is only needed when calling
347 /// `appendSliceAssumeCapacity` instead would be a compile error due to the
348 /// alignment of the `items` parameter.
349 /// Asserts that the list can hold the additional items.
339350 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
340351 const old_len = self.items.len;
341352 const new_len = old_len + items.len;
......@@ -348,7 +359,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
348359 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
349360 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
350361 else
351 std.io.Writer(*Self, error{OutOfMemory}, appendWrite);
362 std.io.Writer(*Self, Allocator.Error, appendWrite);
352363
353364 /// Initializes a Writer which will append to the list.
354365 pub fn writer(self: *Self) Writer {
......@@ -357,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
357368
358369 /// Same as `append` except it returns the number of bytes written, which is always the same
359370 /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
360 /// Invalidates pointers if additional memory is needed.
371 /// Invalidates element pointers if additional memory is needed.
361372 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {
362373 try self.appendSlice(m);
363374 return m.len;
......@@ -365,19 +376,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
365376
366377 /// Append a value to the list `n` times.
367378 /// Allocates more memory as necessary.
368 /// Invalidates pointers if additional memory is needed.
379 /// Invalidates element pointers if additional memory is needed.
369380 /// The function is inline so that a comptime-known `value` parameter will
370381 /// have a more optimal memset codegen in case it has a repeated byte pattern.
371382 pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void {
372383 const old_len = self.items.len;
373 try self.resize(self.items.len + n);
384 try self.resize(try addOrOom(old_len, n));
374385 @memset(self.items[old_len..self.items.len], value);
375386 }
376387
377388 /// Append a value to the list `n` times.
378 /// Asserts the capacity is enough. **Does not** invalidate pointers.
389 /// Never invalidates element pointers.
379390 /// The function is inline so that a comptime-known `value` parameter will
380391 /// have a more optimal memset codegen in case it has a repeated byte pattern.
392 /// Asserts that the list can hold the additional items.
381393 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
382394 const new_len = self.items.len + n;
383395 assert(new_len <= self.capacity);
......@@ -385,9 +397,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
385397 self.items.len = new_len;
386398 }
387399
388 /// Adjust the list's length to `new_len`.
389 /// Does not initialize added items if any.
390 /// Invalidates pointers if additional memory is needed.
400 /// Adjust the list length to `new_len`.
401 /// Additional elements contain the value `undefined`.
402 /// Invalidates element pointers if additional memory is needed.
391403 pub fn resize(self: *Self, new_len: usize) Allocator.Error!void {
392404 try self.ensureTotalCapacity(new_len);
393405 self.items.len = new_len;
......@@ -395,6 +407,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
395407
396408 /// Reduce allocated capacity to `new_len`.
397409 /// May invalidate element pointers.
410 /// Asserts that the new length is less than or equal to the previous length.
398411 pub fn shrinkAndFree(self: *Self, new_len: usize) void {
399412 var unmanaged = self.moveToUnmanaged();
400413 unmanaged.shrinkAndFree(self.allocator, new_len);
......@@ -402,7 +415,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
402415 }
403416
404417 /// Reduce length to `new_len`.
405 /// Invalidates pointers for the elements `items[new_len..]`.
418 /// Invalidates element pointers for the elements `items[new_len..]`.
419 /// Asserts that the new length is less than or equal to the previous length.
406420 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
407421 assert(new_len <= self.items.len);
408422 self.items.len = new_len;
......@@ -422,7 +436,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
422436
423437 /// If the current capacity is less than `new_capacity`, this function will
424438 /// modify the array so that it can hold at least `new_capacity` items.
425 /// Invalidates pointers if additional memory is needed.
439 /// Invalidates element pointers if additional memory is needed.
426440 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void {
427441 if (@sizeOf(T) == 0) {
428442 self.capacity = math.maxInt(usize);
......@@ -437,7 +451,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
437451
438452 /// If the current capacity is less than `new_capacity`, this function will
439453 /// modify the array so that it can hold exactly `new_capacity` items.
440 /// Invalidates pointers if additional memory is needed.
454 /// Invalidates element pointers if additional memory is needed.
441455 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void {
442456 if (@sizeOf(T) == 0) {
443457 self.capacity = math.maxInt(usize);
......@@ -464,13 +478,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
464478 }
465479
466480 /// Modify the array so that it can hold at least `additional_count` **more** items.
467 /// Invalidates pointers if additional memory is needed.
481 /// Invalidates element pointers if additional memory is needed.
468482 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void {
469 return self.ensureTotalCapacity(self.items.len + additional_count);
483 return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count));
470484 }
471485
472486 /// Increases the array's length to match the full capacity that is already allocated.
473 /// The new elements have `undefined` values. **Does not** invalidate pointers.
487 /// The new elements have `undefined` values.
488 /// Never invalidates element pointers.
474489 pub fn expandToCapacity(self: *Self) void {
475490 self.items.len = self.capacity;
476491 }
......@@ -478,14 +493,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
478493 /// Increase length by 1, returning pointer to the new item.
479494 /// The returned pointer becomes invalid when the list resized.
480495 pub fn addOne(self: *Self) Allocator.Error!*T {
481 try self.ensureTotalCapacity(self.items.len + 1);
496 try self.ensureUnusedCapacity(1);
482497 return self.addOneAssumeCapacity();
483498 }
484499
485500 /// Increase length by 1, returning pointer to the new item.
486 /// Asserts that there is already space for the new item without allocating more.
487501 /// The returned pointer becomes invalid when the list is resized.
488 /// **Does not** invalidate element pointers.
502 /// Never invalidates element pointers.
503 /// Asserts that the list can hold one additional item.
489504 pub fn addOneAssumeCapacity(self: *Self) *T {
490505 assert(self.items.len < self.capacity);
491506 self.items.len += 1;
......@@ -498,15 +513,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
498513 /// Resizes list if `self.capacity` is not large enough.
499514 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {
500515 const prev_len = self.items.len;
501 try self.resize(self.items.len + n);
516 try self.resize(try addOrOom(self.items.len, n));
502517 return self.items[prev_len..][0..n];
503518 }
504519
505520 /// Resize the array, adding `n` new elements, which have `undefined` values.
506521 /// The return value is an array pointing to the newly allocated elements.
507 /// Asserts that there is already space for the new item without allocating more.
508 /// **Does not** invalidate element pointers.
522 /// Never invalidates element pointers.
509523 /// The returned pointer becomes invalid when the list is resized.
524 /// Asserts that the list can hold the additional items.
510525 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
511526 assert(self.items.len + n <= self.capacity);
512527 const prev_len = self.items.len;
......@@ -520,15 +535,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
520535 /// Resizes list if `self.capacity` is not large enough.
521536 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {
522537 const prev_len = self.items.len;
523 try self.resize(self.items.len + n);
538 try self.resize(try addOrOom(self.items.len, n));
524539 return self.items[prev_len..][0..n];
525540 }
526541
527542 /// Resize the array, adding `n` new elements, which have `undefined` values.
528543 /// The return value is a slice pointing to the newly allocated elements.
529 /// Asserts that there is already space for the new item without allocating more.
530 /// **Does not** invalidate element pointers.
544 /// Never invalidates element pointers.
531545 /// The returned pointer becomes invalid when the list is resized.
546 /// Asserts that the list can hold the additional items.
532547 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
533548 assert(self.items.len + n <= self.capacity);
534549 const prev_len = self.items.len;
......@@ -537,8 +552,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
537552 }
538553
539554 /// Remove and return the last element from the list.
540 /// Asserts the list has at least one item.
541 /// Invalidates pointers to the removed element.
555 /// Invalidates element pointers to the removed element.
556 /// Asserts that the list is not empty.
542557 pub fn pop(self: *Self) T {
543558 const val = self.items[self.items.len - 1];
544559 self.items.len -= 1;
......@@ -547,7 +562,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
547562
548563 /// Remove and return the last element from the list, or
549564 /// return `null` if list is empty.
550 /// Invalidates pointers to the removed element, if any.
565 /// Invalidates element pointers to the removed element, if any.
551566 pub fn popOrNull(self: *Self) ?T {
552567 if (self.items.len == 0) return null;
553568 return self.pop();
......@@ -568,15 +583,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
568583 return self.allocatedSlice()[self.items.len..];
569584 }
570585
571 /// Return the last element from the list.
572 /// Asserts the list has at least one item.
586 /// Returns the last element from the list.
587 /// Asserts that the list is not empty.
573588 pub fn getLast(self: Self) T {
574589 const val = self.items[self.items.len - 1];
575590 return val;
576591 }
577592
578 /// Return the last element from the list, or
579 /// return `null` if list is empty.
593 /// Returns the last element from the list, or `null` if list is empty.
580594 pub fn getLastOrNull(self: Self) ?T {
581595 if (self.items.len == 0) return null;
582596 return self.getLast();
......@@ -585,17 +599,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
585599}
586600
587601/// An ArrayList, but the allocator is passed as a parameter to the relevant functions
588/// rather than stored in the struct itself. The same allocator **must** be used throughout
602/// rather than stored in the struct itself. The same allocator must be used throughout
589603/// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with
590604/// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`.
591605pub fn ArrayListUnmanaged(comptime T: type) type {
592606 return ArrayListAlignedUnmanaged(T, null);
593607}
594608
595/// An ArrayListAligned, but the allocator is passed as a parameter to the relevant
596/// functions rather than stored in the struct itself. The same allocator **must**
597/// be used throughout the entire lifetime of an ArrayListAlignedUnmanaged.
598/// Initialize directly or with `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`.
609/// A contiguous, growable list of arbitrarily aligned items in memory.
610/// This is a wrapper around an array of T values aligned to `alignment`-byte
611/// addresses. If the specified alignment is `null`, then `@alignOf(T)` is used.
612///
613/// Functions that potentially allocate memory accept an `Allocator` parameter.
614/// Initialize directly or with `initCapacity`, and deinitialize with `deinit`
615/// or use `toOwnedSlice`.
599616pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {
600617 if (alignment) |a| {
601618 if (a == @alignOf(T)) {
......@@ -604,15 +621,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
604621 }
605622 return struct {
606623 const Self = @This();
607 /// Contents of the list. Pointers to elements in this slice are
608 /// **invalid after resizing operations** on the ArrayList unless the
609 /// operation explicitly either: (1) states otherwise or (2) lists the
610 /// invalidated pointers.
624 /// Contents of the list. This field is intended to be accessed
625 /// directly.
611626 ///
612 /// The allocator used determines how element pointers are
613 /// invalidated, so the behavior may vary between lists. To avoid
614 /// illegal behavior, take into account the above paragraph plus the
615 /// explicit statements given in each method.
627 /// Pointers to elements in this slice are invalidated by various
628 /// functions of this ArrayList in accordance with the respective
629 /// documentation. In all cases, "invalidated" means that the memory
630 /// has been passed to an allocator's resize or free function.
616631 items: Slice = &[_]T{},
617632 /// How many T values this list can hold without allocating
618633 /// additional memory.
......@@ -635,8 +650,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
635650
636651 /// Initialize with externally-managed memory. The buffer determines the
637652 /// capacity, and the length is set to zero.
638 /// When initialized this way, all methods that accept an Allocator
639 /// argument are illegal to call.
653 /// When initialized this way, all functions that accept an Allocator
654 /// argument cause illegal behavior.
640655 pub fn initBuffer(buffer: Slice) Self {
641656 return .{
642657 .items = buffer[0..0],
......@@ -695,7 +710,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
695710
696711 /// The caller owns the returned memory. ArrayList becomes empty.
697712 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
698 try self.ensureTotalCapacityPrecise(allocator, self.items.len + 1);
713 try self.ensureTotalCapacityPrecise(allocator, try addOrOom(self.items.len, 1));
699714 self.appendAssumeCapacity(sentinel);
700715 const result = try self.toOwnedSlice(allocator);
701716 return result[0 .. result.len - 1 :sentinel];
......@@ -708,25 +723,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
708723 return cloned;
709724 }
710725
711 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.
712 /// If `n` is equal to the length of the list this operation is equivalent to append.
726 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
727 /// If `i` is equal to the length of the list this operation is equivalent to append.
713728 /// This operation is O(N).
714 /// Invalidates pointers if additional memory is needed.
715 pub fn insert(self: *Self, allocator: Allocator, n: usize, item: T) Allocator.Error!void {
716 const dst = try self.addManyAt(allocator, n, 1);
729 /// Invalidates element pointers if additional memory is needed.
730 /// Asserts that the index is in bounds or equal to the length.
731 pub fn insert(self: *Self, allocator: Allocator, i: usize, item: T) Allocator.Error!void {
732 const dst = try self.addManyAt(allocator, i, 1);
717733 dst[0] = item;
718734 }
719735
720 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.
721 /// If `n` is equal to the length of the list this operation is equivalent to append.
736 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
737 /// If in` is equal to the length of the list this operation is equivalent to append.
722738 /// This operation is O(N).
723 /// Asserts that there is enough capacity for the new item.
724 pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void {
739 /// Asserts that the list has capacity for one additional item.
740 /// Asserts that the index is in bounds or equal to the length.
741 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
725742 assert(self.items.len < self.capacity);
726743 self.items.len += 1;
727744
728 mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]);
729 self.items[n] = item;
745 mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
746 self.items[i] = item;
730747 }
731748
732749 /// Add `count` new elements at position `index`, which have
......@@ -736,6 +753,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
736753 /// Invalidates pre-existing pointers to elements at and after `index`.
737754 /// Invalidates all pre-existing element pointers if capacity must be
738755 /// increased to accomodate the new elements.
756 /// Asserts that the index is in bounds or equal to the length.
739757 pub fn addManyAt(
740758 self: *Self,
741759 allocator: Allocator,
......@@ -751,9 +769,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
751769 /// `undefined` values. Returns a slice pointing to the newly allocated
752770 /// elements, which becomes invalid after various `ArrayList`
753771 /// operations.
754 /// Asserts that there is enough capacity for the new elements.
755772 /// Invalidates pre-existing pointers to elements at and after `index`, but
756773 /// does not invalidate any before that.
774 /// Asserts that the list has capacity for the additional items.
775 /// Asserts that the index is in bounds or equal to the length.
757776 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
758777 const new_len = self.items.len + count;
759778 assert(self.capacity >= new_len);
......@@ -770,6 +789,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
770789 /// Invalidates pre-existing pointers to elements at and after `index`.
771790 /// Invalidates all pre-existing element pointers if capacity must be
772791 /// increased to accomodate the new elements.
792 /// Asserts that the index is in bounds or equal to the length.
773793 pub fn insertSlice(
774794 self: *Self,
775795 allocator: Allocator,
......@@ -787,7 +807,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
787807 /// Replace range of elements `list[start..][0..len]` with `new_items`
788808 /// Grows list if `len < new_items.len`.
789809 /// Shrinks list if `len > new_items.len`
790 /// Invalidates pointers if this ArrayList is resized.
810 /// Invalidates element pointers if this ArrayList is resized.
811 /// Asserts that the start index is in bounds or equal to the length.
791812 pub fn replaceRange(
792813 self: *Self,
793814 allocator: Allocator,
......@@ -801,23 +822,25 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
801822 }
802823
803824 /// Extend the list by 1 element. Allocates more memory as necessary.
804 /// Invalidates pointers if additional memory is needed.
825 /// Invalidates element pointers if additional memory is needed.
805826 pub fn append(self: *Self, allocator: Allocator, item: T) Allocator.Error!void {
806827 const new_item_ptr = try self.addOne(allocator);
807828 new_item_ptr.* = item;
808829 }
809830
810 /// Extend the list by 1 element, but asserting `self.capacity`
811 /// is sufficient to hold an additional item.
831 /// Extend the list by 1 element.
832 /// Never invalidates element pointers.
833 /// Asserts that the list can hold one additional item.
812834 pub fn appendAssumeCapacity(self: *Self, item: T) void {
813835 const new_item_ptr = self.addOneAssumeCapacity();
814836 new_item_ptr.* = item;
815837 }
816838
817839 /// Remove the element at index `i` from the list and return its value.
818 /// Asserts the array has at least one item. Invalidates pointers to
819 /// last element.
840 /// Invalidates pointers to the last element.
820841 /// This operation is O(N).
842 /// Asserts that the list is not empty.
843 /// Asserts that the index is in bounds.
821844 pub fn orderedRemove(self: *Self, i: usize) T {
822845 const newlen = self.items.len - 1;
823846 if (newlen == i) return self.pop();
......@@ -833,6 +856,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
833856 /// The empty slot is filled from the end of the list.
834857 /// Invalidates pointers to last element.
835858 /// This operation is O(1).
859 /// Asserts that the list is not empty.
860 /// Asserts that the index is in bounds.
836861 pub fn swapRemove(self: *Self, i: usize) T {
837862 if (self.items.len - 1 == i) return self.pop();
838863
......@@ -843,14 +868,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
843868
844869 /// Append the slice of items to the list. Allocates more
845870 /// memory as necessary.
846 /// Invalidates pointers if additional memory is needed.
871 /// Invalidates element pointers if additional memory is needed.
847872 pub fn appendSlice(self: *Self, allocator: Allocator, items: []const T) Allocator.Error!void {
848873 try self.ensureUnusedCapacity(allocator, items.len);
849874 self.appendSliceAssumeCapacity(items);
850875 }
851876
852 /// Append the slice of items to the list, asserting the capacity is enough
853 /// to store the new items.
877 /// Append the slice of items to the list.
878 /// Asserts that the list can hold the additional items.
854879 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
855880 const old_len = self.items.len;
856881 const new_len = old_len + items.len;
......@@ -862,15 +887,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
862887 /// Append the slice of items to the list. Allocates more
863888 /// memory as necessary. Only call this function if a call to `appendSlice` instead would
864889 /// be a compile error.
865 /// Invalidates pointers if additional memory is needed.
890 /// Invalidates element pointers if additional memory is needed.
866891 pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void {
867892 try self.ensureUnusedCapacity(allocator, items.len);
868893 self.appendUnalignedSliceAssumeCapacity(items);
869894 }
870895
871 /// Append an unaligned slice of items to the list, asserting the capacity is enough
872 /// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity`
896 /// Append an unaligned slice of items to the list.
897 /// Only call this function if a call to `appendSliceAssumeCapacity`
873898 /// instead would be a compile error.
899 /// Asserts that the list can hold the additional items.
874900 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
875901 const old_len = self.items.len;
876902 const new_len = old_len + items.len;
......@@ -888,7 +914,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
888914 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
889915 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
890916 else
891 std.io.Writer(WriterContext, error{OutOfMemory}, appendWrite);
917 std.io.Writer(WriterContext, Allocator.Error, appendWrite);
892918
893919 /// Initializes a Writer which will append to the list.
894920 pub fn writer(self: *Self, allocator: Allocator) Writer {
......@@ -897,7 +923,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
897923
898924 /// Same as `append` except it returns the number of bytes written, which is always the same
899925 /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
900 /// Invalidates pointers if additional memory is needed.
926 /// Invalidates element pointers if additional memory is needed.
901927 fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
902928 try context.self.appendSlice(context.allocator, m);
903929 return m.len;
......@@ -905,20 +931,20 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
905931
906932 /// Append a value to the list `n` times.
907933 /// Allocates more memory as necessary.
908 /// Invalidates pointers if additional memory is needed.
934 /// Invalidates element pointers if additional memory is needed.
909935 /// The function is inline so that a comptime-known `value` parameter will
910936 /// have a more optimal memset codegen in case it has a repeated byte pattern.
911937 pub inline fn appendNTimes(self: *Self, allocator: Allocator, value: T, n: usize) Allocator.Error!void {
912938 const old_len = self.items.len;
913 try self.resize(allocator, self.items.len + n);
939 try self.resize(allocator, try addOrOom(old_len, n));
914940 @memset(self.items[old_len..self.items.len], value);
915941 }
916942
917943 /// Append a value to the list `n` times.
918 /// **Does not** invalidate pointers.
919 /// Asserts the capacity is enough.
944 /// Never invalidates element pointers.
920945 /// The function is inline so that a comptime-known `value` parameter will
921 /// have a more optimal memset codegen in case it has a repeated byte pattern.
946 /// have better memset codegen in case it has a repeated byte pattern.
947 /// Asserts that the list can hold the additional items.
922948 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
923949 const new_len = self.items.len + n;
924950 assert(new_len <= self.capacity);
......@@ -926,9 +952,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
926952 self.items.len = new_len;
927953 }
928954
929 /// Adjust the list's length to `new_len`.
930 /// Does not initialize added items, if any.
931 /// Invalidates pointers if additional memory is needed.
955 /// Adjust the list length to `new_len`.
956 /// Additional elements contain the value `undefined`.
957 /// Invalidates element pointers if additional memory is needed.
932958 pub fn resize(self: *Self, allocator: Allocator, new_len: usize) Allocator.Error!void {
933959 try self.ensureTotalCapacity(allocator, new_len);
934960 self.items.len = new_len;
......@@ -936,6 +962,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
936962
937963 /// Reduce allocated capacity to `new_len`.
938964 /// May invalidate element pointers.
965 /// Asserts that the new length is less than or equal to the previous length.
939966 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {
940967 assert(new_len <= self.items.len);
941968
......@@ -968,6 +995,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
968995 /// Reduce length to `new_len`.
969996 /// Invalidates pointers to elements `items[new_len..]`.
970997 /// Keeps capacity the same.
998 /// Asserts that the new length is less than or equal to the previous length.
971999 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
9721000 assert(new_len <= self.items.len);
9731001 self.items.len = new_len;
......@@ -987,7 +1015,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
9871015
9881016 /// If the current capacity is less than `new_capacity`, this function will
9891017 /// modify the array so that it can hold at least `new_capacity` items.
990 /// Invalidates pointers if additional memory is needed.
1018 /// Invalidates element pointers if additional memory is needed.
9911019 pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
9921020 if (self.capacity >= new_capacity) return;
9931021
......@@ -997,7 +1025,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
9971025
9981026 /// If the current capacity is less than `new_capacity`, this function will
9991027 /// modify the array so that it can hold exactly `new_capacity` items.
1000 /// Invalidates pointers if additional memory is needed.
1028 /// Invalidates element pointers if additional memory is needed.
10011029 pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
10021030 if (@sizeOf(T) == 0) {
10031031 self.capacity = math.maxInt(usize);
......@@ -1024,34 +1052,34 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
10241052 }
10251053
10261054 /// Modify the array so that it can hold at least `additional_count` **more** items.
1027 /// Invalidates pointers if additional memory is needed.
1055 /// Invalidates element pointers if additional memory is needed.
10281056 pub fn ensureUnusedCapacity(
10291057 self: *Self,
10301058 allocator: Allocator,
10311059 additional_count: usize,
10321060 ) Allocator.Error!void {
1033 return self.ensureTotalCapacity(allocator, self.items.len + additional_count);
1061 return self.ensureTotalCapacity(allocator, try addOrOom(self.items.len, additional_count));
10341062 }
10351063
10361064 /// Increases the array's length to match the full capacity that is already allocated.
10371065 /// The new elements have `undefined` values.
1038 /// **Does not** invalidate pointers.
1066 /// Never invalidates element pointers.
10391067 pub fn expandToCapacity(self: *Self) void {
10401068 self.items.len = self.capacity;
10411069 }
10421070
10431071 /// Increase length by 1, returning pointer to the new item.
1044 /// The returned pointer becomes invalid when the list resized.
1072 /// The returned element pointer becomes invalid when the list is resized.
10451073 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {
1046 const newlen = self.items.len + 1;
1074 const newlen = try addOrOom(self.items.len, 1);
10471075 try self.ensureTotalCapacity(allocator, newlen);
10481076 return self.addOneAssumeCapacity();
10491077 }
10501078
10511079 /// Increase length by 1, returning pointer to the new item.
1052 /// Asserts that there is already space for the new item without allocating more.
1053 /// **Does not** invalidate pointers.
1054 /// The returned pointer becomes invalid when the list resized.
1080 /// Never invalidates element pointers.
1081 /// The returned element pointer becomes invalid when the list is resized.
1082 /// Asserts that the list can hold one additional item.
10551083 pub fn addOneAssumeCapacity(self: *Self) *T {
10561084 assert(self.items.len < self.capacity);
10571085
......@@ -1064,15 +1092,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
10641092 /// The returned pointer becomes invalid when the list is resized.
10651093 pub fn addManyAsArray(self: *Self, allocator: Allocator, comptime n: usize) Allocator.Error!*[n]T {
10661094 const prev_len = self.items.len;
1067 try self.resize(allocator, self.items.len + n);
1095 try self.resize(allocator, try addOrOom(self.items.len, n));
10681096 return self.items[prev_len..][0..n];
10691097 }
10701098
10711099 /// Resize the array, adding `n` new elements, which have `undefined` values.
10721100 /// The return value is an array pointing to the newly allocated elements.
1073 /// Asserts that there is already space for the new item without allocating more.
1074 /// **Does not** invalidate pointers.
1101 /// Never invalidates element pointers.
10751102 /// The returned pointer becomes invalid when the list is resized.
1103 /// Asserts that the list can hold the additional items.
10761104 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
10771105 assert(self.items.len + n <= self.capacity);
10781106 const prev_len = self.items.len;
......@@ -1086,15 +1114,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
10861114 /// Resizes list if `self.capacity` is not large enough.
10871115 pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T {
10881116 const prev_len = self.items.len;
1089 try self.resize(allocator, self.items.len + n);
1117 try self.resize(allocator, try addOrOom(self.items.len, n));
10901118 return self.items[prev_len..][0..n];
10911119 }
10921120
10931121 /// Resize the array, adding `n` new elements, which have `undefined` values.
10941122 /// The return value is a slice pointing to the newly allocated elements.
1095 /// Asserts that there is already space for the new item without allocating more.
1096 /// **Does not** invalidate element pointers.
1123 /// Never invalidates element pointers.
10971124 /// The returned pointer becomes invalid when the list is resized.
1125 /// Asserts that the list can hold the additional items.
10981126 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
10991127 assert(self.items.len + n <= self.capacity);
11001128 const prev_len = self.items.len;
......@@ -1103,8 +1131,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
11031131 }
11041132
11051133 /// Remove and return the last element from the list.
1106 /// Asserts the list has at least one item.
11071134 /// Invalidates pointers to last element.
1135 /// Asserts that the list is not empty.
11081136 pub fn pop(self: *Self) T {
11091137 const val = self.items[self.items.len - 1];
11101138 self.items.len -= 1;
......@@ -1134,7 +1162,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
11341162 }
11351163
11361164 /// Return the last element from the list.
1137 /// Asserts the list has at least one item.
1165 /// Asserts that the list is not empty.
11381166 pub fn getLast(self: Self) T {
11391167 const val = self.items[self.items.len - 1];
11401168 return val;
......@@ -1160,6 +1188,13 @@ fn growCapacity(current: usize, minimum: usize) usize {
11601188 }
11611189}
11621190
1191/// Integer addition returning `error.OutOfMemory` on overflow.
1192fn addOrOom(a: usize, b: usize) error{OutOfMemory}!usize {
1193 const result, const overflow = @addWithOverflow(a, b);
1194 if (overflow != 0) return error.OutOfMemory;
1195 return result;
1196}
1197
11631198test "std.ArrayList/ArrayListUnmanaged.init" {
11641199 {
11651200 var list = ArrayList(i32).init(testing.allocator);
......@@ -1952,3 +1987,51 @@ test "std.ArrayList(u32).getLastOrNull()" {
19521987 const const_list = list;
19531988 try testing.expectEqual(const_list.getLastOrNull().?, 2);
19541989}
1990
1991test "return OutOfMemory when capacity would exceed maximum usize integer value" {
1992 const a = testing.allocator;
1993 const new_item: u32 = 42;
1994
1995 {
1996 var list: ArrayListUnmanaged(u32) = .{
1997 .items = undefined,
1998 .capacity = math.maxInt(usize),
1999 };
2000 list.items.len = math.maxInt(usize);
2001
2002 try testing.expectError(error.OutOfMemory, list.append(a, new_item));
2003 try testing.expectError(error.OutOfMemory, list.appendSlice(a, &.{new_item}));
2004 try testing.expectError(error.OutOfMemory, list.appendNTimes(a, new_item, 1));
2005 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(a, &.{new_item}));
2006 try testing.expectError(error.OutOfMemory, list.addOne(a));
2007 try testing.expectError(error.OutOfMemory, list.addManyAt(a, 0, 1));
2008 try testing.expectError(error.OutOfMemory, list.addManyAsArray(a, 1));
2009 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(a, 1));
2010 try testing.expectError(error.OutOfMemory, list.insert(a, 0, new_item));
2011 try testing.expectError(error.OutOfMemory, list.insertSlice(a, 0, &.{new_item}));
2012 try testing.expectError(error.OutOfMemory, list.toOwnedSliceSentinel(a, 0));
2013 try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(a, 1));
2014 }
2015
2016 {
2017 var list: ArrayList(u32) = .{
2018 .items = undefined,
2019 .capacity = math.maxInt(usize),
2020 .allocator = a,
2021 };
2022 list.items.len = math.maxInt(usize);
2023
2024 try testing.expectError(error.OutOfMemory, list.append(new_item));
2025 try testing.expectError(error.OutOfMemory, list.appendSlice(&.{new_item}));
2026 try testing.expectError(error.OutOfMemory, list.appendNTimes(new_item, 1));
2027 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(&.{new_item}));
2028 try testing.expectError(error.OutOfMemory, list.addOne());
2029 try testing.expectError(error.OutOfMemory, list.addManyAt(0, 1));
2030 try testing.expectError(error.OutOfMemory, list.addManyAsArray(1));
2031 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(1));
2032 try testing.expectError(error.OutOfMemory, list.insert(0, new_item));
2033 try testing.expectError(error.OutOfMemory, list.insertSlice(0, &.{new_item}));
2034 try testing.expectError(error.OutOfMemory, list.toOwnedSliceSentinel(0));
2035 try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(1));
2036 }
2037}