| Crates.io | segmented-vec |
| lib.rs | segmented-vec |
| version | 0.2.3 |
| created_at | 2025-12-28 17:42:28.72754+00 |
| updated_at | 2026-01-03 23:18:28.086869+00 |
| description | A vector with stable element addresses using segmented allocation and O(1) index-to-segment mapping |
| homepage | |
| repository | https://github.com/ddwalias/segmented-vec |
| max_upload_size | |
| id | 2009190 |
| size | 197,702 |
A high-performance vector implementation with stable element addresses. Unlike Vec<T>, elements never move once inserted, making it safe to hold pointers to elements while the collection grows.
push().PREALLOC const generic for stack-allocated elements before heap allocation.Vec-like API: push, pop, get, iter, sort, extend, slicing, and more.SegmentedVec uses a clever allocation strategy where elements are stored in exponentially-sized segments:
Segment 0: [_, _, _, _] (4 elements)
Segment 1: [_, _, _, _, _, _, _, _] (8 elements)
Segment 2: [_, _, _, _, ...] (16 elements)
...
Given an index, the correct segment and offset are computed in O(1) using bit operations:
msb(index + bias) - offsetThis avoids the pointer-chasing of linked lists while guaranteeing address stability.
use segmented_vec::SegmentedVec;
// Create with default settings (no inline preallocation)
let mut vec: SegmentedVec<i32> = SegmentedVec::new();
// Or with inline storage for the first N elements
let mut vec: SegmentedVec<i32, 8> = SegmentedVec::new();
// Use like a normal Vec
vec.push(1);
vec.push(2);
vec.push(3);
// Get a pointer to an element
let ptr = &vec[0] as *const i32;
// Push more elements - the pointer remains valid!
for i in 4..1000 {
vec.push(i);
}
// ptr still points to the first element
assert_eq!(unsafe { *ptr }, 1);
SegmentedVec is ideal when you need:
&T references that must remain valid across insertions.Consider Vec<T> instead if:
as_slice() to return a single contiguous &[T]| Operation | SegmentedVec |
Vec |
|---|---|---|
push |
O(1) amortized | O(1) amortized |
pop |
O(1) | O(1) |
get(i) |
O(1) | O(1) |
| Address stability | Yes | No |
| Memory layout | Segmented | Contiguous |
The index calculation uses only bit operations (bsr, btc, shifts) - typically 3-5 instructions.
The PREALLOC const generic controls inline storage:
// No inline storage - first push allocates
let vec: SegmentedVec<i32, 0> = SegmentedVec::new();
// 8 elements stored inline before heap allocation
let vec: SegmentedVec<i32, 8> = SegmentedVec::new();
PREALLOC must be 0 or a power of 2.
To avoid tiny allocations, the first dynamic segment has a minimum size based on element size:
This matches the optimization strategy used by Vec in the standard library.
Licensed under either of:
at your option.