| ... | ... | @@ -128,7 +128,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 128 | 128 | |
| 129 | 129 | /// The caller owns the returned memory. Empties this ArrayList. |
| 130 | 130 | pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { |
| 131 | | try self.ensureTotalCapacityPrecise(self.items.len + 1); |
| 131 | try self.ensureTotalCapacityPrecise(try addOrOom(self.items.len, 1)); |
| 132 | 132 | self.appendAssumeCapacity(sentinel); |
| 133 | 133 | const result = try self.toOwnedSlice(); |
| 134 | 134 | return result[0 .. result.len - 1 :sentinel]; |
| ... | ... | @@ -141,25 +141,27 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 141 | 141 | return cloned; |
| 142 | 142 | } |
| 143 | 143 | |
| 144 | | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. |
| 145 | | /// If `n` is equal to the length of the list this operation is equivalent to append. |
| 144 | /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. |
| 145 | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 146 | 146 | /// This operation is O(N). |
| 147 | 147 | /// Invalidates pointers if additional memory is needed. |
| 148 | | pub fn insert(self: *Self, n: usize, item: T) Allocator.Error!void { |
| 149 | | const dst = try self.addManyAt(n, 1); |
| 148 | /// **Asserts that `i <= self.items.len`.** |
| 149 | pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void { |
| 150 | const dst = try self.addManyAt(i, 1); |
| 150 | 151 | dst[0] = item; |
| 151 | 152 | } |
| 152 | 153 | |
| 153 | | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. |
| 154 | | /// If `n` is equal to the length of the list this operation is equivalent to append. |
| 154 | /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. |
| 155 | /// If `i` is equal to the length of the list this operation is equivalent to appendAssumeCapacity. |
| 155 | 156 | /// This operation is O(N). |
| 156 | | /// Asserts that there is enough capacity for the new item. |
| 157 | | pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void { |
| 157 | /// **Asserts that `i <= self.items.len`.** |
| 158 | /// **Asserts that `self.items.len < self.capacity` .** |
| 159 | pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { |
| 158 | 160 | assert(self.items.len < self.capacity); |
| 159 | 161 | self.items.len += 1; |
| 160 | 162 | |
| 161 | | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); |
| 162 | | self.items[n] = item; |
| 163 | mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); |
| 164 | self.items[i] = item; |
| 163 | 165 | } |
| 164 | 166 | |
| 165 | 167 | /// Add `count` new elements at position `index`, which have |
| ... | ... | @@ -169,8 +171,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 169 | 171 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 170 | 172 | /// Invalidates all pre-existing element pointers if capacity must be |
| 171 | 173 | /// increased to accomodate the new elements. |
| 174 | /// **Asserts that `index <= self.items.len`.** |
| 172 | 175 | pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T { |
| 173 | | const new_len = self.items.len + count; |
| 176 | const new_len = try addOrOom(self.items.len, count); |
| 174 | 177 | |
| 175 | 178 | if (self.capacity >= new_len) |
| 176 | 179 | return addManyAtAssumeCapacity(self, index, count); |
| ... | ... | @@ -205,9 +208,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 205 | 208 | /// `undefined` values. Returns a slice pointing to the newly allocated |
| 206 | 209 | /// elements, which becomes invalid after various `ArrayList` |
| 207 | 210 | /// operations. |
| 208 | | /// Asserts that there is enough capacity for the new elements. |
| 209 | 211 | /// Invalidates pre-existing pointers to elements at and after `index`, but |
| 210 | 212 | /// does not invalidate any before that. |
| 213 | /// **Asserts that `index <= self.items.len`.** |
| 214 | /// **Asserts that the list can hold `count` additional items.** |
| 211 | 215 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 212 | 216 | const new_len = self.items.len + count; |
| 213 | 217 | assert(self.capacity >= new_len); |
| ... | ... | @@ -224,6 +228,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 224 | 228 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 225 | 229 | /// Invalidates all pre-existing element pointers if capacity must be |
| 226 | 230 | /// increased to accomodate the new elements. |
| 231 | /// **Asserts that `index <= self.items.len`.** |
| 227 | 232 | pub fn insertSlice( |
| 228 | 233 | self: *Self, |
| 229 | 234 | index: usize, |
| ... | ... | @@ -237,8 +242,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 237 | 242 | /// Grows list if `len < new_items.len`. |
| 238 | 243 | /// Shrinks list if `len > new_items.len`. |
| 239 | 244 | /// Invalidates pointers if this ArrayList is resized. |
| 245 | /// **Asserts that `start <= self.items.len`.** |
| 240 | 246 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { |
| 241 | | const after_range = start + len; |
| 247 | const after_range = try addOrOom(start, len); |
| 242 | 248 | const range = self.items[start..after_range]; |
| 243 | 249 | |
| 244 | 250 | if (range.len == new_items.len) |
| ... | ... | @@ -251,7 +257,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 251 | 257 | try self.insertSlice(after_range, rest); |
| 252 | 258 | } else { |
| 253 | 259 | @memcpy(range[0..new_items.len], new_items); |
| 254 | | const after_subrange = start + new_items.len; |
| 260 | const after_subrange = try addOrOom(start, new_items.len); |
| 255 | 261 | |
| 256 | 262 | for (self.items[after_range..], 0..) |item, i| { |
| 257 | 263 | self.items[after_subrange..][i] = item; |
| ... | ... | @@ -261,16 +267,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 261 | 267 | } |
| 262 | 268 | } |
| 263 | 269 | |
| 264 | | /// Extend the list by 1 element. Allocates more memory as necessary. |
| 270 | /// Extends the list by 1 element. Allocates more memory as necessary. |
| 265 | 271 | /// Invalidates pointers if additional memory is needed. |
| 266 | 272 | pub fn append(self: *Self, item: T) Allocator.Error!void { |
| 267 | 273 | const new_item_ptr = try self.addOne(); |
| 268 | 274 | new_item_ptr.* = item; |
| 269 | 275 | } |
| 270 | 276 | |
| 271 | | /// Extend the list by 1 element, but assert `self.capacity` |
| 272 | | /// is sufficient to hold an additional item. **Does not** |
| 277 | /// Extends the list by 1 element. Does not |
| 273 | 278 | /// invalidate pointers. |
| 279 | /// **Asserts that the list can hold one additional item.** |
| 274 | 280 | pub fn appendAssumeCapacity(self: *Self, item: T) void { |
| 275 | 281 | const new_item_ptr = self.addOneAssumeCapacity(); |
| 276 | 282 | new_item_ptr.* = item; |
| ... | ... | @@ -278,10 +284,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 278 | 284 | |
| 279 | 285 | /// Remove the element at index `i`, shift elements after index |
| 280 | 286 | /// `i` forward, and return the removed element. |
| 281 | | /// Asserts the array has at least one item. |
| 282 | 287 | /// Invalidates pointers to end of list. |
| 283 | 288 | /// This operation is O(N). |
| 284 | 289 | /// This preserves item order. Use `swapRemove` if order preservation is not important. |
| 290 | /// **Asserts that `i < self.items.len`.** |
| 291 | /// **Asserts that the list is not empty.** |
| 285 | 292 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 286 | 293 | const newlen = self.items.len - 1; |
| 287 | 294 | if (newlen == i) return self.pop(); |
| ... | ... | @@ -297,6 +304,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 297 | 304 | /// The empty slot is filled from the end of the list. |
| 298 | 305 | /// This operation is O(1). |
| 299 | 306 | /// This may not preserve item order. Use `orderedRemove` if you need to preserve order. |
| 307 | /// **Asserts that `i < self.items.len`.** |
| 308 | /// **Asserts that the list is not empty.** |
| 300 | 309 | pub fn swapRemove(self: *Self, i: usize) T { |
| 301 | 310 | if (self.items.len - 1 == i) return self.pop(); |
| 302 | 311 | |
| ... | ... | @@ -313,8 +322,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 313 | 322 | self.appendSliceAssumeCapacity(items); |
| 314 | 323 | } |
| 315 | 324 | |
| 316 | | /// Append the slice of items to the list, asserting the capacity is already |
| 317 | | /// enough to store the new items. **Does not** invalidate pointers. |
| 325 | /// Append the slice of items to the list. Does not invalidate pointers. |
| 326 | /// **Asserts that the list can hold `items.len` additional items.** |
| 318 | 327 | pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { |
| 319 | 328 | const old_len = self.items.len; |
| 320 | 329 | const new_len = old_len + items.len; |
| ... | ... | @@ -332,10 +341,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 332 | 341 | self.appendUnalignedSliceAssumeCapacity(items); |
| 333 | 342 | } |
| 334 | 343 | |
| 335 | | /// Append the slice of items to the list, asserting the capacity is already |
| 336 | | /// enough to store the new items. **Does not** invalidate pointers. |
| 344 | /// Append the slice of items to the list. **Does not** invalidate pointers. |
| 337 | 345 | /// Only call this function if calling `appendSliceAssumeCapacity` instead |
| 338 | 346 | /// would be a compile error. |
| 347 | /// **Asserts that the list can hold `items.len` additional items.** |
| 339 | 348 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { |
| 340 | 349 | const old_len = self.items.len; |
| 341 | 350 | const new_len = old_len + items.len; |
| ... | ... | @@ -348,7 +357,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 348 | 357 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ |
| 349 | 358 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") |
| 350 | 359 | else |
| 351 | | std.io.Writer(*Self, error{OutOfMemory}, appendWrite); |
| 360 | std.io.Writer(*Self, Allocator.Error, appendWrite); |
| 352 | 361 | |
| 353 | 362 | /// Initializes a Writer which will append to the list. |
| 354 | 363 | pub fn writer(self: *Self) Writer { |
| ... | ... | @@ -370,14 +379,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 370 | 379 | /// have a more optimal memset codegen in case it has a repeated byte pattern. |
| 371 | 380 | pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void { |
| 372 | 381 | const old_len = self.items.len; |
| 373 | | try self.resize(self.items.len + n); |
| 382 | try self.resize(try addOrOom(self.items.len, n)); |
| 374 | 383 | @memset(self.items[old_len..self.items.len], value); |
| 375 | 384 | } |
| 376 | 385 | |
| 377 | 386 | /// Append a value to the list `n` times. |
| 378 | | /// Asserts the capacity is enough. **Does not** invalidate pointers. |
| 387 | /// Does not invalidate pointers. |
| 379 | 388 | /// The function is inline so that a comptime-known `value` parameter will |
| 380 | 389 | /// have a more optimal memset codegen in case it has a repeated byte pattern. |
| 390 | /// **Asserts that the list can hold `n` additional items.** |
| 381 | 391 | pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { |
| 382 | 392 | const new_len = self.items.len + n; |
| 383 | 393 | assert(new_len <= self.capacity); |
| ... | ... | @@ -395,6 +405,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 395 | 405 | |
| 396 | 406 | /// Reduce allocated capacity to `new_len`. |
| 397 | 407 | /// May invalidate element pointers. |
| 408 | /// **Asserts that `new_len <= self.items.len`.** |
| 398 | 409 | pub fn shrinkAndFree(self: *Self, new_len: usize) void { |
| 399 | 410 | var unmanaged = self.moveToUnmanaged(); |
| 400 | 411 | unmanaged.shrinkAndFree(self.allocator, new_len); |
| ... | ... | @@ -403,6 +414,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 403 | 414 | |
| 404 | 415 | /// Reduce length to `new_len`. |
| 405 | 416 | /// Invalidates pointers for the elements `items[new_len..]`. |
| 417 | /// **Asserts that `new_len <= self.items.len`.** |
| 406 | 418 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 407 | 419 | assert(new_len <= self.items.len); |
| 408 | 420 | self.items.len = new_len; |
| ... | ... | @@ -466,7 +478,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 466 | 478 | /// Modify the array so that it can hold at least `additional_count` **more** items. |
| 467 | 479 | /// Invalidates pointers if additional memory is needed. |
| 468 | 480 | pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void { |
| 469 | | return self.ensureTotalCapacity(self.items.len + additional_count); |
| 481 | return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count)); |
| 470 | 482 | } |
| 471 | 483 | |
| 472 | 484 | /// Increases the array's length to match the full capacity that is already allocated. |
| ... | ... | @@ -478,14 +490,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 478 | 490 | /// Increase length by 1, returning pointer to the new item. |
| 479 | 491 | /// The returned pointer becomes invalid when the list resized. |
| 480 | 492 | pub fn addOne(self: *Self) Allocator.Error!*T { |
| 481 | | try self.ensureTotalCapacity(self.items.len + 1); |
| 493 | try self.ensureUnusedCapacity(1); |
| 482 | 494 | return self.addOneAssumeCapacity(); |
| 483 | 495 | } |
| 484 | 496 | |
| 485 | 497 | /// Increase length by 1, returning pointer to the new item. |
| 486 | | /// Asserts that there is already space for the new item without allocating more. |
| 487 | 498 | /// The returned pointer becomes invalid when the list is resized. |
| 488 | | /// **Does not** invalidate element pointers. |
| 499 | /// Does not invalidate element pointers. |
| 500 | /// **Asserts that the list can hold one additional item.** |
| 489 | 501 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 490 | 502 | assert(self.items.len < self.capacity); |
| 491 | 503 | self.items.len += 1; |
| ... | ... | @@ -498,15 +510,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 498 | 510 | /// Resizes list if `self.capacity` is not large enough. |
| 499 | 511 | pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T { |
| 500 | 512 | const prev_len = self.items.len; |
| 501 | | try self.resize(self.items.len + n); |
| 513 | try self.resize(try addOrOom(self.items.len, n)); |
| 502 | 514 | return self.items[prev_len..][0..n]; |
| 503 | 515 | } |
| 504 | 516 | |
| 505 | 517 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 506 | 518 | /// The return value is an array pointing to the newly allocated elements. |
| 507 | | /// Asserts that there is already space for the new item without allocating more. |
| 508 | | /// **Does not** invalidate element pointers. |
| 519 | /// Does not invalidate element pointers. |
| 509 | 520 | /// The returned pointer becomes invalid when the list is resized. |
| 521 | /// **Asserts that the list can hold `n` additional items.** |
| 510 | 522 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 511 | 523 | assert(self.items.len + n <= self.capacity); |
| 512 | 524 | const prev_len = self.items.len; |
| ... | ... | @@ -520,15 +532,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 520 | 532 | /// Resizes list if `self.capacity` is not large enough. |
| 521 | 533 | pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T { |
| 522 | 534 | const prev_len = self.items.len; |
| 523 | | try self.resize(self.items.len + n); |
| 535 | try self.resize(try addOrOom(self.items.len, n)); |
| 524 | 536 | return self.items[prev_len..][0..n]; |
| 525 | 537 | } |
| 526 | 538 | |
| 527 | 539 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 528 | 540 | /// The return value is a slice pointing to the newly allocated elements. |
| 529 | | /// Asserts that there is already space for the new item without allocating more. |
| 530 | | /// **Does not** invalidate element pointers. |
| 541 | /// Does not invalidate element pointers. |
| 531 | 542 | /// The returned pointer becomes invalid when the list is resized. |
| 543 | /// **Asserts that the list can hold `n` additional items.** |
| 532 | 544 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { |
| 533 | 545 | assert(self.items.len + n <= self.capacity); |
| 534 | 546 | const prev_len = self.items.len; |
| ... | ... | @@ -537,8 +549,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 537 | 549 | } |
| 538 | 550 | |
| 539 | 551 | /// Remove and return the last element from the list. |
| 540 | | /// Asserts the list has at least one item. |
| 541 | 552 | /// Invalidates pointers to the removed element. |
| 553 | /// **Asserts that the list is not empty.** |
| 542 | 554 | pub fn pop(self: *Self) T { |
| 543 | 555 | const val = self.items[self.items.len - 1]; |
| 544 | 556 | self.items.len -= 1; |
| ... | ... | @@ -568,15 +580,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 568 | 580 | return self.allocatedSlice()[self.items.len..]; |
| 569 | 581 | } |
| 570 | 582 | |
| 571 | | /// Return the last element from the list. |
| 572 | | /// Asserts the list has at least one item. |
| 583 | /// Returns the last element from the list. |
| 584 | /// **Asserts that the list is not empty.** |
| 573 | 585 | pub fn getLast(self: Self) T { |
| 574 | 586 | const val = self.items[self.items.len - 1]; |
| 575 | 587 | return val; |
| 576 | 588 | } |
| 577 | 589 | |
| 578 | | /// Return the last element from the list, or |
| 579 | | /// return `null` if list is empty. |
| 590 | /// Returns the last element from the list, or `null` if list is empty. |
| 580 | 591 | pub fn getLastOrNull(self: Self) ?T { |
| 581 | 592 | if (self.items.len == 0) return null; |
| 582 | 593 | return self.getLast(); |
| ... | ... | @@ -635,8 +646,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 635 | 646 | |
| 636 | 647 | /// Initialize with externally-managed memory. The buffer determines the |
| 637 | 648 | /// capacity, and the length is set to zero. |
| 638 | | /// When initialized this way, all methods that accept an Allocator |
| 639 | | /// argument are illegal to call. |
| 649 | /// **When initialized this way, all methods that accept an Allocator |
| 650 | /// argument cause illegal behavior**. |
| 640 | 651 | pub fn initBuffer(buffer: Slice) Self { |
| 641 | 652 | return .{ |
| 642 | 653 | .items = buffer[0..0], |
| ... | ... | @@ -695,7 +706,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 695 | 706 | |
| 696 | 707 | /// The caller owns the returned memory. ArrayList becomes empty. |
| 697 | 708 | pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { |
| 698 | | try self.ensureTotalCapacityPrecise(allocator, self.items.len + 1); |
| 709 | try self.ensureTotalCapacityPrecise(allocator, try addOrOom(self.items.len, 1)); |
| 699 | 710 | self.appendAssumeCapacity(sentinel); |
| 700 | 711 | const result = try self.toOwnedSlice(allocator); |
| 701 | 712 | return result[0 .. result.len - 1 :sentinel]; |
| ... | ... | @@ -708,25 +719,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 708 | 719 | return cloned; |
| 709 | 720 | } |
| 710 | 721 | |
| 711 | | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. |
| 712 | | /// If `n` is equal to the length of the list this operation is equivalent to append. |
| 722 | /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. |
| 723 | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 713 | 724 | /// This operation is O(N). |
| 714 | 725 | /// Invalidates pointers if additional memory is needed. |
| 715 | | pub fn insert(self: *Self, allocator: Allocator, n: usize, item: T) Allocator.Error!void { |
| 716 | | const dst = try self.addManyAt(allocator, n, 1); |
| 726 | /// **Asserts that `i < self.items.len`.** |
| 727 | pub fn insert(self: *Self, allocator: Allocator, i: usize, item: T) Allocator.Error!void { |
| 728 | const dst = try self.addManyAt(allocator, i, 1); |
| 717 | 729 | dst[0] = item; |
| 718 | 730 | } |
| 719 | 731 | |
| 720 | | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. |
| 721 | | /// If `n` is equal to the length of the list this operation is equivalent to append. |
| 732 | /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. |
| 733 | /// If in` is equal to the length of the list this operation is equivalent to append. |
| 722 | 734 | /// This operation is O(N). |
| 723 | | /// Asserts that there is enough capacity for the new item. |
| 724 | | pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void { |
| 735 | /// **Asserts that `i < self.items.len`.** |
| 736 | /// **Asserts that the list can hold one additional item.** |
| 737 | pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { |
| 725 | 738 | assert(self.items.len < self.capacity); |
| 726 | 739 | self.items.len += 1; |
| 727 | 740 | |
| 728 | | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); |
| 729 | | self.items[n] = item; |
| 741 | mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); |
| 742 | self.items[i] = item; |
| 730 | 743 | } |
| 731 | 744 | |
| 732 | 745 | /// Add `count` new elements at position `index`, which have |
| ... | ... | @@ -736,6 +749,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 736 | 749 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 737 | 750 | /// Invalidates all pre-existing element pointers if capacity must be |
| 738 | 751 | /// increased to accomodate the new elements. |
| 752 | /// **Asserts that `index <= self.items.len`.** |
| 739 | 753 | pub fn addManyAt( |
| 740 | 754 | self: *Self, |
| 741 | 755 | allocator: Allocator, |
| ... | ... | @@ -751,9 +765,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 751 | 765 | /// `undefined` values. Returns a slice pointing to the newly allocated |
| 752 | 766 | /// elements, which becomes invalid after various `ArrayList` |
| 753 | 767 | /// operations. |
| 754 | | /// Asserts that there is enough capacity for the new elements. |
| 755 | 768 | /// Invalidates pre-existing pointers to elements at and after `index`, but |
| 756 | 769 | /// does not invalidate any before that. |
| 770 | /// **Asserts that `index <= self.items.len`.** |
| 771 | /// **Asserts that the list can hold `count` additional items.** |
| 757 | 772 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 758 | 773 | const new_len = self.items.len + count; |
| 759 | 774 | assert(self.capacity >= new_len); |
| ... | ... | @@ -770,6 +785,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 770 | 785 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 771 | 786 | /// Invalidates all pre-existing element pointers if capacity must be |
| 772 | 787 | /// increased to accomodate the new elements. |
| 788 | /// **Asserts that `index <= self.items.len`.** |
| 773 | 789 | pub fn insertSlice( |
| 774 | 790 | self: *Self, |
| 775 | 791 | allocator: Allocator, |
| ... | ... | @@ -788,6 +804,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 788 | 804 | /// Grows list if `len < new_items.len`. |
| 789 | 805 | /// Shrinks list if `len > new_items.len` |
| 790 | 806 | /// Invalidates pointers if this ArrayList is resized. |
| 807 | /// **Asserts that `start <= self.items.len`.** |
| 791 | 808 | pub fn replaceRange( |
| 792 | 809 | self: *Self, |
| 793 | 810 | allocator: Allocator, |
| ... | ... | @@ -807,17 +824,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 807 | 824 | new_item_ptr.* = item; |
| 808 | 825 | } |
| 809 | 826 | |
| 810 | | /// Extend the list by 1 element, but asserting `self.capacity` |
| 811 | | /// is sufficient to hold an additional item. |
| 827 | /// Extend the list by 1 element. |
| 828 | /// **Asserts that the list can hold one additional item.** |
| 812 | 829 | pub fn appendAssumeCapacity(self: *Self, item: T) void { |
| 813 | 830 | const new_item_ptr = self.addOneAssumeCapacity(); |
| 814 | 831 | new_item_ptr.* = item; |
| 815 | 832 | } |
| 816 | 833 | |
| 817 | 834 | /// Remove the element at index `i` from the list and return its value. |
| 818 | | /// Asserts the array has at least one item. Invalidates pointers to |
| 819 | | /// last element. |
| 835 | /// Invalidates pointers to the last element. |
| 820 | 836 | /// This operation is O(N). |
| 837 | /// **Asserts that `i < self.items.len`.** |
| 838 | /// **Asserts that the list is not empty.** |
| 821 | 839 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 822 | 840 | const newlen = self.items.len - 1; |
| 823 | 841 | if (newlen == i) return self.pop(); |
| ... | ... | @@ -833,6 +851,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 833 | 851 | /// The empty slot is filled from the end of the list. |
| 834 | 852 | /// Invalidates pointers to last element. |
| 835 | 853 | /// This operation is O(1). |
| 854 | /// **Asserts that `i < self.items.len`.** |
| 855 | /// **Asserts that the list is not empty.** |
| 836 | 856 | pub fn swapRemove(self: *Self, i: usize) T { |
| 837 | 857 | if (self.items.len - 1 == i) return self.pop(); |
| 838 | 858 | |
| ... | ... | @@ -849,8 +869,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 849 | 869 | self.appendSliceAssumeCapacity(items); |
| 850 | 870 | } |
| 851 | 871 | |
| 852 | | /// Append the slice of items to the list, asserting the capacity is enough |
| 853 | | /// to store the new items. |
| 872 | /// Append the slice of items to the list. |
| 873 | /// **Asserts that the list can hold `items.len` additional items.** |
| 854 | 874 | pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { |
| 855 | 875 | const old_len = self.items.len; |
| 856 | 876 | const new_len = old_len + items.len; |
| ... | ... | @@ -868,9 +888,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 868 | 888 | self.appendUnalignedSliceAssumeCapacity(items); |
| 869 | 889 | } |
| 870 | 890 | |
| 871 | | /// Append an unaligned slice of items to the list, asserting the capacity is enough |
| 872 | | /// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity` |
| 891 | /// Append an unaligned slice of items to the list. |
| 892 | /// Only call this function if a call to `appendSliceAssumeCapacity` |
| 873 | 893 | /// instead would be a compile error. |
| 894 | /// **Asserts that the list can hold `items.len` additional items.** |
| 874 | 895 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { |
| 875 | 896 | const old_len = self.items.len; |
| 876 | 897 | const new_len = old_len + items.len; |
| ... | ... | @@ -888,7 +909,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 888 | 909 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ |
| 889 | 910 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") |
| 890 | 911 | else |
| 891 | | std.io.Writer(WriterContext, error{OutOfMemory}, appendWrite); |
| 912 | std.io.Writer(WriterContext, Allocator.Error, appendWrite); |
| 892 | 913 | |
| 893 | 914 | /// Initializes a Writer which will append to the list. |
| 894 | 915 | pub fn writer(self: *Self, allocator: Allocator) Writer { |
| ... | ... | @@ -910,15 +931,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 910 | 931 | /// have a more optimal memset codegen in case it has a repeated byte pattern. |
| 911 | 932 | pub inline fn appendNTimes(self: *Self, allocator: Allocator, value: T, n: usize) Allocator.Error!void { |
| 912 | 933 | const old_len = self.items.len; |
| 913 | | try self.resize(allocator, self.items.len + n); |
| 934 | try self.resize(allocator, try addOrOom(self.items.len, n)); |
| 914 | 935 | @memset(self.items[old_len..self.items.len], value); |
| 915 | 936 | } |
| 916 | 937 | |
| 917 | 938 | /// Append a value to the list `n` times. |
| 918 | 939 | /// **Does not** invalidate pointers. |
| 919 | | /// Asserts the capacity is enough. |
| 920 | 940 | /// The function is inline so that a comptime-known `value` parameter will |
| 921 | | /// have a more optimal memset codegen in case it has a repeated byte pattern. |
| 941 | /// have better memset codegen in case it has a repeated byte pattern. |
| 942 | /// **Asserts that the list can hold `n` additional items.** |
| 922 | 943 | pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { |
| 923 | 944 | const new_len = self.items.len + n; |
| 924 | 945 | assert(new_len <= self.capacity); |
| ... | ... | @@ -936,6 +957,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 936 | 957 | |
| 937 | 958 | /// Reduce allocated capacity to `new_len`. |
| 938 | 959 | /// May invalidate element pointers. |
| 960 | /// **Asserts that `new_len <= self.items.len`.** |
| 939 | 961 | pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void { |
| 940 | 962 | assert(new_len <= self.items.len); |
| 941 | 963 | |
| ... | ... | @@ -968,6 +990,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 968 | 990 | /// Reduce length to `new_len`. |
| 969 | 991 | /// Invalidates pointers to elements `items[new_len..]`. |
| 970 | 992 | /// Keeps capacity the same. |
| 993 | /// **Asserts that `new_len <= self.items.len`.** |
| 971 | 994 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 972 | 995 | assert(new_len <= self.items.len); |
| 973 | 996 | self.items.len = new_len; |
| ... | ... | @@ -1030,12 +1053,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1030 | 1053 | allocator: Allocator, |
| 1031 | 1054 | additional_count: usize, |
| 1032 | 1055 | ) Allocator.Error!void { |
| 1033 | | return self.ensureTotalCapacity(allocator, self.items.len + additional_count); |
| 1056 | return self.ensureTotalCapacity(allocator, try addOrOom(self.items.len, additional_count)); |
| 1034 | 1057 | } |
| 1035 | 1058 | |
| 1036 | 1059 | /// Increases the array's length to match the full capacity that is already allocated. |
| 1037 | 1060 | /// The new elements have `undefined` values. |
| 1038 | | /// **Does not** invalidate pointers. |
| 1061 | /// Does not invalidate pointers. |
| 1039 | 1062 | pub fn expandToCapacity(self: *Self) void { |
| 1040 | 1063 | self.items.len = self.capacity; |
| 1041 | 1064 | } |
| ... | ... | @@ -1043,15 +1066,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1043 | 1066 | /// Increase length by 1, returning pointer to the new item. |
| 1044 | 1067 | /// The returned pointer becomes invalid when the list resized. |
| 1045 | 1068 | pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T { |
| 1046 | | const newlen = self.items.len + 1; |
| 1069 | const newlen = try addOrOom(self.items.len, 1); |
| 1047 | 1070 | try self.ensureTotalCapacity(allocator, newlen); |
| 1048 | 1071 | return self.addOneAssumeCapacity(); |
| 1049 | 1072 | } |
| 1050 | 1073 | |
| 1051 | 1074 | /// Increase length by 1, returning pointer to the new item. |
| 1052 | | /// Asserts that there is already space for the new item without allocating more. |
| 1053 | 1075 | /// **Does not** invalidate pointers. |
| 1054 | 1076 | /// The returned pointer becomes invalid when the list resized. |
| 1077 | /// **Asserts that the list can hold one additional item.** |
| 1055 | 1078 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 1056 | 1079 | assert(self.items.len < self.capacity); |
| 1057 | 1080 | |
| ... | ... | @@ -1064,15 +1087,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1064 | 1087 | /// The returned pointer becomes invalid when the list is resized. |
| 1065 | 1088 | pub fn addManyAsArray(self: *Self, allocator: Allocator, comptime n: usize) Allocator.Error!*[n]T { |
| 1066 | 1089 | const prev_len = self.items.len; |
| 1067 | | try self.resize(allocator, self.items.len + n); |
| 1090 | try self.resize(allocator, try addOrOom(self.items.len, n)); |
| 1068 | 1091 | return self.items[prev_len..][0..n]; |
| 1069 | 1092 | } |
| 1070 | 1093 | |
| 1071 | 1094 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1072 | 1095 | /// The return value is an array pointing to the newly allocated elements. |
| 1073 | | /// Asserts that there is already space for the new item without allocating more. |
| 1074 | 1096 | /// **Does not** invalidate pointers. |
| 1075 | 1097 | /// The returned pointer becomes invalid when the list is resized. |
| 1098 | /// **Asserts that the list can hold `n` additional items.** |
| 1076 | 1099 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 1077 | 1100 | assert(self.items.len + n <= self.capacity); |
| 1078 | 1101 | const prev_len = self.items.len; |
| ... | ... | @@ -1086,15 +1109,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1086 | 1109 | /// Resizes list if `self.capacity` is not large enough. |
| 1087 | 1110 | pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T { |
| 1088 | 1111 | const prev_len = self.items.len; |
| 1089 | | try self.resize(allocator, self.items.len + n); |
| 1112 | try self.resize(allocator, try addOrOom(self.items.len, n)); |
| 1090 | 1113 | return self.items[prev_len..][0..n]; |
| 1091 | 1114 | } |
| 1092 | 1115 | |
| 1093 | 1116 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1094 | 1117 | /// The return value is a slice pointing to the newly allocated elements. |
| 1095 | | /// Asserts that there is already space for the new item without allocating more. |
| 1096 | | /// **Does not** invalidate element pointers. |
| 1118 | /// Does not invalidate element pointers. |
| 1097 | 1119 | /// The returned pointer becomes invalid when the list is resized. |
| 1120 | /// **Asserts that the list can hold `n` additional items.** |
| 1098 | 1121 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { |
| 1099 | 1122 | assert(self.items.len + n <= self.capacity); |
| 1100 | 1123 | const prev_len = self.items.len; |
| ... | ... | @@ -1103,8 +1126,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1103 | 1126 | } |
| 1104 | 1127 | |
| 1105 | 1128 | /// Remove and return the last element from the list. |
| 1106 | | /// Asserts the list has at least one item. |
| 1107 | 1129 | /// Invalidates pointers to last element. |
| 1130 | /// **Asserts that the list is not empty.** |
| 1108 | 1131 | pub fn pop(self: *Self) T { |
| 1109 | 1132 | const val = self.items[self.items.len - 1]; |
| 1110 | 1133 | self.items.len -= 1; |
| ... | ... | @@ -1134,7 +1157,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1134 | 1157 | } |
| 1135 | 1158 | |
| 1136 | 1159 | /// Return the last element from the list. |
| 1137 | | /// Asserts the list has at least one item. |
| 1160 | /// **Asserts that the list is not empty.** |
| 1138 | 1161 | pub fn getLast(self: Self) T { |
| 1139 | 1162 | const val = self.items[self.items.len - 1]; |
| 1140 | 1163 | return val; |
| ... | ... | @@ -1160,6 +1183,14 @@ fn growCapacity(current: usize, minimum: usize) usize { |
| 1160 | 1183 | } |
| 1161 | 1184 | } |
| 1162 | 1185 | |
| 1186 | /// Adds a and b, returning `error.OutOfMemory` if overflow occurred. |
| 1187 | /// This is equivalent to `math.add`. See #18467 for why it is used. |
| 1188 | fn addOrOom(a: usize, b: usize) error{OutOfMemory}!usize { |
| 1189 | const ov = @addWithOverflow(a, b); |
| 1190 | if (ov[1] != 0) return error.OutOfMemory; |
| 1191 | return ov[0]; |
| 1192 | } |
| 1193 | |
| 1163 | 1194 | test "std.ArrayList/ArrayListUnmanaged.init" { |
| 1164 | 1195 | { |
| 1165 | 1196 | var list = ArrayList(i32).init(testing.allocator); |
| ... | ... | @@ -1952,3 +1983,49 @@ test "std.ArrayList(u32).getLastOrNull()" { |
| 1952 | 1983 | const const_list = list; |
| 1953 | 1984 | try testing.expectEqual(const_list.getLastOrNull().?, 2); |
| 1954 | 1985 | } |
| 1986 | |
| 1987 | test "return OutOfMemory when capacity would exceed maximum usize integer value" { |
| 1988 | // Because a portable way to create maxInt(usize)-sized slices does not seem to exist yet, this |
| 1989 | // will have to do. |
| 1990 | |
| 1991 | const a = testing.allocator; |
| 1992 | |
| 1993 | var alu = ArrayListUnmanaged(u32){ |
| 1994 | .items = undefined, |
| 1995 | .capacity = math.maxInt(usize), |
| 1996 | }; |
| 1997 | alu.items.len = math.maxInt(usize); |
| 1998 | |
| 1999 | try testing.expectError(error.OutOfMemory, alu.append(a, undefined)); |
| 2000 | try testing.expectError(error.OutOfMemory, alu.appendSlice(a, &.{undefined})); |
| 2001 | try testing.expectError(error.OutOfMemory, alu.appendNTimes(a, undefined, 1)); |
| 2002 | try testing.expectError(error.OutOfMemory, alu.appendUnalignedSlice(a, &.{undefined})); |
| 2003 | try testing.expectError(error.OutOfMemory, alu.addOne(a)); |
| 2004 | try testing.expectError(error.OutOfMemory, alu.addManyAt(a, 0, 1)); |
| 2005 | try testing.expectError(error.OutOfMemory, alu.addManyAsArray(a, 1)); |
| 2006 | try testing.expectError(error.OutOfMemory, alu.addManyAsSlice(a, 1)); |
| 2007 | try testing.expectError(error.OutOfMemory, alu.insert(a, 0, undefined)); |
| 2008 | try testing.expectError(error.OutOfMemory, alu.insertSlice(a, 0, &.{undefined})); |
| 2009 | try testing.expectError(error.OutOfMemory, alu.toOwnedSliceSentinel(a, 0)); |
| 2010 | try testing.expectError(error.OutOfMemory, alu.ensureUnusedCapacity(a, 1)); |
| 2011 | |
| 2012 | var al = ArrayList(u32){ |
| 2013 | .items = undefined, |
| 2014 | .capacity = math.maxInt(usize), |
| 2015 | .allocator = a, |
| 2016 | }; |
| 2017 | al.items.len = math.maxInt(usize); |
| 2018 | |
| 2019 | try testing.expectError(error.OutOfMemory, al.append(undefined)); |
| 2020 | try testing.expectError(error.OutOfMemory, al.appendSlice(&.{undefined})); |
| 2021 | try testing.expectError(error.OutOfMemory, al.appendNTimes(undefined, 1)); |
| 2022 | try testing.expectError(error.OutOfMemory, al.appendUnalignedSlice(&.{undefined})); |
| 2023 | try testing.expectError(error.OutOfMemory, al.addOne()); |
| 2024 | try testing.expectError(error.OutOfMemory, al.addManyAt(0, 1)); |
| 2025 | try testing.expectError(error.OutOfMemory, al.addManyAsArray(1)); |
| 2026 | try testing.expectError(error.OutOfMemory, al.addManyAsSlice(1)); |
| 2027 | try testing.expectError(error.OutOfMemory, al.insert(0, undefined)); |
| 2028 | try testing.expectError(error.OutOfMemory, al.insertSlice(0, &.{undefined})); |
| 2029 | try testing.expectError(error.OutOfMemory, al.toOwnedSliceSentinel(0)); |
| 2030 | try testing.expectError(error.OutOfMemory, al.ensureUnusedCapacity(1)); |
| 2031 | } |