| ... | ... | @@ -26,14 +26,17 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 26 | 26 | /// |
| 27 | 27 | /// Pointers to elements in this slice are invalidated by various |
| 28 | 28 | /// functions of this ArrayList in accordance with the respective |
| 29 | | /// documentation. In all cases, "invalidated" means that the memory |
| 30 | | /// has been passed to this allocator's resize or free function. |
| 29 | /// documentation. |
| 30 | /// An invalidated pointer may point either to valid or freed memory. |
| 31 | 31 | items: Slice, |
| 32 | 32 | /// How many T values this list can hold without allocating |
| 33 | 33 | /// additional memory. |
| 34 | 34 | capacity: usize, |
| 35 | 35 | allocator: Allocator, |
| 36 | 36 | |
| 37 | /// Used to detect memory safety violations. |
| 38 | pointer_stability: debug.SafetyLock, |
| 39 | |
| 37 | 40 | pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T; |
| 38 | 41 | |
| 39 | 42 | pub fn SentinelSlice(comptime s: T) type { |
| ... | ... | @@ -46,6 +49,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 46 | 49 | .items = &[_]T{}, |
| 47 | 50 | .capacity = 0, |
| 48 | 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 | 64 | |
| 61 | 65 | /// Release all allocated memory. |
| 62 | 66 | pub fn deinit(self: Self) void { |
| 67 | self.pointer_stability.assertUnlocked(); |
| 63 | 68 | if (@sizeOf(T) > 0) { |
| 64 | 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 | 90 | /// ArrayList takes ownership of the passed in slice. The slice must have been |
| 69 | 91 | /// allocated with `gpa`. |
| 70 | 92 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| ... | ... | @@ -73,6 +95,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 73 | 95 | .items = slice, |
| 74 | 96 | .capacity = slice.len, |
| 75 | 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 | 107 | .items = slice, |
| 85 | 108 | .capacity = slice.len + 1, |
| 86 | 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 | 115 | /// of this ArrayList. Empties this ArrayList. |
| 92 | 116 | pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment) { |
| 93 | 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 | 123 | self.* = init(allocator); |
| 96 | 124 | return result; |
| 97 | 125 | } |
| 98 | 126 | |
| 99 | 127 | /// The caller owns the returned memory. Empties this ArrayList. |
| 100 | 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 | 130 | pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice { |
| 131 | self.pointer_stability.assertUnlocked(); |
| 102 | 132 | const allocator = self.allocator; |
| 103 | 133 | |
| 104 | 134 | const old_memory = self.allocatedSlice(); |
| ... | ... | @@ -114,6 +144,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 114 | 144 | } |
| 115 | 145 | |
| 116 | 146 | /// The caller owns the returned memory. Empties this ArrayList. |
| 147 | /// May invalidate element pointers if remapping memory cannot be done in place. |
| 117 | 148 | pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { |
| 118 | 149 | // This addition can never overflow because `self.items` can never occupy the whole address space |
| 119 | 150 | try self.ensureTotalCapacityPrecise(self.items.len + 1); |
| ... | ... | @@ -129,28 +160,31 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 129 | 160 | return cloned; |
| 130 | 161 | } |
| 131 | 162 | |
| 132 | | /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. |
| 133 | | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 163 | /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. |
| 164 | /// If `index` is equal to the length of the list this operation is equivalent to append. |
| 134 | 165 | /// This operation is O(N). |
| 135 | 166 | /// Invalidates element pointers if additional memory is needed. |
| 167 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 136 | 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 { |
| 138 | | const dst = try self.addManyAt(i, 1); |
| 169 | pub fn insert(self: *Self, index: usize, item: T) Allocator.Error!void { |
| 170 | self.pointer_stability.assertUnlocked(); |
| 171 | const dst = try self.addManyAt(index, 1); |
| 139 | 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. |
| 143 | | /// If `i` is equal to the length of the list this operation is |
| 175 | /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. |
| 176 | /// If `index` is equal to the length of the list this operation is |
| 144 | 177 | /// equivalent to appendAssumeCapacity. |
| 145 | 178 | /// This operation is O(N). |
| 179 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 146 | 180 | /// Asserts that there is enough capacity for the new item. |
| 147 | 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 | 184 | assert(self.items.len < self.capacity); |
| 150 | 185 | self.items.len += 1; |
| 151 | | |
| 152 | | @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); |
| 153 | | self.items[i] = item; |
| 186 | @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]); |
| 187 | self.items[index] = item; |
| 154 | 188 | } |
| 155 | 189 | |
| 156 | 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 | 197 | /// Asserts that the index is in bounds or equal to the length. |
| 164 | 198 | pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T { |
| 165 | 199 | const new_len = try addOrOom(self.items.len, count); |
| 200 | self.pointer_stability.assertUnlocked(); |
| 166 | 201 | |
| 167 | 202 | if (self.capacity >= new_len) |
| 168 | 203 | return addManyAtAssumeCapacity(self, index, count); |
| ... | ... | @@ -198,11 +233,11 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 198 | 233 | /// `undefined` values. Returns a slice pointing to the newly allocated |
| 199 | 234 | /// elements, which becomes invalid after various `ArrayList` |
| 200 | 235 | /// operations. |
| 236 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 201 | 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 | 238 | /// Asserts that the index is in bounds or equal to the length. |
| 205 | 239 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 240 | self.pointer_stability.assertUnlocked(); |
| 206 | 241 | const new_len = self.items.len + count; |
| 207 | 242 | assert(self.capacity >= new_len); |
| 208 | 243 | const to_move = self.items[index..]; |
| ... | ... | @@ -213,7 +248,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 213 | 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 | 252 | /// This operation is O(N). |
| 218 | 253 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 219 | 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 | 264 | } |
| 230 | 265 | |
| 231 | 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 | 270 | /// Asserts that the range is in bounds. |
| 234 | 271 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { |
| 235 | 272 | var unmanaged = self.moveToUnmanaged(); |
| ... | ... | @@ -238,7 +275,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 238 | 275 | } |
| 239 | 276 | |
| 240 | 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 | 280 | /// Asserts the capacity is enough for additional items. |
| 243 | 281 | pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void { |
| 244 | 282 | var unmanaged = self.moveToUnmanaged(); |
| ... | ... | @@ -275,10 +313,12 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 275 | 313 | |
| 276 | 314 | /// Removes the element at the specified index and returns it. |
| 277 | 315 | /// The empty slot is filled from the end of the list. |
| 316 | /// Invalidates pointers to the end of the list. |
| 278 | 317 | /// This operation is O(1). |
| 279 | 318 | /// This may not preserve item order. Use `orderedRemove` if you need to preserve order. |
| 280 | 319 | /// Asserts that the index is in bounds. |
| 281 | 320 | pub fn swapRemove(self: *Self, i: usize) T { |
| 321 | self.pointer_stability.assertUnlocked(); |
| 282 | 322 | const val = self.items[i]; |
| 283 | 323 | self.items[i] = self.items[self.items.len - 1]; |
| 284 | 324 | self.items[self.items.len - 1] = undefined; |
| ... | ... | @@ -328,6 +368,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 328 | 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 | 373 | pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { |
| 332 | 374 | const gpa = self.allocator; |
| 333 | 375 | var unmanaged = self.moveToUnmanaged(); |
| ... | ... | @@ -379,6 +421,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 379 | 421 | /// Invalidates element pointers for the elements `items[new_len..]`. |
| 380 | 422 | /// Asserts that the new length is less than or equal to the previous length. |
| 381 | 423 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 424 | self.pointer_stability.assertUnlocked(); |
| 382 | 425 | assert(new_len <= self.items.len); |
| 383 | 426 | @memset(self.items[new_len..], undefined); |
| 384 | 427 | self.items.len = new_len; |
| ... | ... | @@ -387,12 +430,14 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 387 | 430 | /// Reduce length to 0. |
| 388 | 431 | /// Invalidates all element pointers. |
| 389 | 432 | pub fn clearRetainingCapacity(self: *Self) void { |
| 433 | self.pointer_stability.assertUnlocked(); |
| 390 | 434 | @memset(self.items, undefined); |
| 391 | 435 | self.items.len = 0; |
| 392 | 436 | } |
| 393 | 437 | |
| 394 | 438 | /// Invalidates all element pointers. |
| 395 | 439 | pub fn clearAndFree(self: *Self) void { |
| 440 | self.pointer_stability.assertUnlocked(); |
| 396 | 441 | self.allocator.free(self.allocatedSlice()); |
| 397 | 442 | self.items.len = 0; |
| 398 | 443 | self.capacity = 0; |
| ... | ... | @@ -424,9 +469,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 424 | 469 | } |
| 425 | 470 | |
| 426 | 471 | if (self.capacity >= new_capacity) return; |
| 427 | | |
| 472 | self.pointer_stability.assertUnlocked(); |
| 428 | 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 | 475 | // a new buffer and doing our own copy. With a realloc() call, |
| 431 | 476 | // the allocator implementation would pointlessly copy our |
| 432 | 477 | // extra capacity. |
| ... | ... | @@ -457,7 +502,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 457 | 502 | } |
| 458 | 503 | |
| 459 | 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 | 507 | pub fn addOne(self: *Self) Allocator.Error!*T { |
| 462 | 508 | // This can never overflow because `self.items` can never occupy the whole address space |
| 463 | 509 | const newlen = self.items.len + 1; |
| ... | ... | @@ -466,7 +512,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 466 | 512 | } |
| 467 | 513 | |
| 468 | 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 | 516 | /// Never invalidates element pointers. |
| 471 | 517 | /// Asserts that the list can hold one additional item. |
| 472 | 518 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| ... | ... | @@ -477,8 +523,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 477 | 523 | |
| 478 | 524 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 479 | 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 | 527 | /// Resizes list if `self.capacity` is not large enough. |
| 528 | /// Invalidates element pointers if additional memory is needed. |
| 482 | 529 | pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T { |
| 483 | 530 | const prev_len = self.items.len; |
| 484 | 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 | 535 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 489 | 536 | /// The return value is an array pointing to the newly allocated elements. |
| 490 | 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 | 539 | /// Asserts that the list can hold the additional items. |
| 493 | 540 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 494 | 541 | assert(self.items.len + n <= self.capacity); |
| ... | ... | @@ -499,8 +546,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 499 | 546 | |
| 500 | 547 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 501 | 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 | 550 | /// Resizes list if `self.capacity` is not large enough. |
| 551 | /// Invalidates element pointers if additional memory is needed. |
| 504 | 552 | pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T { |
| 505 | 553 | const prev_len = self.items.len; |
| 506 | 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 | 558 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 511 | 559 | /// The return value is a slice pointing to the newly allocated elements. |
| 512 | 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 | 562 | /// Asserts that the list can hold the additional items. |
| 515 | 563 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { |
| 516 | 564 | assert(self.items.len + n <= self.capacity); |
| ... | ... | @@ -520,9 +568,10 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 520 | 568 | } |
| 521 | 569 | |
| 522 | 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 | 572 | pub fn pop(self: *Self) ?T { |
| 525 | 573 | if (self.items.len == 0) return null; |
| 574 | self.pointer_stability.assertUnlocked(); |
| 526 | 575 | const val = self.items[self.items.len - 1]; |
| 527 | 576 | self.items[self.items.len - 1] = undefined; |
| 528 | 577 | self.items.len -= 1; |
| ... | ... | @@ -531,6 +580,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 531 | 580 | |
| 532 | 581 | /// Returns a slice of all the items plus the extra capacity, whose memory |
| 533 | 582 | /// contents are `undefined`. |
| 583 | /// The returned pointer may be invalidated by further operations to this list. |
| 534 | 584 | pub fn allocatedSlice(self: Self) Slice { |
| 535 | 585 | // `items.len` is the length, not the capacity. |
| 536 | 586 | return self.items.ptr[0..self.capacity]; |
| ... | ... | @@ -540,6 +590,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 540 | 590 | /// This can be useful for writing directly into an ArrayList. |
| 541 | 591 | /// Note that such an operation must be followed up with a direct |
| 542 | 592 | /// modification of `self.items.len`. |
| 593 | /// The returned pointer may be invalidated by further operations to this list. |
| 543 | 594 | pub fn unusedCapacitySlice(self: Self) []T { |
| 544 | 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 | 605 | |
| 555 | 606 | /// Returns the last element from the list, or `null` if the list is |
| 556 | 607 | /// empty. |
| 608 | /// Never invalidates element pointers. |
| 557 | 609 | pub fn last(self: Self) ?T { |
| 558 | 610 | if (self.items.len == 0) return null; |
| 559 | 611 | return self.items[self.items.len - 1]; |
| ... | ... | @@ -561,6 +613,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 561 | 613 | |
| 562 | 614 | /// Returns a pointer to the last element from the list, or `null` if |
| 563 | 615 | /// the list is empty. |
| 616 | /// The returned pointer may be invalidated by further operations to this list. |
| 564 | 617 | pub fn lastPtr(self: Self) ?*T { |
| 565 | 618 | if (self.items.len == 0) return null; |
| 566 | 619 | return &self.items[self.items.len - 1]; |
| ... | ... | @@ -590,17 +643,21 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 590 | 643 | /// |
| 591 | 644 | /// Pointers to elements in this slice are invalidated by various |
| 592 | 645 | /// functions of this ArrayList in accordance with the respective |
| 593 | | /// documentation. In all cases, "invalidated" means that the memory |
| 594 | | /// has been passed to an allocator's resize or free function. |
| 646 | /// documentation. |
| 647 | /// An invalidated pointer may point either to valid or freed memory. |
| 595 | 648 | items: Slice, |
| 596 | 649 | /// How many T values this list can hold without allocating |
| 597 | 650 | /// additional memory. |
| 598 | 651 | capacity: usize, |
| 599 | 652 | |
| 653 | /// Used to detect memory safety violations. |
| 654 | pointer_stability: debug.SafetyLock, |
| 655 | |
| 600 | 656 | /// An ArrayList containing no elements. |
| 601 | 657 | pub const empty: Self = .{ |
| 602 | 658 | .items = &.{}, |
| 603 | 659 | .capacity = 0, |
| 660 | .pointer_stability = .{}, |
| 604 | 661 | }; |
| 605 | 662 | |
| 606 | 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 | 683 | return .{ |
| 627 | 684 | .items = buffer[0..0], |
| 628 | 685 | .capacity = buffer.len, |
| 686 | .pointer_stability = .{}, |
| 629 | 687 | }; |
| 630 | 688 | } |
| 631 | 689 | |
| 632 | 690 | /// Release all allocated memory. |
| 633 | 691 | pub fn deinit(self: *Self, gpa: Allocator) void { |
| 692 | self.pointer_stability.assertUnlocked(); |
| 634 | 693 | gpa.free(self.allocatedSlice()); |
| 635 | 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 | 714 | /// Convert this list into an analogous memory-managed one. |
| 639 | 715 | /// The returned list has ownership of the underlying memory. |
| 640 | 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 | 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 | 728 | return Self{ |
| 648 | 729 | .items = slice, |
| 649 | 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 | 738 | return Self{ |
| 657 | 739 | .items = slice, |
| 658 | 740 | .capacity = slice.len + 1, |
| 741 | .pointer_stability = .{}, |
| 659 | 742 | }; |
| 660 | 743 | } |
| 661 | 744 | |
| 662 | 745 | /// The caller owns the returned memory. Empties this ArrayList. |
| 663 | 746 | /// Its capacity is cleared, making deinit() safe but unnecessary to call. |
| 747 | /// May invalidate element pointers. |
| 664 | 748 | pub fn toOwnedSlice(self: *Self, gpa: Allocator) Allocator.Error!Slice { |
| 665 | 749 | const old_memory = self.allocatedSlice(); |
| 750 | self.pointer_stability.assertUnlocked(); |
| 666 | 751 | if (gpa.remap(old_memory, self.items.len)) |new_items| { |
| 667 | 752 | self.* = .empty; |
| 668 | 753 | return new_items; |
| ... | ... | @@ -675,7 +760,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 675 | 760 | } |
| 676 | 761 | |
| 677 | 762 | /// The caller owns the returned memory. ArrayList becomes empty. |
| 763 | /// May invalidate element pointers. |
| 678 | 764 | pub fn toOwnedSliceSentinel(self: *Self, gpa: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { |
| 765 | self.pointer_stability.assertUnlocked(); |
| 679 | 766 | // This addition can never overflow because `self.items` can never occupy the whole address space. |
| 680 | 767 | try self.ensureTotalCapacityPrecise(gpa, self.items.len + 1); |
| 681 | 768 | self.appendAssumeCapacity(sentinel); |
| ... | ... | @@ -688,6 +775,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 688 | 775 | /// Its capacity is cleared, making deinit() safe but unnecessary to call. |
| 689 | 776 | /// |
| 690 | 777 | /// Asserts what the capacity is equal to the length. |
| 778 | /// Never invalidates element pointers. |
| 691 | 779 | pub fn toOwnedSliceAssert(self: *Self) Slice { |
| 692 | 780 | assert(self.items.len == self.capacity); |
| 693 | 781 | const items = self.items; |
| ... | ... | @@ -697,6 +785,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 697 | 785 | |
| 698 | 786 | /// The caller owns the returned memory. ArrayList becomes empty. |
| 699 | 787 | /// Asserts what the capacity is equal to the length + 1. |
| 788 | /// Never invalidates element pointers. |
| 700 | 789 | pub fn toOwnedSliceSentinelAssert(self: *Self, comptime sentinel: T) SentinelSlice(sentinel) { |
| 701 | 790 | std.debug.assert(self.items.len + 1 == self.capacity); |
| 702 | 791 | self.appendAssumeCapacity(sentinel); |
| ... | ... | @@ -711,43 +800,41 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 711 | 800 | return cloned; |
| 712 | 801 | } |
| 713 | 802 | |
| 714 | | /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. |
| 715 | | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 803 | /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. |
| 804 | /// If `index` is equal to the length of the list this operation is equivalent to append. |
| 716 | 805 | /// This operation is O(N). |
| 717 | 806 | /// Invalidates element pointers if additional memory is needed. |
| 807 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 718 | 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 { |
| 720 | | const dst = try self.addManyAt(gpa, i, 1); |
| 809 | pub fn insert(self: *Self, gpa: Allocator, index: usize, item: T) Allocator.Error!void { |
| 810 | self.pointer_stability.assertUnlocked(); |
| 811 | const dst = try self.addManyAt(gpa, index, 1); |
| 721 | 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. |
| 725 | | /// |
| 726 | | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 727 | | /// |
| 815 | /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. |
| 816 | /// If `index` is equal to the length of the list this operation is |
| 817 | /// equivalent to appendAssumeCapacity. |
| 728 | 818 | /// This operation is O(N). |
| 729 | | /// |
| 819 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 730 | 820 | /// Asserts that the list has capacity for one additional item. |
| 731 | | /// |
| 732 | 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 | 824 | assert(self.items.len < self.capacity); |
| 735 | 825 | self.items.len += 1; |
| 736 | | |
| 737 | | @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); |
| 738 | | self.items[i] = item; |
| 826 | @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]); |
| 827 | self.items[index] = item; |
| 739 | 828 | } |
| 740 | 829 | |
| 741 | | /// Insert `item` at index `i`, moving `list[i .. list.len]` to higher indices to make room. |
| 742 | | /// |
| 743 | | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 744 | | /// |
| 830 | /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. |
| 831 | /// If `index` is equal to the length of the list this operation is |
| 832 | /// equivalent to appendAssumeCapacity. |
| 745 | 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 | 836 | /// If the list lacks unused capacity for the additional item, returns |
| 748 | 837 | /// `error.OutOfMemory`. |
| 749 | | /// |
| 750 | | /// Asserts that the index is in bounds or equal to the length. |
| 751 | 838 | pub fn insertBounded(self: *Self, i: usize, item: T) error{OutOfMemory}!void { |
| 752 | 839 | if (self.capacity - self.items.len == 0) return error.OutOfMemory; |
| 753 | 840 | return insertAssumeCapacity(self, i, item); |
| ... | ... | @@ -767,20 +854,48 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 767 | 854 | index: usize, |
| 768 | 855 | count: usize, |
| 769 | 856 | ) Allocator.Error![]T { |
| 770 | | var managed = self.toManaged(gpa); |
| 771 | | defer self.* = managed.moveToUnmanaged(); |
| 772 | | return managed.addManyAt(index, count); |
| 857 | const new_len = try addOrOom(self.items.len, count); |
| 858 | self.pointer_stability.assertUnlocked(); |
| 859 | |
| 860 | if (self.capacity >= new_len) |
| 861 | return addManyAtAssumeCapacity(self, index, count); |
| 862 | |
| 863 | // Here we avoid copying allocated but unused bytes by |
| 864 | // attempting a resize in place, and falling back to allocating |
| 865 | // a new buffer and doing our own copy. With a realloc() call, |
| 866 | // the allocator implementation would pointlessly copy our |
| 867 | // extra capacity. |
| 868 | const new_capacity = Aligned(T, alignment).growCapacity(new_len); |
| 869 | const old_memory = self.allocatedSlice(); |
| 870 | if (gpa.remap(old_memory, new_capacity)) |new_memory| { |
| 871 | self.items.ptr = new_memory.ptr; |
| 872 | self.capacity = new_memory.len; |
| 873 | return addManyAtAssumeCapacity(self, index, count); |
| 874 | } |
| 875 | |
| 876 | // Make a new allocation, avoiding `ensureTotalCapacity` in order |
| 877 | // to avoid extra memory copies. |
| 878 | const new_memory = try gpa.alignedAlloc(T, alignment, new_capacity); |
| 879 | const to_move = self.items[index..]; |
| 880 | @memcpy(new_memory[0..index], self.items[0..index]); |
| 881 | @memcpy(new_memory[index + count ..][0..to_move.len], to_move); |
| 882 | gpa.free(old_memory); |
| 883 | self.items = new_memory[0..new_len]; |
| 884 | self.capacity = new_memory.len; |
| 885 | // The inserted elements at `new_memory[index..][0..count]` have |
| 886 | // already been set to `undefined` by memory allocation. |
| 887 | return new_memory[index..][0..count]; |
| 773 | 888 | } |
| 774 | 889 | |
| 775 | 890 | /// Add `count` new elements at position `index`, which have |
| 776 | 891 | /// `undefined` values. Returns a slice pointing to the newly allocated |
| 777 | 892 | /// elements, which becomes invalid after various `ArrayList` |
| 778 | 893 | /// operations. |
| 779 | | /// Invalidates pre-existing pointers to elements at and after `index`, but |
| 780 | | /// does not invalidate any before that. |
| 894 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 781 | 895 | /// Asserts that the list has capacity for the additional items. |
| 782 | 896 | /// Asserts that the index is in bounds or equal to the length. |
| 783 | 897 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 898 | self.pointer_stability.assertUnlocked(); |
| 784 | 899 | const new_len = self.items.len + count; |
| 785 | 900 | assert(self.capacity >= new_len); |
| 786 | 901 | const to_move = self.items[index..]; |
| ... | ... | @@ -795,20 +910,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 795 | 910 | /// `undefined` values, returning a slice pointing to the newly |
| 796 | 911 | /// allocated elements, which becomes invalid after various `ArrayList` |
| 797 | 912 | /// operations. |
| 798 | | /// |
| 799 | | /// Invalidates pre-existing pointers to elements at and after `index`, but |
| 800 | | /// does not invalidate any before that. |
| 801 | | /// |
| 913 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 802 | 914 | /// If the list lacks unused capacity for the additional items, returns |
| 803 | 915 | /// `error.OutOfMemory`. |
| 804 | | /// |
| 805 | 916 | /// Asserts that the index is in bounds or equal to the length. |
| 806 | 917 | pub fn addManyAtBounded(self: *Self, index: usize, count: usize) error{OutOfMemory}![]T { |
| 807 | 918 | if (self.capacity - self.items.len < count) return error.OutOfMemory; |
| 808 | 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 | 923 | /// This operation is O(N). |
| 813 | 924 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 814 | 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 | 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 | 943 | /// This operation is O(N). |
| 833 | 944 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 834 | 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 | 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 | 957 | /// This operation is O(N). |
| 847 | 958 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 848 | 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 | 969 | } |
| 859 | 970 | |
| 860 | 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 | 975 | /// Asserts that the range is in bounds. |
| 863 | 976 | pub fn replaceRange( |
| 864 | 977 | self: *Self, |
| ... | ... | @@ -872,9 +985,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 872 | 985 | } |
| 873 | 986 | |
| 874 | 987 | /// Grows or shrinks the list as necessary. |
| 875 | | /// |
| 876 | | /// Never invalidates element pointers. |
| 877 | | /// |
| 988 | /// Invalidates pointers to elements at and above index `start + len` |
| 989 | /// when `len` and `new_items.len` are unequal. |
| 878 | 990 | /// Asserts the capacity is enough for additional items. |
| 879 | 991 | pub fn replaceRangeAssumeCapacity( |
| 880 | 992 | self: *Self, |
| ... | ... | @@ -883,7 +995,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 883 | 995 | new_items: []const T, |
| 884 | 996 | ) void { |
| 885 | 997 | std.debug.assert(self.capacity - self.items.len >= new_items.len -| len); |
| 886 | | |
| 998 | self.pointer_stability.assertUnlocked(); |
| 887 | 999 | const tail = self.items[start + len ..]; |
| 888 | 1000 | const vacated = self.items[self.items.len - (len -| new_items.len) ..]; |
| 889 | 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 | 1004 | @memset(vacated, undefined); |
| 893 | 1005 | } |
| 894 | 1006 | |
| 895 | | /// Grows or shrinks the list as necessary. |
| 896 | | /// |
| 897 | | /// Never invalidates element pointers. |
| 898 | | /// |
| 1007 | /// Invalidates pointers to elements at and above index `start + len` |
| 1008 | /// when `len` and `new_items.len` are unequal. |
| 899 | 1009 | /// If the unused capacity is insufficient for additional items, |
| 900 | 1010 | /// returns `error.OutOfMemory`. |
| 901 | 1011 | pub fn replaceRangeBounded( |
| ... | ... | @@ -958,6 +1068,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 958 | 1068 | /// |
| 959 | 1069 | /// Invalidates element pointers beyond the first deleted index. |
| 960 | 1070 | pub fn orderedRemoveMany(self: *Self, sorted_indexes: []const usize) void { |
| 1071 | self.pointer_stability.assertUnlocked(); |
| 961 | 1072 | if (sorted_indexes.len == 0) return; |
| 962 | 1073 | var shift: usize = 1; |
| 963 | 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 | 1091 | /// This operation is O(1). |
| 981 | 1092 | /// Asserts that the index is in bounds. |
| 982 | 1093 | pub fn swapRemove(self: *Self, i: usize) T { |
| 1094 | self.pointer_stability.assertUnlocked(); |
| 983 | 1095 | const val = self.items[i]; |
| 984 | 1096 | self.items[i] = self.items[self.items.len - 1]; |
| 985 | 1097 | self.items[self.items.len - 1] = undefined; |
| ... | ... | @@ -996,7 +1108,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 996 | 1108 | } |
| 997 | 1109 | |
| 998 | 1110 | /// Append the slice of items to the list. |
| 999 | | /// |
| 1111 | /// Never invalidates element pointers. |
| 1000 | 1112 | /// Asserts that the list can hold the additional items. |
| 1001 | 1113 | pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { |
| 1002 | 1114 | const old_len = self.items.len; |
| ... | ... | @@ -1007,7 +1119,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1007 | 1119 | } |
| 1008 | 1120 | |
| 1009 | 1121 | /// Append the slice of items to the list. |
| 1010 | | /// |
| 1122 | /// Never invalidates element pointers. |
| 1011 | 1123 | /// If the list lacks unused capacity for the additional items, returns `error.OutOfMemory`. |
| 1012 | 1124 | pub fn appendSliceBounded(self: *Self, items: []const T) error{OutOfMemory}!void { |
| 1013 | 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 | 1139 | /// |
| 1028 | 1140 | /// Intended to be used only when `appendSliceAssumeCapacity` would be |
| 1029 | 1141 | /// a compile error. |
| 1030 | | /// |
| 1142 | /// Never invalidates element pointers. |
| 1031 | 1143 | /// Asserts that the list can hold the additional items. |
| 1032 | 1144 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { |
| 1033 | 1145 | const old_len = self.items.len; |
| ... | ... | @@ -1041,7 +1153,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1041 | 1153 | /// |
| 1042 | 1154 | /// Intended to be used only when `appendSliceAssumeCapacity` would be |
| 1043 | 1155 | /// a compile error. |
| 1044 | | /// |
| 1156 | /// Never invalidates element pointers. |
| 1045 | 1157 | /// If the list lacks unused capacity for the additional items, returns |
| 1046 | 1158 | /// `error.OutOfMemory`. |
| 1047 | 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 | 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 | 1166 | pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { |
| 1053 | 1167 | comptime assert(T == u8); |
| 1054 | 1168 | try self.ensureUnusedCapacity(gpa, fmt.len); |
| ... | ... | @@ -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 | 1179 | pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void { |
| 1063 | 1180 | comptime assert(T == u8); |
| 1064 | 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 | 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 | 1189 | pub fn printBounded(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { |
| 1070 | 1190 | comptime assert(T == u8); |
| 1071 | 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 | 1261 | /// Asserts that the new length is less than or equal to the previous length. |
| 1142 | 1262 | /// If succeds capacity is guaranteed to be equal to the length. |
| 1143 | 1263 | pub fn shrinkAndFreePrecise(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void { |
| 1264 | self.pointer_stability.assertUnlocked(); |
| 1144 | 1265 | assert(new_len <= self.items.len); |
| 1145 | 1266 | |
| 1146 | 1267 | if (@sizeOf(T) == 0) { |
| ... | ... | @@ -1194,6 +1315,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1194 | 1315 | /// Keeps capacity the same. |
| 1195 | 1316 | /// Asserts that the new length is less than or equal to the previous length. |
| 1196 | 1317 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 1318 | self.pointer_stability.assertUnlocked(); |
| 1319 | |
| 1197 | 1320 | assert(new_len <= self.items.len); |
| 1198 | 1321 | @memset(self.items[new_len..], undefined); |
| 1199 | 1322 | self.items.len = new_len; |
| ... | ... | @@ -1202,12 +1325,14 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1202 | 1325 | /// Reduce length to 0. |
| 1203 | 1326 | /// Invalidates all element pointers. |
| 1204 | 1327 | pub fn clearRetainingCapacity(self: *Self) void { |
| 1328 | self.pointer_stability.assertUnlocked(); |
| 1205 | 1329 | @memset(self.items, undefined); |
| 1206 | 1330 | self.items.len = 0; |
| 1207 | 1331 | } |
| 1208 | 1332 | |
| 1209 | 1333 | /// Invalidates all element pointers. |
| 1210 | 1334 | pub fn clearAndFree(self: *Self, gpa: Allocator) void { |
| 1335 | self.pointer_stability.assertUnlocked(); |
| 1211 | 1336 | gpa.free(self.allocatedSlice()); |
| 1212 | 1337 | self.items.len = 0; |
| 1213 | 1338 | self.capacity = 0; |
| ... | ... | @@ -1225,6 +1350,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1225 | 1350 | /// modify the array so that it can hold exactly `new_capacity` items. |
| 1226 | 1351 | /// Invalidates element pointers if additional memory is needed. |
| 1227 | 1352 | pub fn ensureTotalCapacityPrecise(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { |
| 1353 | self.pointer_stability.assertUnlocked(); |
| 1354 | |
| 1228 | 1355 | if (@sizeOf(T) == 0) { |
| 1229 | 1356 | self.capacity = math.maxInt(usize); |
| 1230 | 1357 | return; |
| ... | ... | @@ -1268,7 +1395,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1268 | 1395 | } |
| 1269 | 1396 | |
| 1270 | 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 | 1400 | pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!*T { |
| 1273 | 1401 | // This can never overflow because `self.items` can never occupy the whole address space |
| 1274 | 1402 | const newlen = self.items.len + 1; |
| ... | ... | @@ -1277,11 +1405,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1277 | 1405 | } |
| 1278 | 1406 | |
| 1279 | 1407 | /// Increase length by 1, returning pointer to the new item. |
| 1280 | | /// |
| 1281 | 1408 | /// Never invalidates element pointers. |
| 1282 | | /// |
| 1283 | | /// The returned element pointer becomes invalid when the list is resized. |
| 1284 | | /// |
| 1409 | /// The returned pointer may be invalidated by further operations to this list. |
| 1285 | 1410 | /// Asserts that the list can hold one additional item. |
| 1286 | 1411 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 1287 | 1412 | assert(self.items.len < self.capacity); |
| ... | ... | @@ -1291,11 +1416,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1291 | 1416 | } |
| 1292 | 1417 | |
| 1293 | 1418 | /// Increase length by 1, returning pointer to the new item. |
| 1294 | | /// |
| 1295 | 1419 | /// Never invalidates element pointers. |
| 1296 | | /// |
| 1297 | | /// The returned element pointer becomes invalid when the list is resized. |
| 1298 | | /// |
| 1420 | /// The returned pointer may be invalidated by further operations to this list. |
| 1299 | 1421 | /// If the list lacks unused capacity for the additional item, returns `error.OutOfMemory`. |
| 1300 | 1422 | pub fn addOneBounded(self: *Self) error{OutOfMemory}!*T { |
| 1301 | 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 | 1425 | } |
| 1304 | 1426 | |
| 1305 | 1427 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1428 | /// Invalidates element pointers if additional memory is required. |
| 1306 | 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 | 1431 | pub fn addManyAsArray(self: *Self, gpa: Allocator, comptime n: usize) Allocator.Error!*[n]T { |
| 1309 | 1432 | const prev_len = self.items.len; |
| 1310 | 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 | 1435 | } |
| 1313 | 1436 | |
| 1314 | 1437 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1315 | | /// |
| 1316 | 1438 | /// The return value is an array pointing to the newly allocated elements. |
| 1317 | | /// |
| 1318 | 1439 | /// Never invalidates element pointers. |
| 1319 | | /// |
| 1320 | | /// The returned pointer becomes invalid when the list is resized. |
| 1321 | | /// |
| 1440 | /// The returned pointer may be invalidated by further operations to this list. |
| 1322 | 1441 | /// Asserts that the list can hold the additional items. |
| 1323 | 1442 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 1324 | 1443 | assert(self.items.len + n <= self.capacity); |
| ... | ... | @@ -1328,13 +1447,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1328 | 1447 | } |
| 1329 | 1448 | |
| 1330 | 1449 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1331 | | /// |
| 1332 | 1450 | /// The return value is an array pointing to the newly allocated elements. |
| 1333 | | /// |
| 1334 | 1451 | /// Never invalidates element pointers. |
| 1335 | | /// |
| 1336 | | /// The returned pointer becomes invalid when the list is resized. |
| 1337 | | /// |
| 1452 | /// The returned pointer may be invalidated by further operations to this list. |
| 1338 | 1453 | /// If the list lacks unused capacity for the additional items, returns |
| 1339 | 1454 | /// `error.OutOfMemory`. |
| 1340 | 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 | 1459 | |
| 1345 | 1460 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1346 | 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 | 1463 | /// Resizes list if `self.capacity` is not large enough. |
| 1349 | 1464 | pub fn addManyAsSlice(self: *Self, gpa: Allocator, n: usize) Allocator.Error![]T { |
| 1350 | 1465 | const prev_len = self.items.len; |
| ... | ... | @@ -1354,10 +1469,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1354 | 1469 | |
| 1355 | 1470 | /// Resizes the array, adding `n` new elements, which have `undefined` |
| 1356 | 1471 | /// values, returning a slice pointing to the newly allocated elements. |
| 1357 | | /// |
| 1358 | | /// Never invalidates element pointers. The returned pointer becomes |
| 1359 | | /// invalid when the list is resized. |
| 1360 | | /// |
| 1472 | /// Never invalidates element pointers. |
| 1473 | /// The returned pointer may be invalidated by further operations to this list. |
| 1361 | 1474 | /// Asserts that the list can hold the additional items. |
| 1362 | 1475 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { |
| 1363 | 1476 | assert(self.items.len + n <= self.capacity); |
| ... | ... | @@ -1368,10 +1481,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1368 | 1481 | |
| 1369 | 1482 | /// Resizes the array, adding `n` new elements, which have `undefined` |
| 1370 | 1483 | /// values, returning a slice pointing to the newly allocated elements. |
| 1371 | | /// |
| 1372 | | /// Never invalidates element pointers. The returned pointer becomes |
| 1373 | | /// invalid when the list is resized. |
| 1374 | | /// |
| 1484 | /// Never invalidates element pointers. |
| 1485 | /// The returned pointer may be invalidated by further operations to this list. |
| 1375 | 1486 | /// If the list lacks unused capacity for the additional items, returns |
| 1376 | 1487 | /// `error.OutOfMemory`. |
| 1377 | 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 | 1495 | /// Invalidates pointers to last element. |
| 1385 | 1496 | pub fn pop(self: *Self) ?T { |
| 1386 | 1497 | if (self.items.len == 0) return null; |
| 1498 | self.pointer_stability.assertUnlocked(); |
| 1499 | |
| 1387 | 1500 | const val = self.items[self.items.len - 1]; |
| 1388 | 1501 | self.items[self.items.len - 1] = undefined; |
| 1389 | 1502 | self.items.len -= 1; |
| ... | ... | @@ -1392,6 +1505,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1392 | 1505 | |
| 1393 | 1506 | /// Returns a slice of all the items plus the extra capacity, whose memory |
| 1394 | 1507 | /// contents are `undefined`. |
| 1508 | /// The returned pointer may be invalidated by further operations to this list. |
| 1395 | 1509 | pub fn allocatedSlice(self: Self) Slice { |
| 1396 | 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 | 1514 | /// This can be useful for writing directly into an ArrayList. |
| 1401 | 1515 | /// Note that such an operation must be followed up with a direct |
| 1402 | 1516 | /// modification of `self.items.len`. |
| 1517 | /// The returned pointer may be invalidated by further operations to this list. |
| 1403 | 1518 | pub fn unusedCapacitySlice(self: Self) []T { |
| 1404 | 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 | 1536 | |
| 1422 | 1537 | /// Returns a pointer to the last element from the list, or `null` if |
| 1423 | 1538 | /// the list is empty. |
| 1539 | /// The returned pointer may be invalidated by further operations to this list. |
| 1424 | 1540 | pub fn lastPtr(self: Self) ?*T { |
| 1425 | 1541 | if (self.items.len == 0) return null; |
| 1426 | 1542 | return &self.items[self.items.len - 1]; |
| ... | ... | @@ -2432,6 +2548,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value" |
| 2432 | 2548 | var list: ArrayList(u32) = .{ |
| 2433 | 2549 | .items = undefined, |
| 2434 | 2550 | .capacity = math.maxInt(usize) - 1, |
| 2551 | .pointer_stability = .{}, |
| 2435 | 2552 | }; |
| 2436 | 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 | 2567 | .items = undefined, |
| 2451 | 2568 | .capacity = math.maxInt(usize) - 1, |
| 2452 | 2569 | .allocator = a, |
| 2570 | .pointer_stability = .{}, |
| 2453 | 2571 | }; |
| 2454 | 2572 | list.items.len = math.maxInt(usize) - 1; |
| 2455 | 2573 | |