| ... | @@ -12,10 +12,20 @@ const Allocator = mem.Allocator; | ... | @@ -12,10 +12,20 @@ const Allocator = mem.Allocator; |
| 12 | | 12 | |
| 13 | /// A contiguous, growable list of items in memory. | 13 | /// A contiguous, growable list of items in memory. |
| 14 | /// This is a wrapper around an array of T values. Initialize with `init`. | 14 | /// This is a wrapper around an array of T values. Initialize with `init`. |
| | 15 | /// |
| | 16 | /// This struct internally stores a `std.mem.Allocator` for memory management. |
| | 17 | /// To manually specify an allocator with each method call see `ArrayListUnmanaged`. |
| 15 | pub fn ArrayList(comptime T: type) type { | 18 | pub fn ArrayList(comptime T: type) type { |
| 16 | return ArrayListAligned(T, null); | 19 | return ArrayListAligned(T, null); |
| 17 | } | 20 | } |
| 18 | | 21 | |
| | 22 | /// A contiguous, growable list of arbitrarily aligned items in memory. |
| | 23 | /// This is a wrapper around an array of T values aligned to `alignment`-byte |
| | 24 | /// addresses. If the specified alignment is `null`, then `@alignOf(T)` is used. |
| | 25 | /// Initialize with `init`. |
| | 26 | /// |
| | 27 | /// This struct internally stores a `std.mem.Allocator` for memory management. |
| | 28 | /// To manually specify an allocator with each method call see `ArrayListAlignedUnmanaged`. |
| 19 | pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | 29 | pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 20 | if (alignment) |a| { | 30 | if (alignment) |a| { |
| 21 | if (a == @alignOf(T)) { | 31 | if (a == @alignOf(T)) { |
| ... | @@ -24,9 +34,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -24,9 +34,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 24 | } | 34 | } |
| 25 | return struct { | 35 | return struct { |
| 26 | const Self = @This(); | 36 | const Self = @This(); |
| 27 | | 37 | /// Contents of the list. Pointers to elements in this slice are |
| 28 | /// Content of the ArrayList | 38 | /// **invalid after resizing operations** on the ArrayList, unless the |
| | 39 | /// operation explicitly either: (1) states otherwise or (2) lists the |
| | 40 | /// invalidated pointers. |
| | 41 | /// |
| | 42 | /// The allocator used determines how element pointers are |
| | 43 | /// invalidated, so the behavior may vary between lists. To avoid |
| | 44 | /// illegal behavior, take into account the above paragraph plus the |
| | 45 | /// explicit statements given in each method. |
| 29 | items: Slice, | 46 | items: Slice, |
| | 47 | /// How many T values this list can hold without allocating |
| | 48 | /// additional memory. |
| 30 | capacity: usize, | 49 | capacity: usize, |
| 31 | allocator: *Allocator, | 50 | allocator: *Allocator, |
| 32 | | 51 | |
| ... | @@ -42,7 +61,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -42,7 +61,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 42 | }; | 61 | }; |
| 43 | } | 62 | } |
| 44 | | 63 | |
| 45 | /// Initialize with capacity to hold at least num elements. | 64 | /// Initialize with capacity to hold at least `num` elements. |
| 46 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 65 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 47 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { | 66 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { |
| 48 | var self = Self.init(allocator); | 67 | var self = Self.init(allocator); |
| ... | @@ -79,11 +98,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -79,11 +98,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 79 | }; | 98 | }; |
| 80 | } | 99 | } |
| 81 | | 100 | |
| | 101 | /// Initializes an ArrayListUnmanaged with the `items` and `capacity` fields |
| | 102 | /// of this ArrayList. This ArrayList retains ownership of underlying memory. |
| 82 | pub fn toUnmanaged(self: Self) ArrayListAlignedUnmanaged(T, alignment) { | 103 | pub fn toUnmanaged(self: Self) ArrayListAlignedUnmanaged(T, alignment) { |
| 83 | return .{ .items = self.items, .capacity = self.capacity }; | 104 | return .{ .items = self.items, .capacity = self.capacity }; |
| 84 | } | 105 | } |
| 85 | | 106 | |
| 86 | /// The caller owns the returned memory. ArrayList becomes empty. | 107 | /// The caller owns the returned memory. Empties this ArrayList. |
| 87 | pub fn toOwnedSlice(self: *Self) Slice { | 108 | pub fn toOwnedSlice(self: *Self) Slice { |
| 88 | const allocator = self.allocator; | 109 | const allocator = self.allocator; |
| 89 | const result = allocator.shrink(self.allocatedSlice(), self.items.len); | 110 | const result = allocator.shrink(self.allocatedSlice(), self.items.len); |
| ... | @@ -91,7 +112,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -91,7 +112,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 91 | return result; | 112 | return result; |
| 92 | } | 113 | } |
| 93 | | 114 | |
| 94 | /// The caller owns the returned memory. ArrayList becomes empty. | 115 | /// The caller owns the returned memory. Empties this ArrayList. |
| 95 | pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) ![:sentinel]T { | 116 | pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) ![:sentinel]T { |
| 96 | try self.append(sentinel); | 117 | try self.append(sentinel); |
| 97 | const result = self.toOwnedSlice(); | 118 | const result = self.toOwnedSlice(); |
| ... | @@ -118,9 +139,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -118,9 +139,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 118 | mem.copy(T, self.items[i .. i + items.len], items); | 139 | mem.copy(T, self.items[i .. i + items.len], items); |
| 119 | } | 140 | } |
| 120 | | 141 | |
| 121 | /// Replace range of elements `list[start..start+len]` with `new_items` | 142 | /// Replace range of elements `list[start..start+len]` with `new_items`. |
| 122 | /// grows list if `len < new_items.len`. may allocate | 143 | /// Grows list if `len < new_items.len`. |
| 123 | /// shrinks list if `len > new_items.len` | 144 | /// Shrinks list if `len > new_items.len`. |
| | 145 | /// Invalidates pointers if this ArrayList is resized. |
| 124 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: SliceConst) !void { | 146 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: SliceConst) !void { |
| 125 | const after_range = start + len; | 147 | const after_range = start + len; |
| 126 | const range = self.items[start..after_range]; | 148 | const range = self.items[start..after_range]; |
| ... | @@ -151,15 +173,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -151,15 +173,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 151 | new_item_ptr.* = item; | 173 | new_item_ptr.* = item; |
| 152 | } | 174 | } |
| 153 | | 175 | |
| 154 | /// Extend the list by 1 element, but asserting `self.capacity` | 176 | /// Extend the list by 1 element, but assert `self.capacity` |
| 155 | /// is sufficient to hold an additional item. | 177 | /// is sufficient to hold an additional item. **Does not** |
| | 178 | /// invalidate pointers. |
| 156 | pub fn appendAssumeCapacity(self: *Self, item: T) void { | 179 | pub fn appendAssumeCapacity(self: *Self, item: T) void { |
| 157 | const new_item_ptr = self.addOneAssumeCapacity(); | 180 | const new_item_ptr = self.addOneAssumeCapacity(); |
| 158 | new_item_ptr.* = item; | 181 | new_item_ptr.* = item; |
| 159 | } | 182 | } |
| 160 | | 183 | |
| 161 | /// Remove the element at index `i` from the list and return its value. | 184 | /// Remove the element at index `i`, shift elements after index |
| | 185 | /// `i` forward, and return the removed element. |
| 162 | /// Asserts the array has at least one item. | 186 | /// Asserts the array has at least one item. |
| | 187 | /// Invalidates pointers to end of list. |
| 163 | /// This operation is O(N). | 188 | /// This operation is O(N). |
| 164 | pub fn orderedRemove(self: *Self, i: usize) T { | 189 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 165 | const newlen = self.items.len - 1; | 190 | const newlen = self.items.len - 1; |
| ... | @@ -191,7 +216,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -191,7 +216,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 191 | } | 216 | } |
| 192 | | 217 | |
| 193 | /// Append the slice of items to the list, asserting the capacity is already | 218 | /// Append the slice of items to the list, asserting the capacity is already |
| 194 | /// enough to store the new items. | 219 | /// enough to store the new items. **Does not** invalidate pointers. |
| 195 | pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void { | 220 | pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void { |
| 196 | const oldlen = self.items.len; | 221 | const oldlen = self.items.len; |
| 197 | const newlen = self.items.len + items.len; | 222 | const newlen = self.items.len + items.len; |
| ... | @@ -227,7 +252,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -227,7 +252,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 227 | } | 252 | } |
| 228 | | 253 | |
| 229 | /// Append a value to the list `n` times. | 254 | /// Append a value to the list `n` times. |
| 230 | /// Asserts the capacity is enough. | 255 | /// Asserts the capacity is enough. **Does not** invalidate pointers. |
| 231 | pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { | 256 | pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { |
| 232 | const new_len = self.items.len + n; | 257 | const new_len = self.items.len + n; |
| 233 | assert(new_len <= self.capacity); | 258 | assert(new_len <= self.capacity); |
| ... | @@ -243,7 +268,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -243,7 +268,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 243 | } | 268 | } |
| 244 | | 269 | |
| 245 | /// Reduce allocated capacity to `new_len`. | 270 | /// Reduce allocated capacity to `new_len`. |
| 246 | /// Invalidates element pointers. | 271 | /// May invalidate element pointers. |
| 247 | pub fn shrink(self: *Self, new_len: usize) void { | 272 | pub fn shrink(self: *Self, new_len: usize) void { |
| 248 | assert(new_len <= self.items.len); | 273 | assert(new_len <= self.items.len); |
| 249 | | 274 | |
| ... | @@ -257,13 +282,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -257,13 +282,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 257 | } | 282 | } |
| 258 | | 283 | |
| 259 | /// Reduce length to `new_len`. | 284 | /// Reduce length to `new_len`. |
| 260 | /// Invalidates element pointers. | 285 | /// Invalidates pointers for the elements `items[new_len..]`. |
| 261 | /// Keeps capacity the same. | | |
| 262 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { | 286 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 263 | assert(new_len <= self.items.len); | 287 | assert(new_len <= self.items.len); |
| 264 | self.items.len = new_len; | 288 | self.items.len = new_len; |
| 265 | } | 289 | } |
| 266 | | 290 | |
| | 291 | /// Modify the array so that it can hold at least `new_capacity` items. |
| | 292 | /// Invalidates pointers if additional memory is needed. |
| 267 | pub fn ensureCapacity(self: *Self, new_capacity: usize) !void { | 293 | pub fn ensureCapacity(self: *Self, new_capacity: usize) !void { |
| 268 | var better_capacity = self.capacity; | 294 | var better_capacity = self.capacity; |
| 269 | if (better_capacity >= new_capacity) return; | 295 | if (better_capacity >= new_capacity) return; |
| ... | @@ -280,14 +306,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -280,14 +306,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 280 | } | 306 | } |
| 281 | | 307 | |
| 282 | /// Increases the array's length to match the full capacity that is already allocated. | 308 | /// Increases the array's length to match the full capacity that is already allocated. |
| 283 | /// The new elements have `undefined` values. This operation does not invalidate any | 309 | /// The new elements have `undefined` values. **Does not** invalidate pointers. |
| 284 | /// element pointers. | | |
| 285 | pub fn expandToCapacity(self: *Self) void { | 310 | pub fn expandToCapacity(self: *Self) void { |
| 286 | self.items.len = self.capacity; | 311 | self.items.len = self.capacity; |
| 287 | } | 312 | } |
| 288 | | 313 | |
| 289 | /// Increase length by 1, returning pointer to the new item. | 314 | /// Increase length by 1, returning pointer to the new item. |
| 290 | /// The returned pointer becomes invalid when the list is resized. | 315 | /// The returned pointer becomes invalid when the list resized. |
| 291 | pub fn addOne(self: *Self) !*T { | 316 | pub fn addOne(self: *Self) !*T { |
| 292 | const newlen = self.items.len + 1; | 317 | const newlen = self.items.len + 1; |
| 293 | try self.ensureCapacity(newlen); | 318 | try self.ensureCapacity(newlen); |
| ... | @@ -297,6 +322,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -297,6 +322,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 297 | /// Increase length by 1, returning pointer to the new item. | 322 | /// Increase length by 1, returning pointer to the new item. |
| 298 | /// Asserts that there is already space for the new item without allocating more. | 323 | /// Asserts that there is already space for the new item without allocating more. |
| 299 | /// The returned pointer becomes invalid when the list is resized. | 324 | /// The returned pointer becomes invalid when the list is resized. |
| | 325 | /// **Does not** invalidate element pointers. |
| 300 | pub fn addOneAssumeCapacity(self: *Self) *T { | 326 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 301 | assert(self.items.len < self.capacity); | 327 | assert(self.items.len < self.capacity); |
| 302 | | 328 | |
| ... | @@ -306,6 +332,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -306,6 +332,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 306 | | 332 | |
| 307 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 333 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 308 | /// The return value is an array pointing to the newly allocated elements. | 334 | /// The return value is an array pointing to the newly allocated elements. |
| | 335 | /// The returned pointer becomes invalid when the list is resized. |
| | 336 | /// Resizes list if `self.capacity` is not large enough. |
| 309 | pub fn addManyAsArray(self: *Self, comptime n: usize) !*[n]T { | 337 | pub fn addManyAsArray(self: *Self, comptime n: usize) !*[n]T { |
| 310 | const prev_len = self.items.len; | 338 | const prev_len = self.items.len; |
| 311 | try self.resize(self.items.len + n); | 339 | try self.resize(self.items.len + n); |
| ... | @@ -315,6 +343,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -315,6 +343,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 315 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 343 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 316 | /// The return value is an array pointing to the newly allocated elements. | 344 | /// The return value is an array pointing to the newly allocated elements. |
| 317 | /// Asserts that there is already space for the new item without allocating more. | 345 | /// Asserts that there is already space for the new item without allocating more. |
| | 346 | /// **Does not** invalidate element pointers. |
| | 347 | /// The returned pointer becomes invalid when the list is resized. |
| 318 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { | 348 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 319 | assert(self.items.len + n <= self.capacity); | 349 | assert(self.items.len + n <= self.capacity); |
| 320 | const prev_len = self.items.len; | 350 | const prev_len = self.items.len; |
| ... | @@ -324,21 +354,23 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -324,21 +354,23 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 324 | | 354 | |
| 325 | /// Remove and return the last element from the list. | 355 | /// Remove and return the last element from the list. |
| 326 | /// Asserts the list has at least one item. | 356 | /// Asserts the list has at least one item. |
| | 357 | /// Invalidates pointers to the removed element. |
| 327 | pub fn pop(self: *Self) T { | 358 | pub fn pop(self: *Self) T { |
| 328 | const val = self.items[self.items.len - 1]; | 359 | const val = self.items[self.items.len - 1]; |
| 329 | self.items.len -= 1; | 360 | self.items.len -= 1; |
| 330 | return val; | 361 | return val; |
| 331 | } | 362 | } |
| 332 | | 363 | |
| 333 | /// Remove and return the last element from the list. | 364 | /// Remove and return the last element from the list, or |
| 334 | /// If the list is empty, returns `null`. | 365 | /// return `null` if list is empty. |
| | 366 | /// Invalidates pointers to the removed element, if any. |
| 335 | pub fn popOrNull(self: *Self) ?T { | 367 | pub fn popOrNull(self: *Self) ?T { |
| 336 | if (self.items.len == 0) return null; | 368 | if (self.items.len == 0) return null; |
| 337 | return self.pop(); | 369 | return self.pop(); |
| 338 | } | 370 | } |
| 339 | | 371 | |
| 340 | /// Returns a slice of all the items plus the extra capacity, whose memory | 372 | /// Returns a slice of all the items plus the extra capacity, whose memory |
| 341 | /// contents are undefined. | 373 | /// contents are `undefined`. |
| 342 | pub fn allocatedSlice(self: Self) Slice { | 374 | pub fn allocatedSlice(self: Self) Slice { |
| 343 | // For a nicer API, `items.len` is the length, not the capacity. | 375 | // For a nicer API, `items.len` is the length, not the capacity. |
| 344 | // This requires "unsafe" slicing. | 376 | // This requires "unsafe" slicing. |
| ... | @@ -346,7 +378,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -346,7 +378,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 346 | } | 378 | } |
| 347 | | 379 | |
| 348 | /// Returns a slice of only the extra capacity after items. | 380 | /// Returns a slice of only the extra capacity after items. |
| 349 | /// This can be useful for writing directly into an `ArrayList`. | 381 | /// This can be useful for writing directly into an ArrayList. |
| 350 | /// Note that such an operation must be followed up with a direct | 382 | /// Note that such an operation must be followed up with a direct |
| 351 | /// modification of `self.items.len`. | 383 | /// modification of `self.items.len`. |
| 352 | pub fn unusedCapacitySlice(self: Self) Slice { | 384 | pub fn unusedCapacitySlice(self: Self) Slice { |
| ... | @@ -355,12 +387,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -355,12 +387,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 355 | }; | 387 | }; |
| 356 | } | 388 | } |
| 357 | | 389 | |
| 358 | /// Bring-your-own allocator with every function call. | 390 | /// An ArrayList, but the allocator is passed as a parameter to the relevant functions |
| 359 | /// Initialize directly and deinitialize with `deinit` or use `toOwnedSlice`. | 391 | /// rather than stored in the struct itself. The same allocator **must** be used throughout |
| | 392 | /// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with |
| | 393 | /// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`. |
| 360 | pub fn ArrayListUnmanaged(comptime T: type) type { | 394 | pub fn ArrayListUnmanaged(comptime T: type) type { |
| 361 | return ArrayListAlignedUnmanaged(T, null); | 395 | return ArrayListAlignedUnmanaged(T, null); |
| 362 | } | 396 | } |
| 363 | | 397 | |
| | 398 | /// An ArrayListAligned, but the allocator is passed as a parameter to the relevant |
| | 399 | /// functions rather than stored in the struct itself. The same allocator **must** |
| | 400 | /// be used throughout the entire lifetime of an ArrayListAlignedUnmanaged. |
| | 401 | /// Initialize directly or with `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`. |
| 364 | pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type { | 402 | pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type { |
| 365 | if (alignment) |a| { | 403 | if (alignment) |a| { |
| 366 | if (a == @alignOf(T)) { | 404 | if (a == @alignOf(T)) { |
| ... | @@ -369,9 +407,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -369,9 +407,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 369 | } | 407 | } |
| 370 | return struct { | 408 | return struct { |
| 371 | const Self = @This(); | 409 | const Self = @This(); |
| 372 | | 410 | /// Contents of the list. Pointers to elements in this slice are |
| 373 | /// Content of the ArrayList. | 411 | /// **invalid after resizing operations** on the ArrayList, unless the |
| | 412 | /// operation explicitly either: (1) states otherwise or (2) lists the |
| | 413 | /// invalidated pointers. |
| | 414 | /// |
| | 415 | /// The allocator used determines how element pointers are |
| | 416 | /// invalidated, so the behavior may vary between lists. To avoid |
| | 417 | /// illegal behavior, take into account the above paragraph plus the |
| | 418 | /// explicit statements given in each method. |
| 374 | items: Slice = &[_]T{}, | 419 | items: Slice = &[_]T{}, |
| | 420 | /// How many T values this list can hold without allocating |
| | 421 | /// additional memory. |
| 375 | capacity: usize = 0, | 422 | capacity: usize = 0, |
| 376 | | 423 | |
| 377 | pub const Slice = if (alignment) |a| ([]align(a) T) else []T; | 424 | pub const Slice = if (alignment) |a| ([]align(a) T) else []T; |
| ... | @@ -395,6 +442,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -395,6 +442,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 395 | self.* = undefined; | 442 | self.* = undefined; |
| 396 | } | 443 | } |
| 397 | | 444 | |
| | 445 | /// Convert this list into an analogous memory-managed one. |
| | 446 | /// The returned list has ownership of the underlying memory. |
| 398 | pub fn toManaged(self: *Self, allocator: *Allocator) ArrayListAligned(T, alignment) { | 447 | pub fn toManaged(self: *Self, allocator: *Allocator) ArrayListAligned(T, alignment) { |
| 399 | return .{ .items = self.items, .capacity = self.capacity, .allocator = allocator }; | 448 | return .{ .items = self.items, .capacity = self.capacity, .allocator = allocator }; |
| 400 | } | 449 | } |
| ... | @@ -414,7 +463,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -414,7 +463,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 414 | } | 463 | } |
| 415 | | 464 | |
| 416 | /// Insert `item` at index `n`. Moves `list[n .. list.len]` | 465 | /// Insert `item` at index `n`. Moves `list[n .. list.len]` |
| 417 | /// to make room. | 466 | /// to higher indices to make room. |
| | 467 | /// This operation is O(N). |
| 418 | pub fn insert(self: *Self, allocator: *Allocator, n: usize, item: T) !void { | 468 | pub fn insert(self: *Self, allocator: *Allocator, n: usize, item: T) !void { |
| 419 | try self.ensureCapacity(allocator, self.items.len + 1); | 469 | try self.ensureCapacity(allocator, self.items.len + 1); |
| 420 | self.items.len += 1; | 470 | self.items.len += 1; |
| ... | @@ -423,8 +473,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -423,8 +473,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 423 | self.items[n] = item; | 473 | self.items[n] = item; |
| 424 | } | 474 | } |
| 425 | | 475 | |
| 426 | /// Insert slice `items` at index `i`. Moves | 476 | /// Insert slice `items` at index `i`. Moves `list[i .. list.len]` to |
| 427 | /// `list[i .. list.len]` to make room. | 477 | /// higher indicices make room. |
| 428 | /// This operation is O(N). | 478 | /// This operation is O(N). |
| 429 | pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: SliceConst) !void { | 479 | pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: SliceConst) !void { |
| 430 | try self.ensureCapacity(allocator, self.items.len + items.len); | 480 | try self.ensureCapacity(allocator, self.items.len + items.len); |
| ... | @@ -435,8 +485,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -435,8 +485,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 435 | } | 485 | } |
| 436 | | 486 | |
| 437 | /// Replace range of elements `list[start..start+len]` with `new_items` | 487 | /// Replace range of elements `list[start..start+len]` with `new_items` |
| 438 | /// grows list if `len < new_items.len`. may allocate | 488 | /// Grows list if `len < new_items.len`. |
| 439 | /// shrinks list if `len > new_items.len` | 489 | /// Shrinks list if `len > new_items.len` |
| | 490 | /// Invalidates pointers if this ArrayList is resized. |
| 440 | pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: SliceConst) !void { | 491 | pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: SliceConst) !void { |
| 441 | var managed = self.toManaged(allocator); | 492 | var managed = self.toManaged(allocator); |
| 442 | try managed.replaceRange(start, len, new_items); | 493 | try managed.replaceRange(start, len, new_items); |
| ... | @@ -457,7 +508,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -457,7 +508,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 457 | } | 508 | } |
| 458 | | 509 | |
| 459 | /// Remove the element at index `i` from the list and return its value. | 510 | /// Remove the element at index `i` from the list and return its value. |
| 460 | /// Asserts the array has at least one item. | 511 | /// Asserts the array has at least one item. Invalidates pointers to |
| | 512 | /// last element. |
| 461 | /// This operation is O(N). | 513 | /// This operation is O(N). |
| 462 | pub fn orderedRemove(self: *Self, i: usize) T { | 514 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 463 | const newlen = self.items.len - 1; | 515 | const newlen = self.items.len - 1; |
| ... | @@ -472,6 +524,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -472,6 +524,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 472 | | 524 | |
| 473 | /// Removes the element at the specified index and returns it. | 525 | /// Removes the element at the specified index and returns it. |
| 474 | /// The empty slot is filled from the end of the list. | 526 | /// The empty slot is filled from the end of the list. |
| | 527 | /// Invalidates pointers to last element. |
| 475 | /// This operation is O(1). | 528 | /// This operation is O(1). |
| 476 | pub fn swapRemove(self: *Self, i: usize) T { | 529 | pub fn swapRemove(self: *Self, i: usize) T { |
| 477 | if (self.items.len - 1 == i) return self.pop(); | 530 | if (self.items.len - 1 == i) return self.pop(); |
| ... | @@ -515,6 +568,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -515,6 +568,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 515 | } | 568 | } |
| 516 | | 569 | |
| 517 | /// Append a value to the list `n` times. | 570 | /// Append a value to the list `n` times. |
| | 571 | /// **Does not** invalidate pointers. |
| 518 | /// Asserts the capacity is enough. | 572 | /// Asserts the capacity is enough. |
| 519 | pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { | 573 | pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { |
| 520 | const new_len = self.items.len + n; | 574 | const new_len = self.items.len + n; |
| ... | @@ -524,14 +578,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -524,14 +578,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 524 | } | 578 | } |
| 525 | | 579 | |
| 526 | /// Adjust the list's length to `new_len`. | 580 | /// Adjust the list's length to `new_len`. |
| 527 | /// Does not initialize added items if any. | 581 | /// Does not initialize added items, if any. |
| 528 | pub fn resize(self: *Self, allocator: *Allocator, new_len: usize) !void { | 582 | pub fn resize(self: *Self, allocator: *Allocator, new_len: usize) !void { |
| 529 | try self.ensureCapacity(allocator, new_len); | 583 | try self.ensureCapacity(allocator, new_len); |
| 530 | self.items.len = new_len; | 584 | self.items.len = new_len; |
| 531 | } | 585 | } |
| 532 | | 586 | |
| 533 | /// Reduce allocated capacity to `new_len`. | 587 | /// Reduce allocated capacity to `new_len`. |
| 534 | /// Invalidates element pointers. | | |
| 535 | pub fn shrink(self: *Self, allocator: *Allocator, new_len: usize) void { | 588 | pub fn shrink(self: *Self, allocator: *Allocator, new_len: usize) void { |
| 536 | assert(new_len <= self.items.len); | 589 | assert(new_len <= self.items.len); |
| 537 | | 590 | |
| ... | @@ -545,13 +598,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -545,13 +598,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 545 | } | 598 | } |
| 546 | | 599 | |
| 547 | /// Reduce length to `new_len`. | 600 | /// Reduce length to `new_len`. |
| 548 | /// Invalidates element pointers. | 601 | /// Invalidates pointers to elements `items[new_len..]`. |
| 549 | /// Keeps capacity the same. | 602 | /// Keeps capacity the same. |
| 550 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { | 603 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 551 | assert(new_len <= self.items.len); | 604 | assert(new_len <= self.items.len); |
| 552 | self.items.len = new_len; | 605 | self.items.len = new_len; |
| 553 | } | 606 | } |
| 554 | | 607 | |
| | 608 | /// Modify the array so that it can hold at least `new_capacity` items. |
| | 609 | /// Invalidates pointers if additional memory is needed. |
| 555 | pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void { | 610 | pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void { |
| 556 | var better_capacity = self.capacity; | 611 | var better_capacity = self.capacity; |
| 557 | if (better_capacity >= new_capacity) return; | 612 | if (better_capacity >= new_capacity) return; |
| ... | @@ -568,13 +623,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -568,13 +623,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 568 | | 623 | |
| 569 | /// Increases the array's length to match the full capacity that is already allocated. | 624 | /// Increases the array's length to match the full capacity that is already allocated. |
| 570 | /// The new elements have `undefined` values. | 625 | /// The new elements have `undefined` values. |
| 571 | /// This operation does not invalidate any element pointers. | 626 | /// **Does not** invalidate pointers. |
| 572 | pub fn expandToCapacity(self: *Self) void { | 627 | pub fn expandToCapacity(self: *Self) void { |
| 573 | self.items.len = self.capacity; | 628 | self.items.len = self.capacity; |
| 574 | } | 629 | } |
| 575 | | 630 | |
| 576 | /// Increase length by 1, returning pointer to the new item. | 631 | /// Increase length by 1, returning pointer to the new item. |
| 577 | /// The returned pointer becomes invalid when the list is resized. | 632 | /// The returned pointer becomes invalid when the list resized. |
| 578 | pub fn addOne(self: *Self, allocator: *Allocator) !*T { | 633 | pub fn addOne(self: *Self, allocator: *Allocator) !*T { |
| 579 | const newlen = self.items.len + 1; | 634 | const newlen = self.items.len + 1; |
| 580 | try self.ensureCapacity(allocator, newlen); | 635 | try self.ensureCapacity(allocator, newlen); |
| ... | @@ -583,8 +638,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -583,8 +638,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 583 | | 638 | |
| 584 | /// Increase length by 1, returning pointer to the new item. | 639 | /// Increase length by 1, returning pointer to the new item. |
| 585 | /// Asserts that there is already space for the new item without allocating more. | 640 | /// Asserts that there is already space for the new item without allocating more. |
| 586 | /// The returned pointer becomes invalid when the list is resized. | 641 | /// **Does not** invalidate pointers. |
| 587 | /// This operation does not invalidate any element pointers. | 642 | /// The returned pointer becomes invalid when the list resized. |
| 588 | pub fn addOneAssumeCapacity(self: *Self) *T { | 643 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 589 | assert(self.items.len < self.capacity); | 644 | assert(self.items.len < self.capacity); |
| 590 | | 645 | |
| ... | @@ -594,6 +649,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -594,6 +649,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 594 | | 649 | |
| 595 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 650 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 596 | /// The return value is an array pointing to the newly allocated elements. | 651 | /// The return value is an array pointing to the newly allocated elements. |
| | 652 | /// The returned pointer becomes invalid when the list is resized. |
| 597 | pub fn addManyAsArray(self: *Self, allocator: *Allocator, comptime n: usize) !*[n]T { | 653 | pub fn addManyAsArray(self: *Self, allocator: *Allocator, comptime n: usize) !*[n]T { |
| 598 | const prev_len = self.items.len; | 654 | const prev_len = self.items.len; |
| 599 | try self.resize(allocator, self.items.len + n); | 655 | try self.resize(allocator, self.items.len + n); |
| ... | @@ -603,6 +659,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -603,6 +659,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 603 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 659 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 604 | /// The return value is an array pointing to the newly allocated elements. | 660 | /// The return value is an array pointing to the newly allocated elements. |
| 605 | /// Asserts that there is already space for the new item without allocating more. | 661 | /// Asserts that there is already space for the new item without allocating more. |
| | 662 | /// **Does not** invalidate pointers. |
| | 663 | /// The returned pointer becomes invalid when the list is resized. |
| 606 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { | 664 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 607 | assert(self.items.len + n <= self.capacity); | 665 | assert(self.items.len + n <= self.capacity); |
| 608 | const prev_len = self.items.len; | 666 | const prev_len = self.items.len; |
| ... | @@ -612,7 +670,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -612,7 +670,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 612 | | 670 | |
| 613 | /// Remove and return the last element from the list. | 671 | /// Remove and return the last element from the list. |
| 614 | /// Asserts the list has at least one item. | 672 | /// Asserts the list has at least one item. |
| 615 | /// This operation does not invalidate any element pointers. | 673 | /// Invalidates pointers to last element. |
| 616 | pub fn pop(self: *Self) T { | 674 | pub fn pop(self: *Self) T { |
| 617 | const val = self.items[self.items.len - 1]; | 675 | const val = self.items[self.items.len - 1]; |
| 618 | self.items.len -= 1; | 676 | self.items.len -= 1; |
| ... | @@ -621,7 +679,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -621,7 +679,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 621 | | 679 | |
| 622 | /// Remove and return the last element from the list. | 680 | /// Remove and return the last element from the list. |
| 623 | /// If the list is empty, returns `null`. | 681 | /// If the list is empty, returns `null`. |
| 624 | /// This operation does not invalidate any element pointers. | 682 | /// Invalidates pointers to last element. |
| 625 | pub fn popOrNull(self: *Self) ?T { | 683 | pub fn popOrNull(self: *Self) ?T { |
| 626 | if (self.items.len == 0) return null; | 684 | if (self.items.len == 0) return null; |
| 627 | return self.pop(); | 685 | return self.pop(); |