authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-27 21:33:23+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-27 21:33:23+02:00
logd26018b0f46f14adac17f021782270e13ede5a92
tree2de127d8086084c695c4a2b391687419009919c3
parentd2317110c071d7aff79cc54c0d1ce9907149e4c8
parentcad75a7106cadd971f4cdc0ec4f3ee0fbe2adf09

Merge pull request 'feat: add pointer stability to ArrayList' (#36239) from robbielyman/zig:push-tuqlrxoruyww into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36239 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

3 files changed, 228 insertions(+), 106 deletions(-)

lib/compiler/aro/aro/Compilation.zig+1
......@@ -1601,6 +1601,7 @@ pub fn addSourceFromOwnedBuffer(comp: *Compilation, path: []const u8, buf: []u8,
16011601 var list: std.ArrayList(u8) = .{
16021602 .items = contents[0..i],
16031603 .capacity = contents.len,
1604 .pointer_stability = .{},
16041605 };
16051606 contents = try list.toOwnedSlice(comp.gpa);
16061607 }
lib/std/Io/Writer.zig+3
......@@ -2475,6 +2475,7 @@ pub fn unreachableRebase(w: *Writer, preserve: usize, capacity: usize) Error!voi
24752475
24762476pub fn fromArrayList(array_list: *ArrayList(u8)) Writer {
24772477 defer array_list.* = .empty;
2478 array_list.pointer_stability.assertUnlocked();
24782479 return .{
24792480 .vtable = &.{
24802481 .drain = fixedDrain,
......@@ -2490,6 +2491,7 @@ pub fn toArrayList(w: *Writer) ArrayList(u8) {
24902491 const result: ArrayList(u8) = .{
24912492 .items = w.buffer[0..w.end],
24922493 .capacity = w.buffer.len,
2494 .pointer_stability = .{},
24932495 };
24942496 w.buffer = &.{};
24952497 w.end = 0;
......@@ -2739,6 +2741,7 @@ pub const Allocating = struct {
27392741 const result: std.array_list.Aligned(u8, alignment) = .{
27402742 .items = @alignCast(w.buffer[0..w.end]),
27412743 .capacity = w.buffer.len,
2744 .pointer_stability = .{},
27422745 };
27432746 w.buffer = &.{};
27442747 w.end = 0;
lib/std/array_list.zig+224-106
......@@ -26,14 +26,17 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
2626 ///
2727 /// Pointers to elements in this slice are invalidated by various
2828 /// functions of this ArrayList in accordance with the respective
29 /// documentation. In all cases, "invalidated" means that the memory
30 /// has been passed to this allocator's resize or free function.
29 /// documentation.
30 /// An invalidated pointer may point either to valid or freed memory.
3131 items: Slice,
3232 /// How many T values this list can hold without allocating
3333 /// additional memory.
3434 capacity: usize,
3535 allocator: Allocator,
3636
37 /// Used to detect memory safety violations.
38 pointer_stability: debug.SafetyLock,
39
3740 pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T;
3841
3942 pub fn SentinelSlice(comptime s: T) type {
......@@ -46,6 +49,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
4649 .items = &[_]T{},
4750 .capacity = 0,
4851 .allocator = gpa,
52 .pointer_stability = .{},
4953 };
5054 }
5155
......@@ -60,11 +64,29 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
6064
6165 /// Release all allocated memory.
6266 pub fn deinit(self: Self) void {
67 self.pointer_stability.assertUnlocked();
6368 if (@sizeOf(T) > 0) {
6469 self.allocator.free(self.allocatedSlice());
6570 }
6671 }
6772
73 /// Puts the array list into a state where any method call that would
74 /// cause an existing value pointer to become invalidated will
75 /// instead trigger an assertion.
76 ///
77 /// An additional call to `lockPointers` in such state also triggers an
78 /// assertion.
79 ///
80 /// `unlockPointers` returns the array list to the previous state.
81 pub fn lockPointers(self: *Self) void {
82 self.pointer_stability.lock();
83 }
84
85 /// Undoes a call to `lockPointers`.
86 pub fn unlockPointers(self: *Self) void {
87 self.pointer_stability.unlock();
88 }
89
6890 /// ArrayList takes ownership of the passed in slice. The slice must have been
6991 /// allocated with `gpa`.
7092 /// Deinitialize with `deinit` or use `toOwnedSlice`.
......@@ -73,6 +95,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
7395 .items = slice,
7496 .capacity = slice.len,
7597 .allocator = gpa,
98 .pointer_stability = .{},
7699 };
77100 }
78101
......@@ -84,6 +107,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
84107 .items = slice,
85108 .capacity = slice.len + 1,
86109 .allocator = gpa,
110 .pointer_stability = .{},
87111 };
88112 }
89113
......@@ -91,14 +115,20 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
91115 /// of this ArrayList. Empties this ArrayList.
92116 pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment) {
93117 const allocator = self.allocator;
94 const result: Aligned(T, alignment) = .{ .items = self.items, .capacity = self.capacity };
118 const result: Aligned(T, alignment) = .{
119 .items = self.items,
120 .capacity = self.capacity,
121 .pointer_stability = self.pointer_stability,
122 };
95123 self.* = init(allocator);
96124 return result;
97125 }
98126
99127 /// The caller owns the returned memory. Empties this ArrayList.
100128 /// Its capacity is cleared, making `deinit` safe but unnecessary to call.
129 /// May invalidate element pointers if remapping memory cannot be done in place.
101130 pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice {
131 self.pointer_stability.assertUnlocked();
102132 const allocator = self.allocator;
103133
104134 const old_memory = self.allocatedSlice();
......@@ -114,6 +144,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
114144 }
115145
116146 /// The caller owns the returned memory. Empties this ArrayList.
147 /// May invalidate element pointers if remapping memory cannot be done in place.
117148 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
118149 // This addition can never overflow because `self.items` can never occupy the whole address space
119150 try self.ensureTotalCapacityPrecise(self.items.len + 1);
......@@ -129,28 +160,31 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
129160 return cloned;
130161 }
131162
132 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
133 /// If `i` is equal to the length of the list this operation is equivalent to append.
163 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
164 /// If `index` is equal to the length of the list this operation is equivalent to append.
134165 /// This operation is O(N).
135166 /// Invalidates element pointers if additional memory is needed.
167 /// Invalidates pre-existing pointers to elements at and after `index`.
136168 /// Asserts that the index is in bounds or equal to the length.
137 pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void {
138 const dst = try self.addManyAt(i, 1);
169 pub fn insert(self: *Self, index: usize, item: T) Allocator.Error!void {
170 self.pointer_stability.assertUnlocked();
171 const dst = try self.addManyAt(index, 1);
139172 dst[0] = item;
140173 }
141174
142 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
143 /// If `i` is equal to the length of the list this operation is
175 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
176 /// If `index` is equal to the length of the list this operation is
144177 /// equivalent to appendAssumeCapacity.
145178 /// This operation is O(N).
179 /// Invalidates pre-existing pointers to elements at and after `index`.
146180 /// Asserts that there is enough capacity for the new item.
147181 /// Asserts that the index is in bounds or equal to the length.
148 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
182 pub fn insertAssumeCapacity(self: *Self, index: usize, item: T) void {
183 self.pointer_stability.assertUnlocked();
149184 assert(self.items.len < self.capacity);
150185 self.items.len += 1;
151
152 @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
153 self.items[i] = item;
186 @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]);
187 self.items[index] = item;
154188 }
155189
156190 /// Add `count` new elements at position `index`, which have
......@@ -163,6 +197,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
163197 /// Asserts that the index is in bounds or equal to the length.
164198 pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {
165199 const new_len = try addOrOom(self.items.len, count);
200 self.pointer_stability.assertUnlocked();
166201
167202 if (self.capacity >= new_len)
168203 return addManyAtAssumeCapacity(self, index, count);
......@@ -198,11 +233,11 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
198233 /// `undefined` values. Returns a slice pointing to the newly allocated
199234 /// elements, which becomes invalid after various `ArrayList`
200235 /// operations.
236 /// Invalidates pre-existing pointers to elements at and after `index`.
201237 /// Asserts that there is enough capacity for the new elements.
202 /// Invalidates pre-existing pointers to elements at and after `index`, but
203 /// does not invalidate any before that.
204238 /// Asserts that the index is in bounds or equal to the length.
205239 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
240 self.pointer_stability.assertUnlocked();
206241 const new_len = self.items.len + count;
207242 assert(self.capacity >= new_len);
208243 const to_move = self.items[index..];
......@@ -213,7 +248,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
213248 return result;
214249 }
215250
216 /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.
251 /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room.
217252 /// This operation is O(N).
218253 /// Invalidates pre-existing pointers to elements at and after `index`.
219254 /// Invalidates all pre-existing element pointers if capacity must be
......@@ -229,7 +264,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
229264 }
230265
231266 /// Grows or shrinks the list as necessary.
232 /// Invalidates element pointers if additional capacity is allocated.
267 /// Invalidates element pointers if additional capacity is allocated,
268 /// Invalidates pointers to elements at and above index `start + len`
269 /// when `len` and `new_items.len` are unequal.
233270 /// Asserts that the range is in bounds.
234271 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {
235272 var unmanaged = self.moveToUnmanaged();
......@@ -238,7 +275,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
238275 }
239276
240277 /// Grows or shrinks the list as necessary.
241 /// Never invalidates element pointers.
278 /// Invalidates pointers to elements at and above index `start + len`
279 /// when `len` and `new_items.len` are unequal.
242280 /// Asserts the capacity is enough for additional items.
243281 pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void {
244282 var unmanaged = self.moveToUnmanaged();
......@@ -275,10 +313,12 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
275313
276314 /// Removes the element at the specified index and returns it.
277315 /// The empty slot is filled from the end of the list.
316 /// Invalidates pointers to the end of the list.
278317 /// This operation is O(1).
279318 /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.
280319 /// Asserts that the index is in bounds.
281320 pub fn swapRemove(self: *Self, i: usize) T {
321 self.pointer_stability.assertUnlocked();
282322 const val = self.items[i];
283323 self.items[i] = self.items[self.items.len - 1];
284324 self.items[self.items.len - 1] = undefined;
......@@ -328,6 +368,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
328368 @memcpy(self.items[old_len..][0..items.len], items);
329369 }
330370
371 /// Prints a formatted string into this list.
372 /// Invalidates element pointers if additional memory is needed.
331373 pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
332374 const gpa = self.allocator;
333375 var unmanaged = self.moveToUnmanaged();
......@@ -379,6 +421,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
379421 /// Invalidates element pointers for the elements `items[new_len..]`.
380422 /// Asserts that the new length is less than or equal to the previous length.
381423 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
424 self.pointer_stability.assertUnlocked();
382425 assert(new_len <= self.items.len);
383426 @memset(self.items[new_len..], undefined);
384427 self.items.len = new_len;
......@@ -387,12 +430,14 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
387430 /// Reduce length to 0.
388431 /// Invalidates all element pointers.
389432 pub fn clearRetainingCapacity(self: *Self) void {
433 self.pointer_stability.assertUnlocked();
390434 @memset(self.items, undefined);
391435 self.items.len = 0;
392436 }
393437
394438 /// Invalidates all element pointers.
395439 pub fn clearAndFree(self: *Self) void {
440 self.pointer_stability.assertUnlocked();
396441 self.allocator.free(self.allocatedSlice());
397442 self.items.len = 0;
398443 self.capacity = 0;
......@@ -424,9 +469,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
424469 }
425470
426471 if (self.capacity >= new_capacity) return;
427
472 self.pointer_stability.assertUnlocked();
428473 // Here we avoid copying allocated but unused bytes by
429 // attempting a resize in place, and falling back to allocating
474 // attempting a remap, and falling back to allocating
430475 // a new buffer and doing our own copy. With a realloc() call,
431476 // the allocator implementation would pointlessly copy our
432477 // extra capacity.
......@@ -457,7 +502,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
457502 }
458503
459504 /// Increase length by 1, returning pointer to the new item.
460 /// The returned pointer becomes invalid when the list resized.
505 /// Invalidates element pointers if additional memory is needed.
506 /// The returned pointer may be invalidated by further operations to this list.
461507 pub fn addOne(self: *Self) Allocator.Error!*T {
462508 // This can never overflow because `self.items` can never occupy the whole address space
463509 const newlen = self.items.len + 1;
......@@ -466,7 +512,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
466512 }
467513
468514 /// Increase length by 1, returning pointer to the new item.
469 /// The returned pointer becomes invalid when the list is resized.
515 /// The returned pointer may be invalidated by further operations to this list.
470516 /// Never invalidates element pointers.
471517 /// Asserts that the list can hold one additional item.
472518 pub fn addOneAssumeCapacity(self: *Self) *T {
......@@ -477,8 +523,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
477523
478524 /// Resize the array, adding `n` new elements, which have `undefined` values.
479525 /// The return value is an array pointing to the newly allocated elements.
480 /// The returned pointer becomes invalid when the list is resized.
526 /// The returned pointer may be invalidated by further operations to this list.
481527 /// Resizes list if `self.capacity` is not large enough.
528 /// Invalidates element pointers if additional memory is needed.
482529 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {
483530 const prev_len = self.items.len;
484531 try self.resize(try addOrOom(self.items.len, n));
......@@ -488,7 +535,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
488535 /// Resize the array, adding `n` new elements, which have `undefined` values.
489536 /// The return value is an array pointing to the newly allocated elements.
490537 /// Never invalidates element pointers.
491 /// The returned pointer becomes invalid when the list is resized.
538 /// The returned pointer may be invalidated by further operations to this list.
492539 /// Asserts that the list can hold the additional items.
493540 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
494541 assert(self.items.len + n <= self.capacity);
......@@ -499,8 +546,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
499546
500547 /// Resize the array, adding `n` new elements, which have `undefined` values.
501548 /// The return value is a slice pointing to the newly allocated elements.
502 /// The returned pointer becomes invalid when the list is resized.
549 /// The returned pointer may be invalidated by further operations to this list.
503550 /// Resizes list if `self.capacity` is not large enough.
551 /// Invalidates element pointers if additional memory is needed.
504552 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {
505553 const prev_len = self.items.len;
506554 try self.resize(try addOrOom(self.items.len, n));
......@@ -510,7 +558,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
510558 /// Resize the array, adding `n` new elements, which have `undefined` values.
511559 /// The return value is a slice pointing to the newly allocated elements.
512560 /// Never invalidates element pointers.
513 /// The returned pointer becomes invalid when the list is resized.
561 /// The returned pointer may be invalidated by further operations to this list.
514562 /// Asserts that the list can hold the additional items.
515563 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
516564 assert(self.items.len + n <= self.capacity);
......@@ -520,9 +568,10 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
520568 }
521569
522570 /// Remove and return the last element from the list, or return `null` if list is empty.
523 /// Invalidates element pointers to the removed element, if any.
571 /// Invalidates element pointers to the removed element.
524572 pub fn pop(self: *Self) ?T {
525573 if (self.items.len == 0) return null;
574 self.pointer_stability.assertUnlocked();
526575 const val = self.items[self.items.len - 1];
527576 self.items[self.items.len - 1] = undefined;
528577 self.items.len -= 1;
......@@ -531,6 +580,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
531580
532581 /// Returns a slice of all the items plus the extra capacity, whose memory
533582 /// contents are `undefined`.
583 /// The returned pointer may be invalidated by further operations to this list.
534584 pub fn allocatedSlice(self: Self) Slice {
535585 // `items.len` is the length, not the capacity.
536586 return self.items.ptr[0..self.capacity];
......@@ -540,6 +590,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
540590 /// This can be useful for writing directly into an ArrayList.
541591 /// Note that such an operation must be followed up with a direct
542592 /// modification of `self.items.len`.
593 /// The returned pointer may be invalidated by further operations to this list.
543594 pub fn unusedCapacitySlice(self: Self) []T {
544595 return self.allocatedSlice()[self.items.len..];
545596 }
......@@ -554,6 +605,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
554605
555606 /// Returns the last element from the list, or `null` if the list is
556607 /// empty.
608 /// Never invalidates element pointers.
557609 pub fn last(self: Self) ?T {
558610 if (self.items.len == 0) return null;
559611 return self.items[self.items.len - 1];
......@@ -561,6 +613,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
561613
562614 /// Returns a pointer to the last element from the list, or `null` if
563615 /// the list is empty.
616 /// The returned pointer may be invalidated by further operations to this list.
564617 pub fn lastPtr(self: Self) ?*T {
565618 if (self.items.len == 0) return null;
566619 return &self.items[self.items.len - 1];
......@@ -590,17 +643,21 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
590643 ///
591644 /// Pointers to elements in this slice are invalidated by various
592645 /// functions of this ArrayList in accordance with the respective
593 /// documentation. In all cases, "invalidated" means that the memory
594 /// has been passed to an allocator's resize or free function.
646 /// documentation.
647 /// An invalidated pointer may point either to valid or freed memory.
595648 items: Slice,
596649 /// How many T values this list can hold without allocating
597650 /// additional memory.
598651 capacity: usize,
599652
653 /// Used to detect memory safety violations.
654 pointer_stability: debug.SafetyLock,
655
600656 /// An ArrayList containing no elements.
601657 pub const empty: Self = .{
602658 .items = &.{},
603659 .capacity = 0,
660 .pointer_stability = .{},
604661 };
605662
606663 pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T;
......@@ -626,19 +683,43 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
626683 return .{
627684 .items = buffer[0..0],
628685 .capacity = buffer.len,
686 .pointer_stability = .{},
629687 };
630688 }
631689
632690 /// Release all allocated memory.
633691 pub fn deinit(self: *Self, gpa: Allocator) void {
692 self.pointer_stability.assertUnlocked();
634693 gpa.free(self.allocatedSlice());
635694 self.* = undefined;
636695 }
637696
697 /// Puts the unmanaged array list into a state where any method call that would
698 /// cause an existing value pointer to become invalidated will
699 /// instead trigger an assertion.
700 ///
701 /// An additional call to `lockPointers` in such state also triggers an
702 /// assertion.
703 ///
704 /// `unlockPointers` returns the unmanaged array list to the previous state.
705 pub fn lockPointers(self: *Self) void {
706 self.pointer_stability.lock();
707 }
708
709 /// Undoes a call to `lockPointers`.
710 pub fn unlockPointers(self: *Self) void {
711 self.pointer_stability.unlock();
712 }
713
638714 /// Convert this list into an analogous memory-managed one.
639715 /// The returned list has ownership of the underlying memory.
640716 pub fn toManaged(self: *Self, gpa: Allocator) AlignedManaged(T, alignment) {
641 return .{ .items = self.items, .capacity = self.capacity, .allocator = gpa };
717 return .{
718 .items = self.items,
719 .capacity = self.capacity,
720 .allocator = gpa,
721 .pointer_stability = self.pointer_stability,
722 };
642723 }
643724
644725 /// ArrayList takes ownership of the passed in slice.
......@@ -647,6 +728,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
647728 return Self{
648729 .items = slice,
649730 .capacity = slice.len,
731 .pointer_stability = .{},
650732 };
651733 }
652734
......@@ -656,13 +738,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
656738 return Self{
657739 .items = slice,
658740 .capacity = slice.len + 1,
741 .pointer_stability = .{},
659742 };
660743 }
661744
662745 /// The caller owns the returned memory. Empties this ArrayList.
663746 /// Its capacity is cleared, making deinit() safe but unnecessary to call.
747 /// May invalidate element pointers.
664748 pub fn toOwnedSlice(self: *Self, gpa: Allocator) Allocator.Error!Slice {
665749 const old_memory = self.allocatedSlice();
750 self.pointer_stability.assertUnlocked();
666751 if (gpa.remap(old_memory, self.items.len)) |new_items| {
667752 self.* = .empty;
668753 return new_items;
......@@ -675,7 +760,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
675760 }
676761
677762 /// The caller owns the returned memory. ArrayList becomes empty.
763 /// May invalidate element pointers.
678764 pub fn toOwnedSliceSentinel(self: *Self, gpa: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
765 self.pointer_stability.assertUnlocked();
679766 // This addition can never overflow because `self.items` can never occupy the whole address space.
680767 try self.ensureTotalCapacityPrecise(gpa, self.items.len + 1);
681768 self.appendAssumeCapacity(sentinel);
......@@ -688,6 +775,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
688775 /// Its capacity is cleared, making deinit() safe but unnecessary to call.
689776 ///
690777 /// Asserts what the capacity is equal to the length.
778 /// Never invalidates element pointers.
691779 pub fn toOwnedSliceAssert(self: *Self) Slice {
692780 assert(self.items.len == self.capacity);
693781 const items = self.items;
......@@ -697,6 +785,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
697785
698786 /// The caller owns the returned memory. ArrayList becomes empty.
699787 /// Asserts what the capacity is equal to the length + 1.
788 /// Never invalidates element pointers.
700789 pub fn toOwnedSliceSentinelAssert(self: *Self, comptime sentinel: T) SentinelSlice(sentinel) {
701790 std.debug.assert(self.items.len + 1 == self.capacity);
702791 self.appendAssumeCapacity(sentinel);
......@@ -711,43 +800,41 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
711800 return cloned;
712801 }
713802
714 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
715 /// If `i` is equal to the length of the list this operation is equivalent to append.
803 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
804 /// If `index` is equal to the length of the list this operation is equivalent to append.
716805 /// This operation is O(N).
717806 /// Invalidates element pointers if additional memory is needed.
807 /// Invalidates pre-existing pointers to elements at and after `index`.
718808 /// Asserts that the index is in bounds or equal to the length.
719 pub fn insert(self: *Self, gpa: Allocator, i: usize, item: T) Allocator.Error!void {
720 const dst = try self.addManyAt(gpa, i, 1);
809 pub fn insert(self: *Self, gpa: Allocator, index: usize, item: T) Allocator.Error!void {
810 self.pointer_stability.assertUnlocked();
811 const dst = try self.addManyAt(gpa, index, 1);
721812 dst[0] = item;
722813 }
723814
724 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.
725 ///
726 /// If `i` is equal to the length of the list this operation is equivalent to append.
727 ///
815 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
816 /// If `index` is equal to the length of the list this operation is
817 /// equivalent to appendAssumeCapacity.
728818 /// This operation is O(N).
729 ///
819 /// Invalidates pre-existing pointers to elements at and after `index`.
730820 /// Asserts that the list has capacity for one additional item.
731 ///
732821 /// Asserts that the index is in bounds or equal to the length.
733 pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void {
822 pub fn insertAssumeCapacity(self: *Self, index: usize, item: T) void {
823 self.pointer_stability.assertUnlocked();
734824 assert(self.items.len < self.capacity);
735825 self.items.len += 1;
736
737 @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);
738 self.items[i] = item;
826 @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]);
827 self.items[index] = item;
739828 }
740829
741 /// Insert `item` at index `i`, moving `list[i .. list.len]` to higher indices to make room.
742 ///
743 /// If `i` is equal to the length of the list this operation is equivalent to append.
744 ///
830 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
831 /// If `index` is equal to the length of the list this operation is
832 /// equivalent to appendAssumeCapacity.
745833 /// This operation is O(N).
746 ///
834 /// Invalidates pre-existing pointers to elements at and after `index`.
835 /// Asserts that the index is in bounds or equal to the length.
747836 /// If the list lacks unused capacity for the additional item, returns
748837 /// `error.OutOfMemory`.
749 ///
750 /// Asserts that the index is in bounds or equal to the length.
751838 pub fn insertBounded(self: *Self, i: usize, item: T) error{OutOfMemory}!void {
752839 if (self.capacity - self.items.len == 0) return error.OutOfMemory;
753840 return insertAssumeCapacity(self, i, item);
......@@ -767,20 +854,48 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
767854 index: usize,
768855 count: usize,
769856 ) Allocator.Error![]T {
770 var managed = self.toManaged(gpa);
771 defer self.* = managed.moveToUnmanaged();
772 return managed.addManyAt(index, count);
857 const new_len = try addOrOom(self.items.len, count);
858 self.pointer_stability.assertUnlocked();
859
860 if (self.capacity >= new_len)
861 return addManyAtAssumeCapacity(self, index, count);
862
863 // Here we avoid copying allocated but unused bytes by
864 // attempting a resize in place, and falling back to allocating
865 // a new buffer and doing our own copy. With a realloc() call,
866 // the allocator implementation would pointlessly copy our
867 // extra capacity.
868 const new_capacity = Aligned(T, alignment).growCapacity(new_len);
869 const old_memory = self.allocatedSlice();
870 if (gpa.remap(old_memory, new_capacity)) |new_memory| {
871 self.items.ptr = new_memory.ptr;
872 self.capacity = new_memory.len;
873 return addManyAtAssumeCapacity(self, index, count);
874 }
875
876 // Make a new allocation, avoiding `ensureTotalCapacity` in order
877 // to avoid extra memory copies.
878 const new_memory = try gpa.alignedAlloc(T, alignment, new_capacity);
879 const to_move = self.items[index..];
880 @memcpy(new_memory[0..index], self.items[0..index]);
881 @memcpy(new_memory[index + count ..][0..to_move.len], to_move);
882 gpa.free(old_memory);
883 self.items = new_memory[0..new_len];
884 self.capacity = new_memory.len;
885 // The inserted elements at `new_memory[index..][0..count]` have
886 // already been set to `undefined` by memory allocation.
887 return new_memory[index..][0..count];
773888 }
774889
775890 /// Add `count` new elements at position `index`, which have
776891 /// `undefined` values. Returns a slice pointing to the newly allocated
777892 /// elements, which becomes invalid after various `ArrayList`
778893 /// operations.
779 /// Invalidates pre-existing pointers to elements at and after `index`, but
780 /// does not invalidate any before that.
894 /// Invalidates pre-existing pointers to elements at and after `index`.
781895 /// Asserts that the list has capacity for the additional items.
782896 /// Asserts that the index is in bounds or equal to the length.
783897 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
898 self.pointer_stability.assertUnlocked();
784899 const new_len = self.items.len + count;
785900 assert(self.capacity >= new_len);
786901 const to_move = self.items[index..];
......@@ -795,20 +910,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
795910 /// `undefined` values, returning a slice pointing to the newly
796911 /// allocated elements, which becomes invalid after various `ArrayList`
797912 /// operations.
798 ///
799 /// Invalidates pre-existing pointers to elements at and after `index`, but
800 /// does not invalidate any before that.
801 ///
913 /// Invalidates pre-existing pointers to elements at and after `index`.
802914 /// If the list lacks unused capacity for the additional items, returns
803915 /// `error.OutOfMemory`.
804 ///
805916 /// Asserts that the index is in bounds or equal to the length.
806917 pub fn addManyAtBounded(self: *Self, index: usize, count: usize) error{OutOfMemory}![]T {
807918 if (self.capacity - self.items.len < count) return error.OutOfMemory;
808919 return addManyAtAssumeCapacity(self, index, count);
809920 }
810921
811 /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.
922 /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room.
812923 /// This operation is O(N).
813924 /// Invalidates pre-existing pointers to elements at and after `index`.
814925 /// Invalidates all pre-existing element pointers if capacity must be
......@@ -828,7 +939,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
828939 @memcpy(dst, items);
829940 }
830941
831 /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.
942 /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room.
832943 /// This operation is O(N).
833944 /// Invalidates pre-existing pointers to elements at and after `index`.
834945 /// Asserts that the list has capacity for the additional items.
......@@ -842,7 +953,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
842953 @memcpy(dst, items);
843954 }
844955
845 /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.
956 /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room.
846957 /// This operation is O(N).
847958 /// Invalidates pre-existing pointers to elements at and after `index`.
848959 /// If the list lacks unused capacity for the additional items, returns
......@@ -858,7 +969,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
858969 }
859970
860971 /// Grows or shrinks the list as necessary.
861 /// Invalidates element pointers if additional capacity is allocated.
972 /// Invalidates element pointers if additional capacity is allocated,
973 /// Invalidates pointers to elements at and above index `start + len`
974 /// when `len` and `new_items.len` are unequal.
862975 /// Asserts that the range is in bounds.
863976 pub fn replaceRange(
864977 self: *Self,
......@@ -872,9 +985,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
872985 }
873986
874987 /// Grows or shrinks the list as necessary.
875 ///
876 /// Never invalidates element pointers.
877 ///
988 /// Invalidates pointers to elements at and above index `start + len`
989 /// when `len` and `new_items.len` are unequal.
878990 /// Asserts the capacity is enough for additional items.
879991 pub fn replaceRangeAssumeCapacity(
880992 self: *Self,
......@@ -883,7 +995,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
883995 new_items: []const T,
884996 ) void {
885997 std.debug.assert(self.capacity - self.items.len >= new_items.len -| len);
886
998 self.pointer_stability.assertUnlocked();
887999 const tail = self.items[start + len ..];
8881000 const vacated = self.items[self.items.len - (len -| new_items.len) ..];
8891001 self.items.len = self.items.len - len + new_items.len;
......@@ -892,10 +1004,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
8921004 @memset(vacated, undefined);
8931005 }
8941006
895 /// Grows or shrinks the list as necessary.
896 ///
897 /// Never invalidates element pointers.
898 ///
1007 /// Invalidates pointers to elements at and above index `start + len`
1008 /// when `len` and `new_items.len` are unequal.
8991009 /// If the unused capacity is insufficient for additional items,
9001010 /// returns `error.OutOfMemory`.
9011011 pub fn replaceRangeBounded(
......@@ -958,6 +1068,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
9581068 ///
9591069 /// Invalidates element pointers beyond the first deleted index.
9601070 pub fn orderedRemoveMany(self: *Self, sorted_indexes: []const usize) void {
1071 self.pointer_stability.assertUnlocked();
9611072 if (sorted_indexes.len == 0) return;
9621073 var shift: usize = 1;
9631074 for (sorted_indexes[0 .. sorted_indexes.len - 1], sorted_indexes[1..]) |removed, end| {
......@@ -980,6 +1091,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
9801091 /// This operation is O(1).
9811092 /// Asserts that the index is in bounds.
9821093 pub fn swapRemove(self: *Self, i: usize) T {
1094 self.pointer_stability.assertUnlocked();
9831095 const val = self.items[i];
9841096 self.items[i] = self.items[self.items.len - 1];
9851097 self.items[self.items.len - 1] = undefined;
......@@ -996,7 +1108,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
9961108 }
9971109
9981110 /// Append the slice of items to the list.
999 ///
1111 /// Never invalidates element pointers.
10001112 /// Asserts that the list can hold the additional items.
10011113 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
10021114 const old_len = self.items.len;
......@@ -1007,7 +1119,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
10071119 }
10081120
10091121 /// Append the slice of items to the list.
1010 ///
1122 /// Never invalidates element pointers.
10111123 /// If the list lacks unused capacity for the additional items, returns `error.OutOfMemory`.
10121124 pub fn appendSliceBounded(self: *Self, items: []const T) error{OutOfMemory}!void {
10131125 if (self.capacity - self.items.len < items.len) return error.OutOfMemory;
......@@ -1027,7 +1139,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
10271139 ///
10281140 /// Intended to be used only when `appendSliceAssumeCapacity` would be
10291141 /// a compile error.
1030 ///
1142 /// Never invalidates element pointers.
10311143 /// Asserts that the list can hold the additional items.
10321144 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
10331145 const old_len = self.items.len;
......@@ -1041,7 +1153,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
10411153 ///
10421154 /// Intended to be used only when `appendSliceAssumeCapacity` would be
10431155 /// a compile error.
1044 ///
1156 /// Never invalidates element pointers.
10451157 /// If the list lacks unused capacity for the additional items, returns
10461158 /// `error.OutOfMemory`.
10471159 pub fn appendUnalignedSliceBounded(self: *Self, items: []align(1) const T) error{OutOfMemory}!void {
......@@ -1049,6 +1161,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
10491161 return appendUnalignedSliceAssumeCapacity(self, items);
10501162 }
10511163
1164 /// Prints a formatted string into this list.
1165 /// Invalidates element pointers if additional memory is needed.
10521166 pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
10531167 comptime assert(T == u8);
10541168 try self.ensureUnusedCapacity(gpa, fmt.len);
......@@ -1059,6 +1173,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
10591173 };
10601174 }
10611175
1176 /// Prints a formatted string into this list.
1177 /// Asserts that there is enough capacity for the write.
1178 /// Never invalidates element pointers.
10621179 pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void {
10631180 comptime assert(T == u8);
10641181 var w: std.Io.Writer = .fixed(self.unusedCapacitySlice());
......@@ -1066,6 +1183,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
10661183 self.items.len += w.end;
10671184 }
10681185
1186 /// Prints a formatted string into this list.
1187 /// Returns error.OutOfMemory if additional capacity is needed for the write.
1188 /// Never invalidates element pointers.
10691189 pub fn printBounded(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
10701190 comptime assert(T == u8);
10711191 var w: std.Io.Writer = .fixed(self.unusedCapacitySlice());
......@@ -1141,6 +1261,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
11411261 /// Asserts that the new length is less than or equal to the previous length.
11421262 /// If succeds capacity is guaranteed to be equal to the length.
11431263 pub fn shrinkAndFreePrecise(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void {
1264 self.pointer_stability.assertUnlocked();
11441265 assert(new_len <= self.items.len);
11451266
11461267 if (@sizeOf(T) == 0) {
......@@ -1194,6 +1315,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
11941315 /// Keeps capacity the same.
11951316 /// Asserts that the new length is less than or equal to the previous length.
11961317 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
1318 self.pointer_stability.assertUnlocked();
1319
11971320 assert(new_len <= self.items.len);
11981321 @memset(self.items[new_len..], undefined);
11991322 self.items.len = new_len;
......@@ -1202,12 +1325,14 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
12021325 /// Reduce length to 0.
12031326 /// Invalidates all element pointers.
12041327 pub fn clearRetainingCapacity(self: *Self) void {
1328 self.pointer_stability.assertUnlocked();
12051329 @memset(self.items, undefined);
12061330 self.items.len = 0;
12071331 }
12081332
12091333 /// Invalidates all element pointers.
12101334 pub fn clearAndFree(self: *Self, gpa: Allocator) void {
1335 self.pointer_stability.assertUnlocked();
12111336 gpa.free(self.allocatedSlice());
12121337 self.items.len = 0;
12131338 self.capacity = 0;
......@@ -1225,6 +1350,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
12251350 /// modify the array so that it can hold exactly `new_capacity` items.
12261351 /// Invalidates element pointers if additional memory is needed.
12271352 pub fn ensureTotalCapacityPrecise(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {
1353 self.pointer_stability.assertUnlocked();
1354
12281355 if (@sizeOf(T) == 0) {
12291356 self.capacity = math.maxInt(usize);
12301357 return;
......@@ -1268,7 +1395,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
12681395 }
12691396
12701397 /// Increase length by 1, returning pointer to the new item.
1271 /// The returned element pointer becomes invalid when the list is resized.
1398 /// Invalidates element pointers if additional memory is needed.
1399 /// The returned pointer may be invalidated by further operations to this list.
12721400 pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!*T {
12731401 // This can never overflow because `self.items` can never occupy the whole address space
12741402 const newlen = self.items.len + 1;
......@@ -1277,11 +1405,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
12771405 }
12781406
12791407 /// Increase length by 1, returning pointer to the new item.
1280 ///
12811408 /// Never invalidates element pointers.
1282 ///
1283 /// The returned element pointer becomes invalid when the list is resized.
1284 ///
1409 /// The returned pointer may be invalidated by further operations to this list.
12851410 /// Asserts that the list can hold one additional item.
12861411 pub fn addOneAssumeCapacity(self: *Self) *T {
12871412 assert(self.items.len < self.capacity);
......@@ -1291,11 +1416,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
12911416 }
12921417
12931418 /// Increase length by 1, returning pointer to the new item.
1294 ///
12951419 /// Never invalidates element pointers.
1296 ///
1297 /// The returned element pointer becomes invalid when the list is resized.
1298 ///
1420 /// The returned pointer may be invalidated by further operations to this list.
12991421 /// If the list lacks unused capacity for the additional item, returns `error.OutOfMemory`.
13001422 pub fn addOneBounded(self: *Self) error{OutOfMemory}!*T {
13011423 if (self.capacity - self.items.len < 1) return error.OutOfMemory;
......@@ -1303,8 +1425,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13031425 }
13041426
13051427 /// Resize the array, adding `n` new elements, which have `undefined` values.
1428 /// Invalidates element pointers if additional memory is required.
13061429 /// The return value is an array pointing to the newly allocated elements.
1307 /// The returned pointer becomes invalid when the list is resized.
1430 /// The returned pointer may be invalidated by further operations to this list.
13081431 pub fn addManyAsArray(self: *Self, gpa: Allocator, comptime n: usize) Allocator.Error!*[n]T {
13091432 const prev_len = self.items.len;
13101433 try self.resize(gpa, try addOrOom(self.items.len, n));
......@@ -1312,13 +1435,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13121435 }
13131436
13141437 /// Resize the array, adding `n` new elements, which have `undefined` values.
1315 ///
13161438 /// The return value is an array pointing to the newly allocated elements.
1317 ///
13181439 /// Never invalidates element pointers.
1319 ///
1320 /// The returned pointer becomes invalid when the list is resized.
1321 ///
1440 /// The returned pointer may be invalidated by further operations to this list.
13221441 /// Asserts that the list can hold the additional items.
13231442 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
13241443 assert(self.items.len + n <= self.capacity);
......@@ -1328,13 +1447,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13281447 }
13291448
13301449 /// Resize the array, adding `n` new elements, which have `undefined` values.
1331 ///
13321450 /// The return value is an array pointing to the newly allocated elements.
1333 ///
13341451 /// Never invalidates element pointers.
1335 ///
1336 /// The returned pointer becomes invalid when the list is resized.
1337 ///
1452 /// The returned pointer may be invalidated by further operations to this list.
13381453 /// If the list lacks unused capacity for the additional items, returns
13391454 /// `error.OutOfMemory`.
13401455 pub fn addManyAsArrayBounded(self: *Self, comptime n: usize) error{OutOfMemory}!*[n]T {
......@@ -1344,7 +1459,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13441459
13451460 /// Resize the array, adding `n` new elements, which have `undefined` values.
13461461 /// The return value is a slice pointing to the newly allocated elements.
1347 /// The returned pointer becomes invalid when the list is resized.
1462 /// The returned pointer may be invalidated by further operations to this list.
13481463 /// Resizes list if `self.capacity` is not large enough.
13491464 pub fn addManyAsSlice(self: *Self, gpa: Allocator, n: usize) Allocator.Error![]T {
13501465 const prev_len = self.items.len;
......@@ -1354,10 +1469,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13541469
13551470 /// Resizes the array, adding `n` new elements, which have `undefined`
13561471 /// values, returning a slice pointing to the newly allocated elements.
1357 ///
1358 /// Never invalidates element pointers. The returned pointer becomes
1359 /// invalid when the list is resized.
1360 ///
1472 /// Never invalidates element pointers.
1473 /// The returned pointer may be invalidated by further operations to this list.
13611474 /// Asserts that the list can hold the additional items.
13621475 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
13631476 assert(self.items.len + n <= self.capacity);
......@@ -1368,10 +1481,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13681481
13691482 /// Resizes the array, adding `n` new elements, which have `undefined`
13701483 /// values, returning a slice pointing to the newly allocated elements.
1371 ///
1372 /// Never invalidates element pointers. The returned pointer becomes
1373 /// invalid when the list is resized.
1374 ///
1484 /// Never invalidates element pointers.
1485 /// The returned pointer may be invalidated by further operations to this list.
13751486 /// If the list lacks unused capacity for the additional items, returns
13761487 /// `error.OutOfMemory`.
13771488 pub fn addManyAsSliceBounded(self: *Self, n: usize) error{OutOfMemory}![]T {
......@@ -1384,6 +1495,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13841495 /// Invalidates pointers to last element.
13851496 pub fn pop(self: *Self) ?T {
13861497 if (self.items.len == 0) return null;
1498 self.pointer_stability.assertUnlocked();
1499
13871500 const val = self.items[self.items.len - 1];
13881501 self.items[self.items.len - 1] = undefined;
13891502 self.items.len -= 1;
......@@ -1392,6 +1505,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13921505
13931506 /// Returns a slice of all the items plus the extra capacity, whose memory
13941507 /// contents are `undefined`.
1508 /// The returned pointer may be invalidated by further operations to this list.
13951509 pub fn allocatedSlice(self: Self) Slice {
13961510 return self.items.ptr[0..self.capacity];
13971511 }
......@@ -1400,6 +1514,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
14001514 /// This can be useful for writing directly into an ArrayList.
14011515 /// Note that such an operation must be followed up with a direct
14021516 /// modification of `self.items.len`.
1517 /// The returned pointer may be invalidated by further operations to this list.
14031518 pub fn unusedCapacitySlice(self: Self) []T {
14041519 return self.allocatedSlice()[self.items.len..];
14051520 }
......@@ -1421,6 +1536,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
14211536
14221537 /// Returns a pointer to the last element from the list, or `null` if
14231538 /// the list is empty.
1539 /// The returned pointer may be invalidated by further operations to this list.
14241540 pub fn lastPtr(self: Self) ?*T {
14251541 if (self.items.len == 0) return null;
14261542 return &self.items[self.items.len - 1];
......@@ -2432,6 +2548,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value"
24322548 var list: ArrayList(u32) = .{
24332549 .items = undefined,
24342550 .capacity = math.maxInt(usize) - 1,
2551 .pointer_stability = .{},
24352552 };
24362553 list.items.len = math.maxInt(usize) - 1;
24372554
......@@ -2450,6 +2567,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value"
24502567 .items = undefined,
24512568 .capacity = math.maxInt(usize) - 1,
24522569 .allocator = a,
2570 .pointer_stability = .{},
24532571 };
24542572 list.items.len = math.maxInt(usize) - 1;
24552573