pub struct PoolAllocator<A: Allocator> { /* private fields */ }Expand description
A lock-free, fixed-size block allocator backed by a single pre-allocated slab.
At construction time the slab is divided into equal-sized blocks whose
size is at least max(item_layout.size(), size_of::<FreeNode>()) and
whose alignment is at least max(item_layout.align(), align_of::<FreeNode>()).
All blocks are linked into a free-list; allocation atomically pops the
head; deallocation atomically pushes to the head.
§Constraints
- Allocations larger than
block_layout.size()or with stricter alignment thanblock_layout.align()are rejected (returnNone). - The pool has a fixed
capacity; once all blocks are in use, allocation returnsNone.
§Thread Safety
PoolAllocator is Sync + Send when the backing allocator is Sync +
Send. Both alloc and dealloc use lock-free CAS loops.
Implementations§
Source§impl<A: Allocator> PoolAllocator<A>
impl<A: Allocator> PoolAllocator<A>
Sourcepub fn new(backing: A, item_layout: Layout, capacity: usize) -> Option<Self>
pub fn new(backing: A, item_layout: Layout, capacity: usize) -> Option<Self>
Creates a new pool with capacity blocks sized for item_layout.
The effective block size is max(item_layout.size(), size_of::<FreeNode>())
padded to the effective alignment. Returns None if the backing
allocator fails to allocate the slab.
§Arguments
backing— Allocator used to allocate and later free the slab.item_layout— Layout of the items that will be stored in the pool.capacity— Maximum number of live allocations the pool can hold.
Sourcepub fn typed<T>(backing: A, capacity: usize) -> Option<Self>
pub fn typed<T>(backing: A, capacity: usize) -> Option<Self>
Convenience constructor that derives item_layout from the type T.
Equivalent to PoolAllocator::new(backing, Layout::new::<T>(), capacity).
Examples found in repository?
More examples
9fn main() {
10 let sys = CountingAllocator::new(SystemAllocator);
11
12 println!("=== ExBox & SystemAllocator ===");
13 {
14 let b = ExBox::new(42, &sys).expect("Failed to alloc Box");
15 println!("Box value: {}", *b);
16 }
17
18 let stats = sys.stats();
19 println!("Allocated: {} bytes", stats.bytes_allocated);
20 println!("Deallocated: {} bytes", stats.bytes_freed);
21 println!("Live bytes: {}\n", stats.bytes_live);
22
23 println!("=== ExVec & Arena (Linear Allocation) ===");
24 {
25 let arena = ArenaAllocator::new(&sys);
26
27 let mut v = ExVec::new(&arena);
28 for i in 0..5 {
29 v.push(i * 10);
30 }
31 println!("Vec: {:?}", v.as_slice());
32
33 arena.reset();
34 println!("Arena reset performed");
35 }
36
37 println!("\n=== ExString & Pool (Fixed Size Blocks) ===");
38 {
39 let pool = PoolAllocator::typed::<[u8; 64]>(&sys, 10)
40 .expect("Failed to create Pool");
41
42 let mut s = ExString::new(&pool);
43 s.push_str("Hello from ZigZag!");
44
45 println!("String in Pool: {}", s.as_str());
46 println!("Pool free slots: {}", pool.free_count());
47 }
48
49 println!("\n=== Final Global Stats ===");
50 let final_stats = sys.stats();
51 println!("Total count of alloc() calls: {}", final_stats.allocs);
52 println!("Total count of dealloc() calls: {}", final_stats.deallocs);
53 println!("Total bytes allocated: {}", final_stats.bytes_allocated);
54 println!("Total bytes freed: {}", final_stats.bytes_freed);
55 println!("Current leak/live size: {} bytes", final_stats.bytes_live);
56}Sourcepub fn capacity(&self) -> usize
pub fn capacity(&self) -> usize
Returns the maximum number of blocks this pool can provide simultaneously.
Sourcepub fn block_layout(&self) -> Layout
pub fn block_layout(&self) -> Layout
Returns the padded layout of a single pool block.
Sourcepub fn free_count(&self) -> usize
pub fn free_count(&self) -> usize
Returns the number of blocks currently on the free-list.
This traverses the entire free-list and is O(free_count), so use only for diagnostics / debugging.
Examples found in repository?
More examples
9fn main() {
10 let sys = CountingAllocator::new(SystemAllocator);
11
12 println!("=== ExBox & SystemAllocator ===");
13 {
14 let b = ExBox::new(42, &sys).expect("Failed to alloc Box");
15 println!("Box value: {}", *b);
16 }
17
18 let stats = sys.stats();
19 println!("Allocated: {} bytes", stats.bytes_allocated);
20 println!("Deallocated: {} bytes", stats.bytes_freed);
21 println!("Live bytes: {}\n", stats.bytes_live);
22
23 println!("=== ExVec & Arena (Linear Allocation) ===");
24 {
25 let arena = ArenaAllocator::new(&sys);
26
27 let mut v = ExVec::new(&arena);
28 for i in 0..5 {
29 v.push(i * 10);
30 }
31 println!("Vec: {:?}", v.as_slice());
32
33 arena.reset();
34 println!("Arena reset performed");
35 }
36
37 println!("\n=== ExString & Pool (Fixed Size Blocks) ===");
38 {
39 let pool = PoolAllocator::typed::<[u8; 64]>(&sys, 10)
40 .expect("Failed to create Pool");
41
42 let mut s = ExString::new(&pool);
43 s.push_str("Hello from ZigZag!");
44
45 println!("String in Pool: {}", s.as_str());
46 println!("Pool free slots: {}", pool.free_count());
47 }
48
49 println!("\n=== Final Global Stats ===");
50 let final_stats = sys.stats();
51 println!("Total count of alloc() calls: {}", final_stats.allocs);
52 println!("Total count of dealloc() calls: {}", final_stats.deallocs);
53 println!("Total bytes allocated: {}", final_stats.bytes_allocated);
54 println!("Total bytes freed: {}", final_stats.bytes_freed);
55 println!("Current leak/live size: {} bytes", final_stats.bytes_live);
56}Sourcepub unsafe fn dealloc_zeroed(&self, ptr: NonNull<u8>)
pub unsafe fn dealloc_zeroed(&self, ptr: NonNull<u8>)
Sourcepub unsafe fn wipe_slab(&self)
pub unsafe fn wipe_slab(&self)
Zeroes the entire slab without modifying the free-list.
Intended for secure teardown. Do not call while any block is in use.
§Safety
All blocks — including live ones — will have their bytes set to zero. Any live references into the pool will read garbage (all zeros).
Trait Implementations§
Source§impl<A: Allocator> Allocator for PoolAllocator<A>
impl<A: Allocator> Allocator for PoolAllocator<A>
Source§unsafe fn alloc(&self, layout: Layout) -> Option<NonNull<u8>>
unsafe fn alloc(&self, layout: Layout) -> Option<NonNull<u8>>
Pops one block from the free-list and returns a pointer to it.
Returns None if the pool is exhausted or if layout is too large /
too strictly aligned for the pool’s block size.
§Safety
layout.size()must be ≤block_layout.size().layout.align()must be ≤block_layout.align().- The caller must eventually call
deallocwith the same pointer (and any layout whose size and align fit the pool).
Source§unsafe fn dealloc(&self, ptr: NonNull<u8>, _layout: Layout)
unsafe fn dealloc(&self, ptr: NonNull<u8>, _layout: Layout)
Pushes a block back onto the free-list.
The _layout parameter is ignored; what matters is that ptr belongs
to this pool’s slab.
§Safety
ptrmust have been obtained from this pool viaalloc.ptrmust not be accessed after this call.- Calling
dealloctwice with the same pointer is undefined behaviour (double-free corrupts the free-list).