Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig standard library. Public Type Function

AlignedManaged

Public Type Function
std.array_list.AlignedManaged
pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type

Deprecated.

Fields

items: Slice

Contents of the list. This field is intended to be accessed directly.

Pointers to elements in this slice are invalidated by various functions of this ArrayList in accordance with the respective documentation. An invalidated pointer may point either to valid or freed memory.

capacity: usize

How many T values this list can hold without allocating additional memory.

allocator: Allocator
pointer_stability: debug.SafetyLock

Used to detect memory safety violations.

Types

Values

Functions

pub fn init(gpa: Allocator) Self

Deinitialize with deinit or use toOwnedSlice.

pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self

Initialize with capacity to hold num elements. The resulting capacity will equal num exactly. Deinitialize with deinit or use toOwnedSlice.

pub fn deinit(self: Self) void

Release all allocated memory.

pub fn lockPointers(self: *Self) void

Puts the array list into a state where any method call that would cause an existing value pointer to become invalidated will instead trigger an assertion.

An additional call to lockPointers in such state also triggers an assertion.

unlockPointers returns the array list to the previous state.

pub fn unlockPointers(self: *Self) void

Undoes a call to lockPointers.

pub fn fromOwnedSlice(gpa: Allocator, slice: Slice) Self

ArrayList takes ownership of the passed in slice. The slice must have been allocated with gpa. Deinitialize with deinit or use toOwnedSlice.

pub fn fromOwnedSliceSentinel(gpa: Allocator, comptime sentinel: T, slice: [: sentinel]T) Self

ArrayList takes ownership of the passed in slice. The slice must have been allocated with gpa. Deinitialize with deinit or use toOwnedSlice.

pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment)

Initializes an ArrayList with the items and capacity fields of this ArrayList. Empties this ArrayList.

pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice

The caller owns the returned memory. Empties this ArrayList. Its capacity is cleared, making deinit safe but unnecessary to call. May invalidate element pointers if remapping memory cannot be done in place.

pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel)

The caller owns the returned memory. Empties this ArrayList. May invalidate element pointers if remapping memory cannot be done in place.

pub fn clone(self: Self) Allocator.Error!Self

Creates a copy of this ArrayList, using the same allocator.

pub fn insert(self: *Self, index: usize, item: T) Allocator.Error!void

Insert item at index index. Moves list[index .. list.len] to higher indices to make room. If index is equal to the length of the list this operation is equivalent to append. This operation is O(N). Invalidates element pointers if additional memory is needed. Invalidates pre-existing pointers to elements at and after index. Asserts that the index is in bounds or equal to the length.

pub fn insertAssumeCapacity(self: *Self, index: usize, item: T) void

Insert item at index index. Moves list[index .. list.len] to higher indices to make room. If index is equal to the length of the list this operation is equivalent to appendAssumeCapacity. This operation is O(N). Invalidates pre-existing pointers to elements at and after index. Asserts that there is enough capacity for the new item. Asserts that the index is in bounds or equal to the length.

pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T

Add count new elements at position index, which have undefined values. Returns a slice pointing to the newly allocated elements, which becomes invalid after various ArrayList operations. Invalidates pre-existing pointers to elements at and after index. Invalidates all pre-existing element pointers if capacity must be increased to accommodate the new elements. Asserts that the index is in bounds or equal to the length.

pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T

Add count new elements at position index, which have undefined values. Returns a slice pointing to the newly allocated elements, which becomes invalid after various ArrayList operations. Invalidates pre-existing pointers to elements at and after index. Asserts that there is enough capacity for the new elements. Asserts that the index is in bounds or equal to the length.

pub fn insertSlice(self: *Self, index: usize, items: []const T) Allocator.Error!void

Insert slice items at index index by moving list[index .. list.len] to make room. This operation is O(N). Invalidates pre-existing pointers to elements at and after index. Invalidates all pre-existing element pointers if capacity must be increased to accommodate the new elements. Asserts that the index is in bounds or equal to the length.

pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void

Grows or shrinks the list as necessary. Invalidates element pointers if additional capacity is allocated, Invalidates pointers to elements at and above index start + len when len and new_items.len are unequal. Asserts that the range is in bounds.

pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void

Grows or shrinks the list as necessary. Invalidates pointers to elements at and above index start + len when len and new_items.len are unequal. Asserts the capacity is enough for additional items.

pub fn append(self: *Self, item: T) Allocator.Error!void

Extends the list by 1 element. Allocates more memory as necessary. Invalidates element pointers if additional memory is needed.

pub fn appendAssumeCapacity(self: *Self, item: T) void

Extends the list by 1 element. Never invalidates element pointers. Asserts that the list can hold one additional item.

pub fn orderedRemove(self: *Self, i: usize) T

Remove the element at index i, shift elements after index i forward, and return the removed element. Invalidates element pointers to end of list. This operation is O(N). This preserves item order. Use swapRemove if order preservation is not important. Asserts that the index is in bounds. Asserts that the list is not empty.

pub fn swapRemove(self: *Self, i: usize) T

Removes the element at the specified index and returns it. The empty slot is filled from the end of the list. Invalidates pointers to the end of the list. This operation is O(1). This may not preserve item order. Use orderedRemove if you need to preserve order. Asserts that the index is in bounds.

pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void

Append the slice of items to the list. Allocates more memory as necessary. Invalidates element pointers if additional memory is needed.

pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void

Append the slice of items to the list. Never invalidates element pointers. Asserts that the list can hold the additional items.

pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void

Append an unaligned slice of items to the list. Allocates more memory as necessary. Only call this function if calling appendSlice instead would be a compile error. Invalidates element pointers if additional memory is needed.

pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void

Append the slice of items to the list. Never invalidates element pointers. This function is only needed when calling appendSliceAssumeCapacity instead would be a compile error due to the alignment of the items parameter. Asserts that the list can hold the additional items.

pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error

Prints a formatted string into this list. Invalidates element pointers if additional memory is needed.

pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void
pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void
pub fn resize(self: *Self, new_len: usize) Allocator.Error!void

Adjust the list length to new_len. Additional elements contain the value undefined. Invalidates element pointers if additional memory is needed.

pub fn shrinkAndFree(self: *Self, new_len: usize) void

Reduce allocated capacity to new_len. May invalidate element pointers. Asserts that the new length is less than or equal to the previous length.

pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void

Reduce length to new_len. Invalidates element pointers for the elements items[new_len..]. Asserts that the new length is less than or equal to the previous length.

pub fn clearRetainingCapacity(self: *Self) void

Reduce length to 0. Invalidates all element pointers.

pub fn clearAndFree(self: *Self) void

Invalidates all element pointers.

pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void

If the current capacity is less than new_capacity, this function will modify the array so that it can hold at least new_capacity items. Invalidates element pointers if additional memory is needed.

pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void

If the current capacity is less than new_capacity, this function will modify the array so that it can hold exactly new_capacity items. Invalidates element pointers if additional memory is needed.

pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void

Modify the array so that it can hold at least additional_count more items. Invalidates element pointers if additional memory is needed.

pub fn expandToCapacity(self: *Self) void

Increases the array's length to match the full capacity that is already allocated. The new elements have undefined values. Never invalidates element pointers.

pub fn addOne(self: *Self) Allocator.Error!*T

Increase length by 1, returning pointer to the new item. Invalidates element pointers if additional memory is needed. The returned pointer may be invalidated by further operations to this list.

pub fn addOneAssumeCapacity(self: *Self) *T

Increase length by 1, returning pointer to the new item. The returned pointer may be invalidated by further operations to this list. Never invalidates element pointers. Asserts that the list can hold one additional item.

pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T

Resize the array, adding n new elements, which have undefined values. The return value is an array pointing to the newly allocated elements. The returned pointer may be invalidated by further operations to this list. Resizes list if self.capacity is not large enough. Invalidates element pointers if additional memory is needed.

pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T

Resize the array, adding n new elements, which have undefined values. The return value is an array pointing to the newly allocated elements. Never invalidates element pointers. The returned pointer may be invalidated by further operations to this list. Asserts that the list can hold the additional items.

pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T

Resize the array, adding n new elements, which have undefined values. The return value is a slice pointing to the newly allocated elements. The returned pointer may be invalidated by further operations to this list. Resizes list if self.capacity is not large enough. Invalidates element pointers if additional memory is needed.

pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T

Resize the array, adding n new elements, which have undefined values. The return value is a slice pointing to the newly allocated elements. Never invalidates element pointers. The returned pointer may be invalidated by further operations to this list. Asserts that the list can hold the additional items.

pub fn pop(self: *Self) ?T

Remove and return the last element from the list, or return null if list is empty. Invalidates element pointers to the removed element.

pub fn allocatedSlice(self: Self) Slice

Returns a slice of all the items plus the extra capacity, whose memory contents are undefined. The returned pointer may be invalidated by further operations to this list.

pub fn unusedCapacitySlice(self: Self) []T

Returns a slice of only the extra capacity after items. This can be useful for writing directly into an ArrayList. Note that such an operation must be followed up with a direct modification of self.items.len. The returned pointer may be invalidated by further operations to this list.

pub fn getLast(self: Self) T

Deprecated

pub fn last(self: Self) ?T

Returns the last element from the list, or null if the list is empty. Never invalidates element pointers.

pub fn last(self: Self) ?T

Returns the last element from the list, or null if the list is empty. Never invalidates element pointers.

pub fn lastPtr(self: Self) ?*T

Returns a pointer to the last element from the list, or null if the list is empty. The returned pointer may be invalidated by further operations to this list.

File

array_list.zig:16
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type {
    if (alignment) |a| {
        if (a.toByteUnits() == @alignOf(T)) {
            return AlignedManaged(T, null);
        }
    }
    return struct {
        const Self = @This();
        /// Contents of the list. This field is intended to be accessed
        /// directly.
        ///
        /// Pointers to elements in this slice are invalidated by various
        /// functions of this ArrayList in accordance with the respective
        /// documentation.
        ///  An invalidated pointer may point either to valid or freed memory.
        items: Slice,
        /// How many T values this list can hold without allocating
        /// additional memory.
        capacity: usize,
        allocator: Allocator,

        /// Used to detect memory safety violations.
        pointer_stability: debug.SafetyLock,

        pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T;

        pub fn SentinelSlice(comptime s: T) type {
            return if (alignment) |a| ([:s]align(a.toByteUnits()) T) else [:s]T;
        }

        /// Deinitialize with `deinit` or use `toOwnedSlice`.
        pub fn init(gpa: Allocator) Self {
            return Self{
                .items = &[_]T{},
                .capacity = 0,
                .allocator = gpa,
                .pointer_stability = .{},
            };
        }

        /// Initialize with capacity to hold `num` elements.
        /// The resulting capacity will equal `num` exactly.
        /// Deinitialize with `deinit` or use `toOwnedSlice`.
        pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self {
            var self = Self.init(gpa);
            try self.ensureTotalCapacityPrecise(num);
            return self;
        }

        /// Release all allocated memory.
        pub fn deinit(self: Self) void {
            self.pointer_stability.assertUnlocked();
            if (@sizeOf(T) > 0) {
                self.allocator.free(self.allocatedSlice());
            }
        }

        /// Puts the array list into a state where any method call that would
        /// cause an existing value pointer to become invalidated will
        /// instead trigger an assertion.
        ///
        /// An additional call to `lockPointers` in such state also triggers an
        /// assertion.
        ///
        /// `unlockPointers` returns the array list to the previous state.
        pub fn lockPointers(self: *Self) void {
            self.pointer_stability.lock();
        }

        /// Undoes a call to `lockPointers`.
        pub fn unlockPointers(self: *Self) void {
            self.pointer_stability.unlock();
        }

        /// ArrayList takes ownership of the passed in slice. The slice must have been
        /// allocated with `gpa`.
        /// Deinitialize with `deinit` or use `toOwnedSlice`.
        pub fn fromOwnedSlice(gpa: Allocator, slice: Slice) Self {
            return Self{
                .items = slice,
                .capacity = slice.len,
                .allocator = gpa,
                .pointer_stability = .{},
            };
        }

        /// ArrayList takes ownership of the passed in slice. The slice must have been
        /// allocated with `gpa`.
        /// Deinitialize with `deinit` or use `toOwnedSlice`.
        pub fn fromOwnedSliceSentinel(gpa: Allocator, comptime sentinel: T, slice: [:sentinel]T) Self {
            return Self{
                .items = slice,
                .capacity = slice.len + 1,
                .allocator = gpa,
                .pointer_stability = .{},
            };
        }

        /// Initializes an ArrayList with the `items` and `capacity` fields
        /// of this ArrayList. Empties this ArrayList.
        pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment) {
            const allocator = self.allocator;
            const result: Aligned(T, alignment) = .{
                .items = self.items,
                .capacity = self.capacity,
                .pointer_stability = self.pointer_stability,
            };
            self.* = init(allocator);
            return result;
        }

        /// The caller owns the returned memory. Empties this ArrayList.
        /// Its capacity is cleared, making `deinit` safe but unnecessary to call.
        /// May invalidate element pointers if remapping memory cannot be done in place.
        pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice {
            self.pointer_stability.assertUnlocked();
            const allocator = self.allocator;

            const old_memory = self.allocatedSlice();
            if (allocator.remap(old_memory, self.items.len)) |new_items| {
                self.* = init(allocator);
                return new_items;
            }

            const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);
            @memcpy(new_memory, self.items);
            self.clearAndFree();
            return new_memory;
        }

        /// The caller owns the returned memory. Empties this ArrayList.
        /// May invalidate element pointers if remapping memory cannot be done in place.
        pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
            // This addition can never overflow because `self.items` can never occupy the whole address space
            try self.ensureTotalCapacityPrecise(self.items.len + 1);
            self.appendAssumeCapacity(sentinel);
            const result = try self.toOwnedSlice();
            return result[0 .. result.len - 1 :sentinel];
        }

        /// Creates a copy of this ArrayList, using the same allocator.
        pub fn clone(self: Self) Allocator.Error!Self {
            var cloned = try Self.initCapacity(self.allocator, self.capacity);
            cloned.appendSliceAssumeCapacity(self.items);
            return cloned;
        }

        /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
        /// If `index` is equal to the length of the list this operation is equivalent to append.
        /// This operation is O(N).
        /// Invalidates element pointers if additional memory is needed.
        /// Invalidates pre-existing pointers to elements at and after `index`.
        /// Asserts that the index is in bounds or equal to the length.
        pub fn insert(self: *Self, index: usize, item: T) Allocator.Error!void {
            self.pointer_stability.assertUnlocked();
            const dst = try self.addManyAt(index, 1);
            dst[0] = item;
        }

        /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room.
        /// If `index` is equal to the length of the list this operation is
        /// equivalent to appendAssumeCapacity.
        /// This operation is O(N).
        /// Invalidates pre-existing pointers to elements at and after `index`.
        /// Asserts that there is enough capacity for the new item.
        /// Asserts that the index is in bounds or equal to the length.
        pub fn insertAssumeCapacity(self: *Self, index: usize, item: T) void {
            self.pointer_stability.assertUnlocked();
            assert(self.items.len < self.capacity);
            self.items.len += 1;
            @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]);
            self.items[index] = item;
        }

        /// Add `count` new elements at position `index`, which have
        /// `undefined` values. Returns a slice pointing to the newly allocated
        /// elements, which becomes invalid after various `ArrayList`
        /// operations.
        /// Invalidates pre-existing pointers to elements at and after `index`.
        /// Invalidates all pre-existing element pointers if capacity must be
        /// increased to accommodate the new elements.
        /// Asserts that the index is in bounds or equal to the length.
        pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T {
            const new_len = try addOrOom(self.items.len, count);
            self.pointer_stability.assertUnlocked();

            if (self.capacity >= new_len)
                return addManyAtAssumeCapacity(self, index, count);

            // Here we avoid copying allocated but unused bytes by
            // attempting a resize in place, and falling back to allocating
            // a new buffer and doing our own copy. With a realloc() call,
            // the allocator implementation would pointlessly copy our
            // extra capacity.
            const new_capacity = Aligned(T, alignment).growCapacity(new_len);
            const old_memory = self.allocatedSlice();
            if (self.allocator.remap(old_memory, new_capacity)) |new_memory| {
                self.items.ptr = new_memory.ptr;
                self.capacity = new_memory.len;
                return addManyAtAssumeCapacity(self, index, count);
            }

            // Make a new allocation, avoiding `ensureTotalCapacity` in order
            // to avoid extra memory copies.
            const new_memory = try self.allocator.alignedAlloc(T, alignment, new_capacity);
            const to_move = self.items[index..];
            @memcpy(new_memory[0..index], self.items[0..index]);
            @memcpy(new_memory[index + count ..][0..to_move.len], to_move);
            self.allocator.free(old_memory);
            self.items = new_memory[0..new_len];
            self.capacity = new_memory.len;
            // The inserted elements at `new_memory[index..][0..count]` have
            // already been set to `undefined` by memory allocation.
            return new_memory[index..][0..count];
        }

        /// Add `count` new elements at position `index`, which have
        /// `undefined` values. Returns a slice pointing to the newly allocated
        /// elements, which becomes invalid after various `ArrayList`
        /// operations.
        /// Invalidates pre-existing pointers to elements at and after `index`.
        /// Asserts that there is enough capacity for the new elements.
        /// Asserts that the index is in bounds or equal to the length.
        pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T {
            self.pointer_stability.assertUnlocked();
            const new_len = self.items.len + count;
            assert(self.capacity >= new_len);
            const to_move = self.items[index..];
            self.items.len = new_len;
            @memmove(self.items[index + count ..][0..to_move.len], to_move);
            const result = self.items[index..][0..count];
            @memset(result, undefined);
            return result;
        }

        /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room.
        /// This operation is O(N).
        /// Invalidates pre-existing pointers to elements at and after `index`.
        /// Invalidates all pre-existing element pointers if capacity must be
        /// increased to accommodate the new elements.
        /// Asserts that the index is in bounds or equal to the length.
        pub fn insertSlice(
            self: *Self,
            index: usize,
            items: []const T,
        ) Allocator.Error!void {
            const dst = try self.addManyAt(index, items.len);
            @memcpy(dst, items);
        }

        /// Grows or shrinks the list as necessary.
        /// Invalidates element pointers if additional capacity is allocated,
        /// Invalidates pointers to elements at and above index `start + len`
        /// when `len` and `new_items.len` are unequal.
        /// Asserts that the range is in bounds.
        pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {
            var unmanaged = self.moveToUnmanaged();
            defer self.* = unmanaged.toManaged(self.allocator);
            return unmanaged.replaceRange(self.allocator, start, len, new_items);
        }

        /// Grows or shrinks the list as necessary.
        /// Invalidates pointers to elements at and above index `start + len`
        /// when `len` and `new_items.len` are unequal.
        /// Asserts the capacity is enough for additional items.
        pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void {
            var unmanaged = self.moveToUnmanaged();
            defer self.* = unmanaged.toManaged(self.allocator);
            return unmanaged.replaceRangeAssumeCapacity(start, len, new_items);
        }

        /// Extends the list by 1 element. Allocates more memory as necessary.
        /// Invalidates element pointers if additional memory is needed.
        pub fn append(self: *Self, item: T) Allocator.Error!void {
            const new_item_ptr = try self.addOne();
            new_item_ptr.* = item;
        }

        /// Extends the list by 1 element.
        /// Never invalidates element pointers.
        /// Asserts that the list can hold one additional item.
        pub fn appendAssumeCapacity(self: *Self, item: T) void {
            self.addOneAssumeCapacity().* = item;
        }

        /// Remove the element at index `i`, shift elements after index
        /// `i` forward, and return the removed element.
        /// Invalidates element pointers to end of list.
        /// This operation is O(N).
        /// This preserves item order. Use `swapRemove` if order preservation is not important.
        /// Asserts that the index is in bounds.
        /// Asserts that the list is not empty.
        pub fn orderedRemove(self: *Self, i: usize) T {
            const old_item = self.items[i];
            self.replaceRangeAssumeCapacity(i, 1, &.{});
            return old_item;
        }

        /// Removes the element at the specified index and returns it.
        /// The empty slot is filled from the end of the list.
        /// Invalidates pointers to the end of the list.
        /// This operation is O(1).
        /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.
        /// Asserts that the index is in bounds.
        pub fn swapRemove(self: *Self, i: usize) T {
            self.pointer_stability.assertUnlocked();
            const val = self.items[i];
            self.items[i] = self.items[self.items.len - 1];
            self.items[self.items.len - 1] = undefined;
            self.items.len -= 1;
            return val;
        }

        /// Append the slice of items to the list. Allocates more
        /// memory as necessary.
        /// Invalidates element pointers if additional memory is needed.
        pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void {
            try self.ensureUnusedCapacity(items.len);
            self.appendSliceAssumeCapacity(items);
        }

        /// Append the slice of items to the list.
        /// Never invalidates element pointers.
        /// Asserts that the list can hold the additional items.
        pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
            const old_len = self.items.len;
            const new_len = old_len + items.len;
            assert(new_len <= self.capacity);
            self.items.len = new_len;
            @memcpy(self.items[old_len..][0..items.len], items);
        }

        /// Append an unaligned slice of items to the list. Allocates more
        /// memory as necessary. Only call this function if calling
        /// `appendSlice` instead would be a compile error.
        /// Invalidates element pointers if additional memory is needed.
        pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void {
            try self.ensureUnusedCapacity(items.len);
            self.appendUnalignedSliceAssumeCapacity(items);
        }

        /// Append the slice of items to the list.
        /// Never invalidates element pointers.
        /// This function is only needed when calling
        /// `appendSliceAssumeCapacity` instead would be a compile error due to the
        /// alignment of the `items` parameter.
        /// Asserts that the list can hold the additional items.
        pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
            const old_len = self.items.len;
            const new_len = old_len + items.len;
            assert(new_len <= self.capacity);
            self.items.len = new_len;
            @memcpy(self.items[old_len..][0..items.len], items);
        }

        /// Prints a formatted string into this list.
        /// Invalidates element pointers if additional memory is needed.
        pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
            const gpa = self.allocator;
            var unmanaged = self.moveToUnmanaged();
            defer self.* = unmanaged.toManaged(gpa);
            try unmanaged.print(gpa, fmt, args);
        }

        /// Append a value to the list `n` times.
        /// Allocates more memory as necessary.
        /// Invalidates element pointers if additional memory is needed.
        /// The function is inline so that a comptime-known `value` parameter will
        /// have a more optimal memset codegen in case it has a repeated byte pattern.
        pub inline fn appendNTimes(self: *Self, value: T, n: usize) Allocator.Error!void {
            const old_len = self.items.len;
            try self.resize(try addOrOom(old_len, n));
            @memset(self.items[old_len..self.items.len], value);
        }

        /// Append a value to the list `n` times.
        /// Never invalidates element pointers.
        /// The function is inline so that a comptime-known `value` parameter will
        /// have a more optimal memset codegen in case it has a repeated byte pattern.
        /// Asserts that the list can hold the additional items.
        pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
            const new_len = self.items.len + n;
            assert(new_len <= self.capacity);
            @memset(self.items.ptr[self.items.len..new_len], value);
            self.items.len = new_len;
        }

        /// Adjust the list length to `new_len`.
        /// Additional elements contain the value `undefined`.
        /// Invalidates element pointers if additional memory is needed.
        pub fn resize(self: *Self, new_len: usize) Allocator.Error!void {
            try self.ensureTotalCapacity(new_len);
            self.items.len = new_len;
        }

        /// Reduce allocated capacity to `new_len`.
        /// May invalidate element pointers.
        /// Asserts that the new length is less than or equal to the previous length.
        pub fn shrinkAndFree(self: *Self, new_len: usize) void {
            var unmanaged = self.moveToUnmanaged();
            unmanaged.shrinkAndFree(self.allocator, new_len);
            self.* = unmanaged.toManaged(self.allocator);
        }

        /// Reduce length to `new_len`.
        /// Invalidates element pointers for the elements `items[new_len..]`.
        /// Asserts that the new length is less than or equal to the previous length.
        pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
            self.pointer_stability.assertUnlocked();
            assert(new_len <= self.items.len);
            @memset(self.items[new_len..], undefined);
            self.items.len = new_len;
        }

        /// Reduce length to 0.
        /// Invalidates all element pointers.
        pub fn clearRetainingCapacity(self: *Self) void {
            self.pointer_stability.assertUnlocked();
            @memset(self.items, undefined);
            self.items.len = 0;
        }

        /// Invalidates all element pointers.
        pub fn clearAndFree(self: *Self) void {
            self.pointer_stability.assertUnlocked();
            self.allocator.free(self.allocatedSlice());
            self.items.len = 0;
            self.capacity = 0;
        }

        /// If the current capacity is less than `new_capacity`, this function will
        /// modify the array so that it can hold at least `new_capacity` items.
        /// Invalidates element pointers if additional memory is needed.
        pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void {
            if (@sizeOf(T) == 0) {
                self.capacity = math.maxInt(usize);
                return;
            }

            // Protects growing unnecessarily since better_capacity will be larger.
            if (self.capacity >= new_capacity) return;

            const better_capacity = Aligned(T, alignment).growCapacity(new_capacity);
            return self.ensureTotalCapacityPrecise(better_capacity);
        }

        /// If the current capacity is less than `new_capacity`, this function will
        /// modify the array so that it can hold exactly `new_capacity` items.
        /// Invalidates element pointers if additional memory is needed.
        pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void {
            if (@sizeOf(T) == 0) {
                self.capacity = math.maxInt(usize);
                return;
            }

            if (self.capacity >= new_capacity) return;
            self.pointer_stability.assertUnlocked();
            // Here we avoid copying allocated but unused bytes by
            // attempting a remap, and falling back to allocating
            // a new buffer and doing our own copy. With a realloc() call,
            // the allocator implementation would pointlessly copy our
            // extra capacity.
            const old_memory = self.allocatedSlice();
            if (self.allocator.remap(old_memory, new_capacity)) |new_memory| {
                self.items.ptr = new_memory.ptr;
                self.capacity = new_memory.len;
            } else {
                const new_memory = try self.allocator.alignedAlloc(T, alignment, new_capacity);
                @memcpy(new_memory[0..self.items.len], self.items);
                self.allocator.free(old_memory);
                self.items.ptr = new_memory.ptr;
                self.capacity = new_memory.len;
            }
        }

        /// Modify the array so that it can hold at least `additional_count` **more** items.
        /// Invalidates element pointers if additional memory is needed.
        pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) Allocator.Error!void {
            return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count));
        }

        /// Increases the array's length to match the full capacity that is already allocated.
        /// The new elements have `undefined` values.
        /// Never invalidates element pointers.
        pub fn expandToCapacity(self: *Self) void {
            self.items.len = self.capacity;
        }

        /// Increase length by 1, returning pointer to the new item.
        /// Invalidates element pointers if additional memory is needed.
        /// The returned pointer may be invalidated by further operations to this list.
        pub fn addOne(self: *Self) Allocator.Error!*T {
            // This can never overflow because `self.items` can never occupy the whole address space
            const newlen = self.items.len + 1;
            try self.ensureTotalCapacity(newlen);
            return self.addOneAssumeCapacity();
        }

        /// Increase length by 1, returning pointer to the new item.
        /// The returned pointer may be invalidated by further operations to this list.
        /// Never invalidates element pointers.
        /// Asserts that the list can hold one additional item.
        pub fn addOneAssumeCapacity(self: *Self) *T {
            assert(self.items.len < self.capacity);
            self.items.len += 1;
            return &self.items[self.items.len - 1];
        }

        /// Resize the array, adding `n` new elements, which have `undefined` values.
        /// The return value is an array pointing to the newly allocated elements.
        /// The returned pointer may be invalidated by further operations to this list.
        /// Resizes list if `self.capacity` is not large enough.
        /// Invalidates element pointers if additional memory is needed.
        pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T {
            const prev_len = self.items.len;
            try self.resize(try addOrOom(self.items.len, n));
            return self.items[prev_len..][0..n];
        }

        /// Resize the array, adding `n` new elements, which have `undefined` values.
        /// The return value is an array pointing to the newly allocated elements.
        /// Never invalidates element pointers.
        /// The returned pointer may be invalidated by further operations to this list.
        /// Asserts that the list can hold the additional items.
        pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T {
            assert(self.items.len + n <= self.capacity);
            const prev_len = self.items.len;
            self.items.len += n;
            return self.items[prev_len..][0..n];
        }

        /// Resize the array, adding `n` new elements, which have `undefined` values.
        /// The return value is a slice pointing to the newly allocated elements.
        /// The returned pointer may be invalidated by further operations to this list.
        /// Resizes list if `self.capacity` is not large enough.
        /// Invalidates element pointers if additional memory is needed.
        pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T {
            const prev_len = self.items.len;
            try self.resize(try addOrOom(self.items.len, n));
            return self.items[prev_len..][0..n];
        }

        /// Resize the array, adding `n` new elements, which have `undefined` values.
        /// The return value is a slice pointing to the newly allocated elements.
        /// Never invalidates element pointers.
        /// The returned pointer may be invalidated by further operations to this list.
        /// Asserts that the list can hold the additional items.
        pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T {
            assert(self.items.len + n <= self.capacity);
            const prev_len = self.items.len;
            self.items.len += n;
            return self.items[prev_len..][0..n];
        }

        /// Remove and return the last element from the list, or return `null` if list is empty.
        /// Invalidates element pointers to the removed element.
        pub fn pop(self: *Self) ?T {
            if (self.items.len == 0) return null;
            self.pointer_stability.assertUnlocked();
            const val = self.items[self.items.len - 1];
            self.items[self.items.len - 1] = undefined;
            self.items.len -= 1;
            return val;
        }

        /// Returns a slice of all the items plus the extra capacity, whose memory
        /// contents are `undefined`.
        /// The returned pointer may be invalidated by further operations to this list.
        pub fn allocatedSlice(self: Self) Slice {
            // `items.len` is the length, not the capacity.
            return self.items.ptr[0..self.capacity];
        }

        /// Returns a slice of only the extra capacity after items.
        /// This can be useful for writing directly into an ArrayList.
        /// Note that such an operation must be followed up with a direct
        /// modification of `self.items.len`.
        /// The returned pointer may be invalidated by further operations to this list.
        pub fn unusedCapacitySlice(self: Self) []T {
            return self.allocatedSlice()[self.items.len..];
        }

        /// Deprecated
        pub fn getLast(self: Self) T {
            return self.items[self.items.len - 1];
        }

        /// Deprecated in favor of `last`
        pub const getLastOrNull = last;

        /// Returns the last element from the list, or `null` if the list is
        /// empty.
        /// Never invalidates element pointers.
        pub fn last(self: Self) ?T {
            if (self.items.len == 0) return null;
            return self.items[self.items.len - 1];
        }

        /// Returns a pointer to the last element from the list, or `null` if
        /// the list is empty.
        /// The returned pointer may be invalidated by further operations to this list.
        pub fn lastPtr(self: Self) ?*T {
            if (self.items.len == 0) return null;
            return &self.items[self.items.len - 1];
        }
    };
}