authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-15 23:43:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-15 23:44:36-07:00
logf2721a4cbc45cf4a7ef22800ed69550c3c5dd97d
treee085a7c2ce4a0af4077448e0a4bbc2b984f0a367
parent69461bcae4a78c835bdfe0aae85524342c0f8461

std.ArrayList: pedantic rewordings of documentation and unit tests


1 files changed, 174 insertions(+), 168 deletions(-)

lib/std/array_list.zig+174-168
...@@ -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.
...@@ -144,18 +142,19 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -144,18 +142,19 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
144 /// Insert `item` at index `i`. Moves `list[i .. 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 `i` 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 /// **Asserts that `i <= self.items.len`.**146 /// Asserts that the index is in bounds or equal to the length.
149 pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void {147 pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void {
150 const dst = try self.addManyAt(i, 1);148 const dst = try self.addManyAt(i, 1);
151 dst[0] = item;149 dst[0] = item;
152 }150 }
153151
154 /// Insert `item` at index `i`. Moves `list[i .. 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.
155 /// If `i` is equal to the length of the list this operation is equivalent to appendAssumeCapacity.153 /// If `i` is equal to the length of the list this operation is
154 /// equivalent to appendAssumeCapacity.
156 /// This operation is O(N).155 /// This operation is O(N).
157 /// **Asserts that `i <= self.items.len`.**156 /// Asserts that there is enough capacity for the new item.
158 /// **Asserts that `self.items.len < self.capacity` .**157 /// Asserts that the index is in bounds or equal to the length.
159 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {158 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
160 assert(self.items.len < self.capacity);159 assert(self.items.len < self.capacity);
161 self.items.len += 1;160 self.items.len += 1;
...@@ -171,7 +170,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -171,7 +170,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
171 /// Invalidates pre-existing pointers to elements at and after `index`.170 /// Invalidates pre-existing pointers to elements at and after `index`.
172 /// Invalidates all pre-existing element pointers if capacity must be171 /// Invalidates all pre-existing element pointers if capacity must be
173 /// increased to accomodate the new elements.172 /// increased to accomodate the new elements.
174 /// **Asserts that `index <= self.items.len`.**173 /// Asserts that the index is in bounds or equal to the length.
175 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 {
176 const new_len = try addOrOom(self.items.len, count);175 const new_len = try addOrOom(self.items.len, count);
177176
...@@ -208,10 +207,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -208,10 +207,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
208 /// `undefined` values. Returns a slice pointing to the newly allocated207 /// `undefined` values. Returns a slice pointing to the newly allocated
209 /// elements, which becomes invalid after various `ArrayList`208 /// elements, which becomes invalid after various `ArrayList`
210 /// operations.209 /// operations.
210 /// Asserts that there is enough capacity for the new elements.
211 /// Invalidates pre-existing pointers to elements at and after `index`, but211 /// Invalidates pre-existing pointers to elements at and after `index`, but
212 /// does not invalidate any before that.212 /// does not invalidate any before that.
213 /// **Asserts that `index <= self.items.len`.**213 /// Asserts that the index is in bounds or equal to the length.
214 /// **Asserts that the list can hold `count` additional items.**
215 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {214 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
216 const new_len = self.items.len + count;215 const new_len = self.items.len + count;
217 assert(self.capacity >= new_len);216 assert(self.capacity >= new_len);
...@@ -228,7 +227,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -228,7 +227,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
228 /// Invalidates pre-existing pointers to elements at and after `index`.227 /// Invalidates pre-existing pointers to elements at and after `index`.
229 /// Invalidates all pre-existing element pointers if capacity must be228 /// Invalidates all pre-existing element pointers if capacity must be
230 /// increased to accomodate the new elements.229 /// increased to accomodate the new elements.
231 /// **Asserts that `index <= self.items.len`.**230 /// Asserts that the index is in bounds or equal to the length.
232 pub fn insertSlice(231 pub fn insertSlice(
233 self: *Self,232 self: *Self,
234 index: usize,233 index: usize,
...@@ -241,8 +240,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -241,8 +240,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
241 /// Replace range of elements `list[start..][0..len]` with `new_items`.240 /// Replace range of elements `list[start..][0..len]` with `new_items`.
242 /// Grows list if `len < new_items.len`.241 /// Grows list if `len < new_items.len`.
243 /// Shrinks list if `len > new_items.len`.242 /// Shrinks list if `len > new_items.len`.
244 /// Invalidates pointers if this ArrayList is resized.243 /// Invalidates element pointers if this ArrayList is resized.
245 /// **Asserts that `start <= self.items.len`.**244 /// Asserts that the start index is in bounds or equal to the length.
246 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 {
247 const after_range = try addOrOom(start, len);246 const after_range = try addOrOom(start, len);
248 const range = self.items[start..after_range];247 const range = self.items[start..after_range];
...@@ -268,15 +267,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -268,15 +267,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
268 }267 }
269268
270 /// Extends the list by 1 element. Allocates more memory as necessary.269 /// Extends the list by 1 element. Allocates more memory as necessary.
271 /// Invalidates pointers if additional memory is needed.270 /// Invalidates element pointers if additional memory is needed.
272 pub fn append(self: *Self, item: T) Allocator.Error!void {271 pub fn append(self: *Self, item: T) Allocator.Error!void {
273 const new_item_ptr = try self.addOne();272 const new_item_ptr = try self.addOne();
274 new_item_ptr.* = item;273 new_item_ptr.* = item;
275 }274 }
276275
277 /// Extends the list by 1 element. Does not276 /// Extends the list by 1 element.
278 /// invalidate pointers.277 /// Never invalidates element pointers.
279 /// **Asserts that the list can hold one additional item.**278 /// Asserts that the list can hold one additional item.
280 pub fn appendAssumeCapacity(self: *Self, item: T) void {279 pub fn appendAssumeCapacity(self: *Self, item: T) void {
281 const new_item_ptr = self.addOneAssumeCapacity();280 const new_item_ptr = self.addOneAssumeCapacity();
282 new_item_ptr.* = item;281 new_item_ptr.* = item;
...@@ -284,11 +283,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -284,11 +283,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
284283
285 /// Remove the element at index `i`, shift elements after index284 /// Remove the element at index `i`, shift elements after index
286 /// `i` forward, and return the removed element.285 /// `i` forward, and return the removed element.
287 /// Invalidates pointers to end of list.286 /// Invalidates element pointers to end of list.
288 /// This operation is O(N).287 /// This operation is O(N).
289 /// 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.
290 /// **Asserts that `i < self.items.len`.**289 /// Asserts that the index is in bounds.
291 /// **Asserts that the list is not empty.**290 /// Asserts that the list is not empty.
292 pub fn orderedRemove(self: *Self, i: usize) T {291 pub fn orderedRemove(self: *Self, i: usize) T {
293 const newlen = self.items.len - 1;292 const newlen = self.items.len - 1;
294 if (newlen == i) return self.pop();293 if (newlen == i) return self.pop();
...@@ -304,8 +303,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -304,8 +303,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
304 /// The empty slot is filled from the end of the list.303 /// The empty slot is filled from the end of the list.
305 /// This operation is O(1).304 /// This operation is O(1).
306 /// 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.
307 /// **Asserts that `i < self.items.len`.**306 /// Asserts that the list is not empty.
308 /// **Asserts that the list is not empty.**307 /// Asserts that the index is in bounds.
309 pub fn swapRemove(self: *Self, i: usize) T {308 pub fn swapRemove(self: *Self, i: usize) T {
310 if (self.items.len - 1 == i) return self.pop();309 if (self.items.len - 1 == i) return self.pop();
311310
...@@ -316,14 +315,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -316,14 +315,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
316315
317 /// Append the slice of items to the list. Allocates more316 /// Append the slice of items to the list. Allocates more
318 /// memory as necessary.317 /// memory as necessary.
319 /// Invalidates pointers if additional memory is needed.318 /// Invalidates element pointers if additional memory is needed.
320 pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void {319 pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void {
321 try self.ensureUnusedCapacity(items.len);320 try self.ensureUnusedCapacity(items.len);
322 self.appendSliceAssumeCapacity(items);321 self.appendSliceAssumeCapacity(items);
323 }322 }
324323
325 /// Append the slice of items to the list. Does not invalidate pointers.324 /// Append the slice of items to the list.
326 /// **Asserts that the list can hold `items.len` additional items.**325 /// Never invalidates element pointers.
326 /// Asserts that the list can hold the additional items.
327 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {327 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
328 const old_len = self.items.len;328 const old_len = self.items.len;
329 const new_len = old_len + items.len;329 const new_len = old_len + items.len;
...@@ -335,16 +335,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -335,16 +335,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
335 /// Append an unaligned slice of items to the list. Allocates more335 /// Append an unaligned slice of items to the list. Allocates more
336 /// memory as necessary. Only call this function if calling336 /// memory as necessary. Only call this function if calling
337 /// `appendSlice` instead would be a compile error.337 /// `appendSlice` instead would be a compile error.
338 /// Invalidates pointers if additional memory is needed.338 /// Invalidates element pointers if additional memory is needed.
339 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 {
340 try self.ensureUnusedCapacity(items.len);340 try self.ensureUnusedCapacity(items.len);
341 self.appendUnalignedSliceAssumeCapacity(items);341 self.appendUnalignedSliceAssumeCapacity(items);
342 }342 }
343343
344 /// Append the slice of items to the list. **Does not** invalidate pointers.344 /// Append the slice of items to the list.
345 /// Only call this function if calling `appendSliceAssumeCapacity` instead345 /// Never invalidates element pointers.
346 /// would be a compile error.346 /// This function is only needed when calling
347 /// **Asserts that the list can hold `items.len` additional items.**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.
348 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {350 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
349 const old_len = self.items.len;351 const old_len = self.items.len;
350 const new_len = old_len + items.len;352 const new_len = old_len + items.len;
...@@ -366,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -366,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
366368
367 /// 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
368 /// 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.
369 /// Invalidates pointers if additional memory is needed.371 /// Invalidates element pointers if additional memory is needed.
370 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {372 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {
371 try self.appendSlice(m);373 try self.appendSlice(m);
372 return m.len;374 return m.len;
...@@ -374,20 +376,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -374,20 +376,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
374376
375 /// Append a value to the list `n` times.377 /// Append a value to the list `n` times.
376 /// Allocates more memory as necessary.378 /// Allocates more memory as necessary.
377 /// Invalidates pointers if additional memory is needed.379 /// Invalidates element pointers if additional memory is needed.
378 /// The function is inline so that a comptime-known `value` parameter will380 /// The function is inline so that a comptime-known `value` parameter will
379 /// 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.
380 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 {
381 const old_len = self.items.len;383 const old_len = self.items.len;
382 try self.resize(try addOrOom(self.items.len, n));384 try self.resize(try addOrOom(old_len, n));
383 @memset(self.items[old_len..self.items.len], value);385 @memset(self.items[old_len..self.items.len], value);
384 }386 }
385387
386 /// Append a value to the list `n` times.388 /// Append a value to the list `n` times.
387 /// Does not invalidate pointers.389 /// Never invalidates element pointers.
388 /// The function is inline so that a comptime-known `value` parameter will390 /// The function is inline so that a comptime-known `value` parameter will
389 /// 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.
390 /// **Asserts that the list can hold `n` additional items.**392 /// Asserts that the list can hold the additional items.
391 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {393 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
392 const new_len = self.items.len + n;394 const new_len = self.items.len + n;
393 assert(new_len <= self.capacity);395 assert(new_len <= self.capacity);
...@@ -395,9 +397,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -395,9 +397,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
395 self.items.len = new_len;397 self.items.len = new_len;
396 }398 }
397399
398 /// Adjust the list's length to `new_len`.400 /// Adjust the list length to `new_len`.
399 /// Does not initialize added items if any.401 /// Additional elements contain the value `undefined`.
400 /// Invalidates pointers if additional memory is needed.402 /// Invalidates element pointers if additional memory is needed.
401 pub fn resize(self: *Self, new_len: usize) Allocator.Error!void {403 pub fn resize(self: *Self, new_len: usize) Allocator.Error!void {
402 try self.ensureTotalCapacity(new_len);404 try self.ensureTotalCapacity(new_len);
403 self.items.len = new_len;405 self.items.len = new_len;
...@@ -405,7 +407,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -405,7 +407,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
405407
406 /// Reduce allocated capacity to `new_len`.408 /// Reduce allocated capacity to `new_len`.
407 /// May invalidate element pointers.409 /// May invalidate element pointers.
408 /// **Asserts that `new_len <= self.items.len`.**410 /// Asserts that the new length is less than or equal to the previous length.
409 pub fn shrinkAndFree(self: *Self, new_len: usize) void {411 pub fn shrinkAndFree(self: *Self, new_len: usize) void {
410 var unmanaged = self.moveToUnmanaged();412 var unmanaged = self.moveToUnmanaged();
411 unmanaged.shrinkAndFree(self.allocator, new_len);413 unmanaged.shrinkAndFree(self.allocator, new_len);
...@@ -413,8 +415,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -413,8 +415,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
413 }415 }
414416
415 /// Reduce length to `new_len`.417 /// Reduce length to `new_len`.
416 /// Invalidates pointers for the elements `items[new_len..]`.418 /// Invalidates element pointers for the elements `items[new_len..]`.
417 /// **Asserts that `new_len <= self.items.len`.**419 /// Asserts that the new length is less than or equal to the previous length.
418 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {420 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
419 assert(new_len <= self.items.len);421 assert(new_len <= self.items.len);
420 self.items.len = new_len;422 self.items.len = new_len;
...@@ -434,7 +436,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -434,7 +436,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
434436
435 /// If the current capacity is less than `new_capacity`, this function will437 /// If the current capacity is less than `new_capacity`, this function will
436 /// 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.
437 /// Invalidates pointers if additional memory is needed.439 /// Invalidates element pointers if additional memory is needed.
438 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void {440 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void {
439 if (@sizeOf(T) == 0) {441 if (@sizeOf(T) == 0) {
440 self.capacity = math.maxInt(usize);442 self.capacity = math.maxInt(usize);
...@@ -449,7 +451,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -449,7 +451,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
449451
450 /// If the current capacity is less than `new_capacity`, this function will452 /// If the current capacity is less than `new_capacity`, this function will
451 /// 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.
452 /// Invalidates pointers if additional memory is needed.454 /// Invalidates element pointers if additional memory is needed.
453 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void {455 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void {
454 if (@sizeOf(T) == 0) {456 if (@sizeOf(T) == 0) {
455 self.capacity = math.maxInt(usize);457 self.capacity = math.maxInt(usize);
...@@ -476,13 +478,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -476,13 +478,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
476 }478 }
477479
478 /// 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.
479 /// Invalidates pointers if additional memory is needed.481 /// Invalidates element pointers if additional memory is needed.
480 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void {482 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void {
481 return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count));483 return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count));
482 }484 }
483485
484 /// 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.
485 /// The new elements have `undefined` values. **Does not** invalidate pointers.487 /// The new elements have `undefined` values.
488 /// Never invalidates element pointers.
486 pub fn expandToCapacity(self: *Self) void {489 pub fn expandToCapacity(self: *Self) void {
487 self.items.len = self.capacity;490 self.items.len = self.capacity;
488 }491 }
...@@ -496,8 +499,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -496,8 +499,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
496499
497 /// Increase length by 1, returning pointer to the new item.500 /// Increase length by 1, returning pointer to the new item.
498 /// The returned pointer becomes invalid when the list is resized.501 /// The returned pointer becomes invalid when the list is resized.
499 /// Does not invalidate element pointers.502 /// Never invalidates element pointers.
500 /// **Asserts that the list can hold one additional item.**503 /// Asserts that the list can hold one additional item.
501 pub fn addOneAssumeCapacity(self: *Self) *T {504 pub fn addOneAssumeCapacity(self: *Self) *T {
502 assert(self.items.len < self.capacity);505 assert(self.items.len < self.capacity);
503 self.items.len += 1;506 self.items.len += 1;
...@@ -516,9 +519,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -516,9 +519,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
516519
517 /// Resize the array, adding `n` new elements, which have `undefined` values.520 /// Resize the array, adding `n` new elements, which have `undefined` values.
518 /// 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.
519 /// Does not invalidate element pointers.522 /// Never invalidates element pointers.
520 /// The returned pointer becomes invalid when the list is resized.523 /// The returned pointer becomes invalid when the list is resized.
521 /// **Asserts that the list can hold `n` additional items.**524 /// Asserts that the list can hold the additional items.
522 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {525 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
523 assert(self.items.len + n <= self.capacity);526 assert(self.items.len + n <= self.capacity);
524 const prev_len = self.items.len;527 const prev_len = self.items.len;
...@@ -538,9 +541,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -538,9 +541,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
538541
539 /// Resize the array, adding `n` new elements, which have `undefined` values.542 /// Resize the array, adding `n` new elements, which have `undefined` values.
540 /// 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.
541 /// Does not invalidate element pointers.544 /// Never invalidates element pointers.
542 /// The returned pointer becomes invalid when the list is resized.545 /// The returned pointer becomes invalid when the list is resized.
543 /// **Asserts that the list can hold `n` additional items.**546 /// Asserts that the list can hold the additional items.
544 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {547 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
545 assert(self.items.len + n <= self.capacity);548 assert(self.items.len + n <= self.capacity);
546 const prev_len = self.items.len;549 const prev_len = self.items.len;
...@@ -549,8 +552,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -549,8 +552,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
549 }552 }
550553
551 /// Remove and return the last element from the list.554 /// Remove and return the last element from the list.
552 /// Invalidates pointers to the removed element.555 /// Invalidates element pointers to the removed element.
553 /// **Asserts that the list is not empty.**556 /// Asserts that the list is not empty.
554 pub fn pop(self: *Self) T {557 pub fn pop(self: *Self) T {
555 const val = self.items[self.items.len - 1];558 const val = self.items[self.items.len - 1];
556 self.items.len -= 1;559 self.items.len -= 1;
...@@ -559,7 +562,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -559,7 +562,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
559562
560 /// Remove and return the last element from the list, or563 /// Remove and return the last element from the list, or
561 /// return `null` if list is empty.564 /// return `null` if list is empty.
562 /// Invalidates pointers to the removed element, if any.565 /// Invalidates element pointers to the removed element, if any.
563 pub fn popOrNull(self: *Self) ?T {566 pub fn popOrNull(self: *Self) ?T {
564 if (self.items.len == 0) return null;567 if (self.items.len == 0) return null;
565 return self.pop();568 return self.pop();
...@@ -581,7 +584,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -581,7 +584,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
581 }584 }
582585
583 /// Returns the last element from the list.586 /// Returns the last element from the list.
584 /// **Asserts that the list is not empty.**587 /// Asserts that the list is not empty.
585 pub fn getLast(self: Self) T {588 pub fn getLast(self: Self) T {
586 const val = self.items[self.items.len - 1];589 const val = self.items[self.items.len - 1];
587 return val;590 return val;
...@@ -596,17 +599,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -596,17 +599,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
596}599}
597600
598/// 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
599/// 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
600/// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with603/// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with
601/// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`.604/// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`.
602pub fn ArrayListUnmanaged(comptime T: type) type {605pub fn ArrayListUnmanaged(comptime T: type) type {
603 return ArrayListAlignedUnmanaged(T, null);606 return ArrayListAlignedUnmanaged(T, null);
604}607}
605608
606/// An ArrayListAligned, but the allocator is passed as a parameter to the relevant609/// A contiguous, growable list of arbitrarily aligned items in memory.
607/// 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
608/// be used throughout the entire lifetime of an ArrayListAlignedUnmanaged.611/// addresses. If the specified alignment is `null`, then `@alignOf(T)` is used.
609/// 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`.
610pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {616pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {
611 if (alignment) |a| {617 if (alignment) |a| {
612 if (a == @alignOf(T)) {618 if (a == @alignOf(T)) {
...@@ -615,15 +621,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -615,15 +621,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
615 }621 }
616 return struct {622 return struct {
617 const Self = @This();623 const Self = @This();
618 /// Contents of the list. Pointers to elements in this slice are624 /// Contents of the list. This field is intended to be accessed
619 /// **invalid after resizing operations** on the ArrayList unless the625 /// directly.
620 /// operation explicitly either: (1) states otherwise or (2) lists the
621 /// invalidated pointers.
622 ///626 ///
623 /// The allocator used determines how element pointers are627 /// Pointers to elements in this slice are invalidated by various
624 /// invalidated, so the behavior may vary between lists. To avoid628 /// functions of this ArrayList in accordance with the respective
625 /// illegal behavior, take into account the above paragraph plus the629 /// documentation. In all cases, "invalidated" means that the memory
626 /// explicit statements given in each method.630 /// has been passed to an allocator's resize or free function.
627 items: Slice = &[_]T{},631 items: Slice = &[_]T{},
628 /// How many T values this list can hold without allocating632 /// How many T values this list can hold without allocating
629 /// additional memory.633 /// additional memory.
...@@ -646,8 +650,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -646,8 +650,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
646650
647 /// Initialize with externally-managed memory. The buffer determines the651 /// Initialize with externally-managed memory. The buffer determines the
648 /// capacity, and the length is set to zero.652 /// capacity, and the length is set to zero.
649 /// **When initialized this way, all methods that accept an Allocator653 /// When initialized this way, all functions that accept an Allocator
650 /// argument cause illegal behavior**.654 /// argument cause illegal behavior.
651 pub fn initBuffer(buffer: Slice) Self {655 pub fn initBuffer(buffer: Slice) Self {
652 return .{656 return .{
653 .items = buffer[0..0],657 .items = buffer[0..0],
...@@ -722,8 +726,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -722,8 +726,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
722 /// Insert `item` at index `i`. Moves `list[i .. 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.
723 /// If `i` 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.
724 /// This operation is O(N).728 /// This operation is O(N).
725 /// Invalidates pointers if additional memory is needed.729 /// Invalidates element pointers if additional memory is needed.
726 /// **Asserts that `i < self.items.len`.**730 /// Asserts that the index is in bounds or equal to the length.
727 pub fn insert(self: *Self, allocator: Allocator, i: usize, item: T) Allocator.Error!void {731 pub fn insert(self: *Self, allocator: Allocator, i: usize, item: T) Allocator.Error!void {
728 const dst = try self.addManyAt(allocator, i, 1);732 const dst = try self.addManyAt(allocator, i, 1);
729 dst[0] = item;733 dst[0] = item;
...@@ -732,8 +736,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -732,8 +736,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
732 /// Insert `item` at index `i`. Moves `list[i .. 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.
733 /// If in` 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.
734 /// This operation is O(N).738 /// This operation is O(N).
735 /// **Asserts that `i < self.items.len`.**739 /// Asserts that the list has capacity for one additional item.
736 /// **Asserts that the list can hold one additional item.**740 /// Asserts that the index is in bounds or equal to the length.
737 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {741 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
738 assert(self.items.len < self.capacity);742 assert(self.items.len < self.capacity);
739 self.items.len += 1;743 self.items.len += 1;
...@@ -749,7 +753,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -749,7 +753,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
749 /// Invalidates pre-existing pointers to elements at and after `index`.753 /// Invalidates pre-existing pointers to elements at and after `index`.
750 /// Invalidates all pre-existing element pointers if capacity must be754 /// Invalidates all pre-existing element pointers if capacity must be
751 /// increased to accomodate the new elements.755 /// increased to accomodate the new elements.
752 /// **Asserts that `index <= self.items.len`.**756 /// Asserts that the index is in bounds or equal to the length.
753 pub fn addManyAt(757 pub fn addManyAt(
754 self: *Self,758 self: *Self,
755 allocator: Allocator,759 allocator: Allocator,
...@@ -767,8 +771,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -767,8 +771,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
767 /// operations.771 /// operations.
768 /// Invalidates pre-existing pointers to elements at and after `index`, but772 /// Invalidates pre-existing pointers to elements at and after `index`, but
769 /// does not invalidate any before that.773 /// does not invalidate any before that.
770 /// **Asserts that `index <= self.items.len`.**774 /// Asserts that the list has capacity for the additional items.
771 /// **Asserts that the list can hold `count` additional items.**775 /// Asserts that the index is in bounds or equal to the length.
772 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {776 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
773 const new_len = self.items.len + count;777 const new_len = self.items.len + count;
774 assert(self.capacity >= new_len);778 assert(self.capacity >= new_len);
...@@ -785,7 +789,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -785,7 +789,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
785 /// Invalidates pre-existing pointers to elements at and after `index`.789 /// Invalidates pre-existing pointers to elements at and after `index`.
786 /// Invalidates all pre-existing element pointers if capacity must be790 /// Invalidates all pre-existing element pointers if capacity must be
787 /// increased to accomodate the new elements.791 /// increased to accomodate the new elements.
788 /// **Asserts that `index <= self.items.len`.**792 /// Asserts that the index is in bounds or equal to the length.
789 pub fn insertSlice(793 pub fn insertSlice(
790 self: *Self,794 self: *Self,
791 allocator: Allocator,795 allocator: Allocator,
...@@ -803,8 +807,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -803,8 +807,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
803 /// Replace range of elements `list[start..][0..len]` with `new_items`807 /// Replace range of elements `list[start..][0..len]` with `new_items`
804 /// Grows list if `len < new_items.len`.808 /// Grows list if `len < new_items.len`.
805 /// Shrinks list if `len > new_items.len`809 /// Shrinks list if `len > new_items.len`
806 /// Invalidates pointers if this ArrayList is resized.810 /// Invalidates element pointers if this ArrayList is resized.
807 /// **Asserts that `start <= self.items.len`.**811 /// Asserts that the start index is in bounds or equal to the length.
808 pub fn replaceRange(812 pub fn replaceRange(
809 self: *Self,813 self: *Self,
810 allocator: Allocator,814 allocator: Allocator,
...@@ -818,14 +822,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -818,14 +822,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
818 }822 }
819823
820 /// Extend the list by 1 element. Allocates more memory as necessary.824 /// Extend the list by 1 element. Allocates more memory as necessary.
821 /// Invalidates pointers if additional memory is needed.825 /// Invalidates element pointers if additional memory is needed.
822 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 {
823 const new_item_ptr = try self.addOne(allocator);827 const new_item_ptr = try self.addOne(allocator);
824 new_item_ptr.* = item;828 new_item_ptr.* = item;
825 }829 }
826830
827 /// Extend the list by 1 element.831 /// Extend the list by 1 element.
828 /// **Asserts that the list can hold one additional item.**832 /// Never invalidates element pointers.
833 /// Asserts that the list can hold one additional item.
829 pub fn appendAssumeCapacity(self: *Self, item: T) void {834 pub fn appendAssumeCapacity(self: *Self, item: T) void {
830 const new_item_ptr = self.addOneAssumeCapacity();835 const new_item_ptr = self.addOneAssumeCapacity();
831 new_item_ptr.* = item;836 new_item_ptr.* = item;
...@@ -834,8 +839,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -834,8 +839,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
834 /// 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.
835 /// Invalidates pointers to the last element.840 /// Invalidates pointers to the last element.
836 /// This operation is O(N).841 /// This operation is O(N).
837 /// **Asserts that `i < self.items.len`.**842 /// Asserts that the list is not empty.
838 /// **Asserts that the list is not empty.**843 /// Asserts that the index is in bounds.
839 pub fn orderedRemove(self: *Self, i: usize) T {844 pub fn orderedRemove(self: *Self, i: usize) T {
840 const newlen = self.items.len - 1;845 const newlen = self.items.len - 1;
841 if (newlen == i) return self.pop();846 if (newlen == i) return self.pop();
...@@ -851,8 +856,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -851,8 +856,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
851 /// The empty slot is filled from the end of the list.856 /// The empty slot is filled from the end of the list.
852 /// Invalidates pointers to last element.857 /// Invalidates pointers to last element.
853 /// This operation is O(1).858 /// This operation is O(1).
854 /// **Asserts that `i < self.items.len`.**859 /// Asserts that the list is not empty.
855 /// **Asserts that the list is not empty.**860 /// Asserts that the index is in bounds.
856 pub fn swapRemove(self: *Self, i: usize) T {861 pub fn swapRemove(self: *Self, i: usize) T {
857 if (self.items.len - 1 == i) return self.pop();862 if (self.items.len - 1 == i) return self.pop();
858863
...@@ -863,14 +868,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -863,14 +868,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
863868
864 /// Append the slice of items to the list. Allocates more869 /// Append the slice of items to the list. Allocates more
865 /// memory as necessary.870 /// memory as necessary.
866 /// Invalidates pointers if additional memory is needed.871 /// Invalidates element pointers if additional memory is needed.
867 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 {
868 try self.ensureUnusedCapacity(allocator, items.len);873 try self.ensureUnusedCapacity(allocator, items.len);
869 self.appendSliceAssumeCapacity(items);874 self.appendSliceAssumeCapacity(items);
870 }875 }
871876
872 /// Append the slice of items to the list.877 /// Append the slice of items to the list.
873 /// **Asserts that the list can hold `items.len` additional items.**878 /// Asserts that the list can hold the additional items.
874 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {879 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
875 const old_len = self.items.len;880 const old_len = self.items.len;
876 const new_len = old_len + items.len;881 const new_len = old_len + items.len;
...@@ -882,7 +887,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -882,7 +887,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
882 /// Append the slice of items to the list. Allocates more887 /// Append the slice of items to the list. Allocates more
883 /// 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
884 /// be a compile error.889 /// be a compile error.
885 /// Invalidates pointers if additional memory is needed.890 /// Invalidates element pointers if additional memory is needed.
886 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 {
887 try self.ensureUnusedCapacity(allocator, items.len);892 try self.ensureUnusedCapacity(allocator, items.len);
888 self.appendUnalignedSliceAssumeCapacity(items);893 self.appendUnalignedSliceAssumeCapacity(items);
...@@ -891,7 +896,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -891,7 +896,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
891 /// Append an unaligned slice of items to the list.896 /// Append an unaligned slice of items to the list.
892 /// Only call this function if a call to `appendSliceAssumeCapacity`897 /// Only call this function if a call to `appendSliceAssumeCapacity`
893 /// instead would be a compile error.898 /// instead would be a compile error.
894 /// **Asserts that the list can hold `items.len` additional items.**899 /// Asserts that the list can hold the additional items.
895 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {900 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
896 const old_len = self.items.len;901 const old_len = self.items.len;
897 const new_len = old_len + items.len;902 const new_len = old_len + items.len;
...@@ -918,7 +923,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -918,7 +923,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
918923
919 /// 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
920 /// 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.
921 /// Invalidates pointers if additional memory is needed.926 /// Invalidates element pointers if additional memory is needed.
922 fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {927 fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
923 try context.self.appendSlice(context.allocator, m);928 try context.self.appendSlice(context.allocator, m);
924 return m.len;929 return m.len;
...@@ -926,20 +931,20 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -926,20 +931,20 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
926931
927 /// Append a value to the list `n` times.932 /// Append a value to the list `n` times.
928 /// Allocates more memory as necessary.933 /// Allocates more memory as necessary.
929 /// Invalidates pointers if additional memory is needed.934 /// Invalidates element pointers if additional memory is needed.
930 /// The function is inline so that a comptime-known `value` parameter will935 /// The function is inline so that a comptime-known `value` parameter will
931 /// 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.
932 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 {
933 const old_len = self.items.len;938 const old_len = self.items.len;
934 try self.resize(allocator, try addOrOom(self.items.len, n));939 try self.resize(allocator, try addOrOom(old_len, n));
935 @memset(self.items[old_len..self.items.len], value);940 @memset(self.items[old_len..self.items.len], value);
936 }941 }
937942
938 /// Append a value to the list `n` times.943 /// Append a value to the list `n` times.
939 /// **Does not** invalidate pointers.944 /// Never invalidates element pointers.
940 /// The function is inline so that a comptime-known `value` parameter will945 /// The function is inline so that a comptime-known `value` parameter will
941 /// have better memset codegen in case it has a repeated byte pattern.946 /// have better memset codegen in case it has a repeated byte pattern.
942 /// **Asserts that the list can hold `n` additional items.**947 /// Asserts that the list can hold the additional items.
943 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {948 pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
944 const new_len = self.items.len + n;949 const new_len = self.items.len + n;
945 assert(new_len <= self.capacity);950 assert(new_len <= self.capacity);
...@@ -947,9 +952,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -947,9 +952,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
947 self.items.len = new_len;952 self.items.len = new_len;
948 }953 }
949954
950 /// Adjust the list's length to `new_len`.955 /// Adjust the list length to `new_len`.
951 /// Does not initialize added items, if any.956 /// Additional elements contain the value `undefined`.
952 /// Invalidates pointers if additional memory is needed.957 /// Invalidates element pointers if additional memory is needed.
953 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 {
954 try self.ensureTotalCapacity(allocator, new_len);959 try self.ensureTotalCapacity(allocator, new_len);
955 self.items.len = new_len;960 self.items.len = new_len;
...@@ -957,7 +962,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -957,7 +962,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
957962
958 /// Reduce allocated capacity to `new_len`.963 /// Reduce allocated capacity to `new_len`.
959 /// May invalidate element pointers.964 /// May invalidate element pointers.
960 /// **Asserts that `new_len <= self.items.len`.**965 /// Asserts that the new length is less than or equal to the previous length.
961 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {966 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {
962 assert(new_len <= self.items.len);967 assert(new_len <= self.items.len);
963968
...@@ -990,7 +995,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -990,7 +995,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
990 /// Reduce length to `new_len`.995 /// Reduce length to `new_len`.
991 /// Invalidates pointers to elements `items[new_len..]`.996 /// Invalidates pointers to elements `items[new_len..]`.
992 /// Keeps capacity the same.997 /// Keeps capacity the same.
993 /// **Asserts that `new_len <= self.items.len`.**998 /// Asserts that the new length is less than or equal to the previous length.
994 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {999 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
995 assert(new_len <= self.items.len);1000 assert(new_len <= self.items.len);
996 self.items.len = new_len;1001 self.items.len = new_len;
...@@ -1010,7 +1015,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1010,7 +1015,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
10101015
1011 /// If the current capacity is less than `new_capacity`, this function will1016 /// If the current capacity is less than `new_capacity`, this function will
1012 /// 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.
1013 /// Invalidates pointers if additional memory is needed.1018 /// Invalidates element pointers if additional memory is needed.
1014 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 {
1015 if (self.capacity >= new_capacity) return;1020 if (self.capacity >= new_capacity) return;
10161021
...@@ -1020,7 +1025,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1020,7 +1025,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
10201025
1021 /// If the current capacity is less than `new_capacity`, this function will1026 /// If the current capacity is less than `new_capacity`, this function will
1022 /// 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.
1023 /// Invalidates pointers if additional memory is needed.1028 /// Invalidates element pointers if additional memory is needed.
1024 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 {
1025 if (@sizeOf(T) == 0) {1030 if (@sizeOf(T) == 0) {
1026 self.capacity = math.maxInt(usize);1031 self.capacity = math.maxInt(usize);
...@@ -1047,7 +1052,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1047,7 +1052,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1047 }1052 }
10481053
1049 /// 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.
1050 /// Invalidates pointers if additional memory is needed.1055 /// Invalidates element pointers if additional memory is needed.
1051 pub fn ensureUnusedCapacity(1056 pub fn ensureUnusedCapacity(
1052 self: *Self,1057 self: *Self,
1053 allocator: Allocator,1058 allocator: Allocator,
...@@ -1058,13 +1063,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1058,13 +1063,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
10581063
1059 /// 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.
1060 /// The new elements have `undefined` values.1065 /// The new elements have `undefined` values.
1061 /// Does not invalidate pointers.1066 /// Never invalidates element pointers.
1062 pub fn expandToCapacity(self: *Self) void {1067 pub fn expandToCapacity(self: *Self) void {
1063 self.items.len = self.capacity;1068 self.items.len = self.capacity;
1064 }1069 }
10651070
1066 /// Increase length by 1, returning pointer to the new item.1071 /// Increase length by 1, returning pointer to the new item.
1067 /// The returned pointer becomes invalid when the list resized.1072 /// The returned element pointer becomes invalid when the list is resized.
1068 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {1073 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {
1069 const newlen = try addOrOom(self.items.len, 1);1074 const newlen = try addOrOom(self.items.len, 1);
1070 try self.ensureTotalCapacity(allocator, newlen);1075 try self.ensureTotalCapacity(allocator, newlen);
...@@ -1072,9 +1077,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1072,9 +1077,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1072 }1077 }
10731078
1074 /// Increase length by 1, returning pointer to the new item.1079 /// Increase length by 1, returning pointer to the new item.
1075 /// **Does not** invalidate pointers.1080 /// Never invalidates element pointers.
1076 /// The returned pointer becomes invalid when the list resized.1081 /// The returned element pointer becomes invalid when the list is resized.
1077 /// **Asserts that the list can hold one additional item.**1082 /// Asserts that the list can hold one additional item.
1078 pub fn addOneAssumeCapacity(self: *Self) *T {1083 pub fn addOneAssumeCapacity(self: *Self) *T {
1079 assert(self.items.len < self.capacity);1084 assert(self.items.len < self.capacity);
10801085
...@@ -1093,9 +1098,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1093,9 +1098,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
10931098
1094 /// Resize the array, adding `n` new elements, which have `undefined` values.1099 /// Resize the array, adding `n` new elements, which have `undefined` values.
1095 /// 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.
1096 /// **Does not** invalidate pointers.1101 /// Never invalidates element pointers.
1097 /// The returned pointer becomes invalid when the list is resized.1102 /// The returned pointer becomes invalid when the list is resized.
1098 /// **Asserts that the list can hold `n` additional items.**1103 /// Asserts that the list can hold the additional items.
1099 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {1104 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
1100 assert(self.items.len + n <= self.capacity);1105 assert(self.items.len + n <= self.capacity);
1101 const prev_len = self.items.len;1106 const prev_len = self.items.len;
...@@ -1115,9 +1120,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1115,9 +1120,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
11151120
1116 /// Resize the array, adding `n` new elements, which have `undefined` values.1121 /// Resize the array, adding `n` new elements, which have `undefined` values.
1117 /// 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.
1118 /// Does not invalidate element pointers.1123 /// Never invalidates element pointers.
1119 /// The returned pointer becomes invalid when the list is resized.1124 /// The returned pointer becomes invalid when the list is resized.
1120 /// **Asserts that the list can hold `n` additional items.**1125 /// Asserts that the list can hold the additional items.
1121 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {1126 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
1122 assert(self.items.len + n <= self.capacity);1127 assert(self.items.len + n <= self.capacity);
1123 const prev_len = self.items.len;1128 const prev_len = self.items.len;
...@@ -1127,7 +1132,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1127,7 +1132,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
11271132
1128 /// Remove and return the last element from the list.1133 /// Remove and return the last element from the list.
1129 /// Invalidates pointers to last element.1134 /// Invalidates pointers to last element.
1130 /// **Asserts that the list is not empty.**1135 /// Asserts that the list is not empty.
1131 pub fn pop(self: *Self) T {1136 pub fn pop(self: *Self) T {
1132 const val = self.items[self.items.len - 1];1137 const val = self.items[self.items.len - 1];
1133 self.items.len -= 1;1138 self.items.len -= 1;
...@@ -1157,7 +1162,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1157,7 +1162,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1157 }1162 }
11581163
1159 /// Return the last element from the list.1164 /// Return the last element from the list.
1160 /// **Asserts that the list is not empty.**1165 /// Asserts that the list is not empty.
1161 pub fn getLast(self: Self) T {1166 pub fn getLast(self: Self) T {
1162 const val = self.items[self.items.len - 1];1167 const val = self.items[self.items.len - 1];
1163 return val;1168 return val;
...@@ -1183,12 +1188,11 @@ fn growCapacity(current: usize, minimum: usize) usize {...@@ -1183,12 +1188,11 @@ fn growCapacity(current: usize, minimum: usize) usize {
1183 }1188 }
1184}1189}
11851190
1186/// Adds a and b, returning `error.OutOfMemory` if overflow occurred.1191/// Integer addition returning `error.OutOfMemory` on overflow.
1187/// This is equivalent to `math.add`. See #18467 for why it is used.
1188fn addOrOom(a: usize, b: usize) error{OutOfMemory}!usize {1192fn addOrOom(a: usize, b: usize) error{OutOfMemory}!usize {
1189 const ov = @addWithOverflow(a, b);1193 const result, const overflow = @addWithOverflow(a, b);
1190 if (ov[1] != 0) return error.OutOfMemory;1194 if (overflow != 0) return error.OutOfMemory;
1191 return ov[0];1195 return result;
1192}1196}
11931197
1194test "std.ArrayList/ArrayListUnmanaged.init" {1198test "std.ArrayList/ArrayListUnmanaged.init" {
...@@ -1985,47 +1989,49 @@ test "std.ArrayList(u32).getLastOrNull()" {...@@ -1985,47 +1989,49 @@ test "std.ArrayList(u32).getLastOrNull()" {
1985}1989}
19861990
1987test "return OutOfMemory when capacity would exceed maximum usize integer value" {1991test "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 const a = testing.allocator;
1993 const new_item: u32 = 42;
19921994
1993 var alu = ArrayListUnmanaged(u32){1995 {
1994 .items = undefined,1996 var list: ArrayListUnmanaged(u32) = .{
1995 .capacity = math.maxInt(usize),1997 .items = undefined,
1996 };1998 .capacity = math.maxInt(usize),
1997 alu.items.len = math.maxInt(usize);1999 };
19982000 list.items.len = math.maxInt(usize);
1999 try testing.expectError(error.OutOfMemory, alu.append(a, undefined));2001
2000 try testing.expectError(error.OutOfMemory, alu.appendSlice(a, &.{undefined}));2002 try testing.expectError(error.OutOfMemory, list.append(a, new_item));
2001 try testing.expectError(error.OutOfMemory, alu.appendNTimes(a, undefined, 1));2003 try testing.expectError(error.OutOfMemory, list.appendSlice(a, &.{new_item}));
2002 try testing.expectError(error.OutOfMemory, alu.appendUnalignedSlice(a, &.{undefined}));2004 try testing.expectError(error.OutOfMemory, list.appendNTimes(a, new_item, 1));
2003 try testing.expectError(error.OutOfMemory, alu.addOne(a));2005 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(a, &.{new_item}));
2004 try testing.expectError(error.OutOfMemory, alu.addManyAt(a, 0, 1));2006 try testing.expectError(error.OutOfMemory, list.addOne(a));
2005 try testing.expectError(error.OutOfMemory, alu.addManyAsArray(a, 1));2007 try testing.expectError(error.OutOfMemory, list.addManyAt(a, 0, 1));
2006 try testing.expectError(error.OutOfMemory, alu.addManyAsSlice(a, 1));2008 try testing.expectError(error.OutOfMemory, list.addManyAsArray(a, 1));
2007 try testing.expectError(error.OutOfMemory, alu.insert(a, 0, undefined));2009 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(a, 1));
2008 try testing.expectError(error.OutOfMemory, alu.insertSlice(a, 0, &.{undefined}));2010 try testing.expectError(error.OutOfMemory, list.insert(a, 0, new_item));
2009 try testing.expectError(error.OutOfMemory, alu.toOwnedSliceSentinel(a, 0));2011 try testing.expectError(error.OutOfMemory, list.insertSlice(a, 0, &.{new_item}));
2010 try testing.expectError(error.OutOfMemory, alu.ensureUnusedCapacity(a, 1));2012 try testing.expectError(error.OutOfMemory, list.toOwnedSliceSentinel(a, 0));
20112013 try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(a, 1));
2012 var al = ArrayList(u32){2014 }
2013 .items = undefined,2015
2014 .capacity = math.maxInt(usize),2016 {
2015 .allocator = a,2017 var list: ArrayList(u32) = .{
2016 };2018 .items = undefined,
2017 al.items.len = math.maxInt(usize);2019 .capacity = math.maxInt(usize),
20182020 .allocator = a,
2019 try testing.expectError(error.OutOfMemory, al.append(undefined));2021 };
2020 try testing.expectError(error.OutOfMemory, al.appendSlice(&.{undefined}));2022 list.items.len = math.maxInt(usize);
2021 try testing.expectError(error.OutOfMemory, al.appendNTimes(undefined, 1));2023
2022 try testing.expectError(error.OutOfMemory, al.appendUnalignedSlice(&.{undefined}));2024 try testing.expectError(error.OutOfMemory, list.append(new_item));
2023 try testing.expectError(error.OutOfMemory, al.addOne());2025 try testing.expectError(error.OutOfMemory, list.appendSlice(&.{new_item}));
2024 try testing.expectError(error.OutOfMemory, al.addManyAt(0, 1));2026 try testing.expectError(error.OutOfMemory, list.appendNTimes(new_item, 1));
2025 try testing.expectError(error.OutOfMemory, al.addManyAsArray(1));2027 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(&.{new_item}));
2026 try testing.expectError(error.OutOfMemory, al.addManyAsSlice(1));2028 try testing.expectError(error.OutOfMemory, list.addOne());
2027 try testing.expectError(error.OutOfMemory, al.insert(0, undefined));2029 try testing.expectError(error.OutOfMemory, list.addManyAt(0, 1));
2028 try testing.expectError(error.OutOfMemory, al.insertSlice(0, &.{undefined}));2030 try testing.expectError(error.OutOfMemory, list.addManyAsArray(1));
2029 try testing.expectError(error.OutOfMemory, al.toOwnedSliceSentinel(0));2031 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(1));
2030 try testing.expectError(error.OutOfMemory, al.ensureUnusedCapacity(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 }
2031}2037}