//! Typed bump arena: allocate many objects, free all at once. //! //! `Arena` stores objects in a contiguous `Vec`, returning `ArenaId` //! handles. Clearing the arena resets the length but preserves capacity, //! making subsequent layout passes allocation-free when the page hasn't grown. use std::fmt; /// A handle to an object in an `Arena`. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct ArenaId(u32); impl ArenaId { /// The underlying index. pub fn index(self) -> usize { self.0 as usize } /// Create from a raw index. pub fn from_raw(index: u32) -> Self { ArenaId(index) } } impl fmt::Debug for ArenaId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ArenaId({})", self.0) } } /// A typed bump arena. Objects are allocated sequentially and freed all at once. pub struct Arena { items: Vec, } impl Arena { /// Create an empty arena. pub fn new() -> Self { Self { items: Vec::new() } } /// Create an arena with pre-allocated capacity. pub fn with_capacity(cap: usize) -> Self { Self { items: Vec::with_capacity(cap), } } /// Allocate an item in the arena, returning its handle. pub fn alloc(&mut self, item: T) -> ArenaId { let id = self.items.len() as u32; self.items.push(item); ArenaId(id) } /// Get a reference to an item by its handle. pub fn get(&self, id: ArenaId) -> &T { &self.items[id.0 as usize] } /// Get a mutable reference to an item by its handle. pub fn get_mut(&mut self, id: ArenaId) -> &mut T { &mut self.items[id.0 as usize] } /// Number of items in the arena. pub fn len(&self) -> usize { self.items.len() } /// Returns true if the arena is empty. pub fn is_empty(&self) -> bool { self.items.is_empty() } /// Current capacity (number of items that can be held without reallocation). pub fn capacity(&self) -> usize { self.items.capacity() } /// Clear all items, keeping the allocated memory for reuse. pub fn clear(&mut self) { self.items.clear(); } /// Estimated heap bytes used by the arena. pub fn memory_usage(&self) -> usize { self.items.capacity() * std::mem::size_of::() } /// Iterate over all items. pub fn iter(&self) -> impl Iterator { self.items.iter() } /// Iterate over all items mutably. pub fn iter_mut(&mut self) -> impl Iterator { self.items.iter_mut() } } impl Default for Arena { fn default() -> Self { Self::new() } } impl fmt::Debug for Arena { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Arena") .field("len", &self.items.len()) .field("capacity", &self.items.capacity()) .finish() } } #[cfg(test)] mod tests { use super::*; #[test] fn alloc_and_get() { let mut arena = Arena::new(); let a = arena.alloc(42i32); let b = arena.alloc(99); assert_eq!(*arena.get(a), 42); assert_eq!(*arena.get(b), 99); assert_eq!(arena.len(), 2); } #[test] fn clear_preserves_capacity() { let mut arena = Arena::new(); for i in 0..100 { arena.alloc(i); } let cap = arena.capacity(); arena.clear(); assert_eq!(arena.len(), 0); assert_eq!(arena.capacity(), cap); } #[test] fn mutate() { let mut arena = Arena::new(); let id = arena.alloc(10); *arena.get_mut(id) = 20; assert_eq!(*arena.get(id), 20); } #[test] fn with_capacity() { let arena = Arena::::with_capacity(100); assert!(arena.capacity() >= 100); assert!(arena.is_empty()); } #[test] fn memory_usage_scales() { let mut arena = Arena::new(); for i in 0..50u64 { arena.alloc(i); } assert!(arena.memory_usage() >= 50 * std::mem::size_of::()); } #[test] fn iter() { let mut arena = Arena::new(); arena.alloc(1); arena.alloc(2); arena.alloc(3); let v: Vec<_> = arena.iter().copied().collect(); assert_eq!(v, vec![1, 2, 3]); } }