use bumpalo::Bump;
pub struct ExecArena {
bump: Bump,
}
impl ExecArena {
pub fn new() -> Self {
Self { bump: Bump::new() }
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
bump: Bump::with_capacity(capacity),
}
}
pub fn alloc_str(&self, s: &str) -> &str {
self.bump.alloc_str(s)
}
pub fn alloc<T>(&self, val: T) -> &mut T {
self.bump.alloc(val)
}
pub fn alloc_slice_fill_default<T: Default>(&self, n: usize) -> &mut [T] {
self.bump.alloc_slice_fill_with(n, |_| T::default())
}
pub fn reset(&mut self) {
self.bump.reset();
}
pub fn allocated_bytes(&self) -> usize {
self.bump.allocated_bytes()
}
}
impl Default for ExecArena {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn alloc_str_roundtrip() {
let arena = ExecArena::new();
let s = arena.alloc_str("hello world");
assert_eq!(s, "hello world");
}
#[test]
fn alloc_and_mutate() {
let arena = ExecArena::new();
let val = arena.alloc(42u64);
*val = 99;
assert_eq!(*val, 99);
}
#[test]
fn reset_frees_memory() {
let mut arena = ExecArena::new();
for _ in 0..100 {
arena.alloc_str("some temporary string used in hot loop");
}
let before = arena.allocated_bytes();
assert!(before > 0);
arena.reset();
let s = arena.alloc_str("reused");
assert_eq!(s, "reused");
}
#[test]
fn slice_fill_default() {
let arena = ExecArena::new();
let slice: &mut [String] = arena.alloc_slice_fill_default(4);
assert_eq!(slice.len(), 4);
slice[0] = "a".to_string();
slice[1] = "b".to_string();
assert_eq!(slice[0], "a");
assert_eq!(slice[1], "b");
assert_eq!(slice[2], "");
}
}