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