| ... | @@ -10,7 +10,7 @@ const Allocator = mem.Allocator; | ... | @@ -10,7 +10,7 @@ const Allocator = mem.Allocator; |
| 10 | /// This is a wrapper around an array of T values. Initialize with `init`. | 10 | /// This is a wrapper around an array of T values. Initialize with `init`. |
| 11 | /// | 11 | /// |
| 12 | /// This struct internally stores a `std.mem.Allocator` for memory management. | 12 | /// This struct internally stores a `std.mem.Allocator` for memory management. |
| 13 | /// To manually specify an allocator with each method call see `ArrayListUnmanaged`. | 13 | /// To manually specify an allocator with each function call see `ArrayListUnmanaged`. |
| 14 | pub fn ArrayList(comptime T: type) type { | 14 | pub fn ArrayList(comptime T: type) type { |
| 15 | return ArrayListAligned(T, null); | 15 | return ArrayListAligned(T, null); |
| 16 | } | 16 | } |
| ... | @@ -21,7 +21,7 @@ pub fn ArrayList(comptime T: type) type { | ... | @@ -21,7 +21,7 @@ pub fn ArrayList(comptime T: type) type { |
| 21 | /// Initialize with `init`. | 21 | /// Initialize with `init`. |
| 22 | /// | 22 | /// |
| 23 | /// This struct internally stores a `std.mem.Allocator` for memory management. | 23 | /// This struct internally stores a `std.mem.Allocator` for memory management. |
| 24 | /// To manually specify an allocator with each method call see `ArrayListAlignedUnmanaged`. | 24 | /// To manually specify an allocator with each function call see `ArrayListAlignedUnmanaged`. |
| 25 | pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | 25 | pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 26 | if (alignment) |a| { | 26 | if (alignment) |a| { |
| 27 | if (a == @alignOf(T)) { | 27 | if (a == @alignOf(T)) { |
| ... | @@ -30,15 +30,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -30,15 +30,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 30 | } | 30 | } |
| 31 | return struct { | 31 | return struct { |
| 32 | const Self = @This(); | 32 | const Self = @This(); |
| 33 | /// Contents of the list. Pointers to elements in this slice are | 33 | /// Contents of the list. This field is intended to be accessed |
| 34 | /// **invalid after resizing operations** on the ArrayList unless the | 34 | /// directly. |
| 35 | /// operation explicitly either: (1) states otherwise or (2) lists the | | |
| 36 | /// invalidated pointers. | | |
| 37 | /// | 35 | /// |
| 38 | /// The allocator used determines how element pointers are | 36 | /// Pointers to elements in this slice are invalidated by various |
| 39 | /// invalidated, so the behavior may vary between lists. To avoid | 37 | /// functions of this ArrayList in accordance with the respective |
| 40 | /// illegal behavior, take into account the above paragraph plus the | 38 | /// documentation. In all cases, "invalidated" means that the memory |
| 41 | /// explicit statements given in each method. | 39 | /// has been passed to this allocator's resize or free function. |
| 42 | items: Slice, | 40 | items: Slice, |
| 43 | /// How many T values this list can hold without allocating | 41 | /// How many T values this list can hold without allocating |
| 44 | /// additional memory. | 42 | /// additional memory. |
| ... | @@ -128,7 +126,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -128,7 +126,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 128 | | 126 | |
| 129 | /// The caller owns the returned memory. Empties this ArrayList. | 127 | /// The caller owns the returned memory. Empties this ArrayList. |
| 130 | pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { | 128 | pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { |
| 131 | try self.ensureTotalCapacityPrecise(self.items.len + 1); | 129 | try self.ensureTotalCapacityPrecise(try addOrOom(self.items.len, 1)); |
| 132 | self.appendAssumeCapacity(sentinel); | 130 | self.appendAssumeCapacity(sentinel); |
| 133 | const result = try self.toOwnedSlice(); | 131 | const result = try self.toOwnedSlice(); |
| 134 | return result[0 .. result.len - 1 :sentinel]; | 132 | return result[0 .. result.len - 1 :sentinel]; |
| ... | @@ -141,25 +139,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -141,25 +139,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 141 | return cloned; | 139 | return cloned; |
| 142 | } | 140 | } |
| 143 | | 141 | |
| 144 | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. | 142 | /// 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. | 143 | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 146 | /// This operation is O(N). | 144 | /// This operation is O(N). |
| 147 | /// Invalidates pointers if additional memory is needed. | 145 | /// Invalidates element pointers if additional memory is needed. |
| 148 | pub fn insert(self: *Self, n: usize, item: T) Allocator.Error!void { | 146 | /// Asserts that the index is in bounds or equal to the length. |
| 149 | const dst = try self.addManyAt(n, 1); | 147 | pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void { |
| | 148 | const dst = try self.addManyAt(i, 1); |
| 150 | dst[0] = item; | 149 | dst[0] = item; |
| 151 | } | 150 | } |
| 152 | | 151 | |
| 153 | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. | 152 | /// 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. | 153 | /// If `i` is equal to the length of the list this operation is |
| | 154 | /// equivalent to appendAssumeCapacity. |
| 155 | /// This operation is O(N). | 155 | /// This operation is O(N). |
| 156 | /// Asserts that there is enough capacity for the new item. | 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 the index is in bounds or equal to the length. |
| | 158 | pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { |
| 158 | assert(self.items.len < self.capacity); | 159 | assert(self.items.len < self.capacity); |
| 159 | self.items.len += 1; | 160 | self.items.len += 1; |
| 160 | | 161 | |
| 161 | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); | 162 | mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); |
| 162 | self.items[n] = item; | 163 | self.items[i] = item; |
| 163 | } | 164 | } |
| 164 | | 165 | |
| 165 | /// Add `count` new elements at position `index`, which have | 166 | /// Add `count` new elements at position `index`, which have |
| ... | @@ -169,8 +170,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -169,8 +170,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 169 | /// Invalidates pre-existing pointers to elements at and after `index`. | 170 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 170 | /// Invalidates all pre-existing element pointers if capacity must be | 171 | /// Invalidates all pre-existing element pointers if capacity must be |
| 171 | /// increased to accomodate the new elements. | 172 | /// increased to accomodate the new elements. |
| | 173 | /// Asserts that the index is in bounds or equal to the length. |
| 172 | pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T { | 174 | pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T { |
| 173 | const new_len = self.items.len + count; | 175 | const new_len = try addOrOom(self.items.len, count); |
| 174 | | 176 | |
| 175 | if (self.capacity >= new_len) | 177 | if (self.capacity >= new_len) |
| 176 | return addManyAtAssumeCapacity(self, index, count); | 178 | return addManyAtAssumeCapacity(self, index, count); |
| ... | @@ -208,6 +210,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -208,6 +210,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 208 | /// Asserts that there is enough capacity for the new elements. | 210 | /// 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 the index is in bounds or equal to the length. |
| 211 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { | 214 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 212 | const new_len = self.items.len + count; | 215 | const new_len = self.items.len + count; |
| 213 | assert(self.capacity >= new_len); | 216 | assert(self.capacity >= new_len); |
| ... | @@ -224,6 +227,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -224,6 +227,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 224 | /// Invalidates pre-existing pointers to elements at and after `index`. | 227 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 225 | /// Invalidates all pre-existing element pointers if capacity must be | 228 | /// Invalidates all pre-existing element pointers if capacity must be |
| 226 | /// increased to accomodate the new elements. | 229 | /// increased to accomodate the new elements. |
| | 230 | /// Asserts that the index is in bounds or equal to the length. |
| 227 | pub fn insertSlice( | 231 | pub fn insertSlice( |
| 228 | self: *Self, | 232 | self: *Self, |
| 229 | index: usize, | 233 | index: usize, |
| ... | @@ -236,9 +240,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -236,9 +240,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 236 | /// Replace range of elements `list[start..][0..len]` with `new_items`. | 240 | /// Replace range of elements `list[start..][0..len]` with `new_items`. |
| 237 | /// Grows list if `len < new_items.len`. | 241 | /// Grows list if `len < new_items.len`. |
| 238 | /// Shrinks list if `len > new_items.len`. | 242 | /// Shrinks list if `len > new_items.len`. |
| 239 | /// Invalidates pointers if this ArrayList is resized. | 243 | /// Invalidates element pointers if this ArrayList is resized. |
| | 244 | /// Asserts that the start index is in bounds or equal to the length. |
| 240 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { | 245 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { |
| 241 | const after_range = start + len; | 246 | const after_range = try addOrOom(start, len); |
| 242 | const range = self.items[start..after_range]; | 247 | const range = self.items[start..after_range]; |
| 243 | | 248 | |
| 244 | if (range.len == new_items.len) | 249 | if (range.len == new_items.len) |
| ... | @@ -251,7 +256,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -251,7 +256,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 251 | try self.insertSlice(after_range, rest); | 256 | try self.insertSlice(after_range, rest); |
| 252 | } else { | 257 | } else { |
| 253 | @memcpy(range[0..new_items.len], new_items); | 258 | @memcpy(range[0..new_items.len], new_items); |
| 254 | const after_subrange = start + new_items.len; | 259 | const after_subrange = try addOrOom(start, new_items.len); |
| 255 | | 260 | |
| 256 | for (self.items[after_range..], 0..) |item, i| { | 261 | for (self.items[after_range..], 0..) |item, i| { |
| 257 | self.items[after_subrange..][i] = item; | 262 | self.items[after_subrange..][i] = item; |
| ... | @@ -261,16 +266,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -261,16 +266,16 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 261 | } | 266 | } |
| 262 | } | 267 | } |
| 263 | | 268 | |
| 264 | /// Extend the list by 1 element. Allocates more memory as necessary. | 269 | /// Extends the list by 1 element. Allocates more memory as necessary. |
| 265 | /// Invalidates pointers if additional memory is needed. | 270 | /// Invalidates element pointers if additional memory is needed. |
| 266 | pub fn append(self: *Self, item: T) Allocator.Error!void { | 271 | pub fn append(self: *Self, item: T) Allocator.Error!void { |
| 267 | const new_item_ptr = try self.addOne(); | 272 | const new_item_ptr = try self.addOne(); |
| 268 | new_item_ptr.* = item; | 273 | new_item_ptr.* = item; |
| 269 | } | 274 | } |
| 270 | | 275 | |
| 271 | /// Extend the list by 1 element, but assert `self.capacity` | 276 | /// Extends the list by 1 element. |
| 272 | /// is sufficient to hold an additional item. **Does not** | 277 | /// Never invalidates element pointers. |
| 273 | /// invalidate pointers. | 278 | /// Asserts that the list can hold one additional item. |
| 274 | pub fn appendAssumeCapacity(self: *Self, item: T) void { | 279 | pub fn appendAssumeCapacity(self: *Self, item: T) void { |
| 275 | const new_item_ptr = self.addOneAssumeCapacity(); | 280 | const new_item_ptr = self.addOneAssumeCapacity(); |
| 276 | new_item_ptr.* = item; | 281 | new_item_ptr.* = item; |
| ... | @@ -278,10 +283,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -278,10 +283,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 278 | | 283 | |
| 279 | /// Remove the element at index `i`, shift elements after index | 284 | /// Remove the element at index `i`, shift elements after index |
| 280 | /// `i` forward, and return the removed element. | 285 | /// `i` forward, and return the removed element. |
| 281 | /// Asserts the array has at least one item. | 286 | /// Invalidates element pointers to end of list. |
| 282 | /// Invalidates pointers to end of list. | | |
| 283 | /// This operation is O(N). | 287 | /// This operation is O(N). |
| 284 | /// This preserves item order. Use `swapRemove` if order preservation is not important. | 288 | /// This preserves item order. Use `swapRemove` if order preservation is not important. |
| | 289 | /// Asserts that the index is in bounds. |
| | 290 | /// Asserts that the list is not empty. |
| 285 | pub fn orderedRemove(self: *Self, i: usize) T { | 291 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 286 | const newlen = self.items.len - 1; | 292 | const newlen = self.items.len - 1; |
| 287 | if (newlen == i) return self.pop(); | 293 | if (newlen == i) return self.pop(); |
| ... | @@ -297,6 +303,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -297,6 +303,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 297 | /// The empty slot is filled from the end of the list. | 303 | /// The empty slot is filled from the end of the list. |
| 298 | /// This operation is O(1). | 304 | /// This operation is O(1). |
| 299 | /// This may not preserve item order. Use `orderedRemove` if you need to preserve order. | 305 | /// This may not preserve item order. Use `orderedRemove` if you need to preserve order. |
| | 306 | /// Asserts that the list is not empty. |
| | 307 | /// Asserts that the index is in bounds. |
| 300 | pub fn swapRemove(self: *Self, i: usize) T { | 308 | pub fn swapRemove(self: *Self, i: usize) T { |
| 301 | if (self.items.len - 1 == i) return self.pop(); | 309 | if (self.items.len - 1 == i) return self.pop(); |
| 302 | | 310 | |
| ... | @@ -307,14 +315,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -307,14 +315,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 307 | | 315 | |
| 308 | /// Append the slice of items to the list. Allocates more | 316 | /// Append the slice of items to the list. Allocates more |
| 309 | /// memory as necessary. | 317 | /// memory as necessary. |
| 310 | /// Invalidates pointers if additional memory is needed. | 318 | /// Invalidates element pointers if additional memory is needed. |
| 311 | pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void { | 319 | pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void { |
| 312 | try self.ensureUnusedCapacity(items.len); | 320 | try self.ensureUnusedCapacity(items.len); |
| 313 | self.appendSliceAssumeCapacity(items); | 321 | self.appendSliceAssumeCapacity(items); |
| 314 | } | 322 | } |
| 315 | | 323 | |
| 316 | /// Append the slice of items to the list, asserting the capacity is already | 324 | /// Append the slice of items to the list. |
| 317 | /// enough to store the new items. **Does not** invalidate pointers. | 325 | /// Never invalidates element pointers. |
| | 326 | /// Asserts that the list can hold the 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; |
| ... | @@ -326,16 +335,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -326,16 +335,18 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 326 | /// Append an unaligned slice of items to the list. Allocates more | 335 | /// Append an unaligned slice of items to the list. Allocates more |
| 327 | /// memory as necessary. Only call this function if calling | 336 | /// memory as necessary. Only call this function if calling |
| 328 | /// `appendSlice` instead would be a compile error. | 337 | /// `appendSlice` instead would be a compile error. |
| 329 | /// Invalidates pointers if additional memory is needed. | 338 | /// Invalidates element pointers if additional memory is needed. |
| 330 | pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void { | 339 | pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void { |
| 331 | try self.ensureUnusedCapacity(items.len); | 340 | try self.ensureUnusedCapacity(items.len); |
| 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. |
| 336 | /// enough to store the new items. **Does not** invalidate pointers. | 345 | /// Never invalidates element pointers. |
| 337 | /// Only call this function if calling `appendSliceAssumeCapacity` instead | 346 | /// This function is only needed when calling |
| 338 | /// would be a compile error. | 347 | /// `appendSliceAssumeCapacity` instead would be a compile error due to the |
| | 348 | /// alignment of the `items` parameter. |
| | 349 | /// Asserts that the list can hold the additional items. |
| 339 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { | 350 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { |
| 340 | const old_len = self.items.len; | 351 | const old_len = self.items.len; |
| 341 | const new_len = old_len + items.len; | 352 | const new_len = old_len + items.len; |
| ... | @@ -348,7 +359,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -348,7 +359,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 348 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ | 359 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ |
| 349 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") | 360 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") |
| 350 | else | 361 | else |
| 351 | std.io.Writer(*Self, error{OutOfMemory}, appendWrite); | 362 | std.io.Writer(*Self, Allocator.Error, appendWrite); |
| 352 | | 363 | |
| 353 | /// Initializes a Writer which will append to the list. | 364 | /// Initializes a Writer which will append to the list. |
| 354 | pub fn writer(self: *Self) Writer { | 365 | pub fn writer(self: *Self) Writer { |
| ... | @@ -357,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -357,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 357 | | 368 | |
| 358 | /// Same as `append` except it returns the number of bytes written, which is always the same | 369 | /// Same as `append` except it returns the number of bytes written, which is always the same |
| 359 | /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API. | 370 | /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API. |
| 360 | /// Invalidates pointers if additional memory is needed. | 371 | /// Invalidates element pointers if additional memory is needed. |
| 361 | fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize { | 372 | fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize { |
| 362 | try self.appendSlice(m); | 373 | try self.appendSlice(m); |
| 363 | return m.len; | 374 | return m.len; |
| ... | @@ -365,19 +376,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -365,19 +376,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 365 | | 376 | |
| 366 | /// Append a value to the list `n` times. | 377 | /// Append a value to the list `n` times. |
| 367 | /// Allocates more memory as necessary. | 378 | /// Allocates more memory as necessary. |
| 368 | /// Invalidates pointers if additional memory is needed. | 379 | /// Invalidates element pointers if additional memory is needed. |
| 369 | /// The function is inline so that a comptime-known `value` parameter will | 380 | /// The function is inline so that a comptime-known `value` parameter will |
| 370 | /// have a more optimal memset codegen in case it has a repeated byte pattern. | 381 | /// 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 { | 382 | pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void { |
| 372 | const old_len = self.items.len; | 383 | const old_len = self.items.len; |
| 373 | try self.resize(self.items.len + n); | 384 | try self.resize(try addOrOom(old_len, n)); |
| 374 | @memset(self.items[old_len..self.items.len], value); | 385 | @memset(self.items[old_len..self.items.len], value); |
| 375 | } | 386 | } |
| 376 | | 387 | |
| 377 | /// Append a value to the list `n` times. | 388 | /// Append a value to the list `n` times. |
| 378 | /// Asserts the capacity is enough. **Does not** invalidate pointers. | 389 | /// Never invalidates element pointers. |
| 379 | /// The function is inline so that a comptime-known `value` parameter will | 390 | /// 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. | 391 | /// have a more optimal memset codegen in case it has a repeated byte pattern. |
| | 392 | /// Asserts that the list can hold the additional items. |
| 381 | pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { | 393 | pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { |
| 382 | const new_len = self.items.len + n; | 394 | const new_len = self.items.len + n; |
| 383 | assert(new_len <= self.capacity); | 395 | assert(new_len <= self.capacity); |
| ... | @@ -385,9 +397,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -385,9 +397,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 385 | self.items.len = new_len; | 397 | self.items.len = new_len; |
| 386 | } | 398 | } |
| 387 | | 399 | |
| 388 | /// Adjust the list's length to `new_len`. | 400 | /// Adjust the list length to `new_len`. |
| 389 | /// Does not initialize added items if any. | 401 | /// Additional elements contain the value `undefined`. |
| 390 | /// Invalidates pointers if additional memory is needed. | 402 | /// Invalidates element pointers if additional memory is needed. |
| 391 | pub fn resize(self: *Self, new_len: usize) Allocator.Error!void { | 403 | pub fn resize(self: *Self, new_len: usize) Allocator.Error!void { |
| 392 | try self.ensureTotalCapacity(new_len); | 404 | try self.ensureTotalCapacity(new_len); |
| 393 | self.items.len = new_len; | 405 | self.items.len = new_len; |
| ... | @@ -395,6 +407,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -395,6 +407,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 395 | | 407 | |
| 396 | /// Reduce allocated capacity to `new_len`. | 408 | /// Reduce allocated capacity to `new_len`. |
| 397 | /// May invalidate element pointers. | 409 | /// May invalidate element pointers. |
| | 410 | /// Asserts that the new length is less than or equal to the previous length. |
| 398 | pub fn shrinkAndFree(self: *Self, new_len: usize) void { | 411 | pub fn shrinkAndFree(self: *Self, new_len: usize) void { |
| 399 | var unmanaged = self.moveToUnmanaged(); | 412 | var unmanaged = self.moveToUnmanaged(); |
| 400 | unmanaged.shrinkAndFree(self.allocator, new_len); | 413 | unmanaged.shrinkAndFree(self.allocator, new_len); |
| ... | @@ -402,7 +415,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -402,7 +415,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 402 | } | 415 | } |
| 403 | | 416 | |
| 404 | /// Reduce length to `new_len`. | 417 | /// Reduce length to `new_len`. |
| 405 | /// Invalidates pointers for the elements `items[new_len..]`. | 418 | /// Invalidates element pointers for the elements `items[new_len..]`. |
| | 419 | /// Asserts that the new length is less than or equal to the previous length. |
| 406 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { | 420 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 407 | assert(new_len <= self.items.len); | 421 | assert(new_len <= self.items.len); |
| 408 | self.items.len = new_len; | 422 | self.items.len = new_len; |
| ... | @@ -422,7 +436,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -422,7 +436,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 422 | | 436 | |
| 423 | /// If the current capacity is less than `new_capacity`, this function will | 437 | /// If the current capacity is less than `new_capacity`, this function will |
| 424 | /// modify the array so that it can hold at least `new_capacity` items. | 438 | /// modify the array so that it can hold at least `new_capacity` items. |
| 425 | /// Invalidates pointers if additional memory is needed. | 439 | /// Invalidates element pointers if additional memory is needed. |
| 426 | pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void { | 440 | pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void { |
| 427 | if (@sizeOf(T) == 0) { | 441 | if (@sizeOf(T) == 0) { |
| 428 | self.capacity = math.maxInt(usize); | 442 | self.capacity = math.maxInt(usize); |
| ... | @@ -437,7 +451,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -437,7 +451,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 437 | | 451 | |
| 438 | /// If the current capacity is less than `new_capacity`, this function will | 452 | /// If the current capacity is less than `new_capacity`, this function will |
| 439 | /// modify the array so that it can hold exactly `new_capacity` items. | 453 | /// modify the array so that it can hold exactly `new_capacity` items. |
| 440 | /// Invalidates pointers if additional memory is needed. | 454 | /// Invalidates element pointers if additional memory is needed. |
| 441 | pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void { | 455 | pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void { |
| 442 | if (@sizeOf(T) == 0) { | 456 | if (@sizeOf(T) == 0) { |
| 443 | self.capacity = math.maxInt(usize); | 457 | self.capacity = math.maxInt(usize); |
| ... | @@ -464,13 +478,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -464,13 +478,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 464 | } | 478 | } |
| 465 | | 479 | |
| 466 | /// Modify the array so that it can hold at least `additional_count` **more** items. | 480 | /// Modify the array so that it can hold at least `additional_count` **more** items. |
| 467 | /// Invalidates pointers if additional memory is needed. | 481 | /// Invalidates element pointers if additional memory is needed. |
| 468 | pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void { | 482 | pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void { |
| 469 | return self.ensureTotalCapacity(self.items.len + additional_count); | 483 | return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count)); |
| 470 | } | 484 | } |
| 471 | | 485 | |
| 472 | /// Increases the array's length to match the full capacity that is already allocated. | 486 | /// Increases the array's length to match the full capacity that is already allocated. |
| 473 | /// The new elements have `undefined` values. **Does not** invalidate pointers. | 487 | /// The new elements have `undefined` values. |
| | 488 | /// Never invalidates element pointers. |
| 474 | pub fn expandToCapacity(self: *Self) void { | 489 | pub fn expandToCapacity(self: *Self) void { |
| 475 | self.items.len = self.capacity; | 490 | self.items.len = self.capacity; |
| 476 | } | 491 | } |
| ... | @@ -478,14 +493,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -478,14 +493,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 478 | /// Increase length by 1, returning pointer to the new item. | 493 | /// Increase length by 1, returning pointer to the new item. |
| 479 | /// The returned pointer becomes invalid when the list resized. | 494 | /// The returned pointer becomes invalid when the list resized. |
| 480 | pub fn addOne(self: *Self) Allocator.Error!*T { | 495 | pub fn addOne(self: *Self) Allocator.Error!*T { |
| 481 | try self.ensureTotalCapacity(self.items.len + 1); | 496 | try self.ensureUnusedCapacity(1); |
| 482 | return self.addOneAssumeCapacity(); | 497 | return self.addOneAssumeCapacity(); |
| 483 | } | 498 | } |
| 484 | | 499 | |
| 485 | /// Increase length by 1, returning pointer to the new item. | 500 | /// 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. | 501 | /// The returned pointer becomes invalid when the list is resized. |
| 488 | /// **Does not** invalidate element pointers. | 502 | /// Never invalidates element pointers. |
| | 503 | /// Asserts that the list can hold one additional item. |
| 489 | pub fn addOneAssumeCapacity(self: *Self) *T { | 504 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 490 | assert(self.items.len < self.capacity); | 505 | assert(self.items.len < self.capacity); |
| 491 | self.items.len += 1; | 506 | self.items.len += 1; |
| ... | @@ -498,15 +513,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -498,15 +513,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 498 | /// Resizes list if `self.capacity` is not large enough. | 513 | /// Resizes list if `self.capacity` is not large enough. |
| 499 | pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T { | 514 | pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T { |
| 500 | const prev_len = self.items.len; | 515 | const prev_len = self.items.len; |
| 501 | try self.resize(self.items.len + n); | 516 | try self.resize(try addOrOom(self.items.len, n)); |
| 502 | return self.items[prev_len..][0..n]; | 517 | return self.items[prev_len..][0..n]; |
| 503 | } | 518 | } |
| 504 | | 519 | |
| 505 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 520 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 506 | /// The return value is an array pointing to the newly allocated elements. | 521 | /// 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. | 522 | /// Never invalidates element pointers. |
| 508 | /// **Does not** invalidate element pointers. | | |
| 509 | /// The returned pointer becomes invalid when the list is resized. | 523 | /// The returned pointer becomes invalid when the list is resized. |
| | 524 | /// Asserts that the list can hold the additional items. |
| 510 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { | 525 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 511 | assert(self.items.len + n <= self.capacity); | 526 | assert(self.items.len + n <= self.capacity); |
| 512 | const prev_len = self.items.len; | 527 | const prev_len = self.items.len; |
| ... | @@ -520,15 +535,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -520,15 +535,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 520 | /// Resizes list if `self.capacity` is not large enough. | 535 | /// Resizes list if `self.capacity` is not large enough. |
| 521 | pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T { | 536 | pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T { |
| 522 | const prev_len = self.items.len; | 537 | const prev_len = self.items.len; |
| 523 | try self.resize(self.items.len + n); | 538 | try self.resize(try addOrOom(self.items.len, n)); |
| 524 | return self.items[prev_len..][0..n]; | 539 | return self.items[prev_len..][0..n]; |
| 525 | } | 540 | } |
| 526 | | 541 | |
| 527 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 542 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 528 | /// The return value is a slice pointing to the newly allocated elements. | 543 | /// 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. | 544 | /// Never invalidates element pointers. |
| 530 | /// **Does not** invalidate element pointers. | | |
| 531 | /// The returned pointer becomes invalid when the list is resized. | 545 | /// The returned pointer becomes invalid when the list is resized. |
| | 546 | /// Asserts that the list can hold the additional items. |
| 532 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { | 547 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { |
| 533 | assert(self.items.len + n <= self.capacity); | 548 | assert(self.items.len + n <= self.capacity); |
| 534 | const prev_len = self.items.len; | 549 | const prev_len = self.items.len; |
| ... | @@ -537,8 +552,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -537,8 +552,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 537 | } | 552 | } |
| 538 | | 553 | |
| 539 | /// Remove and return the last element from the list. | 554 | /// Remove and return the last element from the list. |
| 540 | /// Asserts the list has at least one item. | 555 | /// Invalidates element pointers to the removed element. |
| 541 | /// Invalidates pointers to the removed element. | 556 | /// Asserts that the list is not empty. |
| 542 | pub fn pop(self: *Self) T { | 557 | pub fn pop(self: *Self) T { |
| 543 | const val = self.items[self.items.len - 1]; | 558 | const val = self.items[self.items.len - 1]; |
| 544 | self.items.len -= 1; | 559 | self.items.len -= 1; |
| ... | @@ -547,7 +562,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -547,7 +562,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 547 | | 562 | |
| 548 | /// Remove and return the last element from the list, or | 563 | /// Remove and return the last element from the list, or |
| 549 | /// return `null` if list is empty. | 564 | /// return `null` if list is empty. |
| 550 | /// Invalidates pointers to the removed element, if any. | 565 | /// Invalidates element pointers to the removed element, if any. |
| 551 | pub fn popOrNull(self: *Self) ?T { | 566 | pub fn popOrNull(self: *Self) ?T { |
| 552 | if (self.items.len == 0) return null; | 567 | if (self.items.len == 0) return null; |
| 553 | return self.pop(); | 568 | return self.pop(); |
| ... | @@ -568,15 +583,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -568,15 +583,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 568 | return self.allocatedSlice()[self.items.len..]; | 583 | return self.allocatedSlice()[self.items.len..]; |
| 569 | } | 584 | } |
| 570 | | 585 | |
| 571 | /// Return the last element from the list. | 586 | /// Returns the last element from the list. |
| 572 | /// Asserts the list has at least one item. | 587 | /// Asserts that the list is not empty. |
| 573 | pub fn getLast(self: Self) T { | 588 | pub fn getLast(self: Self) T { |
| 574 | const val = self.items[self.items.len - 1]; | 589 | const val = self.items[self.items.len - 1]; |
| 575 | return val; | 590 | return val; |
| 576 | } | 591 | } |
| 577 | | 592 | |
| 578 | /// Return the last element from the list, or | 593 | /// 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 { | 594 | pub fn getLastOrNull(self: Self) ?T { |
| 581 | if (self.items.len == 0) return null; | 595 | if (self.items.len == 0) return null; |
| 582 | return self.getLast(); | 596 | return self.getLast(); |
| ... | @@ -585,17 +599,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -585,17 +599,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 585 | } | 599 | } |
| 586 | | 600 | |
| 587 | /// An ArrayList, but the allocator is passed as a parameter to the relevant functions | 601 | /// An ArrayList, but the allocator is passed as a parameter to the relevant functions |
| 588 | /// rather than stored in the struct itself. The same allocator **must** be used throughout | 602 | /// rather than stored in the struct itself. The same allocator must be used throughout |
| 589 | /// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with | 603 | /// the entire lifetime of an ArrayListUnmanaged. Initialize directly or with |
| 590 | /// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`. | 604 | /// `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`. |
| 591 | pub fn ArrayListUnmanaged(comptime T: type) type { | 605 | pub fn ArrayListUnmanaged(comptime T: type) type { |
| 592 | return ArrayListAlignedUnmanaged(T, null); | 606 | return ArrayListAlignedUnmanaged(T, null); |
| 593 | } | 607 | } |
| 594 | | 608 | |
| 595 | /// An ArrayListAligned, but the allocator is passed as a parameter to the relevant | 609 | /// A contiguous, growable list of arbitrarily aligned items in memory. |
| 596 | /// functions rather than stored in the struct itself. The same allocator **must** | 610 | /// This is a wrapper around an array of T values aligned to `alignment`-byte |
| 597 | /// be used throughout the entire lifetime of an ArrayListAlignedUnmanaged. | 611 | /// addresses. If the specified alignment is `null`, then `@alignOf(T)` is used. |
| 598 | /// Initialize directly or with `initCapacity`, and deinitialize with `deinit` or use `toOwnedSlice`. | 612 | /// |
| | 613 | /// Functions that potentially allocate memory accept an `Allocator` parameter. |
| | 614 | /// Initialize directly or with `initCapacity`, and deinitialize with `deinit` |
| | 615 | /// or use `toOwnedSlice`. |
| 599 | pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type { | 616 | pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type { |
| 600 | if (alignment) |a| { | 617 | if (alignment) |a| { |
| 601 | if (a == @alignOf(T)) { | 618 | if (a == @alignOf(T)) { |
| ... | @@ -604,15 +621,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -604,15 +621,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 604 | } | 621 | } |
| 605 | return struct { | 622 | return struct { |
| 606 | const Self = @This(); | 623 | const Self = @This(); |
| 607 | /// Contents of the list. Pointers to elements in this slice are | 624 | /// Contents of the list. This field is intended to be accessed |
| 608 | /// **invalid after resizing operations** on the ArrayList unless the | 625 | /// directly. |
| 609 | /// operation explicitly either: (1) states otherwise or (2) lists the | | |
| 610 | /// invalidated pointers. | | |
| 611 | /// | 626 | /// |
| 612 | /// The allocator used determines how element pointers are | 627 | /// Pointers to elements in this slice are invalidated by various |
| 613 | /// invalidated, so the behavior may vary between lists. To avoid | 628 | /// functions of this ArrayList in accordance with the respective |
| 614 | /// illegal behavior, take into account the above paragraph plus the | 629 | /// documentation. In all cases, "invalidated" means that the memory |
| 615 | /// explicit statements given in each method. | 630 | /// has been passed to an allocator's resize or free function. |
| 616 | items: Slice = &[_]T{}, | 631 | items: Slice = &[_]T{}, |
| 617 | /// How many T values this list can hold without allocating | 632 | /// How many T values this list can hold without allocating |
| 618 | /// additional memory. | 633 | /// additional memory. |
| ... | @@ -635,8 +650,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -635,8 +650,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 635 | | 650 | |
| 636 | /// Initialize with externally-managed memory. The buffer determines the | 651 | /// Initialize with externally-managed memory. The buffer determines the |
| 637 | /// capacity, and the length is set to zero. | 652 | /// capacity, and the length is set to zero. |
| 638 | /// When initialized this way, all methods that accept an Allocator | 653 | /// When initialized this way, all functions that accept an Allocator |
| 639 | /// argument are illegal to call. | 654 | /// argument cause illegal behavior. |
| 640 | pub fn initBuffer(buffer: Slice) Self { | 655 | pub fn initBuffer(buffer: Slice) Self { |
| 641 | return .{ | 656 | return .{ |
| 642 | .items = buffer[0..0], | 657 | .items = buffer[0..0], |
| ... | @@ -695,7 +710,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -695,7 +710,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 695 | | 710 | |
| 696 | /// The caller owns the returned memory. ArrayList becomes empty. | 711 | /// The caller owns the returned memory. ArrayList becomes empty. |
| 697 | pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { | 712 | pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { |
| 698 | try self.ensureTotalCapacityPrecise(allocator, self.items.len + 1); | 713 | try self.ensureTotalCapacityPrecise(allocator, try addOrOom(self.items.len, 1)); |
| 699 | self.appendAssumeCapacity(sentinel); | 714 | self.appendAssumeCapacity(sentinel); |
| 700 | const result = try self.toOwnedSlice(allocator); | 715 | const result = try self.toOwnedSlice(allocator); |
| 701 | return result[0 .. result.len - 1 :sentinel]; | 716 | return result[0 .. result.len - 1 :sentinel]; |
| ... | @@ -708,25 +723,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -708,25 +723,27 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 708 | return cloned; | 723 | return cloned; |
| 709 | } | 724 | } |
| 710 | | 725 | |
| 711 | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. | 726 | /// 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. | 727 | /// If `i` is equal to the length of the list this operation is equivalent to append. |
| 713 | /// This operation is O(N). | 728 | /// This operation is O(N). |
| 714 | /// Invalidates pointers if additional memory is needed. | 729 | /// Invalidates element pointers if additional memory is needed. |
| 715 | pub fn insert(self: *Self, allocator: Allocator, n: usize, item: T) Allocator.Error!void { | 730 | /// Asserts that the index is in bounds or equal to the length. |
| 716 | const dst = try self.addManyAt(allocator, n, 1); | 731 | pub fn insert(self: *Self, allocator: Allocator, i: usize, item: T) Allocator.Error!void { |
| | 732 | const dst = try self.addManyAt(allocator, i, 1); |
| 717 | dst[0] = item; | 733 | dst[0] = item; |
| 718 | } | 734 | } |
| 719 | | 735 | |
| 720 | /// Insert `item` at index `n`. Moves `list[n .. list.len]` to higher indices to make room. | 736 | /// 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. | 737 | /// If in` is equal to the length of the list this operation is equivalent to append. |
| 722 | /// This operation is O(N). | 738 | /// This operation is O(N). |
| 723 | /// Asserts that there is enough capacity for the new item. | 739 | /// Asserts that the list has capacity for one additional item. |
| 724 | pub fn insertAssumeCapacity(self: *Self, n: usize, item: T) void { | 740 | /// Asserts that the index is in bounds or equal to the length. |
| | 741 | pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { |
| 725 | assert(self.items.len < self.capacity); | 742 | assert(self.items.len < self.capacity); |
| 726 | self.items.len += 1; | 743 | self.items.len += 1; |
| 727 | | 744 | |
| 728 | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); | 745 | mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); |
| 729 | self.items[n] = item; | 746 | self.items[i] = item; |
| 730 | } | 747 | } |
| 731 | | 748 | |
| 732 | /// Add `count` new elements at position `index`, which have | 749 | /// Add `count` new elements at position `index`, which have |
| ... | @@ -736,6 +753,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -736,6 +753,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 736 | /// Invalidates pre-existing pointers to elements at and after `index`. | 753 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 737 | /// Invalidates all pre-existing element pointers if capacity must be | 754 | /// Invalidates all pre-existing element pointers if capacity must be |
| 738 | /// increased to accomodate the new elements. | 755 | /// increased to accomodate the new elements. |
| | 756 | /// Asserts that the index is in bounds or equal to the length. |
| 739 | pub fn addManyAt( | 757 | pub fn addManyAt( |
| 740 | self: *Self, | 758 | self: *Self, |
| 741 | allocator: Allocator, | 759 | allocator: Allocator, |
| ... | @@ -751,9 +769,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -751,9 +769,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 751 | /// `undefined` values. Returns a slice pointing to the newly allocated | 769 | /// `undefined` values. Returns a slice pointing to the newly allocated |
| 752 | /// elements, which becomes invalid after various `ArrayList` | 770 | /// elements, which becomes invalid after various `ArrayList` |
| 753 | /// operations. | 771 | /// operations. |
| 754 | /// Asserts that there is enough capacity for the new elements. | | |
| 755 | /// Invalidates pre-existing pointers to elements at and after `index`, but | 772 | /// Invalidates pre-existing pointers to elements at and after `index`, but |
| 756 | /// does not invalidate any before that. | 773 | /// does not invalidate any before that. |
| | 774 | /// Asserts that the list has capacity for the additional items. |
| | 775 | /// Asserts that the index is in bounds or equal to the length. |
| 757 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { | 776 | pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { |
| 758 | const new_len = self.items.len + count; | 777 | const new_len = self.items.len + count; |
| 759 | assert(self.capacity >= new_len); | 778 | assert(self.capacity >= new_len); |
| ... | @@ -770,6 +789,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -770,6 +789,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 770 | /// Invalidates pre-existing pointers to elements at and after `index`. | 789 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| 771 | /// Invalidates all pre-existing element pointers if capacity must be | 790 | /// Invalidates all pre-existing element pointers if capacity must be |
| 772 | /// increased to accomodate the new elements. | 791 | /// increased to accomodate the new elements. |
| | 792 | /// Asserts that the index is in bounds or equal to the length. |
| 773 | pub fn insertSlice( | 793 | pub fn insertSlice( |
| 774 | self: *Self, | 794 | self: *Self, |
| 775 | allocator: Allocator, | 795 | allocator: Allocator, |
| ... | @@ -787,7 +807,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -787,7 +807,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 787 | /// Replace range of elements `list[start..][0..len]` with `new_items` | 807 | /// Replace range of elements `list[start..][0..len]` with `new_items` |
| 788 | /// Grows list if `len < new_items.len`. | 808 | /// Grows list if `len < new_items.len`. |
| 789 | /// Shrinks list if `len > new_items.len` | 809 | /// Shrinks list if `len > new_items.len` |
| 790 | /// Invalidates pointers if this ArrayList is resized. | 810 | /// Invalidates element pointers if this ArrayList is resized. |
| | 811 | /// Asserts that the start index is in bounds or equal to the length. |
| 791 | pub fn replaceRange( | 812 | pub fn replaceRange( |
| 792 | self: *Self, | 813 | self: *Self, |
| 793 | allocator: Allocator, | 814 | allocator: Allocator, |
| ... | @@ -801,23 +822,25 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -801,23 +822,25 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 801 | } | 822 | } |
| 802 | | 823 | |
| 803 | /// Extend the list by 1 element. Allocates more memory as necessary. | 824 | /// Extend the list by 1 element. Allocates more memory as necessary. |
| 804 | /// Invalidates pointers if additional memory is needed. | 825 | /// Invalidates element pointers if additional memory is needed. |
| 805 | pub fn append(self: *Self, allocator: Allocator, item: T) Allocator.Error!void { | 826 | pub fn append(self: *Self, allocator: Allocator, item: T) Allocator.Error!void { |
| 806 | const new_item_ptr = try self.addOne(allocator); | 827 | const new_item_ptr = try self.addOne(allocator); |
| 807 | new_item_ptr.* = item; | 828 | new_item_ptr.* = item; |
| 808 | } | 829 | } |
| 809 | | 830 | |
| 810 | /// Extend the list by 1 element, but asserting `self.capacity` | 831 | /// Extend the list by 1 element. |
| 811 | /// is sufficient to hold an additional item. | 832 | /// Never invalidates element pointers. |
| | 833 | /// Asserts that the list can hold one additional item. |
| 812 | pub fn appendAssumeCapacity(self: *Self, item: T) void { | 834 | pub fn appendAssumeCapacity(self: *Self, item: T) void { |
| 813 | const new_item_ptr = self.addOneAssumeCapacity(); | 835 | const new_item_ptr = self.addOneAssumeCapacity(); |
| 814 | new_item_ptr.* = item; | 836 | new_item_ptr.* = item; |
| 815 | } | 837 | } |
| 816 | | 838 | |
| 817 | /// Remove the element at index `i` from the list and return its value. | 839 | /// 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 | 840 | /// Invalidates pointers to the last element. |
| 819 | /// last element. | | |
| 820 | /// This operation is O(N). | 841 | /// This operation is O(N). |
| | 842 | /// Asserts that the list is not empty. |
| | 843 | /// Asserts that the index is in bounds. |
| 821 | pub fn orderedRemove(self: *Self, i: usize) T { | 844 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 822 | const newlen = self.items.len - 1; | 845 | const newlen = self.items.len - 1; |
| 823 | if (newlen == i) return self.pop(); | 846 | if (newlen == i) return self.pop(); |
| ... | @@ -833,6 +856,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -833,6 +856,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 833 | /// The empty slot is filled from the end of the list. | 856 | /// The empty slot is filled from the end of the list. |
| 834 | /// Invalidates pointers to last element. | 857 | /// Invalidates pointers to last element. |
| 835 | /// This operation is O(1). | 858 | /// This operation is O(1). |
| | 859 | /// Asserts that the list is not empty. |
| | 860 | /// Asserts that the index is in bounds. |
| 836 | pub fn swapRemove(self: *Self, i: usize) T { | 861 | pub fn swapRemove(self: *Self, i: usize) T { |
| 837 | if (self.items.len - 1 == i) return self.pop(); | 862 | if (self.items.len - 1 == i) return self.pop(); |
| 838 | | 863 | |
| ... | @@ -843,14 +868,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -843,14 +868,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 843 | | 868 | |
| 844 | /// Append the slice of items to the list. Allocates more | 869 | /// Append the slice of items to the list. Allocates more |
| 845 | /// memory as necessary. | 870 | /// memory as necessary. |
| 846 | /// Invalidates pointers if additional memory is needed. | 871 | /// Invalidates element pointers if additional memory is needed. |
| 847 | pub fn appendSlice(self: *Self, allocator: Allocator, items: []const T) Allocator.Error!void { | 872 | pub fn appendSlice(self: *Self, allocator: Allocator, items: []const T) Allocator.Error!void { |
| 848 | try self.ensureUnusedCapacity(allocator, items.len); | 873 | try self.ensureUnusedCapacity(allocator, items.len); |
| 849 | self.appendSliceAssumeCapacity(items); | 874 | self.appendSliceAssumeCapacity(items); |
| 850 | } | 875 | } |
| 851 | | 876 | |
| 852 | /// Append the slice of items to the list, asserting the capacity is enough | 877 | /// Append the slice of items to the list. |
| 853 | /// to store the new items. | 878 | /// Asserts that the list can hold the additional items. |
| 854 | pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { | 879 | pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { |
| 855 | const old_len = self.items.len; | 880 | const old_len = self.items.len; |
| 856 | const new_len = old_len + items.len; | 881 | const new_len = old_len + items.len; |
| ... | @@ -862,15 +887,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -862,15 +887,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 862 | /// Append the slice of items to the list. Allocates more | 887 | /// Append the slice of items to the list. Allocates more |
| 863 | /// memory as necessary. Only call this function if a call to `appendSlice` instead would | 888 | /// memory as necessary. Only call this function if a call to `appendSlice` instead would |
| 864 | /// be a compile error. | 889 | /// be a compile error. |
| 865 | /// Invalidates pointers if additional memory is needed. | 890 | /// Invalidates element pointers if additional memory is needed. |
| 866 | pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void { | 891 | pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void { |
| 867 | try self.ensureUnusedCapacity(allocator, items.len); | 892 | try self.ensureUnusedCapacity(allocator, items.len); |
| 868 | self.appendUnalignedSliceAssumeCapacity(items); | 893 | self.appendUnalignedSliceAssumeCapacity(items); |
| 869 | } | 894 | } |
| 870 | | 895 | |
| 871 | /// Append an unaligned slice of items to the list, asserting the capacity is enough | 896 | /// Append an unaligned slice of items to the list. |
| 872 | /// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity` | 897 | /// Only call this function if a call to `appendSliceAssumeCapacity` |
| 873 | /// instead would be a compile error. | 898 | /// instead would be a compile error. |
| | 899 | /// Asserts that the list can hold the additional items. |
| 874 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { | 900 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { |
| 875 | const old_len = self.items.len; | 901 | const old_len = self.items.len; |
| 876 | const new_len = old_len + items.len; | 902 | const new_len = old_len + items.len; |
| ... | @@ -888,7 +914,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -888,7 +914,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 888 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ | 914 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ |
| 889 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") | 915 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") |
| 890 | else | 916 | else |
| 891 | std.io.Writer(WriterContext, error{OutOfMemory}, appendWrite); | 917 | std.io.Writer(WriterContext, Allocator.Error, appendWrite); |
| 892 | | 918 | |
| 893 | /// Initializes a Writer which will append to the list. | 919 | /// Initializes a Writer which will append to the list. |
| 894 | pub fn writer(self: *Self, allocator: Allocator) Writer { | 920 | pub fn writer(self: *Self, allocator: Allocator) Writer { |
| ... | @@ -897,7 +923,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -897,7 +923,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 897 | | 923 | |
| 898 | /// Same as `append` except it returns the number of bytes written, which is always the same | 924 | /// Same as `append` except it returns the number of bytes written, which is always the same |
| 899 | /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API. | 925 | /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API. |
| 900 | /// Invalidates pointers if additional memory is needed. | 926 | /// Invalidates element pointers if additional memory is needed. |
| 901 | fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize { | 927 | fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize { |
| 902 | try context.self.appendSlice(context.allocator, m); | 928 | try context.self.appendSlice(context.allocator, m); |
| 903 | return m.len; | 929 | return m.len; |
| ... | @@ -905,20 +931,20 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -905,20 +931,20 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 905 | | 931 | |
| 906 | /// Append a value to the list `n` times. | 932 | /// Append a value to the list `n` times. |
| 907 | /// Allocates more memory as necessary. | 933 | /// Allocates more memory as necessary. |
| 908 | /// Invalidates pointers if additional memory is needed. | 934 | /// Invalidates element pointers if additional memory is needed. |
| 909 | /// The function is inline so that a comptime-known `value` parameter will | 935 | /// The function is inline so that a comptime-known `value` parameter will |
| 910 | /// have a more optimal memset codegen in case it has a repeated byte pattern. | 936 | /// 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 { | 937 | pub inline fn appendNTimes(self: *Self, allocator: Allocator, value: T, n: usize) Allocator.Error!void { |
| 912 | const old_len = self.items.len; | 938 | const old_len = self.items.len; |
| 913 | try self.resize(allocator, self.items.len + n); | 939 | try self.resize(allocator, try addOrOom(old_len, n)); |
| 914 | @memset(self.items[old_len..self.items.len], value); | 940 | @memset(self.items[old_len..self.items.len], value); |
| 915 | } | 941 | } |
| 916 | | 942 | |
| 917 | /// Append a value to the list `n` times. | 943 | /// Append a value to the list `n` times. |
| 918 | /// **Does not** invalidate pointers. | 944 | /// Never invalidates element pointers. |
| 919 | /// Asserts the capacity is enough. | | |
| 920 | /// The function is inline so that a comptime-known `value` parameter will | 945 | /// 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. | 946 | /// have better memset codegen in case it has a repeated byte pattern. |
| | 947 | /// Asserts that the list can hold the additional items. |
| 922 | pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { | 948 | pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { |
| 923 | const new_len = self.items.len + n; | 949 | const new_len = self.items.len + n; |
| 924 | assert(new_len <= self.capacity); | 950 | assert(new_len <= self.capacity); |
| ... | @@ -926,9 +952,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -926,9 +952,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 926 | self.items.len = new_len; | 952 | self.items.len = new_len; |
| 927 | } | 953 | } |
| 928 | | 954 | |
| 929 | /// Adjust the list's length to `new_len`. | 955 | /// Adjust the list length to `new_len`. |
| 930 | /// Does not initialize added items, if any. | 956 | /// Additional elements contain the value `undefined`. |
| 931 | /// Invalidates pointers if additional memory is needed. | 957 | /// Invalidates element pointers if additional memory is needed. |
| 932 | pub fn resize(self: *Self, allocator: Allocator, new_len: usize) Allocator.Error!void { | 958 | pub fn resize(self: *Self, allocator: Allocator, new_len: usize) Allocator.Error!void { |
| 933 | try self.ensureTotalCapacity(allocator, new_len); | 959 | try self.ensureTotalCapacity(allocator, new_len); |
| 934 | self.items.len = new_len; | 960 | self.items.len = new_len; |
| ... | @@ -936,6 +962,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -936,6 +962,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 936 | | 962 | |
| 937 | /// Reduce allocated capacity to `new_len`. | 963 | /// Reduce allocated capacity to `new_len`. |
| 938 | /// May invalidate element pointers. | 964 | /// May invalidate element pointers. |
| | 965 | /// Asserts that the new length is less than or equal to the previous length. |
| 939 | pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void { | 966 | pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void { |
| 940 | assert(new_len <= self.items.len); | 967 | assert(new_len <= self.items.len); |
| 941 | | 968 | |
| ... | @@ -968,6 +995,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -968,6 +995,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 968 | /// Reduce length to `new_len`. | 995 | /// Reduce length to `new_len`. |
| 969 | /// Invalidates pointers to elements `items[new_len..]`. | 996 | /// Invalidates pointers to elements `items[new_len..]`. |
| 970 | /// Keeps capacity the same. | 997 | /// Keeps capacity the same. |
| | 998 | /// Asserts that the new length is less than or equal to the previous length. |
| 971 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { | 999 | pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { |
| 972 | assert(new_len <= self.items.len); | 1000 | assert(new_len <= self.items.len); |
| 973 | self.items.len = new_len; | 1001 | self.items.len = new_len; |
| ... | @@ -987,7 +1015,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -987,7 +1015,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 987 | | 1015 | |
| 988 | /// If the current capacity is less than `new_capacity`, this function will | 1016 | /// If the current capacity is less than `new_capacity`, this function will |
| 989 | /// modify the array so that it can hold at least `new_capacity` items. | 1017 | /// modify the array so that it can hold at least `new_capacity` items. |
| 990 | /// Invalidates pointers if additional memory is needed. | 1018 | /// Invalidates element pointers if additional memory is needed. |
| 991 | pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void { | 1019 | pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void { |
| 992 | if (self.capacity >= new_capacity) return; | 1020 | if (self.capacity >= new_capacity) return; |
| 993 | | 1021 | |
| ... | @@ -997,7 +1025,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -997,7 +1025,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 997 | | 1025 | |
| 998 | /// If the current capacity is less than `new_capacity`, this function will | 1026 | /// If the current capacity is less than `new_capacity`, this function will |
| 999 | /// modify the array so that it can hold exactly `new_capacity` items. | 1027 | /// modify the array so that it can hold exactly `new_capacity` items. |
| 1000 | /// Invalidates pointers if additional memory is needed. | 1028 | /// Invalidates element pointers if additional memory is needed. |
| 1001 | pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void { | 1029 | pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void { |
| 1002 | if (@sizeOf(T) == 0) { | 1030 | if (@sizeOf(T) == 0) { |
| 1003 | self.capacity = math.maxInt(usize); | 1031 | self.capacity = math.maxInt(usize); |
| ... | @@ -1024,34 +1052,34 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -1024,34 +1052,34 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1024 | } | 1052 | } |
| 1025 | | 1053 | |
| 1026 | /// Modify the array so that it can hold at least `additional_count` **more** items. | 1054 | /// Modify the array so that it can hold at least `additional_count` **more** items. |
| 1027 | /// Invalidates pointers if additional memory is needed. | 1055 | /// Invalidates element pointers if additional memory is needed. |
| 1028 | pub fn ensureUnusedCapacity( | 1056 | pub fn ensureUnusedCapacity( |
| 1029 | self: *Self, | 1057 | self: *Self, |
| 1030 | allocator: Allocator, | 1058 | allocator: Allocator, |
| 1031 | additional_count: usize, | 1059 | additional_count: usize, |
| 1032 | ) Allocator.Error!void { | 1060 | ) Allocator.Error!void { |
| 1033 | return self.ensureTotalCapacity(allocator, self.items.len + additional_count); | 1061 | return self.ensureTotalCapacity(allocator, try addOrOom(self.items.len, additional_count)); |
| 1034 | } | 1062 | } |
| 1035 | | 1063 | |
| 1036 | /// Increases the array's length to match the full capacity that is already allocated. | 1064 | /// Increases the array's length to match the full capacity that is already allocated. |
| 1037 | /// The new elements have `undefined` values. | 1065 | /// The new elements have `undefined` values. |
| 1038 | /// **Does not** invalidate pointers. | 1066 | /// Never invalidates element pointers. |
| 1039 | pub fn expandToCapacity(self: *Self) void { | 1067 | pub fn expandToCapacity(self: *Self) void { |
| 1040 | self.items.len = self.capacity; | 1068 | self.items.len = self.capacity; |
| 1041 | } | 1069 | } |
| 1042 | | 1070 | |
| 1043 | /// Increase length by 1, returning pointer to the new item. | 1071 | /// Increase length by 1, returning pointer to the new item. |
| 1044 | /// The returned pointer becomes invalid when the list resized. | 1072 | /// The returned element pointer becomes invalid when the list is resized. |
| 1045 | pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T { | 1073 | pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T { |
| 1046 | const newlen = self.items.len + 1; | 1074 | const newlen = try addOrOom(self.items.len, 1); |
| 1047 | try self.ensureTotalCapacity(allocator, newlen); | 1075 | try self.ensureTotalCapacity(allocator, newlen); |
| 1048 | return self.addOneAssumeCapacity(); | 1076 | return self.addOneAssumeCapacity(); |
| 1049 | } | 1077 | } |
| 1050 | | 1078 | |
| 1051 | /// Increase length by 1, returning pointer to the new item. | 1079 | /// Increase length by 1, returning pointer to the new item. |
| 1052 | /// Asserts that there is already space for the new item without allocating more. | 1080 | /// Never invalidates element pointers. |
| 1053 | /// **Does not** invalidate pointers. | 1081 | /// The returned element pointer becomes invalid when the list is resized. |
| 1054 | /// The returned pointer becomes invalid when the list resized. | 1082 | /// Asserts that the list can hold one additional item. |
| 1055 | pub fn addOneAssumeCapacity(self: *Self) *T { | 1083 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 1056 | assert(self.items.len < self.capacity); | 1084 | assert(self.items.len < self.capacity); |
| 1057 | | 1085 | |
| ... | @@ -1064,15 +1092,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -1064,15 +1092,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1064 | /// The returned pointer becomes invalid when the list is resized. | 1092 | /// 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 { | 1093 | pub fn addManyAsArray(self: *Self, allocator: Allocator, comptime n: usize) Allocator.Error!*[n]T { |
| 1066 | const prev_len = self.items.len; | 1094 | const prev_len = self.items.len; |
| 1067 | try self.resize(allocator, self.items.len + n); | 1095 | try self.resize(allocator, try addOrOom(self.items.len, n)); |
| 1068 | return self.items[prev_len..][0..n]; | 1096 | return self.items[prev_len..][0..n]; |
| 1069 | } | 1097 | } |
| 1070 | | 1098 | |
| 1071 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 1099 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1072 | /// The return value is an array pointing to the newly allocated elements. | 1100 | /// 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. | 1101 | /// Never invalidates element pointers. |
| 1074 | /// **Does not** invalidate pointers. | | |
| 1075 | /// The returned pointer becomes invalid when the list is resized. | 1102 | /// The returned pointer becomes invalid when the list is resized. |
| | 1103 | /// Asserts that the list can hold the additional items. |
| 1076 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { | 1104 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 1077 | assert(self.items.len + n <= self.capacity); | 1105 | assert(self.items.len + n <= self.capacity); |
| 1078 | const prev_len = self.items.len; | 1106 | const prev_len = self.items.len; |
| ... | @@ -1086,15 +1114,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -1086,15 +1114,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1086 | /// Resizes list if `self.capacity` is not large enough. | 1114 | /// Resizes list if `self.capacity` is not large enough. |
| 1087 | pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T { | 1115 | pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T { |
| 1088 | const prev_len = self.items.len; | 1116 | const prev_len = self.items.len; |
| 1089 | try self.resize(allocator, self.items.len + n); | 1117 | try self.resize(allocator, try addOrOom(self.items.len, n)); |
| 1090 | return self.items[prev_len..][0..n]; | 1118 | return self.items[prev_len..][0..n]; |
| 1091 | } | 1119 | } |
| 1092 | | 1120 | |
| 1093 | /// Resize the array, adding `n` new elements, which have `undefined` values. | 1121 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1094 | /// The return value is a slice pointing to the newly allocated elements. | 1122 | /// 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. | 1123 | /// Never invalidates element pointers. |
| 1096 | /// **Does not** invalidate element pointers. | | |
| 1097 | /// The returned pointer becomes invalid when the list is resized. | 1124 | /// The returned pointer becomes invalid when the list is resized. |
| | 1125 | /// Asserts that the list can hold the additional items. |
| 1098 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { | 1126 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { |
| 1099 | assert(self.items.len + n <= self.capacity); | 1127 | assert(self.items.len + n <= self.capacity); |
| 1100 | const prev_len = self.items.len; | 1128 | const prev_len = self.items.len; |
| ... | @@ -1103,8 +1131,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -1103,8 +1131,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1103 | } | 1131 | } |
| 1104 | | 1132 | |
| 1105 | /// Remove and return the last element from the list. | 1133 | /// Remove and return the last element from the list. |
| 1106 | /// Asserts the list has at least one item. | | |
| 1107 | /// Invalidates pointers to last element. | 1134 | /// Invalidates pointers to last element. |
| | 1135 | /// Asserts that the list is not empty. |
| 1108 | pub fn pop(self: *Self) T { | 1136 | pub fn pop(self: *Self) T { |
| 1109 | const val = self.items[self.items.len - 1]; | 1137 | const val = self.items[self.items.len - 1]; |
| 1110 | self.items.len -= 1; | 1138 | self.items.len -= 1; |
| ... | @@ -1134,7 +1162,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -1134,7 +1162,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 1134 | } | 1162 | } |
| 1135 | | 1163 | |
| 1136 | /// Return the last element from the list. | 1164 | /// Return the last element from the list. |
| 1137 | /// Asserts the list has at least one item. | 1165 | /// Asserts that the list is not empty. |
| 1138 | pub fn getLast(self: Self) T { | 1166 | pub fn getLast(self: Self) T { |
| 1139 | const val = self.items[self.items.len - 1]; | 1167 | const val = self.items[self.items.len - 1]; |
| 1140 | return val; | 1168 | return val; |
| ... | @@ -1160,6 +1188,13 @@ fn growCapacity(current: usize, minimum: usize) usize { | ... | @@ -1160,6 +1188,13 @@ fn growCapacity(current: usize, minimum: usize) usize { |
| 1160 | } | 1188 | } |
| 1161 | } | 1189 | } |
| 1162 | | 1190 | |
| | 1191 | /// Integer addition returning `error.OutOfMemory` on overflow. |
| | 1192 | fn addOrOom(a: usize, b: usize) error{OutOfMemory}!usize { |
| | 1193 | const result, const overflow = @addWithOverflow(a, b); |
| | 1194 | if (overflow != 0) return error.OutOfMemory; |
| | 1195 | return result; |
| | 1196 | } |
| | 1197 | |
| 1163 | test "std.ArrayList/ArrayListUnmanaged.init" { | 1198 | test "std.ArrayList/ArrayListUnmanaged.init" { |
| 1164 | { | 1199 | { |
| 1165 | var list = ArrayList(i32).init(testing.allocator); | 1200 | var list = ArrayList(i32).init(testing.allocator); |
| ... | @@ -1952,3 +1987,51 @@ test "std.ArrayList(u32).getLastOrNull()" { | ... | @@ -1952,3 +1987,51 @@ test "std.ArrayList(u32).getLastOrNull()" { |
| 1952 | const const_list = list; | 1987 | const const_list = list; |
| 1953 | try testing.expectEqual(const_list.getLastOrNull().?, 2); | 1988 | try testing.expectEqual(const_list.getLastOrNull().?, 2); |
| 1954 | } | 1989 | } |
| | 1990 | |
| | 1991 | test "return OutOfMemory when capacity would exceed maximum usize integer value" { |
| | 1992 | const a = testing.allocator; |
| | 1993 | const new_item: u32 = 42; |
| | 1994 | |
| | 1995 | { |
| | 1996 | var list: ArrayListUnmanaged(u32) = .{ |
| | 1997 | .items = undefined, |
| | 1998 | .capacity = math.maxInt(usize), |
| | 1999 | }; |
| | 2000 | list.items.len = math.maxInt(usize); |
| | 2001 | |
| | 2002 | try testing.expectError(error.OutOfMemory, list.append(a, new_item)); |
| | 2003 | try testing.expectError(error.OutOfMemory, list.appendSlice(a, &.{new_item})); |
| | 2004 | try testing.expectError(error.OutOfMemory, list.appendNTimes(a, new_item, 1)); |
| | 2005 | try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(a, &.{new_item})); |
| | 2006 | try testing.expectError(error.OutOfMemory, list.addOne(a)); |
| | 2007 | try testing.expectError(error.OutOfMemory, list.addManyAt(a, 0, 1)); |
| | 2008 | try testing.expectError(error.OutOfMemory, list.addManyAsArray(a, 1)); |
| | 2009 | try testing.expectError(error.OutOfMemory, list.addManyAsSlice(a, 1)); |
| | 2010 | try testing.expectError(error.OutOfMemory, list.insert(a, 0, new_item)); |
| | 2011 | try testing.expectError(error.OutOfMemory, list.insertSlice(a, 0, &.{new_item})); |
| | 2012 | try testing.expectError(error.OutOfMemory, list.toOwnedSliceSentinel(a, 0)); |
| | 2013 | try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(a, 1)); |
| | 2014 | } |
| | 2015 | |
| | 2016 | { |
| | 2017 | var list: ArrayList(u32) = .{ |
| | 2018 | .items = undefined, |
| | 2019 | .capacity = math.maxInt(usize), |
| | 2020 | .allocator = a, |
| | 2021 | }; |
| | 2022 | list.items.len = math.maxInt(usize); |
| | 2023 | |
| | 2024 | try testing.expectError(error.OutOfMemory, list.append(new_item)); |
| | 2025 | try testing.expectError(error.OutOfMemory, list.appendSlice(&.{new_item})); |
| | 2026 | try testing.expectError(error.OutOfMemory, list.appendNTimes(new_item, 1)); |
| | 2027 | try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(&.{new_item})); |
| | 2028 | try testing.expectError(error.OutOfMemory, list.addOne()); |
| | 2029 | try testing.expectError(error.OutOfMemory, list.addManyAt(0, 1)); |
| | 2030 | try testing.expectError(error.OutOfMemory, list.addManyAsArray(1)); |
| | 2031 | try testing.expectError(error.OutOfMemory, list.addManyAsSlice(1)); |
| | 2032 | try testing.expectError(error.OutOfMemory, list.insert(0, new_item)); |
| | 2033 | try testing.expectError(error.OutOfMemory, list.insertSlice(0, &.{new_item})); |
| | 2034 | try testing.expectError(error.OutOfMemory, list.toOwnedSliceSentinel(0)); |
| | 2035 | try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(1)); |
| | 2036 | } |
| | 2037 | } |