| Crates.io | stackmap |
| lib.rs | stackmap |
| version | 0.1.2 |
| created_at | 2025-03-21 17:12:50.748101+00 |
| updated_at | 2025-05-16 09:50:42.906286+00 |
| description | A fast stack-only hashmap for small high-performance scenarios |
| homepage | https://github.com/deanchalk/stackmap |
| repository | https://github.com/deanchalk/stackmap |
| max_upload_size | |
| id | 1600873 |
| size | 38,853 |
A zero-heap-allocation, fixed-capacity hash map that lives entirely on the stack.
StackMap is a specialized hash map implementation optimized for small collections where allocation avoidance and deterministic performance are critical. It uses a simple linear probing approach with all storage pre-allocated on the stack at compile time.
Key benefits:
no_std environments or where dynamic allocation is prohibitively expensiveHashMap instead)Add this to your Cargo.toml:
[dependencies]
stackmap = "0.1.0"
use stackmap::StackMap;
fn main() {
// Create a new map with i32 keys, String values, and capacity for 8 entries
let mut map = StackMap::<i32, String, 8>::new();
// Insert key-value pairs
map.insert_or_update(1, "One".to_string()).unwrap();
map.insert_or_update(2, "Two".to_string()).unwrap();
// Retrieve values
assert_eq!(map.get(&1), Some(&"One".to_string()));
// Update existing values
map.insert_or_update(1, "ONE".to_string()).unwrap();
assert_eq!(map.get(&1), Some(&"ONE".to_string()));
// Remove entries
let removed = map.remove(&2);
assert_eq!(removed, Some("Two".to_string()));
// Check size
assert_eq!(map.len(), 1);
// Iterate over entries
for (key, value) in map.iter() {
println!("{}: {}", key, value);
}
}
All operations are O(N) in the worst case, where N is the capacity of the map. For small maps (N ≤ 32), this linear performance is typically faster than more complex data structures due to cache locality and avoidance of indirection.
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| Create | O(1) | O(N) on stack |
| Insert | O(N) | O(1) |
| Get | O(N) | O(1) |
| Remove | O(N) | O(1) |
| Iterate | O(N) | O(1) |
Since StackMap stores all its entries on the stack, using large capacity values (e.g., N > 32) may lead to stack overflow in resource-constrained environments. Choose the capacity parameter carefully based on your expected maximum collection size.
StackMap guarantees zero heap allocations for its internal bookkeeping. However, if your key or value types themselves require heap allocation (like String or Vec), those allocations will still occur. For truly zero-allocation usage, use types that don't allocate, such as primitives, arrays, or custom stack-only structures.
Below are some comparative benchmarks showing StackMap performance versus Rust's standard HashMap for small collections:
Insert 8 elements (i32 keys):
StackMap: 14 ns
HashMap: 84 ns
Lookup 8 elements (i32 keys):
StackMap: 11 ns
HashMap: 21 ns
Insert 8 elements (String keys):
StackMap: 112 ns
HashMap: 163 ns
Lookup 8 elements (String keys):
StackMap: 73 ns
HashMap: 89 ns
As expected, the performance advantage of StackMap is most pronounced for small collections with simple key types. The gap narrows or reverses as collection sizes grow beyond ~32 elements.
StackMap uses a simple linear probing strategy with deleted entry flagging. When an entry is removed, it's marked as deleted rather than physically removed, preserving the probing sequence for future lookups.
This simplistic approach works well for small collections but becomes inefficient for larger ones, which aligns with the intended use case.
Both key and value types must implement:
CloneDefaultAdditionally, keys must implement:
EqPlanned enhancements for future versions:
serde serializationLicensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.