stack_arena/lib.rs
1//! # stack-arena
2//!
3//! A fast, stack-like arena allocator for efficient memory management, implemented in Rust.
4//!
5//! ## Overview
6//!
7//! This library provides a set of memory allocation tools that follow a stack-like
8//! (Last-In-First-Out) allocation pattern. It's designed for scenarios where performance
9//! is critical and memory usage needs to be minimized with low per-allocation overhead.
10//!
11//! ## When to Use
12//!
13//! Stack-arena is ideal for scenarios where:
14//!
15//! - You need to allocate many small objects in sequence
16//! - Objects follow a stack-like (LIFO) allocation/deallocation pattern
17//! - Memory usage needs to be minimized with low per-allocation overhead
18//! - Performance is critical, especially for parsers, interpreters, or compilers
19//! - You want to avoid the overhead of the system allocator for short-lived objects
20//!
21//! ## Architecture
22//!
23//! The library is organized in layers:
24//!
25//! 1. [`Chunk`] - The lowest level, representing a contiguous region of memory
26//! 2. [`BufferArena`] - Manages a single memory chunk with bump allocation
27//! 3. [`StackArena`] - Manages multiple chunks with LIFO allocation/deallocation
28//! 4. [`ObjectStack`] - High-level interface for building objects incrementally
29//!
30//! ## Features
31//!
32//! - Efficient allocation of variable-sized objects with minimal overhead
33//! - Stack-like (LIFO) allocation and deallocation pattern
34//! - Memory is managed in chunks, automatically growing when needed, with old chunks preserved to maintain pointer validity
35//! - Objects can be built incrementally using `extend` and `finish` methods
36//! - Implements `std::fmt::Write` for string formatting directly into objects
37//! - Implements the [`Allocator`] trait for compatibility with allocation APIs
38//! - Automatic chunk reuse for improved performance
39//!
40//! ## Usage Examples
41//!
42//! ### Using ObjectStack (high-level API)
43//!
44//! The [`ObjectStack`] provides a user-friendly interface for building and managing objects:
45//!
46//! ```rust
47//! use stack_arena::ObjectStack;
48//! use std::fmt::Write;
49//!
50//! let mut stack = ObjectStack::new();
51//!
52//! // Push a complete object
53//! stack.push(b"greetings!");
54//!
55//! // Build an object incrementally
56//! stack.extend("hello");
57//! stack.extend(" ");
58//! stack.extend("world");
59//! write!(&mut stack, "!").unwrap();
60//! let ptr = stack.finish();
61//!
62//! // Access the object
63//! let hello_world = unsafe { std::str::from_utf8_unchecked(ptr.as_ref()) };
64//! assert_eq!(hello_world, "hello world!");
65//!
66//! // Pop the object when done
67//! stack.pop();
68//! ```
69//!
70//! ### Using StackArena (low-level API)
71//!
72//! The [`StackArena`] provides more control over memory allocation:
73//!
74//! ```rust
75//! use stack_arena::{StackArena, Allocator};
76//! use std::alloc::Layout;
77//!
78//! // Create with default chunk size (4096 bytes)
79//! let mut arena = StackArena::new();
80//!
81//! // Or create with a custom chunk size
82//! let mut custom_arena = StackArena::with_chunk_size(8192);
83//!
84//! // Allocate memory
85//! let layout = Layout::from_size_align(10, 1).unwrap();
86//! let ptr = unsafe { arena.allocate(layout).unwrap() };
87//!
88//! // Use the memory...
89//! unsafe { std::ptr::write_bytes(ptr.as_ptr() as *mut u8, 0xAA, 10) };
90//!
91//! // Deallocate when done
92//! unsafe { arena.deallocate(ptr.cast(), layout) };
93//! ```
94//!
95//! ## Performance
96//!
97//! The library is optimized for scenarios with many small allocations that follow
98//! a stack-like pattern. Benchmarks show it significantly outperforms the system
99//! allocator in these cases:
100//!
101//! - Up to 10x faster for consecutive small allocations
102//! - Minimal overhead for allocation and deallocation
103//! - Efficient memory reuse with the LIFO pattern
104//! - Reduced memory fragmentation
105//!
106//! ## Safety
107//!
108//! - All returned pointers are valid until the corresponding object is deallocated
109//! - Objects are stored in contiguous memory chunks
110//! - Unsafe operations are used internally for performance
111//! - The library follows LIFO (Last-In-First-Out) allocation pattern for efficiency
112//! - Users must ensure proper memory safety when working with raw pointers
113
114mod buffer_arena;
115mod chunk;
116mod error;
117mod object_stack;
118mod stack_arena;
119mod traits;
120
121pub use buffer_arena::BufferArena;
122pub use error::AllocError;
123pub use object_stack::ObjectStack;
124pub use stack_arena::StackArena;
125pub use traits::Allocator;
126
127#[cfg(test)]
128mod tests {
129 use crate::ObjectStack;
130 use std::fmt::Write;
131
132 #[test]
133 fn test_object_stack() {
134 let mut stack = ObjectStack::new();
135
136 // Test extending with string slices
137 stack.extend("hello");
138 stack.extend(" ");
139 stack.extend("world");
140
141 // Test Write trait implementation
142 write!(&mut stack, "!").unwrap();
143
144 // Finish and verify
145 let result = unsafe { stack.finish().as_ref() };
146 let expected = b"hello world!";
147 assert_eq!(result, expected);
148 }
149
150 #[test]
151 fn test_push_and_pop() {
152 let mut stack = ObjectStack::new();
153
154 // Push some objects
155 stack.push(b"first");
156 stack.push(b"second");
157
158 // Verify length
159 assert_eq!(stack.len(), 2);
160
161 // Pop and verify
162 stack.pop();
163 assert_eq!(stack.len(), 1);
164 }
165}