# std.ArrayList (Zig 0.16.0) Dynamic array (vector) that grows as needed. **Note:** `std.ArrayListUnmanaged` is deprecated - use `std.ArrayList` (unmanaged-style API with allocator passed to methods). ## Initialization ```zig // Use the supported explicit empty initializer. var list: std.ArrayList(u32) = .empty; defer list.deinit(allocator); // With pre-allocated capacity var reserved = try std.ArrayList(u32).initCapacity(allocator, 100); defer reserved.deinit(allocator); // From existing slice (takes ownership) var list = std.ArrayList(u32).fromOwnedSlice(existing_slice); // Fixed buffer: use bounded/no-allocator operations only. Passing an allocator // to a method on an initBuffer list is illegal. var buffer: [8]i32 = undefined; var stack = std.ArrayList(i32).initBuffer(&buffer); ``` ## Basic Operations ```zig // Append try list.append(allocator, 42); try list.appendSlice(allocator, &[_]u32{1, 2, 3}); // Append without allocation (asserts capacity exists) list.appendAssumeCapacity(42); list.appendSliceAssumeCapacity(&[_]u32{1, 2, 3}); // Access items const items = list.items; // []T slice const first = list.items[0]; const last = list.getLast(); // returns T; asserts if empty const maybe_last = list.getLastOrNull(); // returns ?T const popped = list.pop(); // returns ?T, removes last // Insert at index try list.insert(allocator, 2, value); try list.insertSlice(allocator, 2, slice); // Remove const removed_ordered = list.orderedRemove(index); // O(n), preserves order const removed_swapped = list.swapRemove(index); // O(1), changes order ``` ## Capacity Management ```zig // Ensure space for N more items try list.ensureUnusedCapacity(allocator, 10); // Ensure total capacity is at least N try list.ensureTotalCapacity(allocator, 100); // Attempt to shrink capacity. If resizing runs out of memory, the list keeps // excess capacity while still reducing its logical length. list.shrinkAndFree(allocator, list.items.len); // Clear list.clearRetainingCapacity(); // keeps memory list.clearAndFree(allocator); // frees memory ``` ## Ownership Transfer ```zig // Get owned slice (empties list, caller owns memory) const owned = try list.toOwnedSlice(allocator); defer allocator.free(owned); // Get null-terminated slice const z_str = try list.toOwnedSliceSentinel(allocator, 0); defer allocator.free(z_str); ``` ## Iteration ```zig for (list.items) |item| { // read-only } for (list.items) |*item| { item.* += 1; // modify in place } for (list.items, 0..) |item, i| { // with index } ``` ## Common Patterns ```zig // Collect from iterator var list: std.ArrayList(u8) = .empty; for (some_iterator) |item| { try list.append(allocator, item); } // Build string var buf: std.ArrayList(u8) = .empty; try buf.appendSlice(allocator, "Hello "); try buf.appendSlice(allocator, name); const result = try buf.toOwnedSlice(allocator); // Remove while iterating (iterate backwards) var i: usize = list.items.len; while (i > 0) { i -= 1; if (shouldRemove(list.items[i])) { _ = list.swapRemove(i); } } ``` ## Reserve-First Pattern (Exception Safety) When inserting into multiple containers or when partial mutation would corrupt state, use **reserve-first**: separate fallible reservation from infallible mutation. ```zig // BAD - partial failure leaves invalid state fn addItem(list: *std.ArrayList(u32), map: *std.AutoHashMapUnmanaged(u32, usize), gpa: Allocator, value: u32) !void { try list.append(gpa, value); // Can fail try map.put(gpa, value, list.items.len - 1); // If this fails, list has orphan entry! } // GOOD - reserve first, then mutate fn addItem(list: *std.ArrayList(u32), map: *std.AutoHashMapUnmanaged(u32, usize), gpa: Allocator, value: u32) !void { if (map.contains(value)) return error.DuplicateItem; const index = list.items.len; // Phase 1: Reserve. Logical contents are unchanged, but capacity may grow // and existing element pointers may be invalidated. try list.ensureUnusedCapacity(gpa, 1); try map.ensureUnusedCapacity(gpa, 1); errdefer comptime unreachable; // Phase 2: No errors after this point // Phase 3: Mutate (infallible) list.appendAssumeCapacity(value); map.putAssumeCapacityNoClobber(value, index); } ``` **Key methods:** - `ensureUnusedCapacity(gpa, n)` - Reserve space for n more items. It can fail and can reallocate, but it does not append or remove logical elements. - `appendAssumeCapacity(item)` - Append without allocation (cannot fail, asserts capacity) - `appendSliceAssumeCapacity(items)` - Append slice without allocation See **[Reserve-First Exception Safety](patterns.md#reserve-first-exception-safety)** for detailed explanation and real-world examples. ## BoundedArray Replacement `std.BoundedArray` was REMOVED in 0.15.x. Use `initBuffer` instead: ```zig // OLD (removed) var arr = std.BoundedArray(u8, 64){}; // NEW var buffer: [64]u8 = undefined; var arr = std.ArrayList(u8).initBuffer(&buffer); // Bounded operations report capacity exhaustion. try arr.appendBounded(value); // error.OutOfMemory if full // Assume-capacity operations assert; allocator-taking operations are illegal // for an initBuffer list. ```