| ... | @@ -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 various | 27 | /// Pointers to elements in this slice are invalidated by various |
| 28 | /// functions of this ArrayList in accordance with the respective | 28 | /// functions of this ArrayList in accordance with the respective |
| 29 | /// documentation. In all cases, "invalidated" means that the memory | 29 | /// 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 allocating | 32 | /// 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, |
| 36 | | 36 | |
| | 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; |
| 38 | | 41 | |
| 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 | } |
| 51 | | 55 | |
| ... | @@ -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 |
| 60 | | 64 | |
| 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 | } |
| 67 | | 72 | |
| | 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 been | 90 | /// 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 | } |
| 78 | | 101 | |
| ... | @@ -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 | } |
| 89 | | 113 | |
| ... | @@ -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 | } |
| 98 | | 126 | |
| 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; |
| 103 | | 133 | |
| 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 | } |
| 115 | | 145 | |
| 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 space | 149 | // 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 | } |
| 131 | | 162 | |
| 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 | } |
| 141 | | 174 | |
| 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 is | 176 | /// 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; |
| 151 | | 186 | @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 | } |
| 155 | | 189 | |
| 156 | /// Add `count` new elements at position `index`, which have | 190 | /// 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(); |
| 166 | | 201 | |
| 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 allocated | 233 | /// `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 | } |
| 215 | | 250 | |
| 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 be | 254 | /// 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 | } |
| 230 | | 265 | |
| 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 | } |
| 239 | | 276 | |
| 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 |
| 275 | | 313 | |
| 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 | } |
| 330 | | 370 | |
| | 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 | } |
| 393 | | 437 | |
| 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 | } |
| 425 | | 470 | |
| 426 | if (self.capacity >= new_capacity) return; | 471 | if (self.capacity >= new_capacity) return; |
| 427 | | 472 | self.pointer_stability.assertUnlocked(); |
| 428 | // Here we avoid copying allocated but unused bytes by | 473 | // 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 |
| 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 our | 476 | // 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 | } |
| 458 | | 503 | |
| 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 space | 508 | // 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 | } |
| 467 | | 513 | |
| 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 |
| 477 | | 523 | |
| 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 |
| 499 | | 546 | |
| 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 | } |
| 521 | | 569 | |
| 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 |
| 531 | | 580 | |
| 532 | /// Returns a slice of all the items plus the extra capacity, whose memory | 581 | /// 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 direct | 591 | /// 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 |
| 554 | | 605 | |
| 555 | /// Returns the last element from the list, or `null` if the list is | 606 | /// 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 |
| 561 | | 613 | |
| 562 | /// Returns a pointer to the last element from the list, or `null` if | 614 | /// 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 various | 644 | /// Pointers to elements in this slice are invalidated by various |
| 592 | /// functions of this ArrayList in accordance with the respective | 645 | /// functions of this ArrayList in accordance with the respective |
| 593 | /// documentation. In all cases, "invalidated" means that the memory | 646 | /// 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 allocating | 649 | /// How many T values this list can hold without allocating |
| 597 | /// additional memory. | 650 | /// additional memory. |
| 598 | capacity: usize, | 651 | capacity: usize, |
| 599 | | 652 | |
| | 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 | }; |
| 605 | | 662 | |
| 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 | } |
| 631 | | 689 | |
| 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 | } |
| 637 | | 696 | |
| | 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 | } |
| 643 | | 724 | |
| 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 | } |
| 652 | | 734 | |
| ... | @@ -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 | } |
| 661 | | 744 | |
| 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 | } |
| 676 | | 761 | |
| 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 { |
| 697 | | 785 | |
| 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 | } |
| 713 | | 802 | |
| 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 | } |
| 723 | | 814 | |
| 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; |
| 736 | | 826 | @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 | } |
| 740 | | 829 | |
| 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, returns | 836 | /// 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 | } |
| 774 | | 889 | |
| 775 | /// Add `count` new elements at position `index`, which have | 890 | /// Add `count` new elements at position `index`, which have |
| 776 | /// `undefined` values. Returns a slice pointing to the newly allocated | 891 | /// `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`, but | 894 | /// 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 newly | 910 | /// `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, returns | 914 | /// 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 | } |
| 810 | | 921 | |
| 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 be | 925 | /// 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 | } |
| 830 | | 941 | |
| 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 | } |
| 844 | | 955 | |
| 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, returns | 959 | /// 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 | } |
| 859 | | 970 | |
| 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 | } |
| 873 | | 986 | |
| 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); |
| 886 | | 998 | 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 | } |
| 894 | | 1006 | |
| 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 | } |
| 997 | | 1109 | |
| 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 | } |
| 1008 | | 1120 | |
| 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 be | 1140 | /// 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 be | 1154 | /// 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, returns | 1157 | /// 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 | } |
| 1051 | | 1163 | |
| | 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 | } |
| 1061 | | 1175 | |
| | 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 | } |
| 1068 | | 1185 | |
| | 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); |
| 1145 | | 1266 | |
| 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 | } |
| 1208 | | 1332 | |
| 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 | } |
| 1269 | | 1396 | |
| 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 space | 1401 | // 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 | } |
| 1278 | | 1406 | |
| 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 | } |
| 1292 | | 1417 | |
| 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 | } |
| 1304 | | 1426 | |
| 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 | } |
| 1313 | | 1436 | |
| 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 | } |
| 1329 | | 1448 | |
| 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, returns | 1453 | /// 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 { |
| 1344 | | 1459 | |
| 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 { |
| 1354 | | 1469 | |
| 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 becomes | 1473 | /// 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 { |
| 1368 | | 1481 | |
| 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 becomes | 1485 | /// 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, returns | 1486 | /// 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 { |
| 1392 | | 1505 | |
| 1393 | /// Returns a slice of all the items plus the extra capacity, whose memory | 1506 | /// 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 direct | 1515 | /// 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 { |
| 1421 | | 1536 | |
| 1422 | /// Returns a pointer to the last element from the list, or `null` if | 1537 | /// 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; |
| 2437 | | 2554 | |
| ... | @@ -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; |
| 2455 | | 2573 | |