HiSlab
A high-performance slab allocator using hierarchical bitmaps for O(1) slot allocation and deallocation. Backed by anonymous mmap with demand paging.
Features
- O(1) insert and remove — hierarchical bitmap finds a free slot in constant time regardless of fragmentation
- mmap-backed storage — virtual memory reserved upfront, physical pages committed on demand; pointer never moves
- Huge page support — initial capacity pre-faulted with
MADV_POPULATE_WRITE | MADV_HUGEPAGE - Stable
u32indices — inserted elements keep their index until removed - SIMD optimized — bitmap operations use AVX-512, AVX2, NEON, or scalar at compile time
- Tagging —
TaggedHiSlabmaintains a second bitmap to track a subset of elements - Buffer pool —
BufferSlab<N>for fixed-size raw byte buffers with RAII guards - Random sampling — uniform random selection over occupied/tagged slots (feature
rand)
Crates
[]
= "0.2"
# Optional: random sampling
= { = "0.2", = ["rand"] }
HiSlab
use HiSlab;
// Reserve virtual space for 65 536 slots, pre-fault the first 1 024
let mut slab = new.unwrap;
// insert() returns a stable u32 index
let idx = slab.insert;
assert_eq!;
// remove() returns the value
let val = slab.remove;
assert_eq!;
assert!;
// Freed slots are reused
let idx2 = slab.insert;
assert_eq!;
new(initial_capacity, virtual_capacity)
| Parameter | Description |
|---|---|
initial_capacity |
Slots pre-faulted immediately (zero page faults on first accesses) |
virtual_capacity |
Maximum number of slots (hard cap — insert panics if exceeded) |
Both are u32. initial_capacity must be <= virtual_capacity.
Core methods
| Method | Description |
|---|---|
insert(val) -> u32 |
Insert a value, returns its stable index |
remove(idx) -> Option<T> |
Remove and return the value, or None if empty |
get(idx) -> Option<&T> |
Borrow the value at index |
get_mut(idx) -> Option<&mut T> |
Mutably borrow the value at index |
is_occupied(idx) -> bool |
Check if a slot is occupied |
slab[idx] |
Panics if the slot is empty |
Iteration
// Shared reference
for in &slab
// Mutable reference
for in &mut slab
// Consuming (moves values out)
for in slab
// Callback — avoids iterator overhead
slab.for_each_occupied;
Unsafe fast access
// Caller guarantees the slot is occupied
unsafe
TaggedHiSlab
TaggedHiSlab<T> wraps a HiSlab and maintains a second bitmap to mark a subset of elements as tagged. All base slab operations are identical.
use TaggedHiSlab;
let mut slab = new.unwrap;
let a = slab.insert; // not tagged
let b = slab.insert_tagged; // inserted and tagged in one call
slab.tag; // tag an existing element (returns false if already tagged)
slab.untag; // remove tag
assert!;
assert!;
Tagging methods
| Method | Description |
|---|---|
insert_tagged(val) -> u32 |
Insert and tag in one step |
tag(idx) -> bool |
Tag an existing element |
untag(idx) -> bool |
Remove tag from an element |
is_tagged(idx) -> bool |
Check if an element is tagged |
Iterating tagged elements
// Callback — fastest
slab.for_each_tagged;
// Iterator
for in slab.iter_tagged
for in slab.iter_tagged_mut
Bulk operations on tagged elements
// Remove tagged elements that fail the predicate
slab.retain_tagged;
// Untag (but keep in slab) elements that fail the predicate
slab.retain_tag;
BufferSlab
BufferSlab<N> is a pool of fixed-size raw byte buffers. Slots are managed through RAII AutoGuards that free automatically on drop.
use BufferSlab;
// Pre-fault 4 slots, reserve space for 128
let pool = new.unwrap;
let mut g0 = pool.allocate; // panics if pool is full
let g1 = pool.try_allocate.unwrap; // returns None if pool is full
g0.as_slice_mut.fill;
assert_eq!;
assert_eq!;
// Drop releases the slot back to the pool
drop;
drop;
AutoGuard API
| Method | Description |
|---|---|
as_slice() -> &[u8] |
Read-only view of the N bytes |
as_slice_mut() -> &mut [u8] |
Mutable view of the N bytes |
as_ptr() -> *mut u8 |
Raw pointer (valid while guard is alive) |
index() -> u32 |
Slot index in the pool |
Multiple guards can coexist simultaneously. BufferSlab is !Send + !Sync.
Random sampling (feature rand)
Available on both HiSlab and TaggedHiSlab.
use HiSlab;
use thread_rng;
let mut rng = thread_rng;
// Pick one random occupied element
if let Some = slab.random_occupied
if let Some = slab.random_occupied_mut
// Pick N elements with possible duplicates
let sample = slab.random_occupied_many;
// Pick N unique elements
let unique = slab.random_occupied_unique;
// Count occupied slots
let n = slab.count_occupied;
TaggedHiSlab adds the same methods for the tagged subset:
random_tagged, random_tagged_mut, random_tagged_many, random_tagged_unique, count_tagged.
Architecture
HiSlab uses a 4-level hierarchical bitmap:
lvl4 (u8) → 8 bits summarize lvl3
lvl3 (BitBlock) → 512 bits summarize lvl2
lvl2 (BitBlock) → 512 bits summarize lvl1
lvl1 (BitBlock) → 512 bits track actual data slots
Each BitBlock is 512 bits (8 × u64), aligned to 64 bytes. Insert descends the tree to find a free slot; fullness/emptiness propagates upward.
SIMD support
Bitmap operations select exactly one implementation path at compile time — no runtime dispatch overhead.
| Architecture | Feature | Used for |
|---|---|---|
| x86_64 | AVX-512 | 512-bit comparisons |
| x86_64 | AVX2 | 256-bit comparisons |
| aarch64 | NEON | 128-bit comparisons |
| Fallback | Scalar | Loop over 8 × u64 |
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.