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,...@@ -1601,6 +1601,7 @@ pub fn addSourceFromOwnedBuffer(comp: *Compilation, path: []const u8, buf: []u8,
1601 var list: std.ArrayList(u8) = .{1601 var list: std.ArrayList(u8) = .{
1602 .items = contents[0..i],1602 .items = contents[0..i],
1603 .capacity = contents.len,1603 .capacity = contents.len,
1604 .pointer_stability = .{},
1604 };1605 };
1605 contents = try list.toOwnedSlice(comp.gpa);1606 contents = try list.toOwnedSlice(comp.gpa);
1606 }1607 }
lib/std/Io/Writer.zig+3
...@@ -2475,6 +2475,7 @@ pub fn unreachableRebase(w: *Writer, preserve: usize, capacity: usize) Error!voi...@@ -2475,6 +2475,7 @@ pub fn unreachableRebase(w: *Writer, preserve: usize, capacity: usize) Error!voi
24752475
2476pub fn fromArrayList(array_list: *ArrayList(u8)) Writer {2476pub fn fromArrayList(array_list: *ArrayList(u8)) Writer {
2477 defer array_list.* = .empty;2477 defer array_list.* = .empty;
2478 array_list.pointer_stability.assertUnlocked();
2478 return .{2479 return .{
2479 .vtable = &.{2480 .vtable = &.{
2480 .drain = fixedDrain,2481 .drain = fixedDrain,
...@@ -2490,6 +2491,7 @@ pub fn toArrayList(w: *Writer) ArrayList(u8) {...@@ -2490,6 +2491,7 @@ pub fn toArrayList(w: *Writer) ArrayList(u8) {
2490 const result: ArrayList(u8) = .{2491 const result: ArrayList(u8) = .{
2491 .items = w.buffer[0..w.end],2492 .items = w.buffer[0..w.end],
2492 .capacity = w.buffer.len,2493 .capacity = w.buffer.len,
2494 .pointer_stability = .{},
2493 };2495 };
2494 w.buffer = &.{};2496 w.buffer = &.{};
2495 w.end = 0;2497 w.end = 0;
...@@ -2739,6 +2741,7 @@ pub const Allocating = struct {...@@ -2739,6 +2741,7 @@ pub const Allocating = struct {
2739 const result: std.array_list.Aligned(u8, alignment) = .{2741 const result: std.array_list.Aligned(u8, alignment) = .{
2740 .items = @alignCast(w.buffer[0..w.end]),2742 .items = @alignCast(w.buffer[0..w.end]),
2741 .capacity = w.buffer.len,2743 .capacity = w.buffer.len,
2744 .pointer_stability = .{},
2742 };2745 };
2743 w.buffer = &.{};2746 w.buffer = &.{};
2744 w.end = 0;2747 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...@@ -26,14 +26,17 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
26 ///26 ///
27 /// Pointers to elements in this slice are invalidated by various27 /// Pointers to elements in this slice are invalidated by various
28 /// functions of this ArrayList in accordance with the respective28 /// functions of this ArrayList in accordance with the respective
29 /// documentation. In all cases, "invalidated" means that the memory29 /// documentation.
30 /// has been passed to this allocator's resize or free function.30 /// An invalidated pointer may point either to valid or freed memory.
31 items: Slice,31 items: Slice,
32 /// How many T values this list can hold without allocating32 /// How many T values this list can hold without allocating
33 /// additional memory.33 /// additional memory.
34 capacity: usize,34 capacity: usize,
35 allocator: Allocator,35 allocator: Allocator,
3636
37 /// Used to detect memory safety violations.
38 pointer_stability: debug.SafetyLock,
39
37 pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T;40 pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T;
3841
39 pub fn SentinelSlice(comptime s: T) type {42 pub fn SentinelSlice(comptime s: T) type {
...@@ -46,6 +49,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -46,6 +49,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
46 .items = &[_]T{},49 .items = &[_]T{},
47 .capacity = 0,50 .capacity = 0,
48 .allocator = gpa,51 .allocator = gpa,
52 .pointer_stability = .{},
49 };53 };
50 }54 }
5155
...@@ -60,11 +64,29 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -60,11 +64,29 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
6064
61 /// Release all allocated memory.65 /// Release all allocated memory.
62 pub fn deinit(self: Self) void {66 pub fn deinit(self: Self) void {
67 self.pointer_stability.assertUnlocked();
63 if (@sizeOf(T) > 0) {68 if (@sizeOf(T) > 0) {
64 self.allocator.free(self.allocatedSlice());69 self.allocator.free(self.allocatedSlice());
65 }70 }
66 }71 }
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
68 /// ArrayList takes ownership of the passed in slice. The slice must have been90 /// ArrayList takes ownership of the passed in slice. The slice must have been
69 /// allocated with `gpa`.91 /// allocated with `gpa`.
70 /// Deinitialize with `deinit` or use `toOwnedSlice`.92 /// Deinitialize with `deinit` or use `toOwnedSlice`.
...@@ -73,6 +95,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -73,6 +95,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
73 .items = slice,95 .items = slice,
74 .capacity = slice.len,96 .capacity = slice.len,
75 .allocator = gpa,97 .allocator = gpa,
98 .pointer_stability = .{},
76 };99 };
77 }100 }
78101
...@@ -84,6 +107,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -84,6 +107,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
84 .items = slice,107 .items = slice,
85 .capacity = slice.len + 1,108 .capacity = slice.len + 1,
86 .allocator = gpa,109 .allocator = gpa,
110 .pointer_stability = .{},
87 };111 };
88 }112 }
89113
...@@ -91,14 +115,20 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -91,14 +115,20 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
91 /// of this ArrayList. Empties this ArrayList.115 /// of this ArrayList. Empties this ArrayList.
92 pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment) {116 pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment) {
93 const allocator = self.allocator;117 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 };
95 self.* = init(allocator);123 self.* = init(allocator);
96 return result;124 return result;
97 }125 }
98126
99 /// The caller owns the returned memory. Empties this ArrayList.127 /// The caller owns the returned memory. Empties this ArrayList.
100 /// Its capacity is cleared, making `deinit` safe but unnecessary to call.128 /// Its capacity is cleared, making `deinit` safe but unnecessary to call.
129 /// May invalidate element pointers if remapping memory cannot be done in place.
101 pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice {130 pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice {
131 self.pointer_stability.assertUnlocked();
102 const allocator = self.allocator;132 const allocator = self.allocator;
103133
104 const old_memory = self.allocatedSlice();134 const old_memory = self.allocatedSlice();
...@@ -114,6 +144,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -114,6 +144,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
114 }144 }
115145
116 /// The caller owns the returned memory. Empties this ArrayList.146 /// The caller owns the returned memory. Empties this ArrayList.
147 /// May invalidate element pointers if remapping memory cannot be done in place.
117 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {148 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
118 // This addition can never overflow because `self.items` can never occupy the whole address space149 // This addition can never overflow because `self.items` can never occupy the whole address space
119 try self.ensureTotalCapacityPrecise(self.items.len + 1);150 try self.ensureTotalCapacityPrecise(self.items.len + 1);
...@@ -129,28 +160,31 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -129,28 +160,31 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
129 return cloned;160 return cloned;
130 }161 }
131162
132 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.163 /// Insert `item` at index `index`. Moves `list[index .. 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.164 /// If `index` is equal to the length of the list this operation is equivalent to append.
134 /// This operation is O(N).165 /// This operation is O(N).
135 /// Invalidates element pointers if additional memory is needed.166 /// Invalidates element pointers if additional memory is needed.
167 /// Invalidates pre-existing pointers to elements at and after `index`.
136 /// Asserts that the index is in bounds or equal to the length.168 /// 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 {169 pub fn insert(self: *Self, index: usize, item: T) Allocator.Error!void {
138 const dst = try self.addManyAt(i, 1);170 self.pointer_stability.assertUnlocked();
171 const dst = try self.addManyAt(index, 1);
139 dst[0] = item;172 dst[0] = item;
140 }173 }
141174
142 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.175 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
143 /// If `i` is equal to the length of the list this operation is176 /// If `index` is equal to the length of the list this operation is
144 /// equivalent to appendAssumeCapacity.177 /// equivalent to appendAssumeCapacity.
145 /// This operation is O(N).178 /// This operation is O(N).
179 /// Invalidates pre-existing pointers to elements at and after `index`.
146 /// Asserts that there is enough capacity for the new item.180 /// Asserts that there is enough capacity for the new item.
147 /// Asserts that the index is in bounds or equal to the length.181 /// 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();
149 assert(self.items.len < self.capacity);184 assert(self.items.len < self.capacity);
150 self.items.len += 1;185 self.items.len += 1;
151186 @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]);
152 @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);187 self.items[index] = item;
153 self.items[i] = item;
154 }188 }
155189
156 /// Add `count` new elements at position `index`, which have190 /// Add `count` new elements at position `index`, which have
...@@ -163,6 +197,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -163,6 +197,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
163 /// Asserts that the index is in bounds or equal to the length.197 /// Asserts that the index is in bounds or equal to the length.
164 pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {198 pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {
165 const new_len = try addOrOom(self.items.len, count);199 const new_len = try addOrOom(self.items.len, count);
200 self.pointer_stability.assertUnlocked();
166201
167 if (self.capacity >= new_len)202 if (self.capacity >= new_len)
168 return addManyAtAssumeCapacity(self, index, count);203 return addManyAtAssumeCapacity(self, index, count);
...@@ -198,11 +233,11 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -198,11 +233,11 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
198 /// `undefined` values. Returns a slice pointing to the newly allocated233 /// `undefined` values. Returns a slice pointing to the newly allocated
199 /// elements, which becomes invalid after various `ArrayList`234 /// elements, which becomes invalid after various `ArrayList`
200 /// operations.235 /// operations.
236 /// Invalidates pre-existing pointers to elements at and after `index`.
201 /// Asserts that there is enough capacity for the new elements.237 /// 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.
204 /// Asserts that the index is in bounds or equal to the length.238 /// Asserts that the index is in bounds or equal to the length.
205 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {239 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
240 self.pointer_stability.assertUnlocked();
206 const new_len = self.items.len + count;241 const new_len = self.items.len + count;
207 assert(self.capacity >= new_len);242 assert(self.capacity >= new_len);
208 const to_move = self.items[index..];243 const to_move = self.items[index..];
...@@ -213,7 +248,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -213,7 +248,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
213 return result;248 return result;
214 }249 }
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.
217 /// This operation is O(N).252 /// This operation is O(N).
218 /// Invalidates pre-existing pointers to elements at and after `index`.253 /// Invalidates pre-existing pointers to elements at and after `index`.
219 /// Invalidates all pre-existing element pointers if capacity must be254 /// 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...@@ -229,7 +264,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
229 }264 }
230265
231 /// Grows or shrinks the list as necessary.266 /// 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.
233 /// Asserts that the range is in bounds.270 /// Asserts that the range is in bounds.
234 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {271 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {
235 var unmanaged = self.moveToUnmanaged();272 var unmanaged = self.moveToUnmanaged();
...@@ -238,7 +275,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -238,7 +275,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
238 }275 }
239276
240 /// Grows or shrinks the list as necessary.277 /// 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.
242 /// Asserts the capacity is enough for additional items.280 /// Asserts the capacity is enough for additional items.
243 pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void {281 pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void {
244 var unmanaged = self.moveToUnmanaged();282 var unmanaged = self.moveToUnmanaged();
...@@ -275,10 +313,12 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -275,10 +313,12 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
275313
276 /// Removes the element at the specified index and returns it.314 /// Removes the element at the specified index and returns it.
277 /// The empty slot is filled from the end of the list.315 /// The empty slot is filled from the end of the list.
316 /// Invalidates pointers to the end of the list.
278 /// This operation is O(1).317 /// This operation is O(1).
279 /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.318 /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.
280 /// Asserts that the index is in bounds.319 /// Asserts that the index is in bounds.
281 pub fn swapRemove(self: *Self, i: usize) T {320 pub fn swapRemove(self: *Self, i: usize) T {
321 self.pointer_stability.assertUnlocked();
282 const val = self.items[i];322 const val = self.items[i];
283 self.items[i] = self.items[self.items.len - 1];323 self.items[i] = self.items[self.items.len - 1];
284 self.items[self.items.len - 1] = undefined;324 self.items[self.items.len - 1] = undefined;
...@@ -328,6 +368,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -328,6 +368,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
328 @memcpy(self.items[old_len..][0..items.len], items);368 @memcpy(self.items[old_len..][0..items.len], items);
329 }369 }
330370
371 /// Prints a formatted string into this list.
372 /// Invalidates element pointers if additional memory is needed.
331 pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {373 pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
332 const gpa = self.allocator;374 const gpa = self.allocator;
333 var unmanaged = self.moveToUnmanaged();375 var unmanaged = self.moveToUnmanaged();
...@@ -379,6 +421,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -379,6 +421,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
379 /// Invalidates element pointers for the elements `items[new_len..]`.421 /// Invalidates element pointers for the elements `items[new_len..]`.
380 /// Asserts that the new length is less than or equal to the previous length.422 /// Asserts that the new length is less than or equal to the previous length.
381 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {423 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
424 self.pointer_stability.assertUnlocked();
382 assert(new_len <= self.items.len);425 assert(new_len <= self.items.len);
383 @memset(self.items[new_len..], undefined);426 @memset(self.items[new_len..], undefined);
384 self.items.len = new_len;427 self.items.len = new_len;
...@@ -387,12 +430,14 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -387,12 +430,14 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
387 /// Reduce length to 0.430 /// Reduce length to 0.
388 /// Invalidates all element pointers.431 /// Invalidates all element pointers.
389 pub fn clearRetainingCapacity(self: *Self) void {432 pub fn clearRetainingCapacity(self: *Self) void {
433 self.pointer_stability.assertUnlocked();
390 @memset(self.items, undefined);434 @memset(self.items, undefined);
391 self.items.len = 0;435 self.items.len = 0;
392 }436 }
393437
394 /// Invalidates all element pointers.438 /// Invalidates all element pointers.
395 pub fn clearAndFree(self: *Self) void {439 pub fn clearAndFree(self: *Self) void {
440 self.pointer_stability.assertUnlocked();
396 self.allocator.free(self.allocatedSlice());441 self.allocator.free(self.allocatedSlice());
397 self.items.len = 0;442 self.items.len = 0;
398 self.capacity = 0;443 self.capacity = 0;
...@@ -424,9 +469,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -424,9 +469,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
424 }469 }
425470
426 if (self.capacity >= new_capacity) return;471 if (self.capacity >= new_capacity) return;
427472 self.pointer_stability.assertUnlocked();
428 // Here we avoid copying allocated but unused bytes by473 // Here we avoid copying allocated but unused bytes by
429 // attempting a resize in place, and falling back to allocating474 // attempting a remap, and falling back to allocating
430 // a new buffer and doing our own copy. With a realloc() call,475 // a new buffer and doing our own copy. With a realloc() call,
431 // the allocator implementation would pointlessly copy our476 // the allocator implementation would pointlessly copy our
432 // extra capacity.477 // extra capacity.
...@@ -457,7 +502,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -457,7 +502,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
457 }502 }
458503
459 /// Increase length by 1, returning pointer to the new item.504 /// 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.
461 pub fn addOne(self: *Self) Allocator.Error!*T {507 pub fn addOne(self: *Self) Allocator.Error!*T {
462 // This can never overflow because `self.items` can never occupy the whole address space508 // This can never overflow because `self.items` can never occupy the whole address space
463 const newlen = self.items.len + 1;509 const newlen = self.items.len + 1;
...@@ -466,7 +512,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -466,7 +512,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
466 }512 }
467513
468 /// Increase length by 1, returning pointer to the new item.514 /// 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.
470 /// Never invalidates element pointers.516 /// Never invalidates element pointers.
471 /// Asserts that the list can hold one additional item.517 /// Asserts that the list can hold one additional item.
472 pub fn addOneAssumeCapacity(self: *Self) *T {518 pub fn addOneAssumeCapacity(self: *Self) *T {
...@@ -477,8 +523,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -477,8 +523,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
477523
478 /// Resize the array, adding `n` new elements, which have `undefined` values.524 /// Resize the array, adding `n` new elements, which have `undefined` values.
479 /// The return value is an array pointing to the newly allocated elements.525 /// 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.
481 /// Resizes list if `self.capacity` is not large enough.527 /// Resizes list if `self.capacity` is not large enough.
528 /// Invalidates element pointers if additional memory is needed.
482 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {529 pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {
483 const prev_len = self.items.len;530 const prev_len = self.items.len;
484 try self.resize(try addOrOom(self.items.len, n));531 try self.resize(try addOrOom(self.items.len, n));
...@@ -488,7 +535,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -488,7 +535,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
488 /// Resize the array, adding `n` new elements, which have `undefined` values.535 /// Resize the array, adding `n` new elements, which have `undefined` values.
489 /// The return value is an array pointing to the newly allocated elements.536 /// The return value is an array pointing to the newly allocated elements.
490 /// Never invalidates element pointers.537 /// 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.
492 /// Asserts that the list can hold the additional items.539 /// Asserts that the list can hold the additional items.
493 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {540 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
494 assert(self.items.len + n <= self.capacity);541 assert(self.items.len + n <= self.capacity);
...@@ -499,8 +546,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -499,8 +546,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
499546
500 /// Resize the array, adding `n` new elements, which have `undefined` values.547 /// Resize the array, adding `n` new elements, which have `undefined` values.
501 /// The return value is a slice pointing to the newly allocated elements.548 /// 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.
503 /// Resizes list if `self.capacity` is not large enough.550 /// Resizes list if `self.capacity` is not large enough.
551 /// Invalidates element pointers if additional memory is needed.
504 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {552 pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {
505 const prev_len = self.items.len;553 const prev_len = self.items.len;
506 try self.resize(try addOrOom(self.items.len, n));554 try self.resize(try addOrOom(self.items.len, n));
...@@ -510,7 +558,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -510,7 +558,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
510 /// Resize the array, adding `n` new elements, which have `undefined` values.558 /// Resize the array, adding `n` new elements, which have `undefined` values.
511 /// The return value is a slice pointing to the newly allocated elements.559 /// The return value is a slice pointing to the newly allocated elements.
512 /// Never invalidates element pointers.560 /// 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.
514 /// Asserts that the list can hold the additional items.562 /// Asserts that the list can hold the additional items.
515 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {563 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
516 assert(self.items.len + n <= self.capacity);564 assert(self.items.len + n <= self.capacity);
...@@ -520,9 +568,10 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -520,9 +568,10 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
520 }568 }
521569
522 /// Remove and return the last element from the list, or return `null` if list is empty.570 /// 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.
524 pub fn pop(self: *Self) ?T {572 pub fn pop(self: *Self) ?T {
525 if (self.items.len == 0) return null;573 if (self.items.len == 0) return null;
574 self.pointer_stability.assertUnlocked();
526 const val = self.items[self.items.len - 1];575 const val = self.items[self.items.len - 1];
527 self.items[self.items.len - 1] = undefined;576 self.items[self.items.len - 1] = undefined;
528 self.items.len -= 1;577 self.items.len -= 1;
...@@ -531,6 +580,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -531,6 +580,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
531580
532 /// Returns a slice of all the items plus the extra capacity, whose memory581 /// Returns a slice of all the items plus the extra capacity, whose memory
533 /// contents are `undefined`.582 /// contents are `undefined`.
583 /// The returned pointer may be invalidated by further operations to this list.
534 pub fn allocatedSlice(self: Self) Slice {584 pub fn allocatedSlice(self: Self) Slice {
535 // `items.len` is the length, not the capacity.585 // `items.len` is the length, not the capacity.
536 return self.items.ptr[0..self.capacity];586 return self.items.ptr[0..self.capacity];
...@@ -540,6 +590,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -540,6 +590,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
540 /// This can be useful for writing directly into an ArrayList.590 /// This can be useful for writing directly into an ArrayList.
541 /// Note that such an operation must be followed up with a direct591 /// Note that such an operation must be followed up with a direct
542 /// modification of `self.items.len`.592 /// modification of `self.items.len`.
593 /// The returned pointer may be invalidated by further operations to this list.
543 pub fn unusedCapacitySlice(self: Self) []T {594 pub fn unusedCapacitySlice(self: Self) []T {
544 return self.allocatedSlice()[self.items.len..];595 return self.allocatedSlice()[self.items.len..];
545 }596 }
...@@ -554,6 +605,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -554,6 +605,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
554605
555 /// Returns the last element from the list, or `null` if the list is606 /// Returns the last element from the list, or `null` if the list is
556 /// empty.607 /// empty.
608 /// Never invalidates element pointers.
557 pub fn last(self: Self) ?T {609 pub fn last(self: Self) ?T {
558 if (self.items.len == 0) return null;610 if (self.items.len == 0) return null;
559 return self.items[self.items.len - 1];611 return self.items[self.items.len - 1];
...@@ -561,6 +613,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -561,6 +613,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
561613
562 /// Returns a pointer to the last element from the list, or `null` if614 /// Returns a pointer to the last element from the list, or `null` if
563 /// the list is empty.615 /// the list is empty.
616 /// The returned pointer may be invalidated by further operations to this list.
564 pub fn lastPtr(self: Self) ?*T {617 pub fn lastPtr(self: Self) ?*T {
565 if (self.items.len == 0) return null;618 if (self.items.len == 0) return null;
566 return &self.items[self.items.len - 1];619 return &self.items[self.items.len - 1];
...@@ -590,17 +643,21 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -590,17 +643,21 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
590 ///643 ///
591 /// Pointers to elements in this slice are invalidated by various644 /// Pointers to elements in this slice are invalidated by various
592 /// functions of this ArrayList in accordance with the respective645 /// functions of this ArrayList in accordance with the respective
593 /// documentation. In all cases, "invalidated" means that the memory646 /// documentation.
594 /// has been passed to an allocator's resize or free function.647 /// An invalidated pointer may point either to valid or freed memory.
595 items: Slice,648 items: Slice,
596 /// How many T values this list can hold without allocating649 /// How many T values this list can hold without allocating
597 /// additional memory.650 /// additional memory.
598 capacity: usize,651 capacity: usize,
599652
653 /// Used to detect memory safety violations.
654 pointer_stability: debug.SafetyLock,
655
600 /// An ArrayList containing no elements.656 /// An ArrayList containing no elements.
601 pub const empty: Self = .{657 pub const empty: Self = .{
602 .items = &.{},658 .items = &.{},
603 .capacity = 0,659 .capacity = 0,
660 .pointer_stability = .{},
604 };661 };
605662
606 pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T;663 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 {...@@ -626,19 +683,43 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
626 return .{683 return .{
627 .items = buffer[0..0],684 .items = buffer[0..0],
628 .capacity = buffer.len,685 .capacity = buffer.len,
686 .pointer_stability = .{},
629 };687 };
630 }688 }
631689
632 /// Release all allocated memory.690 /// Release all allocated memory.
633 pub fn deinit(self: *Self, gpa: Allocator) void {691 pub fn deinit(self: *Self, gpa: Allocator) void {
692 self.pointer_stability.assertUnlocked();
634 gpa.free(self.allocatedSlice());693 gpa.free(self.allocatedSlice());
635 self.* = undefined;694 self.* = undefined;
636 }695 }
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
638 /// Convert this list into an analogous memory-managed one.714 /// Convert this list into an analogous memory-managed one.
639 /// The returned list has ownership of the underlying memory.715 /// The returned list has ownership of the underlying memory.
640 pub fn toManaged(self: *Self, gpa: Allocator) AlignedManaged(T, alignment) {716 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 };
642 }723 }
643724
644 /// ArrayList takes ownership of the passed in slice.725 /// ArrayList takes ownership of the passed in slice.
...@@ -647,6 +728,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -647,6 +728,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
647 return Self{728 return Self{
648 .items = slice,729 .items = slice,
649 .capacity = slice.len,730 .capacity = slice.len,
731 .pointer_stability = .{},
650 };732 };
651 }733 }
652734
...@@ -656,13 +738,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -656,13 +738,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
656 return Self{738 return Self{
657 .items = slice,739 .items = slice,
658 .capacity = slice.len + 1,740 .capacity = slice.len + 1,
741 .pointer_stability = .{},
659 };742 };
660 }743 }
661744
662 /// The caller owns the returned memory. Empties this ArrayList.745 /// The caller owns the returned memory. Empties this ArrayList.
663 /// Its capacity is cleared, making deinit() safe but unnecessary to call.746 /// Its capacity is cleared, making deinit() safe but unnecessary to call.
747 /// May invalidate element pointers.
664 pub fn toOwnedSlice(self: *Self, gpa: Allocator) Allocator.Error!Slice {748 pub fn toOwnedSlice(self: *Self, gpa: Allocator) Allocator.Error!Slice {
665 const old_memory = self.allocatedSlice();749 const old_memory = self.allocatedSlice();
750 self.pointer_stability.assertUnlocked();
666 if (gpa.remap(old_memory, self.items.len)) |new_items| {751 if (gpa.remap(old_memory, self.items.len)) |new_items| {
667 self.* = .empty;752 self.* = .empty;
668 return new_items;753 return new_items;
...@@ -675,7 +760,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -675,7 +760,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
675 }760 }
676761
677 /// The caller owns the returned memory. ArrayList becomes empty.762 /// The caller owns the returned memory. ArrayList becomes empty.
763 /// May invalidate element pointers.
678 pub fn toOwnedSliceSentinel(self: *Self, gpa: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {764 pub fn toOwnedSliceSentinel(self: *Self, gpa: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
765 self.pointer_stability.assertUnlocked();
679 // This addition can never overflow because `self.items` can never occupy the whole address space.766 // This addition can never overflow because `self.items` can never occupy the whole address space.
680 try self.ensureTotalCapacityPrecise(gpa, self.items.len + 1);767 try self.ensureTotalCapacityPrecise(gpa, self.items.len + 1);
681 self.appendAssumeCapacity(sentinel);768 self.appendAssumeCapacity(sentinel);
...@@ -688,6 +775,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -688,6 +775,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
688 /// Its capacity is cleared, making deinit() safe but unnecessary to call.775 /// Its capacity is cleared, making deinit() safe but unnecessary to call.
689 ///776 ///
690 /// Asserts what the capacity is equal to the length.777 /// Asserts what the capacity is equal to the length.
778 /// Never invalidates element pointers.
691 pub fn toOwnedSliceAssert(self: *Self) Slice {779 pub fn toOwnedSliceAssert(self: *Self) Slice {
692 assert(self.items.len == self.capacity);780 assert(self.items.len == self.capacity);
693 const items = self.items;781 const items = self.items;
...@@ -697,6 +785,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -697,6 +785,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
697785
698 /// The caller owns the returned memory. ArrayList becomes empty.786 /// The caller owns the returned memory. ArrayList becomes empty.
699 /// Asserts what the capacity is equal to the length + 1.787 /// Asserts what the capacity is equal to the length + 1.
788 /// Never invalidates element pointers.
700 pub fn toOwnedSliceSentinelAssert(self: *Self, comptime sentinel: T) SentinelSlice(sentinel) {789 pub fn toOwnedSliceSentinelAssert(self: *Self, comptime sentinel: T) SentinelSlice(sentinel) {
701 std.debug.assert(self.items.len + 1 == self.capacity);790 std.debug.assert(self.items.len + 1 == self.capacity);
702 self.appendAssumeCapacity(sentinel);791 self.appendAssumeCapacity(sentinel);
...@@ -711,43 +800,41 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -711,43 +800,41 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
711 return cloned;800 return cloned;
712 }801 }
713802
714 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.803 /// Insert `item` at index `index`. Moves `list[index .. 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.804 /// If `index` is equal to the length of the list this operation is equivalent to append.
716 /// This operation is O(N).805 /// This operation is O(N).
717 /// Invalidates element pointers if additional memory is needed.806 /// Invalidates element pointers if additional memory is needed.
807 /// Invalidates pre-existing pointers to elements at and after `index`.
718 /// Asserts that the index is in bounds or equal to the length.808 /// 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 {809 pub fn insert(self: *Self, gpa: Allocator, index: usize, item: T) Allocator.Error!void {
720 const dst = try self.addManyAt(gpa, i, 1);810 self.pointer_stability.assertUnlocked();
811 const dst = try self.addManyAt(gpa, index, 1);
721 dst[0] = item;812 dst[0] = item;
722 }813 }
723814
724 /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room.815 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
725 ///816 /// If `index` is equal to the length of the list this operation is
726 /// If `i` is equal to the length of the list this operation is equivalent to append.817 /// equivalent to appendAssumeCapacity.
727 ///
728 /// This operation is O(N).818 /// This operation is O(N).
729 ///819 /// Invalidates pre-existing pointers to elements at and after `index`.
730 /// Asserts that the list has capacity for one additional item.820 /// Asserts that the list has capacity for one additional item.
731 ///
732 /// Asserts that the index is in bounds or equal to the length.821 /// 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();
734 assert(self.items.len < self.capacity);824 assert(self.items.len < self.capacity);
735 self.items.len += 1;825 self.items.len += 1;
736826 @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]);
737 @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]);827 self.items[index] = item;
738 self.items[i] = item;
739 }828 }
740829
741 /// Insert `item` at index `i`, moving `list[i .. list.len]` to higher indices to make room.830 /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
742 ///831 /// If `index` is equal to the length of the list this operation is
743 /// If `i` is equal to the length of the list this operation is equivalent to append.832 /// equivalent to appendAssumeCapacity.
744 ///
745 /// This operation is O(N).833 /// 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.
747 /// If the list lacks unused capacity for the additional item, returns836 /// If the list lacks unused capacity for the additional item, returns
748 /// `error.OutOfMemory`.837 /// `error.OutOfMemory`.
749 ///
750 /// Asserts that the index is in bounds or equal to the length.
751 pub fn insertBounded(self: *Self, i: usize, item: T) error{OutOfMemory}!void {838 pub fn insertBounded(self: *Self, i: usize, item: T) error{OutOfMemory}!void {
752 if (self.capacity - self.items.len == 0) return error.OutOfMemory;839 if (self.capacity - self.items.len == 0) return error.OutOfMemory;
753 return insertAssumeCapacity(self, i, item);840 return insertAssumeCapacity(self, i, item);
...@@ -767,20 +854,48 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -767,20 +854,48 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
767 index: usize,854 index: usize,
768 count: usize,855 count: usize,
769 ) Allocator.Error![]T {856 ) Allocator.Error![]T {
770 var managed = self.toManaged(gpa);857 const new_len = try addOrOom(self.items.len, count);
771 defer self.* = managed.moveToUnmanaged();858 self.pointer_stability.assertUnlocked();
772 return managed.addManyAt(index, count);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];
773 }888 }
774889
775 /// Add `count` new elements at position `index`, which have890 /// Add `count` new elements at position `index`, which have
776 /// `undefined` values. Returns a slice pointing to the newly allocated891 /// `undefined` values. Returns a slice pointing to the newly allocated
777 /// elements, which becomes invalid after various `ArrayList`892 /// elements, which becomes invalid after various `ArrayList`
778 /// operations.893 /// operations.
779 /// Invalidates pre-existing pointers to elements at and after `index`, but894 /// Invalidates pre-existing pointers to elements at and after `index`.
780 /// does not invalidate any before that.
781 /// Asserts that the list has capacity for the additional items.895 /// Asserts that the list has capacity for the additional items.
782 /// Asserts that the index is in bounds or equal to the length.896 /// Asserts that the index is in bounds or equal to the length.
783 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {897 pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
898 self.pointer_stability.assertUnlocked();
784 const new_len = self.items.len + count;899 const new_len = self.items.len + count;
785 assert(self.capacity >= new_len);900 assert(self.capacity >= new_len);
786 const to_move = self.items[index..];901 const to_move = self.items[index..];
...@@ -795,20 +910,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -795,20 +910,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
795 /// `undefined` values, returning a slice pointing to the newly910 /// `undefined` values, returning a slice pointing to the newly
796 /// allocated elements, which becomes invalid after various `ArrayList`911 /// allocated elements, which becomes invalid after various `ArrayList`
797 /// operations.912 /// operations.
798 ///913 /// Invalidates pre-existing pointers to elements at and after `index`.
799 /// Invalidates pre-existing pointers to elements at and after `index`, but
800 /// does not invalidate any before that.
801 ///
802 /// If the list lacks unused capacity for the additional items, returns914 /// If the list lacks unused capacity for the additional items, returns
803 /// `error.OutOfMemory`.915 /// `error.OutOfMemory`.
804 ///
805 /// Asserts that the index is in bounds or equal to the length.916 /// Asserts that the index is in bounds or equal to the length.
806 pub fn addManyAtBounded(self: *Self, index: usize, count: usize) error{OutOfMemory}![]T {917 pub fn addManyAtBounded(self: *Self, index: usize, count: usize) error{OutOfMemory}![]T {
807 if (self.capacity - self.items.len < count) return error.OutOfMemory;918 if (self.capacity - self.items.len < count) return error.OutOfMemory;
808 return addManyAtAssumeCapacity(self, index, count);919 return addManyAtAssumeCapacity(self, index, count);
809 }920 }
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.
812 /// This operation is O(N).923 /// This operation is O(N).
813 /// Invalidates pre-existing pointers to elements at and after `index`.924 /// Invalidates pre-existing pointers to elements at and after `index`.
814 /// Invalidates all pre-existing element pointers if capacity must be925 /// 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 {...@@ -828,7 +939,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
828 @memcpy(dst, items);939 @memcpy(dst, items);
829 }940 }
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.
832 /// This operation is O(N).943 /// This operation is O(N).
833 /// Invalidates pre-existing pointers to elements at and after `index`.944 /// Invalidates pre-existing pointers to elements at and after `index`.
834 /// Asserts that the list has capacity for the additional items.945 /// 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 {...@@ -842,7 +953,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
842 @memcpy(dst, items);953 @memcpy(dst, items);
843 }954 }
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.
846 /// This operation is O(N).957 /// This operation is O(N).
847 /// Invalidates pre-existing pointers to elements at and after `index`.958 /// Invalidates pre-existing pointers to elements at and after `index`.
848 /// If the list lacks unused capacity for the additional items, returns959 /// 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 {...@@ -858,7 +969,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
858 }969 }
859970
860 /// Grows or shrinks the list as necessary.971 /// 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.
862 /// Asserts that the range is in bounds.975 /// Asserts that the range is in bounds.
863 pub fn replaceRange(976 pub fn replaceRange(
864 self: *Self,977 self: *Self,
...@@ -872,9 +985,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -872,9 +985,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
872 }985 }
873986
874 /// Grows or shrinks the list as necessary.987 /// Grows or shrinks the list as necessary.
875 ///988 /// Invalidates pointers to elements at and above index `start + len`
876 /// Never invalidates element pointers.989 /// when `len` and `new_items.len` are unequal.
877 ///
878 /// Asserts the capacity is enough for additional items.990 /// Asserts the capacity is enough for additional items.
879 pub fn replaceRangeAssumeCapacity(991 pub fn replaceRangeAssumeCapacity(
880 self: *Self,992 self: *Self,
...@@ -883,7 +995,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -883,7 +995,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
883 new_items: []const T,995 new_items: []const T,
884 ) void {996 ) void {
885 std.debug.assert(self.capacity - self.items.len >= new_items.len -| len);997 std.debug.assert(self.capacity - self.items.len >= new_items.len -| len);
886998 self.pointer_stability.assertUnlocked();
887 const tail = self.items[start + len ..];999 const tail = self.items[start + len ..];
888 const vacated = self.items[self.items.len - (len -| new_items.len) ..];1000 const vacated = self.items[self.items.len - (len -| new_items.len) ..];
889 self.items.len = self.items.len - len + new_items.len;1001 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 {...@@ -892,10 +1004,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
892 @memset(vacated, undefined);1004 @memset(vacated, undefined);
893 }1005 }
8941006
895 /// Grows or shrinks the list as necessary.1007 /// Invalidates pointers to elements at and above index `start + len`
896 ///1008 /// when `len` and `new_items.len` are unequal.
897 /// Never invalidates element pointers.
898 ///
899 /// If the unused capacity is insufficient for additional items,1009 /// If the unused capacity is insufficient for additional items,
900 /// returns `error.OutOfMemory`.1010 /// returns `error.OutOfMemory`.
901 pub fn replaceRangeBounded(1011 pub fn replaceRangeBounded(
...@@ -958,6 +1068,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -958,6 +1068,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
958 ///1068 ///
959 /// Invalidates element pointers beyond the first deleted index.1069 /// Invalidates element pointers beyond the first deleted index.
960 pub fn orderedRemoveMany(self: *Self, sorted_indexes: []const usize) void {1070 pub fn orderedRemoveMany(self: *Self, sorted_indexes: []const usize) void {
1071 self.pointer_stability.assertUnlocked();
961 if (sorted_indexes.len == 0) return;1072 if (sorted_indexes.len == 0) return;
962 var shift: usize = 1;1073 var shift: usize = 1;
963 for (sorted_indexes[0 .. sorted_indexes.len - 1], sorted_indexes[1..]) |removed, end| {1074 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 {...@@ -980,6 +1091,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
980 /// This operation is O(1).1091 /// This operation is O(1).
981 /// Asserts that the index is in bounds.1092 /// Asserts that the index is in bounds.
982 pub fn swapRemove(self: *Self, i: usize) T {1093 pub fn swapRemove(self: *Self, i: usize) T {
1094 self.pointer_stability.assertUnlocked();
983 const val = self.items[i];1095 const val = self.items[i];
984 self.items[i] = self.items[self.items.len - 1];1096 self.items[i] = self.items[self.items.len - 1];
985 self.items[self.items.len - 1] = undefined;1097 self.items[self.items.len - 1] = undefined;
...@@ -996,7 +1108,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -996,7 +1108,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
996 }1108 }
9971109
998 /// Append the slice of items to the list.1110 /// Append the slice of items to the list.
999 ///1111 /// Never invalidates element pointers.
1000 /// Asserts that the list can hold the additional items.1112 /// Asserts that the list can hold the additional items.
1001 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {1113 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
1002 const old_len = self.items.len;1114 const old_len = self.items.len;
...@@ -1007,7 +1119,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1007,7 +1119,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1007 }1119 }
10081120
1009 /// Append the slice of items to the list.1121 /// Append the slice of items to the list.
1010 ///1122 /// Never invalidates element pointers.
1011 /// If the list lacks unused capacity for the additional items, returns `error.OutOfMemory`.1123 /// If the list lacks unused capacity for the additional items, returns `error.OutOfMemory`.
1012 pub fn appendSliceBounded(self: *Self, items: []const T) error{OutOfMemory}!void {1124 pub fn appendSliceBounded(self: *Self, items: []const T) error{OutOfMemory}!void {
1013 if (self.capacity - self.items.len < items.len) return error.OutOfMemory;1125 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 {...@@ -1027,7 +1139,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1027 ///1139 ///
1028 /// Intended to be used only when `appendSliceAssumeCapacity` would be1140 /// Intended to be used only when `appendSliceAssumeCapacity` would be
1029 /// a compile error.1141 /// a compile error.
1030 ///1142 /// Never invalidates element pointers.
1031 /// Asserts that the list can hold the additional items.1143 /// Asserts that the list can hold the additional items.
1032 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {1144 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
1033 const old_len = self.items.len;1145 const old_len = self.items.len;
...@@ -1041,7 +1153,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1041,7 +1153,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1041 ///1153 ///
1042 /// Intended to be used only when `appendSliceAssumeCapacity` would be1154 /// Intended to be used only when `appendSliceAssumeCapacity` would be
1043 /// a compile error.1155 /// a compile error.
1044 ///1156 /// Never invalidates element pointers.
1045 /// If the list lacks unused capacity for the additional items, returns1157 /// If the list lacks unused capacity for the additional items, returns
1046 /// `error.OutOfMemory`.1158 /// `error.OutOfMemory`.
1047 pub fn appendUnalignedSliceBounded(self: *Self, items: []align(1) const T) error{OutOfMemory}!void {1159 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 {...@@ -1049,6 +1161,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1049 return appendUnalignedSliceAssumeCapacity(self, items);1161 return appendUnalignedSliceAssumeCapacity(self, items);
1050 }1162 }
10511163
1164 /// Prints a formatted string into this list.
1165 /// Invalidates element pointers if additional memory is needed.
1052 pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {1166 pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
1053 comptime assert(T == u8);1167 comptime assert(T == u8);
1054 try self.ensureUnusedCapacity(gpa, fmt.len);1168 try self.ensureUnusedCapacity(gpa, fmt.len);
...@@ -1059,6 +1173,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1059,6 +1173,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1059 };1173 };
1060 }1174 }
10611175
1176 /// Prints a formatted string into this list.
1177 /// Asserts that there is enough capacity for the write.
1178 /// Never invalidates element pointers.
1062 pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void {1179 pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void {
1063 comptime assert(T == u8);1180 comptime assert(T == u8);
1064 var w: std.Io.Writer = .fixed(self.unusedCapacitySlice());1181 var w: std.Io.Writer = .fixed(self.unusedCapacitySlice());
...@@ -1066,6 +1183,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1066,6 +1183,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1066 self.items.len += w.end;1183 self.items.len += w.end;
1067 }1184 }
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.
1069 pub fn printBounded(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {1189 pub fn printBounded(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
1070 comptime assert(T == u8);1190 comptime assert(T == u8);
1071 var w: std.Io.Writer = .fixed(self.unusedCapacitySlice());1191 var w: std.Io.Writer = .fixed(self.unusedCapacitySlice());
...@@ -1141,6 +1261,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1141,6 +1261,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1141 /// Asserts that the new length is less than or equal to the previous length.1261 /// Asserts that the new length is less than or equal to the previous length.
1142 /// If succeds capacity is guaranteed to be equal to the length.1262 /// If succeds capacity is guaranteed to be equal to the length.
1143 pub fn shrinkAndFreePrecise(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void {1263 pub fn shrinkAndFreePrecise(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void {
1264 self.pointer_stability.assertUnlocked();
1144 assert(new_len <= self.items.len);1265 assert(new_len <= self.items.len);
11451266
1146 if (@sizeOf(T) == 0) {1267 if (@sizeOf(T) == 0) {
...@@ -1194,6 +1315,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1194,6 +1315,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1194 /// Keeps capacity the same.1315 /// Keeps capacity the same.
1195 /// Asserts that the new length is less than or equal to the previous length.1316 /// Asserts that the new length is less than or equal to the previous length.
1196 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {1317 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
1318 self.pointer_stability.assertUnlocked();
1319
1197 assert(new_len <= self.items.len);1320 assert(new_len <= self.items.len);
1198 @memset(self.items[new_len..], undefined);1321 @memset(self.items[new_len..], undefined);
1199 self.items.len = new_len;1322 self.items.len = new_len;
...@@ -1202,12 +1325,14 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1202,12 +1325,14 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1202 /// Reduce length to 0.1325 /// Reduce length to 0.
1203 /// Invalidates all element pointers.1326 /// Invalidates all element pointers.
1204 pub fn clearRetainingCapacity(self: *Self) void {1327 pub fn clearRetainingCapacity(self: *Self) void {
1328 self.pointer_stability.assertUnlocked();
1205 @memset(self.items, undefined);1329 @memset(self.items, undefined);
1206 self.items.len = 0;1330 self.items.len = 0;
1207 }1331 }
12081332
1209 /// Invalidates all element pointers.1333 /// Invalidates all element pointers.
1210 pub fn clearAndFree(self: *Self, gpa: Allocator) void {1334 pub fn clearAndFree(self: *Self, gpa: Allocator) void {
1335 self.pointer_stability.assertUnlocked();
1211 gpa.free(self.allocatedSlice());1336 gpa.free(self.allocatedSlice());
1212 self.items.len = 0;1337 self.items.len = 0;
1213 self.capacity = 0;1338 self.capacity = 0;
...@@ -1225,6 +1350,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1225,6 +1350,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1225 /// modify the array so that it can hold exactly `new_capacity` items.1350 /// modify the array so that it can hold exactly `new_capacity` items.
1226 /// Invalidates element pointers if additional memory is needed.1351 /// Invalidates element pointers if additional memory is needed.
1227 pub fn ensureTotalCapacityPrecise(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {1352 pub fn ensureTotalCapacityPrecise(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {
1353 self.pointer_stability.assertUnlocked();
1354
1228 if (@sizeOf(T) == 0) {1355 if (@sizeOf(T) == 0) {
1229 self.capacity = math.maxInt(usize);1356 self.capacity = math.maxInt(usize);
1230 return;1357 return;
...@@ -1268,7 +1395,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1268,7 +1395,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1268 }1395 }
12691396
1270 /// Increase length by 1, returning pointer to the new item.1397 /// 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.
1272 pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!*T {1400 pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!*T {
1273 // This can never overflow because `self.items` can never occupy the whole address space1401 // This can never overflow because `self.items` can never occupy the whole address space
1274 const newlen = self.items.len + 1;1402 const newlen = self.items.len + 1;
...@@ -1277,11 +1405,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1277,11 +1405,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1277 }1405 }
12781406
1279 /// Increase length by 1, returning pointer to the new item.1407 /// Increase length by 1, returning pointer to the new item.
1280 ///
1281 /// Never invalidates element pointers.1408 /// Never invalidates element pointers.
1282 ///1409 /// The returned pointer may be invalidated by further operations to this list.
1283 /// The returned element pointer becomes invalid when the list is resized.
1284 ///
1285 /// Asserts that the list can hold one additional item.1410 /// Asserts that the list can hold one additional item.
1286 pub fn addOneAssumeCapacity(self: *Self) *T {1411 pub fn addOneAssumeCapacity(self: *Self) *T {
1287 assert(self.items.len < self.capacity);1412 assert(self.items.len < self.capacity);
...@@ -1291,11 +1416,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1291,11 +1416,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1291 }1416 }
12921417
1293 /// Increase length by 1, returning pointer to the new item.1418 /// Increase length by 1, returning pointer to the new item.
1294 ///
1295 /// Never invalidates element pointers.1419 /// Never invalidates element pointers.
1296 ///1420 /// The returned pointer may be invalidated by further operations to this list.
1297 /// The returned element pointer becomes invalid when the list is resized.
1298 ///
1299 /// If the list lacks unused capacity for the additional item, returns `error.OutOfMemory`.1421 /// If the list lacks unused capacity for the additional item, returns `error.OutOfMemory`.
1300 pub fn addOneBounded(self: *Self) error{OutOfMemory}!*T {1422 pub fn addOneBounded(self: *Self) error{OutOfMemory}!*T {
1301 if (self.capacity - self.items.len < 1) return error.OutOfMemory;1423 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 {...@@ -1303,8 +1425,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1303 }1425 }
13041426
1305 /// Resize the array, adding `n` new elements, which have `undefined` values.1427 /// Resize the array, adding `n` new elements, which have `undefined` values.
1428 /// Invalidates element pointers if additional memory is required.
1306 /// The return value is an array pointing to the newly allocated elements.1429 /// 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.
1308 pub fn addManyAsArray(self: *Self, gpa: Allocator, comptime n: usize) Allocator.Error!*[n]T {1431 pub fn addManyAsArray(self: *Self, gpa: Allocator, comptime n: usize) Allocator.Error!*[n]T {
1309 const prev_len = self.items.len;1432 const prev_len = self.items.len;
1310 try self.resize(gpa, try addOrOom(self.items.len, n));1433 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 {...@@ -1312,13 +1435,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1312 }1435 }
13131436
1314 /// Resize the array, adding `n` new elements, which have `undefined` values.1437 /// Resize the array, adding `n` new elements, which have `undefined` values.
1315 ///
1316 /// The return value is an array pointing to the newly allocated elements.1438 /// The return value is an array pointing to the newly allocated elements.
1317 ///
1318 /// Never invalidates element pointers.1439 /// Never invalidates element pointers.
1319 ///1440 /// The returned pointer may be invalidated by further operations to this list.
1320 /// The returned pointer becomes invalid when the list is resized.
1321 ///
1322 /// Asserts that the list can hold the additional items.1441 /// Asserts that the list can hold the additional items.
1323 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {1442 pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
1324 assert(self.items.len + n <= self.capacity);1443 assert(self.items.len + n <= self.capacity);
...@@ -1328,13 +1447,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1328,13 +1447,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1328 }1447 }
13291448
1330 /// Resize the array, adding `n` new elements, which have `undefined` values.1449 /// Resize the array, adding `n` new elements, which have `undefined` values.
1331 ///
1332 /// The return value is an array pointing to the newly allocated elements.1450 /// The return value is an array pointing to the newly allocated elements.
1333 ///
1334 /// Never invalidates element pointers.1451 /// Never invalidates element pointers.
1335 ///1452 /// The returned pointer may be invalidated by further operations to this list.
1336 /// The returned pointer becomes invalid when the list is resized.
1337 ///
1338 /// If the list lacks unused capacity for the additional items, returns1453 /// If the list lacks unused capacity for the additional items, returns
1339 /// `error.OutOfMemory`.1454 /// `error.OutOfMemory`.
1340 pub fn addManyAsArrayBounded(self: *Self, comptime n: usize) error{OutOfMemory}!*[n]T {1455 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 {...@@ -1344,7 +1459,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13441459
1345 /// Resize the array, adding `n` new elements, which have `undefined` values.1460 /// Resize the array, adding `n` new elements, which have `undefined` values.
1346 /// The return value is a slice pointing to the newly allocated elements.1461 /// 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.
1348 /// Resizes list if `self.capacity` is not large enough.1463 /// Resizes list if `self.capacity` is not large enough.
1349 pub fn addManyAsSlice(self: *Self, gpa: Allocator, n: usize) Allocator.Error![]T {1464 pub fn addManyAsSlice(self: *Self, gpa: Allocator, n: usize) Allocator.Error![]T {
1350 const prev_len = self.items.len;1465 const prev_len = self.items.len;
...@@ -1354,10 +1469,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1354,10 +1469,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13541469
1355 /// Resizes the array, adding `n` new elements, which have `undefined`1470 /// Resizes the array, adding `n` new elements, which have `undefined`
1356 /// values, returning a slice pointing to the newly allocated elements.1471 /// values, returning a slice pointing to the newly allocated elements.
1357 ///1472 /// Never invalidates element pointers.
1358 /// Never invalidates element pointers. The returned pointer becomes1473 /// The returned pointer may be invalidated by further operations to this list.
1359 /// invalid when the list is resized.
1360 ///
1361 /// Asserts that the list can hold the additional items.1474 /// Asserts that the list can hold the additional items.
1362 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {1475 pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
1363 assert(self.items.len + n <= self.capacity);1476 assert(self.items.len + n <= self.capacity);
...@@ -1368,10 +1481,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1368,10 +1481,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13681481
1369 /// Resizes the array, adding `n` new elements, which have `undefined`1482 /// Resizes the array, adding `n` new elements, which have `undefined`
1370 /// values, returning a slice pointing to the newly allocated elements.1483 /// values, returning a slice pointing to the newly allocated elements.
1371 ///1484 /// Never invalidates element pointers.
1372 /// Never invalidates element pointers. The returned pointer becomes1485 /// The returned pointer may be invalidated by further operations to this list.
1373 /// invalid when the list is resized.
1374 ///
1375 /// If the list lacks unused capacity for the additional items, returns1486 /// If the list lacks unused capacity for the additional items, returns
1376 /// `error.OutOfMemory`.1487 /// `error.OutOfMemory`.
1377 pub fn addManyAsSliceBounded(self: *Self, n: usize) error{OutOfMemory}![]T {1488 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 {...@@ -1384,6 +1495,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1384 /// Invalidates pointers to last element.1495 /// Invalidates pointers to last element.
1385 pub fn pop(self: *Self) ?T {1496 pub fn pop(self: *Self) ?T {
1386 if (self.items.len == 0) return null;1497 if (self.items.len == 0) return null;
1498 self.pointer_stability.assertUnlocked();
1499
1387 const val = self.items[self.items.len - 1];1500 const val = self.items[self.items.len - 1];
1388 self.items[self.items.len - 1] = undefined;1501 self.items[self.items.len - 1] = undefined;
1389 self.items.len -= 1;1502 self.items.len -= 1;
...@@ -1392,6 +1505,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1392,6 +1505,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13921505
1393 /// Returns a slice of all the items plus the extra capacity, whose memory1506 /// Returns a slice of all the items plus the extra capacity, whose memory
1394 /// contents are `undefined`.1507 /// contents are `undefined`.
1508 /// The returned pointer may be invalidated by further operations to this list.
1395 pub fn allocatedSlice(self: Self) Slice {1509 pub fn allocatedSlice(self: Self) Slice {
1396 return self.items.ptr[0..self.capacity];1510 return self.items.ptr[0..self.capacity];
1397 }1511 }
...@@ -1400,6 +1514,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1400,6 +1514,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1400 /// This can be useful for writing directly into an ArrayList.1514 /// This can be useful for writing directly into an ArrayList.
1401 /// Note that such an operation must be followed up with a direct1515 /// Note that such an operation must be followed up with a direct
1402 /// modification of `self.items.len`.1516 /// modification of `self.items.len`.
1517 /// The returned pointer may be invalidated by further operations to this list.
1403 pub fn unusedCapacitySlice(self: Self) []T {1518 pub fn unusedCapacitySlice(self: Self) []T {
1404 return self.allocatedSlice()[self.items.len..];1519 return self.allocatedSlice()[self.items.len..];
1405 }1520 }
...@@ -1421,6 +1536,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1421,6 +1536,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
14211536
1422 /// Returns a pointer to the last element from the list, or `null` if1537 /// Returns a pointer to the last element from the list, or `null` if
1423 /// the list is empty.1538 /// the list is empty.
1539 /// The returned pointer may be invalidated by further operations to this list.
1424 pub fn lastPtr(self: Self) ?*T {1540 pub fn lastPtr(self: Self) ?*T {
1425 if (self.items.len == 0) return null;1541 if (self.items.len == 0) return null;
1426 return &self.items[self.items.len - 1];1542 return &self.items[self.items.len - 1];
...@@ -2432,6 +2548,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value"...@@ -2432,6 +2548,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value"
2432 var list: ArrayList(u32) = .{2548 var list: ArrayList(u32) = .{
2433 .items = undefined,2549 .items = undefined,
2434 .capacity = math.maxInt(usize) - 1,2550 .capacity = math.maxInt(usize) - 1,
2551 .pointer_stability = .{},
2435 };2552 };
2436 list.items.len = math.maxInt(usize) - 1;2553 list.items.len = math.maxInt(usize) - 1;
24372554
...@@ -2450,6 +2567,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value"...@@ -2450,6 +2567,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value"
2450 .items = undefined,2567 .items = undefined,
2451 .capacity = math.maxInt(usize) - 1,2568 .capacity = math.maxInt(usize) - 1,
2452 .allocator = a,2569 .allocator = a,
2570 .pointer_stability = .{},
2453 };2571 };
2454 list.items.len = math.maxInt(usize) - 1;2572 list.items.len = math.maxInt(usize) - 1;
24552573