authorgravatar for 119271574+notcancername@users.noreply.github.comnotcancername <119271574+notcancername@users.noreply.github.com> 2024-01-07 05:09:54+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-15 23:44:36-07:00
log69461bcae4a78c835bdfe0aae85524342c0f8461
tree920b81234bdd9b0fdc2947ce800e95d1cd372e91
parent32e88251e48d9f4a412b08acbd04d5694ec91e19

std.array_list: Document and reduce illegal behavior in ArrayLists


1 files changed, 155 insertions(+), 78 deletions(-)

lib/std/array_list.zig+155-78
...@@ -128,7 +128,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -128,7 +128,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
128128
129 /// The caller owns the returned memory. Empties this ArrayList.129 /// The caller owns the returned memory. Empties this ArrayList.
130 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {130 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
131 try self.ensureTotalCapacityPrecise(self.items.len + 1);131 try self.ensureTotalCapacityPrecise(try addOrOom(self.items.len, 1));
132 self.appendAssumeCapacity(sentinel);132 self.appendAssumeCapacity(sentinel);
133 const result = try self.toOwnedSlice();133 const result = try self.toOwnedSlice();
134 return result[0 .. result.len - 1 :sentinel];134 return result[0 .. result.len - 1 :sentinel];
...@@ -141,25 +141,27 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -141,25 +141,27 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
141 return cloned;141 return cloned;
142 }142 }
143143
144 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.144 /// 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.145 /// If `i` is equal to the length of the list this operation is equivalent to append.
146 /// This operation is O(N).146 /// This operation is O(N).
147 /// Invalidates pointers if additional memory is needed.147 /// Invalidates pointers if additional memory is needed.
148 pub fn insert(self: *Self, n: usize, item: T) Allocator.Error!void {148 /// **Asserts that `i <= self.items.len`.**
149 const dst = try self.addManyAt(n, 1);149 pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void {
150 const dst = try self.addManyAt(i, 1);
150 dst[0] = item;151 dst[0] = item;
151 }152 }
152153
153 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.154 /// 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.155 /// If `i` is equal to the length of the list this operation is equivalent to appendAssumeCapacity.
155 /// This operation is O(N).156 /// This operation is O(N).
156 /// Asserts that there is enough capacity for the new item.157 /// **Asserts that `i <= self.items.len`.**
157 pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void {158 /// **Asserts that `self.items.len < self.capacity` .**
159 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
158 assert(self.items.len < self.capacity);160 assert(self.items.len < self.capacity);
159 self.items.len += 1;161 self.items.len += 1;
160162
161 mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]);163 mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
162 self.items[n] = item;164 self.items[i] = item;
163 }165 }
164166
165 /// Add `count` new elements at position `index`, which have167 /// Add `count` new elements at position `index`, which have
...@@ -169,8 +171,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -169,8 +171,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
169 /// Invalidates pre-existing pointers to elements at and after `index`.171 /// Invalidates pre-existing pointers to elements at and after `index`.
170 /// Invalidates all pre-existing element pointers if capacity must be172 /// Invalidates all pre-existing element pointers if capacity must be
171 /// increased to accomodate the new elements.173 /// increased to accomodate the new elements.
174 /// **Asserts that `index <= self.items.len`.**
172 pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {175 pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {
173 const new_len = self.items.len + count;176 const new_len = try addOrOom(self.items.len, count);
174177
175 if (self.capacity >= new_len)178 if (self.capacity >= new_len)
176 return addManyAtAssumeCapacity(self, index, count);179 return addManyAtAssumeCapacity(self, index, count);
...@@ -205,9 +208,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -205,9 +208,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
205 /// `undefined` values. Returns a slice pointing to the newly allocated208 /// `undefined` values. Returns a slice pointing to the newly allocated
206 /// elements, which becomes invalid after various `ArrayList`209 /// elements, which becomes invalid after various `ArrayList`
207 /// operations.210 /// operations.
208 /// 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 `index <= self.items.len`.**
214 /// **Asserts that the list can hold `count` additional items.**
211 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {215 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
212 const new_len = self.items.len + count;216 const new_len = self.items.len + count;
213 assert(self.capacity >= new_len);217 assert(self.capacity >= new_len);
...@@ -224,6 +228,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -224,6 +228,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
224 /// Invalidates pre-existing pointers to elements at and after `index`.228 /// Invalidates pre-existing pointers to elements at and after `index`.
225 /// Invalidates all pre-existing element pointers if capacity must be229 /// Invalidates all pre-existing element pointers if capacity must be
226 /// increased to accomodate the new elements.230 /// increased to accomodate the new elements.
231 /// **Asserts that `index <= self.items.len`.**
227 pub fn insertSlice(232 pub fn insertSlice(
228 self: *Self,233 self: *Self,
229 index: usize,234 index: usize,
...@@ -237,8 +242,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -237,8 +242,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
237 /// Grows list if `len < new_items.len`.242 /// Grows list if `len < new_items.len`.
238 /// Shrinks list if `len > new_items.len`.243 /// Shrinks list if `len > new_items.len`.
239 /// Invalidates pointers if this ArrayList is resized.244 /// Invalidates pointers if this ArrayList is resized.
245 /// **Asserts that `start <= self.items.len`.**
240 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {246 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {
241 const after_range = start + len;247 const after_range = try addOrOom(start, len);
242 const range = self.items[start..after_range];248 const range = self.items[start..after_range];
243249
244 if (range.len == new_items.len)250 if (range.len == new_items.len)
...@@ -251,7 +257,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -251,7 +257,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
251 try self.insertSlice(after_range, rest);257 try self.insertSlice(after_range, rest);
252 } else {258 } else {
253 @memcpy(range[0..new_items.len], new_items);259 @memcpy(range[0..new_items.len], new_items);
254 const after_subrange = start + new_items.len;260 const after_subrange = try addOrOom(start, new_items.len);
255261
256 for (self.items[after_range..], 0..) |item, i| {262 for (self.items[after_range..], 0..) |item, i| {
257 self.items[after_subrange..][i] = item;263 self.items[after_subrange..][i] = item;
...@@ -261,16 +267,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -261,16 +267,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
261 }267 }
262 }268 }
263269
264 /// Extend the list by 1 element. Allocates more memory as necessary.270 /// Extends the list by 1 element. Allocates more memory as necessary.
265 /// Invalidates pointers if additional memory is needed.271 /// Invalidates pointers if additional memory is needed.
266 pub fn append(self: *Self, item: T) Allocator.Error!void {272 pub fn append(self: *Self, item: T) Allocator.Error!void {
267 const new_item_ptr = try self.addOne();273 const new_item_ptr = try self.addOne();
268 new_item_ptr.* = item;274 new_item_ptr.* = item;
269 }275 }
270276
271 /// Extend the list by 1 element, but assert `self.capacity`277 /// Extends the list by 1 element. Does not
272 /// is sufficient to hold an additional item. **Does not**
273 /// invalidate pointers.278 /// invalidate pointers.
279 /// **Asserts that the list can hold one additional item.**
274 pub fn appendAssumeCapacity(self: *Self, item: T) void {280 pub fn appendAssumeCapacity(self: *Self, item: T) void {
275 const new_item_ptr = self.addOneAssumeCapacity();281 const new_item_ptr = self.addOneAssumeCapacity();
276 new_item_ptr.* = item;282 new_item_ptr.* = item;
...@@ -278,10 +284,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -278,10 +284,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
278284
279 /// Remove the element at index `i`, shift elements after index285 /// Remove the element at index `i`, shift elements after index
280 /// `i` forward, and return the removed element.286 /// `i` forward, and return the removed element.
281 /// Asserts the array has at least one item.
282 /// Invalidates pointers to end of list.287 /// Invalidates pointers to end of list.
283 /// This operation is O(N).288 /// This operation is O(N).
284 /// This preserves item order. Use `swapRemove` if order preservation is not important.289 /// This preserves item order. Use `swapRemove` if order preservation is not important.
290 /// **Asserts that `i < self.items.len`.**
291 /// **Asserts that the list is not empty.**
285 pub fn orderedRemove(self: *Self, i: usize) T {292 pub fn orderedRemove(self: *Self, i: usize) T {
286 const newlen = self.items.len - 1;293 const newlen = self.items.len - 1;
287 if (newlen == i) return self.pop();294 if (newlen == i) return self.pop();
...@@ -297,6 +304,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -297,6 +304,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
297 /// The empty slot is filled from the end of the list.304 /// The empty slot is filled from the end of the list.
298 /// This operation is O(1).305 /// This operation is O(1).
299 /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.306 /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.
307 /// **Asserts that `i < self.items.len`.**
308 /// **Asserts that the list is not empty.**
300 pub fn swapRemove(self: *Self, i: usize) T {309 pub fn swapRemove(self: *Self, i: usize) T {
301 if (self.items.len - 1 == i) return self.pop();310 if (self.items.len - 1 == i) return self.pop();
302311
...@@ -313,8 +322,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -313,8 +322,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
313 self.appendSliceAssumeCapacity(items);322 self.appendSliceAssumeCapacity(items);
314 }323 }
315324
316 /// Append the slice of items to the list, asserting the capacity is already325 /// Append the slice of items to the list. Does not invalidate pointers.
317 /// enough to store the new items. **Does not** invalidate pointers.326 /// **Asserts that the list can hold `items.len` 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;
...@@ -332,10 +341,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -332,10 +341,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
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. **Does not** invalidate pointers.
336 /// enough to store the new items. **Does not** invalidate pointers.
337 /// Only call this function if calling `appendSliceAssumeCapacity` instead345 /// Only call this function if calling `appendSliceAssumeCapacity` instead
338 /// would be a compile error.346 /// would be a compile error.
347 /// **Asserts that the list can hold `items.len` additional items.**
339 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {348 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
340 const old_len = self.items.len;349 const old_len = self.items.len;
341 const new_len = old_len + items.len;350 const new_len = old_len + items.len;
...@@ -348,7 +357,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -348,7 +357,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
348 @compileError("The Writer interface is only defined for ArrayList(u8) " ++357 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
349 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")358 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
350 else359 else
351 std.io.Writer(*Self, error{OutOfMemory}, appendWrite);360 std.io.Writer(*Self, Allocator.Error, appendWrite);
352361
353 /// Initializes a Writer which will append to the list.362 /// Initializes a Writer which will append to the list.
354 pub fn writer(self: *Self) Writer {363 pub fn writer(self: *Self) Writer {
...@@ -370,14 +379,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -370,14 +379,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
370 /// have a more optimal memset codegen in case it has a repeated byte pattern.379 /// 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 {380 pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void {
372 const old_len = self.items.len;381 const old_len = self.items.len;
373 try self.resize(self.items.len + n);382 try self.resize(try addOrOom(self.items.len, n));
374 @memset(self.items[old_len..self.items.len], value);383 @memset(self.items[old_len..self.items.len], value);
375 }384 }
376385
377 /// Append a value to the list `n` times.386 /// Append a value to the list `n` times.
378 /// Asserts the capacity is enough. **Does not** invalidate pointers.387 /// Does not invalidate pointers.
379 /// The function is inline so that a comptime-known `value` parameter will388 /// 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.389 /// have a more optimal memset codegen in case it has a repeated byte pattern.
390 /// **Asserts that the list can hold `n` additional items.**
381 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {391 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
382 const new_len = self.items.len + n;392 const new_len = self.items.len + n;
383 assert(new_len <= self.capacity);393 assert(new_len <= self.capacity);
...@@ -395,6 +405,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -395,6 +405,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
395405
396 /// Reduce allocated capacity to `new_len`.406 /// Reduce allocated capacity to `new_len`.
397 /// May invalidate element pointers.407 /// May invalidate element pointers.
408 /// **Asserts that `new_len <= self.items.len`.**
398 pub fn shrinkAndFree(self: *Self, new_len: usize) void {409 pub fn shrinkAndFree(self: *Self, new_len: usize) void {
399 var unmanaged = self.moveToUnmanaged();410 var unmanaged = self.moveToUnmanaged();
400 unmanaged.shrinkAndFree(self.allocator, new_len);411 unmanaged.shrinkAndFree(self.allocator, new_len);
...@@ -403,6 +414,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -403,6 +414,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
403414
404 /// Reduce length to `new_len`.415 /// Reduce length to `new_len`.
405 /// Invalidates pointers for the elements `items[new_len..]`.416 /// Invalidates pointers for the elements `items[new_len..]`.
417 /// **Asserts that `new_len <= self.items.len`.**
406 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {418 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
407 assert(new_len <= self.items.len);419 assert(new_len <= self.items.len);
408 self.items.len = new_len;420 self.items.len = new_len;
...@@ -466,7 +478,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -466,7 +478,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
466 /// Modify the array so that it can hold at least `additional_count` **more** items.478 /// Modify the array so that it can hold at least `additional_count` **more** items.
467 /// Invalidates pointers if additional memory is needed.479 /// Invalidates pointers if additional memory is needed.
468 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void {480 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void {
469 return self.ensureTotalCapacity(self.items.len + additional_count);481 return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count));
470 }482 }
471483
472 /// Increases the array's length to match the full capacity that is already allocated.484 /// Increases the array's length to match the full capacity that is already allocated.
...@@ -478,14 +490,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -478,14 +490,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
478 /// Increase length by 1, returning pointer to the new item.490 /// Increase length by 1, returning pointer to the new item.
479 /// The returned pointer becomes invalid when the list resized.491 /// The returned pointer becomes invalid when the list resized.
480 pub fn addOne(self: *Self) Allocator.Error!*T {492 pub fn addOne(self: *Self) Allocator.Error!*T {
481 try self.ensureTotalCapacity(self.items.len + 1);493 try self.ensureUnusedCapacity(1);
482 return self.addOneAssumeCapacity();494 return self.addOneAssumeCapacity();
483 }495 }
484496
485 /// Increase length by 1, returning pointer to the new item.497 /// 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.498 /// The returned pointer becomes invalid when the list is resized.
488 /// **Does not** invalidate element pointers.499 /// Does not invalidate element pointers.
500 /// **Asserts that the list can hold one additional item.**
489 pub fn addOneAssumeCapacity(self: *Self) *T {501 pub fn addOneAssumeCapacity(self: *Self) *T {
490 assert(self.items.len < self.capacity);502 assert(self.items.len < self.capacity);
491 self.items.len += 1;503 self.items.len += 1;
...@@ -498,15 +510,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -498,15 +510,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
498 /// Resizes list if `self.capacity` is not large enough.510 /// Resizes list if `self.capacity` is not large enough.
499 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {511 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {
500 const prev_len = self.items.len;512 const prev_len = self.items.len;
501 try self.resize(self.items.len + n);513 try self.resize(try addOrOom(self.items.len, n));
502 return self.items[prev_len..][0..n];514 return self.items[prev_len..][0..n];
503 }515 }
504516
505 /// Resize the array, adding `n` new elements, which have `undefined` values.517 /// Resize the array, adding `n` new elements, which have `undefined` values.
506 /// The return value is an array pointing to the newly allocated elements.518 /// 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.519 /// Does not invalidate element pointers.
508 /// **Does not** invalidate element pointers.
509 /// The returned pointer becomes invalid when the list is resized.520 /// The returned pointer becomes invalid when the list is resized.
521 /// **Asserts that the list can hold `n` additional items.**
510 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {522 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
511 assert(self.items.len + n <= self.capacity);523 assert(self.items.len + n <= self.capacity);
512 const prev_len = self.items.len;524 const prev_len = self.items.len;
...@@ -520,15 +532,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -520,15 +532,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
520 /// Resizes list if `self.capacity` is not large enough.532 /// Resizes list if `self.capacity` is not large enough.
521 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {533 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {
522 const prev_len = self.items.len;534 const prev_len = self.items.len;
523 try self.resize(self.items.len + n);535 try self.resize(try addOrOom(self.items.len, n));
524 return self.items[prev_len..][0..n];536 return self.items[prev_len..][0..n];
525 }537 }
526538
527 /// Resize the array, adding `n` new elements, which have `undefined` values.539 /// Resize the array, adding `n` new elements, which have `undefined` values.
528 /// The return value is a slice pointing to the newly allocated elements.540 /// 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.541 /// Does not invalidate element pointers.
530 /// **Does not** invalidate element pointers.
531 /// The returned pointer becomes invalid when the list is resized.542 /// The returned pointer becomes invalid when the list is resized.
543 /// **Asserts that the list can hold `n` additional items.**
532 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {544 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
533 assert(self.items.len + n <= self.capacity);545 assert(self.items.len + n <= self.capacity);
534 const prev_len = self.items.len;546 const prev_len = self.items.len;
...@@ -537,8 +549,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -537,8 +549,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
537 }549 }
538550
539 /// Remove and return the last element from the list.551 /// 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.552 /// Invalidates pointers to the removed element.
553 /// **Asserts that the list is not empty.**
542 pub fn pop(self: *Self) T {554 pub fn pop(self: *Self) T {
543 const val = self.items[self.items.len - 1];555 const val = self.items[self.items.len - 1];
544 self.items.len -= 1;556 self.items.len -= 1;
...@@ -568,15 +580,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -568,15 +580,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
568 return self.allocatedSlice()[self.items.len..];580 return self.allocatedSlice()[self.items.len..];
569 }581 }
570582
571 /// Return the last element from the list.583 /// Returns the last element from the list.
572 /// Asserts the list has at least one item.584 /// **Asserts that the list is not empty.**
573 pub fn getLast(self: Self) T {585 pub fn getLast(self: Self) T {
574 const val = self.items[self.items.len - 1];586 const val = self.items[self.items.len - 1];
575 return val;587 return val;
576 }588 }
577589
578 /// Return the last element from the list, or590 /// 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 {591 pub fn getLastOrNull(self: Self) ?T {
581 if (self.items.len == 0) return null;592 if (self.items.len == 0) return null;
582 return self.getLast();593 return self.getLast();
...@@ -635,8 +646,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -635,8 +646,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
635646
636 /// Initialize with externally-managed memory. The buffer determines the647 /// Initialize with externally-managed memory. The buffer determines the
637 /// capacity, and the length is set to zero.648 /// capacity, and the length is set to zero.
638 /// When initialized this way, all methods that accept an Allocator649 /// **When initialized this way, all methods that accept an Allocator
639 /// argument are illegal to call.650 /// argument cause illegal behavior**.
640 pub fn initBuffer(buffer: Slice) Self {651 pub fn initBuffer(buffer: Slice) Self {
641 return .{652 return .{
642 .items = buffer[0..0],653 .items = buffer[0..0],
...@@ -695,7 +706,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -695,7 +706,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
695706
696 /// The caller owns the returned memory. ArrayList becomes empty.707 /// The caller owns the returned memory. ArrayList becomes empty.
697 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {708 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
698 try self.ensureTotalCapacityPrecise(allocator, self.items.len + 1);709 try self.ensureTotalCapacityPrecise(allocator, try addOrOom(self.items.len, 1));
699 self.appendAssumeCapacity(sentinel);710 self.appendAssumeCapacity(sentinel);
700 const result = try self.toOwnedSlice(allocator);711 const result = try self.toOwnedSlice(allocator);
701 return result[0 .. result.len - 1 :sentinel];712 return result[0 .. result.len - 1 :sentinel];
...@@ -708,25 +719,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -708,25 +719,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
708 return cloned;719 return cloned;
709 }720 }
710721
711 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.722 /// 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.723 /// If `i` is equal to the length of the list this operation is equivalent to append.
713 /// This operation is O(N).724 /// This operation is O(N).
714 /// Invalidates pointers if additional memory is needed.725 /// Invalidates pointers if additional memory is needed.
715 pub fn insert(self: *Self, allocator: Allocator, n: usize, item: T) Allocator.Error!void {726 /// **Asserts that `i < self.items.len`.**
716 const dst = try self.addManyAt(allocator, n, 1);727 pub fn insert(self: *Self, allocator: Allocator, i: usize, item: T) Allocator.Error!void {
728 const dst = try self.addManyAt(allocator, i, 1);
717 dst[0] = item;729 dst[0] = item;
718 }730 }
719731
720 /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room.732 /// 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.733 /// If in` is equal to the length of the list this operation is equivalent to append.
722 /// This operation is O(N).734 /// This operation is O(N).
723 /// Asserts that there is enough capacity for the new item.735 /// **Asserts that `i < self.items.len`.**
724 pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void {736 /// **Asserts that the list can hold one additional item.**
737 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
725 assert(self.items.len < self.capacity);738 assert(self.items.len < self.capacity);
726 self.items.len += 1;739 self.items.len += 1;
727740
728 mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]);741 mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
729 self.items[n] = item;742 self.items[i] = item;
730 }743 }
731744
732 /// Add `count` new elements at position `index`, which have745 /// Add `count` new elements at position `index`, which have
...@@ -736,6 +749,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -736,6 +749,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
736 /// Invalidates pre-existing pointers to elements at and after `index`.749 /// Invalidates pre-existing pointers to elements at and after `index`.
737 /// Invalidates all pre-existing element pointers if capacity must be750 /// Invalidates all pre-existing element pointers if capacity must be
738 /// increased to accomodate the new elements.751 /// increased to accomodate the new elements.
752 /// **Asserts that `index <= self.items.len`.**
739 pub fn addManyAt(753 pub fn addManyAt(
740 self: *Self,754 self: *Self,
741 allocator: Allocator,755 allocator: Allocator,
...@@ -751,9 +765,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -751,9 +765,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
751 /// `undefined` values. Returns a slice pointing to the newly allocated765 /// `undefined` values. Returns a slice pointing to the newly allocated
752 /// elements, which becomes invalid after various `ArrayList`766 /// elements, which becomes invalid after various `ArrayList`
753 /// operations.767 /// operations.
754 /// Asserts that there is enough capacity for the new elements.
755 /// Invalidates pre-existing pointers to elements at and after `index`, but768 /// Invalidates pre-existing pointers to elements at and after `index`, but
756 /// does not invalidate any before that.769 /// does not invalidate any before that.
770 /// **Asserts that `index <= self.items.len`.**
771 /// **Asserts that the list can hold `count` additional items.**
757 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {772 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
758 const new_len = self.items.len + count;773 const new_len = self.items.len + count;
759 assert(self.capacity >= new_len);774 assert(self.capacity >= new_len);
...@@ -770,6 +785,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -770,6 +785,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
770 /// Invalidates pre-existing pointers to elements at and after `index`.785 /// Invalidates pre-existing pointers to elements at and after `index`.
771 /// Invalidates all pre-existing element pointers if capacity must be786 /// Invalidates all pre-existing element pointers if capacity must be
772 /// increased to accomodate the new elements.787 /// increased to accomodate the new elements.
788 /// **Asserts that `index <= self.items.len`.**
773 pub fn insertSlice(789 pub fn insertSlice(
774 self: *Self,790 self: *Self,
775 allocator: Allocator,791 allocator: Allocator,
...@@ -788,6 +804,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -788,6 +804,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
788 /// Grows list if `len < new_items.len`.804 /// Grows list if `len < new_items.len`.
789 /// Shrinks list if `len > new_items.len`805 /// Shrinks list if `len > new_items.len`
790 /// Invalidates pointers if this ArrayList is resized.806 /// Invalidates pointers if this ArrayList is resized.
807 /// **Asserts that `start <= self.items.len`.**
791 pub fn replaceRange(808 pub fn replaceRange(
792 self: *Self,809 self: *Self,
793 allocator: Allocator,810 allocator: Allocator,
...@@ -807,17 +824,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -807,17 +824,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
807 new_item_ptr.* = item;824 new_item_ptr.* = item;
808 }825 }
809826
810 /// Extend the list by 1 element, but asserting `self.capacity`827 /// Extend the list by 1 element.
811 /// is sufficient to hold an additional item.828 /// **Asserts that the list can hold one additional item.**
812 pub fn appendAssumeCapacity(self: *Self, item: T) void {829 pub fn appendAssumeCapacity(self: *Self, item: T) void {
813 const new_item_ptr = self.addOneAssumeCapacity();830 const new_item_ptr = self.addOneAssumeCapacity();
814 new_item_ptr.* = item;831 new_item_ptr.* = item;
815 }832 }
816833
817 /// Remove the element at index `i` from the list and return its value.834 /// Remove the element at index `i` from the list and return its value.
818 /// Asserts the array has at least one item. Invalidates pointers to835 /// Invalidates pointers to the last element.
819 /// last element.
820 /// This operation is O(N).836 /// This operation is O(N).
837 /// **Asserts that `i < self.items.len`.**
838 /// **Asserts that the list is not empty.**
821 pub fn orderedRemove(self: *Self, i: usize) T {839 pub fn orderedRemove(self: *Self, i: usize) T {
822 const newlen = self.items.len - 1;840 const newlen = self.items.len - 1;
823 if (newlen == i) return self.pop();841 if (newlen == i) return self.pop();
...@@ -833,6 +851,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -833,6 +851,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
833 /// The empty slot is filled from the end of the list.851 /// The empty slot is filled from the end of the list.
834 /// Invalidates pointers to last element.852 /// Invalidates pointers to last element.
835 /// This operation is O(1).853 /// This operation is O(1).
854 /// **Asserts that `i < self.items.len`.**
855 /// **Asserts that the list is not empty.**
836 pub fn swapRemove(self: *Self, i: usize) T {856 pub fn swapRemove(self: *Self, i: usize) T {
837 if (self.items.len - 1 == i) return self.pop();857 if (self.items.len - 1 == i) return self.pop();
838858
...@@ -849,8 +869,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -849,8 +869,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
849 self.appendSliceAssumeCapacity(items);869 self.appendSliceAssumeCapacity(items);
850 }870 }
851871
852 /// Append the slice of items to the list, asserting the capacity is enough872 /// Append the slice of items to the list.
853 /// to store the new items.873 /// **Asserts that the list can hold `items.len` additional items.**
854 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {874 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
855 const old_len = self.items.len;875 const old_len = self.items.len;
856 const new_len = old_len + items.len;876 const new_len = old_len + items.len;
...@@ -868,9 +888,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -868,9 +888,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
868 self.appendUnalignedSliceAssumeCapacity(items);888 self.appendUnalignedSliceAssumeCapacity(items);
869 }889 }
870890
871 /// Append an unaligned slice of items to the list, asserting the capacity is enough891 /// Append an unaligned slice of items to the list.
872 /// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity`892 /// Only call this function if a call to `appendSliceAssumeCapacity`
873 /// instead would be a compile error.893 /// instead would be a compile error.
894 /// **Asserts that the list can hold `items.len` additional items.**
874 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {895 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
875 const old_len = self.items.len;896 const old_len = self.items.len;
876 const new_len = old_len + items.len;897 const new_len = old_len + items.len;
...@@ -888,7 +909,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -888,7 +909,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
888 @compileError("The Writer interface is only defined for ArrayList(u8) " ++909 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
889 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")910 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
890 else911 else
891 std.io.Writer(WriterContext, error{OutOfMemory}, appendWrite);912 std.io.Writer(WriterContext, Allocator.Error, appendWrite);
892913
893 /// Initializes a Writer which will append to the list.914 /// Initializes a Writer which will append to the list.
894 pub fn writer(self: *Self, allocator: Allocator) Writer {915 pub fn writer(self: *Self, allocator: Allocator) Writer {
...@@ -910,15 +931,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -910,15 +931,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
910 /// have a more optimal memset codegen in case it has a repeated byte pattern.931 /// 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 {932 pub inline fn appendNTimes(self: *Self, allocator: Allocator, value: T, n: usize) Allocator.Error!void {
912 const old_len = self.items.len;933 const old_len = self.items.len;
913 try self.resize(allocator, self.items.len + n);934 try self.resize(allocator, try addOrOom(self.items.len, n));
914 @memset(self.items[old_len..self.items.len], value);935 @memset(self.items[old_len..self.items.len], value);
915 }936 }
916937
917 /// Append a value to the list `n` times.938 /// Append a value to the list `n` times.
918 /// **Does not** invalidate pointers.939 /// **Does not** invalidate pointers.
919 /// Asserts the capacity is enough.
920 /// The function is inline so that a comptime-known `value` parameter will940 /// 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.941 /// have better memset codegen in case it has a repeated byte pattern.
942 /// **Asserts that the list can hold `n` additional items.**
922 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {943 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
923 const new_len = self.items.len + n;944 const new_len = self.items.len + n;
924 assert(new_len <= self.capacity);945 assert(new_len <= self.capacity);
...@@ -936,6 +957,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -936,6 +957,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
936957
937 /// Reduce allocated capacity to `new_len`.958 /// Reduce allocated capacity to `new_len`.
938 /// May invalidate element pointers.959 /// May invalidate element pointers.
960 /// **Asserts that `new_len <= self.items.len`.**
939 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {961 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {
940 assert(new_len <= self.items.len);962 assert(new_len <= self.items.len);
941963
...@@ -968,6 +990,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -968,6 +990,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
968 /// Reduce length to `new_len`.990 /// Reduce length to `new_len`.
969 /// Invalidates pointers to elements `items[new_len..]`.991 /// Invalidates pointers to elements `items[new_len..]`.
970 /// Keeps capacity the same.992 /// Keeps capacity the same.
993 /// **Asserts that `new_len <= self.items.len`.**
971 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {994 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
972 assert(new_len <= self.items.len);995 assert(new_len <= self.items.len);
973 self.items.len = new_len;996 self.items.len = new_len;
...@@ -1030,12 +1053,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1030,12 +1053,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1030 allocator: Allocator,1053 allocator: Allocator,
1031 additional_count: usize,1054 additional_count: usize,
1032 ) Allocator.Error!void {1055 ) Allocator.Error!void {
1033 return self.ensureTotalCapacity(allocator, self.items.len + additional_count);1056 return self.ensureTotalCapacity(allocator, try addOrOom(self.items.len, additional_count));
1034 }1057 }
10351058
1036 /// Increases the array's length to match the full capacity that is already allocated.1059 /// Increases the array's length to match the full capacity that is already allocated.
1037 /// The new elements have `undefined` values.1060 /// The new elements have `undefined` values.
1038 /// **Does not** invalidate pointers.1061 /// Does not invalidate pointers.
1039 pub fn expandToCapacity(self: *Self) void {1062 pub fn expandToCapacity(self: *Self) void {
1040 self.items.len = self.capacity;1063 self.items.len = self.capacity;
1041 }1064 }
...@@ -1043,15 +1066,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1043,15 +1066,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1043 /// Increase length by 1, returning pointer to the new item.1066 /// Increase length by 1, returning pointer to the new item.
1044 /// The returned pointer becomes invalid when the list resized.1067 /// The returned pointer becomes invalid when the list resized.
1045 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {1068 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {
1046 const newlen = self.items.len + 1;1069 const newlen = try addOrOom(self.items.len, 1);
1047 try self.ensureTotalCapacity(allocator, newlen);1070 try self.ensureTotalCapacity(allocator, newlen);
1048 return self.addOneAssumeCapacity();1071 return self.addOneAssumeCapacity();
1049 }1072 }
10501073
1051 /// Increase length by 1, returning pointer to the new item.1074 /// 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.1075 /// **Does not** invalidate pointers.
1054 /// The returned pointer becomes invalid when the list resized.1076 /// The returned pointer becomes invalid when the list resized.
1077 /// **Asserts that the list can hold one additional item.**
1055 pub fn addOneAssumeCapacity(self: *Self) *T {1078 pub fn addOneAssumeCapacity(self: *Self) *T {
1056 assert(self.items.len < self.capacity);1079 assert(self.items.len < self.capacity);
10571080
...@@ -1064,15 +1087,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1064,15 +1087,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1064 /// The returned pointer becomes invalid when the list is resized.1087 /// 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 {1088 pub fn addManyAsArray(self: *Self, allocator: Allocator, comptime n: usize) Allocator.Error!*[n]T {
1066 const prev_len = self.items.len;1089 const prev_len = self.items.len;
1067 try self.resize(allocator, self.items.len + n);1090 try self.resize(allocator, try addOrOom(self.items.len, n));
1068 return self.items[prev_len..][0..n];1091 return self.items[prev_len..][0..n];
1069 }1092 }
10701093
1071 /// Resize the array, adding `n` new elements, which have `undefined` values.1094 /// Resize the array, adding `n` new elements, which have `undefined` values.
1072 /// The return value is an array pointing to the newly allocated elements.1095 /// 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.1096 /// **Does not** invalidate pointers.
1075 /// The returned pointer becomes invalid when the list is resized.1097 /// The returned pointer becomes invalid when the list is resized.
1098 /// **Asserts that the list can hold `n` additional items.**
1076 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {1099 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
1077 assert(self.items.len + n <= self.capacity);1100 assert(self.items.len + n <= self.capacity);
1078 const prev_len = self.items.len;1101 const prev_len = self.items.len;
...@@ -1086,15 +1109,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1086,15 +1109,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1086 /// Resizes list if `self.capacity` is not large enough.1109 /// Resizes list if `self.capacity` is not large enough.
1087 pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T {1110 pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T {
1088 const prev_len = self.items.len;1111 const prev_len = self.items.len;
1089 try self.resize(allocator, self.items.len + n);1112 try self.resize(allocator, try addOrOom(self.items.len, n));
1090 return self.items[prev_len..][0..n];1113 return self.items[prev_len..][0..n];
1091 }1114 }
10921115
1093 /// Resize the array, adding `n` new elements, which have `undefined` values.1116 /// Resize the array, adding `n` new elements, which have `undefined` values.
1094 /// The return value is a slice pointing to the newly allocated elements.1117 /// 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.1118 /// Does not invalidate element pointers.
1096 /// **Does not** invalidate element pointers.
1097 /// The returned pointer becomes invalid when the list is resized.1119 /// The returned pointer becomes invalid when the list is resized.
1120 /// **Asserts that the list can hold `n` additional items.**
1098 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {1121 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
1099 assert(self.items.len + n <= self.capacity);1122 assert(self.items.len + n <= self.capacity);
1100 const prev_len = self.items.len;1123 const prev_len = self.items.len;
...@@ -1103,8 +1126,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1103,8 +1126,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1103 }1126 }
11041127
1105 /// Remove and return the last element from the list.1128 /// Remove and return the last element from the list.
1106 /// Asserts the list has at least one item.
1107 /// Invalidates pointers to last element.1129 /// Invalidates pointers to last element.
1130 /// **Asserts that the list is not empty.**
1108 pub fn pop(self: *Self) T {1131 pub fn pop(self: *Self) T {
1109 const val = self.items[self.items.len - 1];1132 const val = self.items[self.items.len - 1];
1110 self.items.len -= 1;1133 self.items.len -= 1;
...@@ -1134,7 +1157,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1134,7 +1157,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1134 }1157 }
11351158
1136 /// Return the last element from the list.1159 /// Return the last element from the list.
1137 /// Asserts the list has at least one item.1160 /// **Asserts that the list is not empty.**
1138 pub fn getLast(self: Self) T {1161 pub fn getLast(self: Self) T {
1139 const val = self.items[self.items.len - 1];1162 const val = self.items[self.items.len - 1];
1140 return val;1163 return val;
...@@ -1160,6 +1183,14 @@ fn growCapacity(current: usize, minimum: usize) usize {...@@ -1160,6 +1183,14 @@ fn growCapacity(current: usize, minimum: usize) usize {
1160 }1183 }
1161}1184}
11621185
1186/// Adds a and b, returning `error.OutOfMemory` if overflow occurred.
1187/// This is equivalent to `math.add`. See #18467 for why it is used.
1188fn addOrOom(a: usize, b: usize) error{OutOfMemory}!usize {
1189 const ov = @addWithOverflow(a, b);
1190 if (ov[1] != 0) return error.OutOfMemory;
1191 return ov[0];
1192}
1193
1163test "std.ArrayList/ArrayListUnmanaged.init" {1194test "std.ArrayList/ArrayListUnmanaged.init" {
1164 {1195 {
1165 var list = ArrayList(i32).init(testing.allocator);1196 var list = ArrayList(i32).init(testing.allocator);
...@@ -1952,3 +1983,49 @@ test "std.ArrayList(u32).getLastOrNull()" {...@@ -1952,3 +1983,49 @@ test "std.ArrayList(u32).getLastOrNull()" {
1952 const const_list = list;1983 const const_list = list;
1953 try testing.expectEqual(const_list.getLastOrNull().?, 2);1984 try testing.expectEqual(const_list.getLastOrNull().?, 2);
1954}1985}
1986
1987test "return OutOfMemory when capacity would exceed maximum usize integer value" {
1988 // Because a portable way to create maxInt(usize)-sized slices does not seem to exist yet, this
1989 // will have to do.
1990
1991 const a = testing.allocator;
1992
1993 var alu = ArrayListUnmanaged(u32){
1994 .items = undefined,
1995 .capacity = math.maxInt(usize),
1996 };
1997 alu.items.len = math.maxInt(usize);
1998
1999 try testing.expectError(error.OutOfMemory, alu.append(a, undefined));
2000 try testing.expectError(error.OutOfMemory, alu.appendSlice(a, &.{undefined}));
2001 try testing.expectError(error.OutOfMemory, alu.appendNTimes(a, undefined, 1));
2002 try testing.expectError(error.OutOfMemory, alu.appendUnalignedSlice(a, &.{undefined}));
2003 try testing.expectError(error.OutOfMemory, alu.addOne(a));
2004 try testing.expectError(error.OutOfMemory, alu.addManyAt(a, 0, 1));
2005 try testing.expectError(error.OutOfMemory, alu.addManyAsArray(a, 1));
2006 try testing.expectError(error.OutOfMemory, alu.addManyAsSlice(a, 1));
2007 try testing.expectError(error.OutOfMemory, alu.insert(a, 0, undefined));
2008 try testing.expectError(error.OutOfMemory, alu.insertSlice(a, 0, &.{undefined}));
2009 try testing.expectError(error.OutOfMemory, alu.toOwnedSliceSentinel(a, 0));
2010 try testing.expectError(error.OutOfMemory, alu.ensureUnusedCapacity(a, 1));
2011
2012 var al = ArrayList(u32){
2013 .items = undefined,
2014 .capacity = math.maxInt(usize),
2015 .allocator = a,
2016 };
2017 al.items.len = math.maxInt(usize);
2018
2019 try testing.expectError(error.OutOfMemory, al.append(undefined));
2020 try testing.expectError(error.OutOfMemory, al.appendSlice(&.{undefined}));
2021 try testing.expectError(error.OutOfMemory, al.appendNTimes(undefined, 1));
2022 try testing.expectError(error.OutOfMemory, al.appendUnalignedSlice(&.{undefined}));
2023 try testing.expectError(error.OutOfMemory, al.addOne());
2024 try testing.expectError(error.OutOfMemory, al.addManyAt(0, 1));
2025 try testing.expectError(error.OutOfMemory, al.addManyAsArray(1));
2026 try testing.expectError(error.OutOfMemory, al.addManyAsSlice(1));
2027 try testing.expectError(error.OutOfMemory, al.insert(0, undefined));
2028 try testing.expectError(error.OutOfMemory, al.insertSlice(0, &.{undefined}));
2029 try testing.expectError(error.OutOfMemory, al.toOwnedSliceSentinel(0));
2030 try testing.expectError(error.OutOfMemory, al.ensureUnusedCapacity(1));
2031}