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;...@@ -10,7 +10,7 @@ const Allocator = mem.Allocator;
10/// This is a wrapper around an array of T values. Initialize with `init`.10/// This is a wrapper around an array of T values. Initialize with `init`.
11///11///
12/// This struct internally stores a `std.mem.Allocator` for memory management.12/// 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`.
14pub fn ArrayList(comptime T: type) type {14pub fn ArrayList(comptime T: type) type {
15 return ArrayListAligned(T, null);15 return ArrayListAligned(T, null);
16}16}
...@@ -21,7 +21,7 @@ pub fn ArrayList(comptime T: type) type {...@@ -21,7 +21,7 @@ pub fn ArrayList(comptime T: type) type {
21/// Initialize with `init`.21/// Initialize with `init`.
22///22///
23/// This struct internally stores a `std.mem.Allocator` for memory management.23/// 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`.
25pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {25pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
26 if (alignment) |a| {26 if (alignment) |a| {
27 if (a == @alignOf(T)) {27 if (a == @alignOf(T)) {
...@@ -30,15 +30,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -30,15 +30,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
30 }30 }
31 return struct {31 return struct {
32 const Self = @This();32 const Self = @This();
33 /// Contents of the list. Pointers to elements in this slice are33 /// Contents of the list. This field is intended to be accessed
34 /// **invalid after resizing operations** on the ArrayList unless the34 /// directly.
35 /// operation explicitly either: (1) states otherwise or (2) lists the
36 /// invalidated pointers.
37 ///35 ///
38 /// The allocator used determines how element pointers are36 /// Pointers to elements in this slice are invalidated by various
39 /// invalidated, so the behavior may vary between lists. To avoid37 /// functions of this ArrayList in accordance with the respective
40 /// illegal behavior, take into account the above paragraph plus the38 /// documentation. In all cases, "invalidated" means that the memory
41 /// explicit statements given in each method.39 /// has been passed to this allocator's resize or free function.
42 items: Slice,40 items: Slice,
43 /// How many T values this list can hold without allocating41 /// How many T values this list can hold without allocating
44 /// additional memory.42 /// additional memory.
...@@ -128,7 +126,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -128,7 +126,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
128126
129 /// The caller owns the returned memory. Empties this ArrayList.127 /// The caller owns the returned memory. Empties this ArrayList.
130 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {128 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));
132 self.appendAssumeCapacity(sentinel);130 self.appendAssumeCapacity(sentinel);
133 const result = try self.toOwnedSlice();131 const result = try self.toOwnedSlice();
134 return result[0 .. result.len - 1 :sentinel];132 return result[0 .. result.len - 1 :sentinel];
...@@ -141,25 +139,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -141,25 +139,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
141 return cloned;139 return cloned;
142 }140 }
143141
144 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.142 /// Insert `item` at index `i`. Moves `list[i .. 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.143 /// If `i` is equal to the length of the list this operation is equivalent to append.
146 /// This operation is O(N).144 /// This operation is O(N).
147 /// Invalidates pointers if additional memory is needed.145 /// Invalidates element pointers if additional memory is needed.
148 pub fn insert(self: *Self, n: usize, item: T) Allocator.Error!void {146 /// Asserts that the index is in bounds or equal to the length.
149 const dst = try self.addManyAt(n, 1);147 pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void {
148 const dst = try self.addManyAt(i, 1);
150 dst[0] = item;149 dst[0] = item;
151 }150 }
152151
153 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.152 /// Insert `item` at index `i`. Moves `list[i .. 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.153 /// If `i` is equal to the length of the list this operation is
154 /// equivalent to appendAssumeCapacity.
155 /// This operation is O(N).155 /// This operation is O(N).
156 /// Asserts that there is enough capacity for the new item.156 /// 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 {
158 assert(self.items.len < self.capacity);159 assert(self.items.len < self.capacity);
159 self.items.len += 1;160 self.items.len += 1;
160161
161 mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]);162 mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
162 self.items[n] = item;163 self.items[i] = item;
163 }164 }
164165
165 /// Add `count` new elements at position `index`, which have166 /// Add `count` new elements at position `index`, which have
...@@ -169,8 +170,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -169,8 +170,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
169 /// Invalidates pre-existing pointers to elements at and after `index`.170 /// Invalidates pre-existing pointers to elements at and after `index`.
170 /// Invalidates all pre-existing element pointers if capacity must be171 /// Invalidates all pre-existing element pointers if capacity must be
171 /// increased to accomodate the new elements.172 /// increased to accomodate the new elements.
173 /// Asserts that the index is in bounds or equal to the length.
172 pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {174 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
175 if (self.capacity >= new_len)177 if (self.capacity >= new_len)
176 return addManyAtAssumeCapacity(self, index, count);178 return addManyAtAssumeCapacity(self, index, count);
...@@ -208,6 +210,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -208,6 +210,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
208 /// Asserts that there is enough capacity for the new elements.210 /// Asserts that there is enough capacity for the new elements.
209 /// Invalidates pre-existing pointers to elements at and after `index`, but211 /// Invalidates pre-existing pointers to elements at and after `index`, but
210 /// does not invalidate any before that.212 /// does not invalidate any before that.
213 /// Asserts that the index is in bounds or equal to the length.
211 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {214 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
212 const new_len = self.items.len + count;215 const new_len = self.items.len + count;
213 assert(self.capacity >= new_len);216 assert(self.capacity >= new_len);
...@@ -224,6 +227,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -224,6 +227,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
224 /// Invalidates pre-existing pointers to elements at and after `index`.227 /// Invalidates pre-existing pointers to elements at and after `index`.
225 /// Invalidates all pre-existing element pointers if capacity must be228 /// Invalidates all pre-existing element pointers if capacity must be
226 /// increased to accomodate the new elements.229 /// increased to accomodate the new elements.
230 /// Asserts that the index is in bounds or equal to the length.
227 pub fn insertSlice(231 pub fn insertSlice(
228 self: *Self,232 self: *Self,
229 index: usize,233 index: usize,
...@@ -236,9 +240,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -236,9 +240,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
236 /// Replace range of elements `list[start..][0..len]` with `new_items`.240 /// Replace range of elements `list[start..][0..len]` with `new_items`.
237 /// Grows list if `len < new_items.len`.241 /// Grows list if `len < new_items.len`.
238 /// Shrinks list if `len > new_items.len`.242 /// 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.
240 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {245 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);
242 const range = self.items[start..after_range];247 const range = self.items[start..after_range];
243248
244 if (range.len == new_items.len)249 if (range.len == new_items.len)
...@@ -251,7 +256,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -251,7 +256,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
251 try self.insertSlice(after_range, rest);256 try self.insertSlice(after_range, rest);
252 } else {257 } else {
253 @memcpy(range[0..new_items.len], new_items);258 @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
256 for (self.items[after_range..], 0..) |item, i| {261 for (self.items[after_range..], 0..) |item, i| {
257 self.items[after_subrange..][i] = item;262 self.items[after_subrange..][i] = item;
...@@ -261,16 +266,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -261,16 +266,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
261 }266 }
262 }267 }
263268
264 /// Extend the list by 1 element. Allocates more memory as necessary.269 /// Extends the list by 1 element. Allocates more memory as necessary.
265 /// Invalidates pointers if additional memory is needed.270 /// Invalidates element pointers if additional memory is needed.
266 pub fn append(self: *Self, item: T) Allocator.Error!void {271 pub fn append(self: *Self, item: T) Allocator.Error!void {
267 const new_item_ptr = try self.addOne();272 const new_item_ptr = try self.addOne();
268 new_item_ptr.* = item;273 new_item_ptr.* = item;
269 }274 }
270275
271 /// Extend the list by 1 element, but assert `self.capacity`276 /// Extends the list by 1 element.
272 /// is sufficient to hold an additional item. **Does not**277 /// Never invalidates element pointers.
273 /// invalidate pointers.278 /// Asserts that the list can hold one additional item.
274 pub fn appendAssumeCapacity(self: *Self, item: T) void {279 pub fn appendAssumeCapacity(self: *Self, item: T) void {
275 const new_item_ptr = self.addOneAssumeCapacity();280 const new_item_ptr = self.addOneAssumeCapacity();
276 new_item_ptr.* = item;281 new_item_ptr.* = item;
...@@ -278,10 +283,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -278,10 +283,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
278283
279 /// Remove the element at index `i`, shift elements after index284 /// Remove the element at index `i`, shift elements after index
280 /// `i` forward, and return the removed element.285 /// `i` forward, and return the removed element.
281 /// Asserts the array has at least one item.286 /// Invalidates element pointers to end of list.
282 /// Invalidates pointers to end of list.
283 /// This operation is O(N).287 /// This operation is O(N).
284 /// This preserves item order. Use `swapRemove` if order preservation is not important.288 /// 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.
285 pub fn orderedRemove(self: *Self, i: usize) T {291 pub fn orderedRemove(self: *Self, i: usize) T {
286 const newlen = self.items.len - 1;292 const newlen = self.items.len - 1;
287 if (newlen == i) return self.pop();293 if (newlen == i) return self.pop();
...@@ -297,6 +303,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -297,6 +303,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
297 /// The empty slot is filled from the end of the list.303 /// The empty slot is filled from the end of the list.
298 /// This operation is O(1).304 /// This operation is O(1).
299 /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.305 /// 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.
300 pub fn swapRemove(self: *Self, i: usize) T {308 pub fn swapRemove(self: *Self, i: usize) T {
301 if (self.items.len - 1 == i) return self.pop();309 if (self.items.len - 1 == i) return self.pop();
302310
...@@ -307,14 +315,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -307,14 +315,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
307315
308 /// Append the slice of items to the list. Allocates more316 /// Append the slice of items to the list. Allocates more
309 /// memory as necessary.317 /// memory as necessary.
310 /// Invalidates pointers if additional memory is needed.318 /// Invalidates element pointers if additional memory is needed.
311 pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void {319 pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void {
312 try self.ensureUnusedCapacity(items.len);320 try self.ensureUnusedCapacity(items.len);
313 self.appendSliceAssumeCapacity(items);321 self.appendSliceAssumeCapacity(items);
314 }322 }
315323
316 /// Append the slice of items to the list, asserting the capacity is already324 /// Append the slice of items to the list.
317 /// enough to store the new items. **Does not** invalidate pointers.325 /// Never invalidates element pointers.
326 /// Asserts that the list can hold the additional items.
318 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {327 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
319 const old_len = self.items.len;328 const old_len = self.items.len;
320 const new_len = old_len + items.len;329 const new_len = old_len + items.len;
...@@ -326,16 +335,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -326,16 +335,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
326 /// Append an unaligned slice of items to the list. Allocates more335 /// Append an unaligned slice of items to the list. Allocates more
327 /// memory as necessary. Only call this function if calling336 /// memory as necessary. Only call this function if calling
328 /// `appendSlice` instead would be a compile error.337 /// `appendSlice` instead would be a compile error.
329 /// Invalidates pointers if additional memory is needed.338 /// Invalidates element pointers if additional memory is needed.
330 pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void {339 pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void {
331 try self.ensureUnusedCapacity(items.len);340 try self.ensureUnusedCapacity(items.len);
332 self.appendUnalignedSliceAssumeCapacity(items);341 self.appendUnalignedSliceAssumeCapacity(items);
333 }342 }
334343
335 /// Append the slice of items to the list, asserting the capacity is already344 /// Append the slice of items to the list.
336 /// enough to store the new items. **Does not** invalidate pointers.345 /// Never invalidates element pointers.
337 /// Only call this function if calling `appendSliceAssumeCapacity` instead346 /// This function is only needed when calling
338 /// would be a compile error.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.
339 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {350 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
340 const old_len = self.items.len;351 const old_len = self.items.len;
341 const new_len = old_len + items.len;352 const new_len = old_len + items.len;
...@@ -348,7 +359,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -348,7 +359,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
348 @compileError("The Writer interface is only defined for ArrayList(u8) " ++359 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
349 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")360 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
350 else361 else
351 std.io.Writer(*Self, error{OutOfMemory}, appendWrite);362 std.io.Writer(*Self, Allocator.Error, appendWrite);
352363
353 /// Initializes a Writer which will append to the list.364 /// Initializes a Writer which will append to the list.
354 pub fn writer(self: *Self) Writer {365 pub fn writer(self: *Self) Writer {
...@@ -357,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -357,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
357368
358 /// Same as `append` except it returns the number of bytes written, which is always the same369 /// Same as `append` except it returns the number of bytes written, which is always the same
359 /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.370 /// 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.
361 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {372 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {
362 try self.appendSlice(m);373 try self.appendSlice(m);
363 return m.len;374 return m.len;
...@@ -365,19 +376,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -365,19 +376,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
365376
366 /// Append a value to the list `n` times.377 /// Append a value to the list `n` times.
367 /// Allocates more memory as necessary.378 /// Allocates more memory as necessary.
368 /// Invalidates pointers if additional memory is needed.379 /// Invalidates element pointers if additional memory is needed.
369 /// The function is inline so that a comptime-known `value` parameter will380 /// The function is inline so that a comptime-known `value` parameter will
370 /// have a more optimal memset codegen in case it has a repeated byte pattern.381 /// have a more optimal memset codegen in case it has a repeated byte pattern.
371 pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void {382 pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void {
372 const old_len = self.items.len;383 const old_len = self.items.len;
373 try self.resize(self.items.len + n);384 try self.resize(try addOrOom(old_len, n));
374 @memset(self.items[old_len..self.items.len], value);385 @memset(self.items[old_len..self.items.len], value);
375 }386 }
376387
377 /// Append a value to the list `n` times.388 /// Append a value to the list `n` times.
378 /// Asserts the capacity is enough. **Does not** invalidate pointers.389 /// Never invalidates element pointers.
379 /// The function is inline so that a comptime-known `value` parameter will390 /// The function is inline so that a comptime-known `value` parameter will
380 /// have a more optimal memset codegen in case it has a repeated byte pattern.391 /// have a more optimal memset codegen in case it has a repeated byte pattern.
392 /// Asserts that the list can hold the additional items.
381 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {393 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
382 const new_len = self.items.len + n;394 const new_len = self.items.len + n;
383 assert(new_len <= self.capacity);395 assert(new_len <= self.capacity);
...@@ -385,9 +397,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -385,9 +397,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
385 self.items.len = new_len;397 self.items.len = new_len;
386 }398 }
387399
388 /// Adjust the list's length to `new_len`.400 /// Adjust the list length to `new_len`.
389 /// Does not initialize added items if any.401 /// Additional elements contain the value `undefined`.
390 /// Invalidates pointers if additional memory is needed.402 /// Invalidates element pointers if additional memory is needed.
391 pub fn resize(self: *Self, new_len: usize) Allocator.Error!void {403 pub fn resize(self: *Self, new_len: usize) Allocator.Error!void {
392 try self.ensureTotalCapacity(new_len);404 try self.ensureTotalCapacity(new_len);
393 self.items.len = new_len;405 self.items.len = new_len;
...@@ -395,6 +407,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -395,6 +407,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
395407
396 /// Reduce allocated capacity to `new_len`.408 /// Reduce allocated capacity to `new_len`.
397 /// May invalidate element pointers.409 /// May invalidate element pointers.
410 /// Asserts that the new length is less than or equal to the previous length.
398 pub fn shrinkAndFree(self: *Self, new_len: usize) void {411 pub fn shrinkAndFree(self: *Self, new_len: usize) void {
399 var unmanaged = self.moveToUnmanaged();412 var unmanaged = self.moveToUnmanaged();
400 unmanaged.shrinkAndFree(self.allocator, new_len);413 unmanaged.shrinkAndFree(self.allocator, new_len);
...@@ -402,7 +415,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -402,7 +415,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
402 }415 }
403416
404 /// Reduce length to `new_len`.417 /// 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.
406 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {420 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
407 assert(new_len <= self.items.len);421 assert(new_len <= self.items.len);
408 self.items.len = new_len;422 self.items.len = new_len;
...@@ -422,7 +436,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -422,7 +436,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
422436
423 /// If the current capacity is less than `new_capacity`, this function will437 /// If the current capacity is less than `new_capacity`, this function will
424 /// modify the array so that it can hold at least `new_capacity` items.438 /// 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.
426 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void {440 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void {
427 if (@sizeOf(T) == 0) {441 if (@sizeOf(T) == 0) {
428 self.capacity = math.maxInt(usize);442 self.capacity = math.maxInt(usize);
...@@ -437,7 +451,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -437,7 +451,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
437451
438 /// If the current capacity is less than `new_capacity`, this function will452 /// If the current capacity is less than `new_capacity`, this function will
439 /// modify the array so that it can hold exactly `new_capacity` items.453 /// 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.
441 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void {455 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void {
442 if (@sizeOf(T) == 0) {456 if (@sizeOf(T) == 0) {
443 self.capacity = math.maxInt(usize);457 self.capacity = math.maxInt(usize);
...@@ -464,13 +478,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -464,13 +478,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
464 }478 }
465479
466 /// Modify the array so that it can hold at least `additional_count` **more** items.480 /// 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.
468 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void {482 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));
470 }484 }
471485
472 /// Increases the array's length to match the full capacity that is already allocated.486 /// 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.
474 pub fn expandToCapacity(self: *Self) void {489 pub fn expandToCapacity(self: *Self) void {
475 self.items.len = self.capacity;490 self.items.len = self.capacity;
476 }491 }
...@@ -478,14 +493,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -478,14 +493,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
478 /// Increase length by 1, returning pointer to the new item.493 /// Increase length by 1, returning pointer to the new item.
479 /// The returned pointer becomes invalid when the list resized.494 /// The returned pointer becomes invalid when the list resized.
480 pub fn addOne(self: *Self) Allocator.Error!*T {495 pub fn addOne(self: *Self) Allocator.Error!*T {
481 try self.ensureTotalCapacity(self.items.len + 1);496 try self.ensureUnusedCapacity(1);
482 return self.addOneAssumeCapacity();497 return self.addOneAssumeCapacity();
483 }498 }
484499
485 /// Increase length by 1, returning pointer to the new item.500 /// Increase length by 1, returning pointer to the new item.
486 /// Asserts that there is already space for the new item without allocating more.
487 /// The returned pointer becomes invalid when the list is resized.501 /// 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.
489 pub fn addOneAssumeCapacity(self: *Self) *T {504 pub fn addOneAssumeCapacity(self: *Self) *T {
490 assert(self.items.len < self.capacity);505 assert(self.items.len < self.capacity);
491 self.items.len += 1;506 self.items.len += 1;
...@@ -498,15 +513,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -498,15 +513,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
498 /// Resizes list if `self.capacity` is not large enough.513 /// Resizes list if `self.capacity` is not large enough.
499 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {514 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {
500 const prev_len = self.items.len;515 const prev_len = self.items.len;
501 try self.resize(self.items.len + n);516 try self.resize(try addOrOom(self.items.len, n));
502 return self.items[prev_len..][0..n];517 return self.items[prev_len..][0..n];
503 }518 }
504519
505 /// Resize the array, adding `n` new elements, which have `undefined` values.520 /// Resize the array, adding `n` new elements, which have `undefined` values.
506 /// The return value is an array pointing to the newly allocated elements.521 /// 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.522 /// Never invalidates element pointers.
508 /// **Does not** invalidate element pointers.
509 /// The returned pointer becomes invalid when the list is resized.523 /// The returned pointer becomes invalid when the list is resized.
524 /// Asserts that the list can hold the additional items.
510 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {525 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
511 assert(self.items.len + n <= self.capacity);526 assert(self.items.len + n <= self.capacity);
512 const prev_len = self.items.len;527 const prev_len = self.items.len;
...@@ -520,15 +535,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -520,15 +535,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
520 /// Resizes list if `self.capacity` is not large enough.535 /// Resizes list if `self.capacity` is not large enough.
521 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {536 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {
522 const prev_len = self.items.len;537 const prev_len = self.items.len;
523 try self.resize(self.items.len + n);538 try self.resize(try addOrOom(self.items.len, n));
524 return self.items[prev_len..][0..n];539 return self.items[prev_len..][0..n];
525 }540 }
526541
527 /// Resize the array, adding `n` new elements, which have `undefined` values.542 /// Resize the array, adding `n` new elements, which have `undefined` values.
528 /// The return value is a slice pointing to the newly allocated elements.543 /// 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.544 /// Never invalidates element pointers.
530 /// **Does not** invalidate element pointers.
531 /// The returned pointer becomes invalid when the list is resized.545 /// The returned pointer becomes invalid when the list is resized.
546 /// Asserts that the list can hold the additional items.
532 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {547 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
533 assert(self.items.len + n <= self.capacity);548 assert(self.items.len + n <= self.capacity);
534 const prev_len = self.items.len;549 const prev_len = self.items.len;
...@@ -537,8 +552,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -537,8 +552,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
537 }552 }
538553
539 /// Remove and return the last element from the list.554 /// Remove and return the last element from the list.
540 /// Asserts the list has at least one item.555 /// Invalidates element pointers to the removed element.
541 /// Invalidates pointers to the removed element.556 /// Asserts that the list is not empty.
542 pub fn pop(self: *Self) T {557 pub fn pop(self: *Self) T {
543 const val = self.items[self.items.len - 1];558 const val = self.items[self.items.len - 1];
544 self.items.len -= 1;559 self.items.len -= 1;
...@@ -547,7 +562,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -547,7 +562,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
547562
548 /// Remove and return the last element from the list, or563 /// Remove and return the last element from the list, or
549 /// return `null` if list is empty.564 /// 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.
551 pub fn popOrNull(self: *Self) ?T {566 pub fn popOrNull(self: *Self) ?T {
552 if (self.items.len == 0) return null;567 if (self.items.len == 0) return null;
553 return self.pop();568 return self.pop();
...@@ -568,15 +583,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -568,15 +583,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
568 return self.allocatedSlice()[self.items.len..];583 return self.allocatedSlice()[self.items.len..];
569 }584 }
570585
571 /// Return the last element from the list.586 /// Returns the last element from the list.
572 /// Asserts the list has at least one item.587 /// Asserts that the list is not empty.
573 pub fn getLast(self: Self) T {588 pub fn getLast(self: Self) T {
574 const val = self.items[self.items.len - 1];589 const val = self.items[self.items.len - 1];
575 return val;590 return val;
576 }591 }
577592
578 /// Return the last element from the list, or593 /// Returns the last element from the list, or `null` if list is empty.
579 /// return `null` if list is empty.
580 pub fn getLastOrNull(self: Self) ?T {594 pub fn getLastOrNull(self: Self) ?T {
581 if (self.items.len == 0) return null;595 if (self.items.len == 0) return null;
582 return self.getLast();596 return self.getLast();
...@@ -585,17 +599,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -585,17 +599,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
585}599}
586600
587/// An ArrayList, but the allocator is passed as a parameter to the relevant functions601/// 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 throughout602/// rather than stored in the struct itself. The same allocator must be used throughout
589/// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with603/// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with
590/// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`.604/// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`.
591pub fn ArrayListUnmanaged(comptime T: type) type {605pub fn ArrayListUnmanaged(comptime T: type) type {
592 return ArrayListAlignedUnmanaged(T, null);606 return ArrayListAlignedUnmanaged(T, null);
593}607}
594608
595/// An ArrayListAligned, but the allocator is passed as a parameter to the relevant609/// A contiguous, growable list of arbitrarily aligned items in memory.
596/// functions rather than stored in the struct itself. The same allocator **must**610/// This is a wrapper around an array of T values aligned to `alignment`-byte
597/// be used throughout the entire lifetime of an ArrayListAlignedUnmanaged.611/// addresses. If the specified alignment is `null`, then `@alignOf(T)` is used.
598/// Initialize directly or with `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`.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`.
599pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {616pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {
600 if (alignment) |a| {617 if (alignment) |a| {
601 if (a == @alignOf(T)) {618 if (a == @alignOf(T)) {
...@@ -604,15 +621,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -604,15 +621,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
604 }621 }
605 return struct {622 return struct {
606 const Self = @This();623 const Self = @This();
607 /// Contents of the list. Pointers to elements in this slice are624 /// Contents of the list. This field is intended to be accessed
608 /// **invalid after resizing operations** on the ArrayList unless the625 /// directly.
609 /// operation explicitly either: (1) states otherwise or (2) lists the
610 /// invalidated pointers.
611 ///626 ///
612 /// The allocator used determines how element pointers are627 /// Pointers to elements in this slice are invalidated by various
613 /// invalidated, so the behavior may vary between lists. To avoid628 /// functions of this ArrayList in accordance with the respective
614 /// illegal behavior, take into account the above paragraph plus the629 /// documentation. In all cases, "invalidated" means that the memory
615 /// explicit statements given in each method.630 /// has been passed to an allocator's resize or free function.
616 items: Slice = &[_]T{},631 items: Slice = &[_]T{},
617 /// How many T values this list can hold without allocating632 /// How many T values this list can hold without allocating
618 /// additional memory.633 /// additional memory.
...@@ -635,8 +650,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -635,8 +650,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
635650
636 /// Initialize with externally-managed memory. The buffer determines the651 /// Initialize with externally-managed memory. The buffer determines the
637 /// capacity, and the length is set to zero.652 /// capacity, and the length is set to zero.
638 /// When initialized this way, all methods that accept an Allocator653 /// When initialized this way, all functions that accept an Allocator
639 /// argument are illegal to call.654 /// argument cause illegal behavior.
640 pub fn initBuffer(buffer: Slice) Self {655 pub fn initBuffer(buffer: Slice) Self {
641 return .{656 return .{
642 .items = buffer[0..0],657 .items = buffer[0..0],
...@@ -695,7 +710,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -695,7 +710,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
695710
696 /// The caller owns the returned memory. ArrayList becomes empty.711 /// The caller owns the returned memory. ArrayList becomes empty.
697 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {712 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));
699 self.appendAssumeCapacity(sentinel);714 self.appendAssumeCapacity(sentinel);
700 const result = try self.toOwnedSlice(allocator);715 const result = try self.toOwnedSlice(allocator);
701 return result[0 .. result.len - 1 :sentinel];716 return result[0 .. result.len - 1 :sentinel];
...@@ -708,25 +723,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -708,25 +723,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
708 return cloned;723 return cloned;
709 }724 }
710725
711 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.726 /// Insert `item` at index `i`. Moves `list[i .. 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.727 /// If `i` is equal to the length of the list this operation is equivalent to append.
713 /// This operation is O(N).728 /// This operation is O(N).
714 /// Invalidates pointers if additional memory is needed.729 /// Invalidates element pointers if additional memory is needed.
715 pub fn insert(self: *Self, allocator: Allocator, n: usize, item: T) Allocator.Error!void {730 /// Asserts that the index is in bounds or equal to the length.
716 const dst = try self.addManyAt(allocator, n, 1);731 pub fn insert(self: *Self, allocator: Allocator, i: usize, item: T) Allocator.Error!void {
732 const dst = try self.addManyAt(allocator, i, 1);
717 dst[0] = item;733 dst[0] = item;
718 }734 }
719735
720 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.736 /// Insert `item` at index `i`. Moves `list[i .. 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.737 /// If in` is equal to the length of the list this operation is equivalent to append.
722 /// This operation is O(N).738 /// This operation is O(N).
723 /// Asserts that there is enough capacity for the new item.739 /// Asserts that the list has capacity for one additional item.
724 pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void {740 /// Asserts that the index is in bounds or equal to the length.
741 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
725 assert(self.items.len < self.capacity);742 assert(self.items.len < self.capacity);
726 self.items.len += 1;743 self.items.len += 1;
727744
728 mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]);745 mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
729 self.items[n] = item;746 self.items[i] = item;
730 }747 }
731748
732 /// Add `count` new elements at position `index`, which have749 /// Add `count` new elements at position `index`, which have
...@@ -736,6 +753,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -736,6 +753,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
736 /// Invalidates pre-existing pointers to elements at and after `index`.753 /// Invalidates pre-existing pointers to elements at and after `index`.
737 /// Invalidates all pre-existing element pointers if capacity must be754 /// Invalidates all pre-existing element pointers if capacity must be
738 /// increased to accomodate the new elements.755 /// increased to accomodate the new elements.
756 /// Asserts that the index is in bounds or equal to the length.
739 pub fn addManyAt(757 pub fn addManyAt(
740 self: *Self,758 self: *Self,
741 allocator: Allocator,759 allocator: Allocator,
...@@ -751,9 +769,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -751,9 +769,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
751 /// `undefined` values. Returns a slice pointing to the newly allocated769 /// `undefined` values. Returns a slice pointing to the newly allocated
752 /// elements, which becomes invalid after various `ArrayList`770 /// elements, which becomes invalid after various `ArrayList`
753 /// operations.771 /// operations.
754 /// Asserts that there is enough capacity for the new elements.
755 /// Invalidates pre-existing pointers to elements at and after `index`, but772 /// Invalidates pre-existing pointers to elements at and after `index`, but
756 /// does not invalidate any before that.773 /// 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.
757 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {776 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
758 const new_len = self.items.len + count;777 const new_len = self.items.len + count;
759 assert(self.capacity >= new_len);778 assert(self.capacity >= new_len);
...@@ -770,6 +789,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -770,6 +789,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
770 /// Invalidates pre-existing pointers to elements at and after `index`.789 /// Invalidates pre-existing pointers to elements at and after `index`.
771 /// Invalidates all pre-existing element pointers if capacity must be790 /// Invalidates all pre-existing element pointers if capacity must be
772 /// increased to accomodate the new elements.791 /// increased to accomodate the new elements.
792 /// Asserts that the index is in bounds or equal to the length.
773 pub fn insertSlice(793 pub fn insertSlice(
774 self: *Self,794 self: *Self,
775 allocator: Allocator,795 allocator: Allocator,
...@@ -787,7 +807,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -787,7 +807,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
787 /// Replace range of elements `list[start..][0..len]` with `new_items`807 /// Replace range of elements `list[start..][0..len]` with `new_items`
788 /// Grows list if `len < new_items.len`.808 /// Grows list if `len < new_items.len`.
789 /// Shrinks list if `len > new_items.len`809 /// 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.
791 pub fn replaceRange(812 pub fn replaceRange(
792 self: *Self,813 self: *Self,
793 allocator: Allocator,814 allocator: Allocator,
...@@ -801,23 +822,25 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -801,23 +822,25 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
801 }822 }
802823
803 /// Extend the list by 1 element. Allocates more memory as necessary.824 /// 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.
805 pub fn append(self: *Self, allocator: Allocator, item: T) Allocator.Error!void {826 pub fn append(self: *Self, allocator: Allocator, item: T) Allocator.Error!void {
806 const new_item_ptr = try self.addOne(allocator);827 const new_item_ptr = try self.addOne(allocator);
807 new_item_ptr.* = item;828 new_item_ptr.* = item;
808 }829 }
809830
810 /// Extend the list by 1 element, but asserting `self.capacity`831 /// Extend the list by 1 element.
811 /// is sufficient to hold an additional item.832 /// Never invalidates element pointers.
833 /// Asserts that the list can hold one additional item.
812 pub fn appendAssumeCapacity(self: *Self, item: T) void {834 pub fn appendAssumeCapacity(self: *Self, item: T) void {
813 const new_item_ptr = self.addOneAssumeCapacity();835 const new_item_ptr = self.addOneAssumeCapacity();
814 new_item_ptr.* = item;836 new_item_ptr.* = item;
815 }837 }
816838
817 /// Remove the element at index `i` from the list and return its value.839 /// Remove the element at index `i` from the list and return its value.
818 /// Asserts the array has at least one item. Invalidates pointers to840 /// Invalidates pointers to the last element.
819 /// last element.
820 /// This operation is O(N).841 /// This operation is O(N).
842 /// Asserts that the list is not empty.
843 /// Asserts that the index is in bounds.
821 pub fn orderedRemove(self: *Self, i: usize) T {844 pub fn orderedRemove(self: *Self, i: usize) T {
822 const newlen = self.items.len - 1;845 const newlen = self.items.len - 1;
823 if (newlen == i) return self.pop();846 if (newlen == i) return self.pop();
...@@ -833,6 +856,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -833,6 +856,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
833 /// The empty slot is filled from the end of the list.856 /// The empty slot is filled from the end of the list.
834 /// Invalidates pointers to last element.857 /// Invalidates pointers to last element.
835 /// This operation is O(1).858 /// This operation is O(1).
859 /// Asserts that the list is not empty.
860 /// Asserts that the index is in bounds.
836 pub fn swapRemove(self: *Self, i: usize) T {861 pub fn swapRemove(self: *Self, i: usize) T {
837 if (self.items.len - 1 == i) return self.pop();862 if (self.items.len - 1 == i) return self.pop();
838863
...@@ -843,14 +868,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -843,14 +868,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
843868
844 /// Append the slice of items to the list. Allocates more869 /// Append the slice of items to the list. Allocates more
845 /// memory as necessary.870 /// memory as necessary.
846 /// Invalidates pointers if additional memory is needed.871 /// Invalidates element pointers if additional memory is needed.
847 pub fn appendSlice(self: *Self, allocator: Allocator, items: []const T) Allocator.Error!void {872 pub fn appendSlice(self: *Self, allocator: Allocator, items: []const T) Allocator.Error!void {
848 try self.ensureUnusedCapacity(allocator, items.len);873 try self.ensureUnusedCapacity(allocator, items.len);
849 self.appendSliceAssumeCapacity(items);874 self.appendSliceAssumeCapacity(items);
850 }875 }
851876
852 /// Append the slice of items to the list, asserting the capacity is enough877 /// Append the slice of items to the list.
853 /// to store the new items.878 /// Asserts that the list can hold the additional items.
854 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {879 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
855 const old_len = self.items.len;880 const old_len = self.items.len;
856 const new_len = old_len + items.len;881 const new_len = old_len + items.len;
...@@ -862,15 +887,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -862,15 +887,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
862 /// Append the slice of items to the list. Allocates more887 /// Append the slice of items to the list. Allocates more
863 /// memory as necessary. Only call this function if a call to `appendSlice` instead would888 /// memory as necessary. Only call this function if a call to `appendSlice` instead would
864 /// be a compile error.889 /// be a compile error.
865 /// Invalidates pointers if additional memory is needed.890 /// Invalidates element pointers if additional memory is needed.
866 pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void {891 pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void {
867 try self.ensureUnusedCapacity(allocator, items.len);892 try self.ensureUnusedCapacity(allocator, items.len);
868 self.appendUnalignedSliceAssumeCapacity(items);893 self.appendUnalignedSliceAssumeCapacity(items);
869 }894 }
870895
871 /// Append an unaligned slice of items to the list, asserting the capacity is enough896 /// Append an unaligned slice of items to the list.
872 /// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity`897 /// Only call this function if a call to `appendSliceAssumeCapacity`
873 /// instead would be a compile error.898 /// instead would be a compile error.
899 /// Asserts that the list can hold the additional items.
874 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {900 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
875 const old_len = self.items.len;901 const old_len = self.items.len;
876 const new_len = old_len + items.len;902 const new_len = old_len + items.len;
...@@ -888,7 +914,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -888,7 +914,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
888 @compileError("The Writer interface is only defined for ArrayList(u8) " ++914 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
889 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")915 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
890 else916 else
891 std.io.Writer(WriterContext, error{OutOfMemory}, appendWrite);917 std.io.Writer(WriterContext, Allocator.Error, appendWrite);
892918
893 /// Initializes a Writer which will append to the list.919 /// Initializes a Writer which will append to the list.
894 pub fn writer(self: *Self, allocator: Allocator) Writer {920 pub fn writer(self: *Self, allocator: Allocator) Writer {
...@@ -897,7 +923,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -897,7 +923,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
897923
898 /// Same as `append` except it returns the number of bytes written, which is always the same924 /// Same as `append` except it returns the number of bytes written, which is always the same
899 /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.925 /// 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.
901 fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {927 fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
902 try context.self.appendSlice(context.allocator, m);928 try context.self.appendSlice(context.allocator, m);
903 return m.len;929 return m.len;
...@@ -905,20 +931,20 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -905,20 +931,20 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
905931
906 /// Append a value to the list `n` times.932 /// Append a value to the list `n` times.
907 /// Allocates more memory as necessary.933 /// Allocates more memory as necessary.
908 /// Invalidates pointers if additional memory is needed.934 /// Invalidates element pointers if additional memory is needed.
909 /// The function is inline so that a comptime-known `value` parameter will935 /// The function is inline so that a comptime-known `value` parameter will
910 /// have a more optimal memset codegen in case it has a repeated byte pattern.936 /// have a more optimal memset codegen in case it has a repeated byte pattern.
911 pub inline fn appendNTimes(self: *Self, allocator: Allocator, value: T, n: usize) Allocator.Error!void {937 pub inline fn appendNTimes(self: *Self, allocator: Allocator, value: T, n: usize) Allocator.Error!void {
912 const old_len = self.items.len;938 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));
914 @memset(self.items[old_len..self.items.len], value);940 @memset(self.items[old_len..self.items.len], value);
915 }941 }
916942
917 /// Append a value to the list `n` times.943 /// Append a value to the list `n` times.
918 /// **Does not** invalidate pointers.944 /// Never invalidates element pointers.
919 /// Asserts the capacity is enough.
920 /// The function is inline so that a comptime-known `value` parameter will945 /// 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.
922 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {948 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
923 const new_len = self.items.len + n;949 const new_len = self.items.len + n;
924 assert(new_len <= self.capacity);950 assert(new_len <= self.capacity);
...@@ -926,9 +952,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -926,9 +952,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
926 self.items.len = new_len;952 self.items.len = new_len;
927 }953 }
928954
929 /// Adjust the list's length to `new_len`.955 /// Adjust the list length to `new_len`.
930 /// Does not initialize added items, if any.956 /// Additional elements contain the value `undefined`.
931 /// Invalidates pointers if additional memory is needed.957 /// Invalidates element pointers if additional memory is needed.
932 pub fn resize(self: *Self, allocator: Allocator, new_len: usize) Allocator.Error!void {958 pub fn resize(self: *Self, allocator: Allocator, new_len: usize) Allocator.Error!void {
933 try self.ensureTotalCapacity(allocator, new_len);959 try self.ensureTotalCapacity(allocator, new_len);
934 self.items.len = new_len;960 self.items.len = new_len;
...@@ -936,6 +962,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -936,6 +962,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
936962
937 /// Reduce allocated capacity to `new_len`.963 /// Reduce allocated capacity to `new_len`.
938 /// May invalidate element pointers.964 /// May invalidate element pointers.
965 /// Asserts that the new length is less than or equal to the previous length.
939 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {966 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {
940 assert(new_len <= self.items.len);967 assert(new_len <= self.items.len);
941968
...@@ -968,6 +995,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -968,6 +995,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
968 /// Reduce length to `new_len`.995 /// Reduce length to `new_len`.
969 /// Invalidates pointers to elements `items[new_len..]`.996 /// Invalidates pointers to elements `items[new_len..]`.
970 /// Keeps capacity the same.997 /// Keeps capacity the same.
998 /// Asserts that the new length is less than or equal to the previous length.
971 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {999 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
972 assert(new_len <= self.items.len);1000 assert(new_len <= self.items.len);
973 self.items.len = new_len;1001 self.items.len = new_len;
...@@ -987,7 +1015,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -987,7 +1015,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
9871015
988 /// If the current capacity is less than `new_capacity`, this function will1016 /// If the current capacity is less than `new_capacity`, this function will
989 /// modify the array so that it can hold at least `new_capacity` items.1017 /// 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.
991 pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {1019 pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
992 if (self.capacity >= new_capacity) return;1020 if (self.capacity >= new_capacity) return;
9931021
...@@ -997,7 +1025,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -997,7 +1025,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
9971025
998 /// If the current capacity is less than `new_capacity`, this function will1026 /// If the current capacity is less than `new_capacity`, this function will
999 /// modify the array so that it can hold exactly `new_capacity` items.1027 /// 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.
1001 pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {1029 pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
1002 if (@sizeOf(T) == 0) {1030 if (@sizeOf(T) == 0) {
1003 self.capacity = math.maxInt(usize);1031 self.capacity = math.maxInt(usize);
...@@ -1024,34 +1052,34 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1024,34 +1052,34 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1024 }1052 }
10251053
1026 /// Modify the array so that it can hold at least `additional_count` **more** items.1054 /// 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.
1028 pub fn ensureUnusedCapacity(1056 pub fn ensureUnusedCapacity(
1029 self: *Self,1057 self: *Self,
1030 allocator: Allocator,1058 allocator: Allocator,
1031 additional_count: usize,1059 additional_count: usize,
1032 ) Allocator.Error!void {1060 ) 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));
1034 }1062 }
10351063
1036 /// Increases the array's length to match the full capacity that is already allocated.1064 /// Increases the array's length to match the full capacity that is already allocated.
1037 /// The new elements have `undefined` values.1065 /// The new elements have `undefined` values.
1038 /// **Does not** invalidate pointers.1066 /// Never invalidates element pointers.
1039 pub fn expandToCapacity(self: *Self) void {1067 pub fn expandToCapacity(self: *Self) void {
1040 self.items.len = self.capacity;1068 self.items.len = self.capacity;
1041 }1069 }
10421070
1043 /// Increase length by 1, returning pointer to the new item.1071 /// 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.
1045 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {1073 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);
1047 try self.ensureTotalCapacity(allocator, newlen);1075 try self.ensureTotalCapacity(allocator, newlen);
1048 return self.addOneAssumeCapacity();1076 return self.addOneAssumeCapacity();
1049 }1077 }
10501078
1051 /// Increase length by 1, returning pointer to the new item.1079 /// Increase length by 1, returning pointer to the new item.
1052 /// Asserts that there is already space for the new item without allocating more.1080 /// Never invalidates element pointers.
1053 /// **Does not** invalidate pointers.1081 /// The returned element pointer becomes invalid when the list is resized.
1054 /// The returned pointer becomes invalid when the list resized.1082 /// Asserts that the list can hold one additional item.
1055 pub fn addOneAssumeCapacity(self: *Self) *T {1083 pub fn addOneAssumeCapacity(self: *Self) *T {
1056 assert(self.items.len < self.capacity);1084 assert(self.items.len < self.capacity);
10571085
...@@ -1064,15 +1092,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1064,15 +1092,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1064 /// The returned pointer becomes invalid when the list is resized.1092 /// The returned pointer becomes invalid when the list is resized.
1065 pub fn addManyAsArray(self: *Self, allocator: Allocator, comptime n: usize) Allocator.Error!*[n]T {1093 pub fn addManyAsArray(self: *Self, allocator: Allocator, comptime n: usize) Allocator.Error!*[n]T {
1066 const prev_len = self.items.len;1094 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));
1068 return self.items[prev_len..][0..n];1096 return self.items[prev_len..][0..n];
1069 }1097 }
10701098
1071 /// Resize the array, adding `n` new elements, which have `undefined` values.1099 /// Resize the array, adding `n` new elements, which have `undefined` values.
1072 /// The return value is an array pointing to the newly allocated elements.1100 /// 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.1101 /// Never invalidates element pointers.
1074 /// **Does not** invalidate pointers.
1075 /// The returned pointer becomes invalid when the list is resized.1102 /// The returned pointer becomes invalid when the list is resized.
1103 /// Asserts that the list can hold the additional items.
1076 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {1104 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
1077 assert(self.items.len + n <= self.capacity);1105 assert(self.items.len + n <= self.capacity);
1078 const prev_len = self.items.len;1106 const prev_len = self.items.len;
...@@ -1086,15 +1114,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1086,15 +1114,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1086 /// Resizes list if `self.capacity` is not large enough.1114 /// Resizes list if `self.capacity` is not large enough.
1087 pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T {1115 pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T {
1088 const prev_len = self.items.len;1116 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));
1090 return self.items[prev_len..][0..n];1118 return self.items[prev_len..][0..n];
1091 }1119 }
10921120
1093 /// Resize the array, adding `n` new elements, which have `undefined` values.1121 /// Resize the array, adding `n` new elements, which have `undefined` values.
1094 /// The return value is a slice pointing to the newly allocated elements.1122 /// 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.1123 /// Never invalidates element pointers.
1096 /// **Does not** invalidate element pointers.
1097 /// The returned pointer becomes invalid when the list is resized.1124 /// The returned pointer becomes invalid when the list is resized.
1125 /// Asserts that the list can hold the additional items.
1098 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {1126 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
1099 assert(self.items.len + n <= self.capacity);1127 assert(self.items.len + n <= self.capacity);
1100 const prev_len = self.items.len;1128 const prev_len = self.items.len;
...@@ -1103,8 +1131,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1103,8 +1131,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1103 }1131 }
11041132
1105 /// Remove and return the last element from the list.1133 /// Remove and return the last element from the list.
1106 /// Asserts the list has at least one item.
1107 /// Invalidates pointers to last element.1134 /// Invalidates pointers to last element.
1135 /// Asserts that the list is not empty.
1108 pub fn pop(self: *Self) T {1136 pub fn pop(self: *Self) T {
1109 const val = self.items[self.items.len - 1];1137 const val = self.items[self.items.len - 1];
1110 self.items.len -= 1;1138 self.items.len -= 1;
...@@ -1134,7 +1162,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1134,7 +1162,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1134 }1162 }
11351163
1136 /// Return the last element from the list.1164 /// Return the last element from the list.
1137 /// Asserts the list has at least one item.1165 /// Asserts that the list is not empty.
1138 pub fn getLast(self: Self) T {1166 pub fn getLast(self: Self) T {
1139 const val = self.items[self.items.len - 1];1167 const val = self.items[self.items.len - 1];
1140 return val;1168 return val;
...@@ -1160,6 +1188,13 @@ fn growCapacity(current: usize, minimum: usize) usize {...@@ -1160,6 +1188,13 @@ fn growCapacity(current: usize, minimum: usize) usize {
1160 }1188 }
1161}1189}
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
1163test "std.ArrayList/ArrayListUnmanaged.init" {1198test "std.ArrayList/ArrayListUnmanaged.init" {
1164 {1199 {
1165 var list = ArrayList(i32).init(testing.allocator);1200 var list = ArrayList(i32).init(testing.allocator);
...@@ -1952,3 +1987,51 @@ test "std.ArrayList(u32).getLastOrNull()" {...@@ -1952,3 +1987,51 @@ test "std.ArrayList(u32).getLastOrNull()" {
1952 const const_list = list;1987 const const_list = list;
1953 try testing.expectEqual(const_list.getLastOrNull().?, 2);1988 try testing.expectEqual(const_list.getLastOrNull().?, 2);
1954}1989}
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}