3.3 KiB
3.3 KiB
std.SegmentedList - removed in Zig 0.16.0
Primary Zig 0.16 release-note source: https://ziglang.org/download/0.16.0/release-notes.html
std.SegmentedList was removed in Zig 0.16. Do not use the API below in new code. Choose a project-owned segmented container, an arena-backed structure, an index-based std.ArrayList, or another stable-handle design depending on the ownership/lifetime requirement.
A dynamic list where element pointers remain stable across growth. Unlike ArrayList, appending never invalidates existing pointers. Elements are stored in exponentially-sized segments.
When to Use
- Need stable pointers to elements (pointers survive append)
- Arena allocator backing (avoids wasted memory on reallocation)
- Non-copyable element types
- Stack-like access patterns (append/pop)
Trade-offs
- Elements not contiguous (most are, but not guaranteed)
- O(log n) random access (vs O(1) for ArrayList)
- Higher per-element overhead
Initialization
// Without preallocation
var list = std.SegmentedList(i32, 0){};
defer list.deinit(allocator);
// With preallocation (must be power of 2)
// First N elements stored inline, no allocation needed
var list = std.SegmentedList(i32, 16){};
defer list.deinit(allocator);
Basic Operations
// Append (pointer remains valid forever)
try list.append(allocator, 42);
try list.appendSlice(allocator, &[_]i32{ 1, 2, 3 });
// Get pointer to element (STABLE across appends)
const ptr = list.at(0); // *i32
ptr.* = 100; // modify in place
// Add and get pointer in one operation
const new_ptr = try list.addOne(allocator);
new_ptr.* = 42;
// Pop
const last = list.pop(); // ?i32
// Length
const n = list.count();
// Or: list.len
Iteration
// Forward iteration with mutable access
var it = list.iterator(0); // start at index 0
while (it.next()) |ptr| {
ptr.* += 1; // modify in place
}
// Const iteration
var it = list.constIterator(0);
while (it.next()) |ptr| {
std.debug.print("{}\n", .{ptr.*});
}
// Bidirectional
while (it.prev()) |ptr| {
// ...
}
// Peek without advancing
if (it.peek()) |ptr| {
// ...
}
// Jump to index
it.set(50);
Capacity Management
// Grow capacity
try list.growCapacity(allocator, 100);
try list.setCapacity(allocator, 100); // grow or shrink
// Shrink
list.shrinkCapacity(allocator, 50); // may fail silently
list.shrinkRetainingCapacity(new_len);
// Clear
list.clearRetainingCapacity();
list.clearAndFree(allocator);
Copy to Contiguous Slice
var dest: [100]i32 = undefined;
list.writeToSlice(&dest, 0); // copy from index 0
// Copy subset
list.writeToSlice(dest[50..], 50); // copy starting at index 50
Memory Layout
Segments grow exponentially:
prealloc=0: shelf 0: 1 element
shelf 1: 2 elements
shelf 2: 4 elements
...
prealloc=4: prealloc: 4 elements (inline)
shelf 0: 8 elements
shelf 1: 16 elements
...
Common Pattern: Object Pool with Stable References
const Object = struct {
data: [1024]u8,
next: ?*Object,
};
var pool = std.SegmentedList(Object, 64){};
// Create objects - pointers remain valid
const obj1 = try pool.addOne(allocator);
const obj2 = try pool.addOne(allocator);
obj1.next = obj2; // safe: obj2 pointer won't change