3.7 KiB
Historical std.SegmentedList Reference (Unavailable in Zig 0.16.0)
Primary Zig 0.16 release-note source: https://ziglang.org/download/0.16.0/release-notes.html
std.SegmentedList is not exported by the Zig 0.16 standard library, and there is no compatibility alias with these methods. The material below is retained as a legacy API inventory for migration and source archaeology; none of its snippets compile against Zig 0.16 as written. 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.
Historically, the implementation described here was a dynamic list whose element pointers remained stable across growth. Unlike ArrayList, appending did not invalidate existing pointers, and elements were stored in exponentially sized segments. These are historical behavior and layout notes, not Zig 0.16 guarantees.
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 were not globally contiguous; each individual segment was contiguous
- O(log n) random access (vs O(1) for ArrayList)
- Higher per-element overhead
Legacy 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);
Legacy 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);
Legacy 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
...
Legacy 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