use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
pub struct Arena {
total_allocated: RefCell<usize>,
storage: RefCell<Vec<Rc<dyn std::any::Any>>>,
}
impl Arena {
pub fn new() -> Self {
Self {
total_allocated: RefCell::new(0),
storage: RefCell::new(Vec::new()),
}
}
pub fn alloc<T: 'static>(&self, value: T) -> Rc<T> {
*self.total_allocated.borrow_mut() += 1;
let rc = Rc::new(value);
self.storage
.borrow_mut()
.push(rc.clone() as Rc<dyn std::any::Any>);
rc
}
pub fn total_allocated(&self) -> usize {
*self.total_allocated.borrow()
}
pub fn num_items(&self) -> usize {
self.storage.borrow().len()
}
pub fn clear(&self) {
self.storage.borrow_mut().clear();
*self.total_allocated.borrow_mut() = 0;
}
}
impl Default for Arena {
fn default() -> Self {
Self::new()
}
}
pub struct StringInterner {
map: RefCell<HashMap<String, Rc<str>>>,
}
impl StringInterner {
pub fn new() -> Self {
Self {
map: RefCell::new(HashMap::new()),
}
}
pub fn intern(&self, s: &str) -> Rc<str> {
let mut map = self.map.borrow_mut();
if let Some(interned) = map.get(s) {
Rc::clone(interned)
} else {
let rc: Rc<str> = Rc::from(s);
map.insert(s.to_string(), Rc::clone(&rc));
rc
}
}
pub fn stats(&self) -> (usize, usize) {
let map = self.map.borrow();
let total_size: usize = map.values().map(|s| s.len()).sum();
(map.len(), total_size)
}
pub fn clear(&self) {
self.map.borrow_mut().clear();
}
}
impl Default for StringInterner {
fn default() -> Self {
Self::new()
}
}
pub struct BumpAllocator<T> {
storage: RefCell<Vec<T>>,
count: RefCell<usize>,
}
impl<T> BumpAllocator<T> {
pub fn with_capacity(capacity: usize) -> Self {
Self {
storage: RefCell::new(Vec::with_capacity(capacity)),
count: RefCell::new(0),
}
}
pub fn alloc(&self, value: T) -> usize {
let mut storage = self.storage.borrow_mut();
let index = storage.len();
storage.push(value);
*self.count.borrow_mut() += 1;
index
}
pub fn get(&self, index: usize) -> Option<T>
where
T: Clone,
{
self.storage.borrow().get(index).cloned()
}
pub fn len(&self) -> usize {
self.storage.borrow().len()
}
pub fn is_empty(&self) -> bool {
self.storage.borrow().is_empty()
}
pub fn clear(&self) {
self.storage.borrow_mut().clear();
*self.count.borrow_mut() = 0;
}
}
impl<T> Default for BumpAllocator<T> {
fn default() -> Self {
Self::with_capacity(128)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arena_basic() {
let arena = Arena::new();
let x = arena.alloc(42i32);
assert_eq!(*x, 42);
let y = arena.alloc("hello".to_string());
assert_eq!(y.as_ref(), "hello");
assert_eq!(arena.total_allocated(), 2);
}
#[test]
fn test_string_interner() {
let interner = StringInterner::new();
let s1 = interner.intern("hello");
let s2 = interner.intern("hello");
let s3 = interner.intern("world");
assert_eq!(&*s1, "hello");
assert_eq!(&*s2, "hello");
assert_eq!(&*s3, "world");
assert!(Rc::ptr_eq(&s1, &s2));
assert!(!Rc::ptr_eq(&s1, &s3));
let (num_strings, _) = interner.stats();
assert_eq!(num_strings, 2); }
#[test]
fn test_bump_allocator() {
let alloc = BumpAllocator::with_capacity(10);
let idx1 = alloc.alloc(42i32);
let idx2 = alloc.alloc(100i32);
assert_eq!(idx1, 0);
assert_eq!(idx2, 1);
assert_eq!(alloc.get(idx1), Some(42));
assert_eq!(alloc.get(idx2), Some(100));
assert_eq!(alloc.len(), 2);
}
#[test]
fn test_arena_many_allocations() {
let arena = Arena::new();
for i in 0..1000 {
let _x = arena.alloc(i);
}
assert_eq!(arena.total_allocated(), 1000);
assert_eq!(arena.num_items(), 1000);
arena.clear();
assert_eq!(arena.total_allocated(), 0);
assert_eq!(arena.num_items(), 0);
}
#[test]
fn test_arena_default() {
let arena = Arena::default();
assert_eq!(arena.total_allocated(), 0);
assert_eq!(arena.num_items(), 0);
}
#[test]
fn test_string_interner_default() {
let interner = StringInterner::default();
let (count, size) = interner.stats();
assert_eq!(count, 0);
assert_eq!(size, 0);
}
#[test]
fn test_string_interner_clear() {
let interner = StringInterner::new();
interner.intern("hello");
interner.intern("world");
let (count, _) = interner.stats();
assert_eq!(count, 2);
interner.clear();
let (count_after, size_after) = interner.stats();
assert_eq!(count_after, 0);
assert_eq!(size_after, 0);
}
#[test]
fn test_bump_allocator_default() {
let alloc: BumpAllocator<i32> = BumpAllocator::default();
assert!(alloc.is_empty());
assert_eq!(alloc.len(), 0);
}
#[test]
fn test_bump_allocator_is_empty() {
let alloc = BumpAllocator::with_capacity(10);
assert!(alloc.is_empty());
alloc.alloc(42i32);
assert!(!alloc.is_empty());
}
#[test]
fn test_bump_allocator_clear() {
let alloc = BumpAllocator::with_capacity(10);
alloc.alloc(1i32);
alloc.alloc(2i32);
alloc.alloc(3i32);
assert_eq!(alloc.len(), 3);
alloc.clear();
assert!(alloc.is_empty());
assert_eq!(alloc.len(), 0);
}
#[test]
fn test_bump_allocator_get_out_of_bounds() {
let alloc = BumpAllocator::with_capacity(10);
alloc.alloc(42i32);
assert_eq!(alloc.get(0), Some(42));
assert_eq!(alloc.get(1), None);
assert_eq!(alloc.get(100), None);
}
#[test]
fn test_string_interner_stats() {
let interner = StringInterner::new();
interner.intern("abc");
interner.intern("defgh");
let (count, total_size) = interner.stats();
assert_eq!(count, 2);
assert_eq!(total_size, 8); }
#[test]
fn test_arena_clear() {
let arena = Arena::new();
arena.alloc(1i32);
arena.alloc(2i32);
assert_eq!(arena.total_allocated(), 2);
arena.clear();
assert_eq!(arena.total_allocated(), 0);
assert_eq!(arena.num_items(), 0);
}
#[test]
fn test_arena_alloc_different_types() {
let arena = Arena::new();
let int_val = arena.alloc(42i64);
let str_val = arena.alloc("hello".to_string());
let vec_val = arena.alloc(vec![1, 2, 3]);
assert_eq!(*int_val, 42i64);
assert_eq!(&*str_val, "hello");
assert_eq!(&*vec_val, &vec![1, 2, 3]);
assert_eq!(arena.total_allocated(), 3);
}
}