| ... | ... | @@ -34,6 +34,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 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 { |
| ... | ... | @@ -60,11 +63,29 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 60 | 63 | |
| 61 | 64 | /// Release all allocated memory. |
| 62 | 65 | pub fn deinit(self: Self) void { |
| 66 | self.pointer_stability.assertUnlocked(); |
| 63 | 67 | if (@sizeOf(T) > 0) { |
| 64 | 68 | self.allocator.free(self.allocatedSlice()); |
| 65 | 69 | } |
| 66 | 70 | } |
| 67 | 71 | |
| 72 | /// Puts the array list into a state where any method call that would |
| 73 | /// cause an existing value pointer to become invalidated will |
| 74 | /// instead trigger an assertion. |
| 75 | /// |
| 76 | /// An additional call to `lockPointers` in such state also triggers an |
| 77 | /// assertion. |
| 78 | /// |
| 79 | /// `unlockPointers` returns the array list to the previous state. |
| 80 | pub fn lockPointers(self: *Self) void { |
| 81 | self.pointer_stability.lock(); |
| 82 | } |
| 83 | |
| 84 | /// Undoes a call to `lockPointers`. |
| 85 | pub fn unlockPointers(self: *Self) void { |
| 86 | self.pointer_stability.unlock(); |
| 87 | } |
| 88 | |
| 68 | 89 | /// ArrayList takes ownership of the passed in slice. The slice must have been |
| 69 | 90 | /// allocated with `gpa`. |
| 70 | 91 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| ... | ... | @@ -90,6 +111,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 90 | 111 | /// Initializes an ArrayList with the `items` and `capacity` fields |
| 91 | 112 | /// of this ArrayList. Empties this ArrayList. |
| 92 | 113 | pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment) { |
| 114 | self.pointer_stability.assertUnlocked(); |
| 93 | 115 | const allocator = self.allocator; |
| 94 | 116 | const result: Aligned(T, alignment) = .{ .items = self.items, .capacity = self.capacity }; |
| 95 | 117 | self.* = init(allocator); |
| ... | ... | @@ -146,6 +168,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 146 | 168 | /// Asserts that there is enough capacity for the new item. |
| 147 | 169 | /// Asserts that the index is in bounds or equal to the length. |
| 148 | 170 | pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { |
| 171 | self.pointer_stability.lock(); |
| 172 | defer self.pointer_stability.unlock(); |
| 173 | |
| 149 | 174 | assert(self.items.len < self.capacity); |
| 150 | 175 | self.items.len += 1; |
| 151 | 176 | |
| ... | ... | @@ -167,6 +192,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 167 | 192 | if (self.capacity >= new_len) |
| 168 | 193 | return addManyAtAssumeCapacity(self, index, count); |
| 169 | 194 | |
| 195 | self.pointer_stability.lock(); |
| 196 | defer self.pointer_stability.unlock(); |
| 170 | 197 | // Here we avoid copying allocated but unused bytes by |
| 171 | 198 | // attempting a resize in place, and falling back to allocating |
| 172 | 199 | // a new buffer and doing our own copy. With a realloc() call, |
| ... | ... | @@ -199,8 +226,6 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 199 | 226 | /// elements, which becomes invalid after various `ArrayList` |
| 200 | 227 | /// operations. |
| 201 | 228 | /// 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 | 229 | /// Asserts that the index is in bounds or equal to the length. |
| 205 | 230 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 206 | 231 | const new_len = self.items.len + count; |
| ... | ... | @@ -379,6 +404,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 379 | 404 | /// Invalidates element pointers for the elements `items[new_len..]`. |
| 380 | 405 | /// Asserts that the new length is less than or equal to the previous length. |
| 381 | 406 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 407 | self.pointer_stability.lock(); |
| 408 | defer self.pointer_stability.unlock(); |
| 409 | |
| 382 | 410 | assert(new_len <= self.items.len); |
| 383 | 411 | @memset(self.items[new_len..], undefined); |
| 384 | 412 | self.items.len = new_len; |
| ... | ... | @@ -387,12 +415,15 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 387 | 415 | /// Reduce length to 0. |
| 388 | 416 | /// Invalidates all element pointers. |
| 389 | 417 | pub fn clearRetainingCapacity(self: *Self) void { |
| 418 | self.pointer_stability.lock(); |
| 419 | defer self.pointer_stability.unlock(); |
| 390 | 420 | @memset(self.items, undefined); |
| 391 | 421 | self.items.len = 0; |
| 392 | 422 | } |
| 393 | 423 | |
| 394 | 424 | /// Invalidates all element pointers. |
| 395 | 425 | pub fn clearAndFree(self: *Self) void { |
| 426 | self.pointer_stability.assertUnlocked(); |
| 396 | 427 | self.allocator.free(self.allocatedSlice()); |
| 397 | 428 | self.items.len = 0; |
| 398 | 429 | self.capacity = 0; |
| ... | ... | @@ -418,6 +449,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 418 | 449 | /// modify the array so that it can hold exactly `new_capacity` items. |
| 419 | 450 | /// Invalidates element pointers if additional memory is needed. |
| 420 | 451 | pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void { |
| 452 | self.pointer_stability.lock(); |
| 453 | defer self.pointer_stability.unlock(); |
| 454 | |
| 421 | 455 | if (@sizeOf(T) == 0) { |
| 422 | 456 | self.capacity = math.maxInt(usize); |
| 423 | 457 | return; |
| ... | ... | @@ -523,6 +557,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type |
| 523 | 557 | /// Invalidates element pointers to the removed element, if any. |
| 524 | 558 | pub fn pop(self: *Self) ?T { |
| 525 | 559 | if (self.items.len == 0) return null; |
| 560 | self.pointer_stability.lock(); |
| 561 | defer self.pointer_stability.unlock(); |
| 526 | 562 | const val = self.items[self.items.len - 1]; |
| 527 | 563 | self.items[self.items.len - 1] = undefined; |
| 528 | 564 | self.items.len -= 1; |
| ... | ... | @@ -584,6 +620,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 584 | 620 | /// additional memory. |
| 585 | 621 | capacity: usize, |
| 586 | 622 | |
| 623 | /// Used to detect memory safety violations. |
| 624 | pointer_stability: debug.SafetyLock = .{}, |
| 625 | |
| 587 | 626 | /// An ArrayList containing no elements. |
| 588 | 627 | pub const empty: Self = .{ |
| 589 | 628 | .items = &.{}, |
| ... | ... | @@ -618,10 +657,28 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 618 | 657 | |
| 619 | 658 | /// Release all allocated memory. |
| 620 | 659 | pub fn deinit(self: *Self, gpa: Allocator) void { |
| 660 | self.pointer_stability.assertUnlocked(); |
| 621 | 661 | gpa.free(self.allocatedSlice()); |
| 622 | 662 | self.* = undefined; |
| 623 | 663 | } |
| 624 | 664 | |
| 665 | /// Puts the unmanaged array list into a state where any method call that would |
| 666 | /// cause an existing value pointer to become invalidated will |
| 667 | /// instead trigger an assertion. |
| 668 | /// |
| 669 | /// An additional call to `lockPointers` in such state also triggers an |
| 670 | /// assertion. |
| 671 | /// |
| 672 | /// `unlockPointers` returns the unmanaged array list to the previous state. |
| 673 | pub fn lockPointers(self: *Self) void { |
| 674 | self.pointer_stability.lock(); |
| 675 | } |
| 676 | |
| 677 | /// Undoes a call to `lockPointers`. |
| 678 | pub fn unlockPointers(self: *Self) void { |
| 679 | self.pointer_stability.unlock(); |
| 680 | } |
| 681 | |
| 625 | 682 | /// Convert this list into an analogous memory-managed one. |
| 626 | 683 | /// The returned list has ownership of the underlying memory. |
| 627 | 684 | pub fn toManaged(self: *Self, gpa: Allocator) AlignedManaged(T, alignment) { |
| ... | ... | @@ -718,6 +775,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 718 | 775 | /// |
| 719 | 776 | /// Asserts that the index is in bounds or equal to the length. |
| 720 | 777 | pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { |
| 778 | self.pointer_stability.lock(); |
| 779 | defer self.pointer_stability.unlock(); |
| 780 | |
| 721 | 781 | assert(self.items.len < self.capacity); |
| 722 | 782 | self.items.len += 1; |
| 723 | 783 | |
| ... | ... | @@ -763,11 +823,12 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 763 | 823 | /// `undefined` values. Returns a slice pointing to the newly allocated |
| 764 | 824 | /// elements, which becomes invalid after various `ArrayList` |
| 765 | 825 | /// operations. |
| 766 | | /// Invalidates pre-existing pointers to elements at and after `index`, but |
| 767 | | /// does not invalidate any before that. |
| 768 | 826 | /// Asserts that the list has capacity for the additional items. |
| 769 | 827 | /// Asserts that the index is in bounds or equal to the length. |
| 770 | 828 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 829 | self.pointer_stability.lock(); |
| 830 | defer self.pointer_stability.unlock(); |
| 831 | |
| 771 | 832 | const new_len = self.items.len + count; |
| 772 | 833 | assert(self.capacity >= new_len); |
| 773 | 834 | const to_move = self.items[index..]; |
| ... | ... | @@ -783,9 +844,6 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 783 | 844 | /// allocated elements, which becomes invalid after various `ArrayList` |
| 784 | 845 | /// operations. |
| 785 | 846 | /// |
| 786 | | /// Invalidates pre-existing pointers to elements at and after `index`, but |
| 787 | | /// does not invalidate any before that. |
| 788 | | /// |
| 789 | 847 | /// If the list lacks unused capacity for the additional items, returns |
| 790 | 848 | /// `error.OutOfMemory`. |
| 791 | 849 | /// |
| ... | ... | @@ -967,6 +1025,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 967 | 1025 | /// This operation is O(1). |
| 968 | 1026 | /// Asserts that the index is in bounds. |
| 969 | 1027 | pub fn swapRemove(self: *Self, i: usize) T { |
| 1028 | self.pointer_stability.lock(); |
| 1029 | defer self.pointer_stability.unlock(); |
| 970 | 1030 | const val = self.items[i]; |
| 971 | 1031 | self.items[i] = self.items[self.items.len - 1]; |
| 972 | 1032 | self.items[self.items.len - 1] = undefined; |
| ... | ... | @@ -1128,6 +1188,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1128 | 1188 | /// Asserts that the new length is less than or equal to the previous length. |
| 1129 | 1189 | /// If succeds capacity is guaranteed to be equal to the length. |
| 1130 | 1190 | pub fn shrinkAndFreePrecise(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void { |
| 1191 | self.pointer_stability.lock(); |
| 1192 | defer self.pointer_stability.unlock(); |
| 1131 | 1193 | assert(new_len <= self.items.len); |
| 1132 | 1194 | |
| 1133 | 1195 | if (@sizeOf(T) == 0) { |
| ... | ... | @@ -1181,6 +1243,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1181 | 1243 | /// Keeps capacity the same. |
| 1182 | 1244 | /// Asserts that the new length is less than or equal to the previous length. |
| 1183 | 1245 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 1246 | self.pointer_stability.lock(); |
| 1247 | defer self.pointer_stability.unlock(); |
| 1248 | |
| 1184 | 1249 | assert(new_len <= self.items.len); |
| 1185 | 1250 | @memset(self.items[new_len..], undefined); |
| 1186 | 1251 | self.items.len = new_len; |
| ... | ... | @@ -1189,12 +1254,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1189 | 1254 | /// Reduce length to 0. |
| 1190 | 1255 | /// Invalidates all element pointers. |
| 1191 | 1256 | pub fn clearRetainingCapacity(self: *Self) void { |
| 1257 | self.pointer_stability.lock(); |
| 1258 | defer self.pointer_stability.unlock(); |
| 1192 | 1259 | @memset(self.items, undefined); |
| 1193 | 1260 | self.items.len = 0; |
| 1194 | 1261 | } |
| 1195 | 1262 | |
| 1196 | 1263 | /// Invalidates all element pointers. |
| 1197 | 1264 | pub fn clearAndFree(self: *Self, gpa: Allocator) void { |
| 1265 | self.pointer_stability.lock(); |
| 1266 | defer self.pointer_stability.unlock(); |
| 1198 | 1267 | gpa.free(self.allocatedSlice()); |
| 1199 | 1268 | self.items.len = 0; |
| 1200 | 1269 | self.capacity = 0; |
| ... | ... | @@ -1212,6 +1281,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1212 | 1281 | /// modify the array so that it can hold exactly `new_capacity` items. |
| 1213 | 1282 | /// Invalidates element pointers if additional memory is needed. |
| 1214 | 1283 | pub fn ensureTotalCapacityPrecise(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { |
| 1284 | self.pointer_stability.lock(); |
| 1285 | defer self.pointer_stability.unlock(); |
| 1286 | |
| 1215 | 1287 | if (@sizeOf(T) == 0) { |
| 1216 | 1288 | self.capacity = math.maxInt(usize); |
| 1217 | 1289 | return; |
| ... | ... | @@ -1371,6 +1443,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { |
| 1371 | 1443 | /// Invalidates pointers to last element. |
| 1372 | 1444 | pub fn pop(self: *Self) ?T { |
| 1373 | 1445 | if (self.items.len == 0) return null; |
| 1446 | self.pointer_stability.lock(); |
| 1447 | defer self.pointer_stability.unlock(); |
| 1448 | |
| 1374 | 1449 | const val = self.items[self.items.len - 1]; |
| 1375 | 1450 | self.items[self.items.len - 1] = undefined; |
| 1376 | 1451 | self.items.len -= 1; |