# ArrayList

> The growable array, now unmanaged.

```zig
const std = @import("std");
const expect = std.testing.expect;

test "build up a list" {
    const gpa = std.testing.allocator;

    // `.empty` replaces `init(allocator)`. The list does not store the
    // allocator, so every method that may allocate takes one.
    var list: std.ArrayList(u8) = .empty;
    defer list.deinit(gpa);

    try list.append(gpa, 'h');
    try list.appendSlice(gpa, "ello");

    try expect(std.mem.eql(u8, list.items, "hello"));
    try expect(list.items.len == 5);
}

test "items is a plain slice" {
    const gpa = std.testing.allocator;
    var list: std.ArrayList(u32) = .empty;
    defer list.deinit(gpa);

    for (0..5) |i| try list.append(gpa, @intCast(i * i));

    // `.items` is a `[]T` into the list's buffer, valid until the next
    // reallocation, so do not hold it across an append.
    try expect(list.items[4] == 16);
}

test "pop and remove" {
    const gpa = std.testing.allocator;
    var list: std.ArrayList(u8) = .empty;
    defer list.deinit(gpa);

    try list.appendSlice(gpa, "abcd");
    try expect(list.pop().? == 'd');
    _ = list.orderedRemove(0); // shifts the rest down
    try expect(std.mem.eql(u8, list.items, "bc"));
}

test "preallocate when the size is known" {
    const gpa = std.testing.allocator;
    var list: std.ArrayList(u8) = .empty;
    defer list.deinit(gpa);

    // One allocation instead of a growth sequence.
    try list.ensureTotalCapacity(gpa, 100);
    for (0..100) |_| list.appendAssumeCapacity('x');
    try expect(list.items.len == 100);
}

test "take ownership of the buffer" {
    const gpa = std.testing.allocator;
    var list: std.ArrayList(u8) = .empty;
    try list.appendSlice(gpa, "owned");

    // `toOwnedSlice` hands you the memory and empties the list, so the
    // caller frees the slice rather than deinit-ing the list.
    const slice = try list.toOwnedSlice(gpa);
    defer gpa.free(slice);
    try expect(std.mem.eql(u8, slice, "owned"));
}
```

*Runnable: compiled to WebAssembly and executed by CI against Zig master. (`03-standard-library.arraylist`)*

## It is unmanaged now

This is the change most likely to break code you find online. `std.ArrayList`
used to store its allocator:

```zig
var list = std.ArrayList(u8).init(allocator);   // old
defer list.deinit();
try list.append('a');
```

On master, `ArrayList` **is** the unmanaged variant. It holds no allocator, so
you supply one to every method that might allocate:

```zig
var list: std.ArrayList(u8) = .empty;           // current
defer list.deinit(gpa);
try list.append(gpa, 'a');
```

More typing, but the allocator is visible at every call site that can fail, and
the struct is two words smaller.

## `.items` is a borrowed slice

`list.items` points into the list's buffer. Appending may reallocate, which
invalidates any slice you were holding. Take `.items` when you need it; do not
stash it across mutations.

## Preallocate when you can

`ensureTotalCapacity` followed by `appendAssumeCapacity` turns a growth
sequence into one allocation, and the `AssumeCapacity` calls cannot fail, so
they need no `try`.

## Handing off ownership

`toOwnedSlice(gpa)` gives you the buffer and leaves the list empty. The caller
now frees the slice, and the list needs no `deinit`.
