use std::cell::RefCell;
pub struct Arena {
buf: Vec<u8>,
offset: usize,
}
impl Arena {
pub fn new(capacity: usize) -> Self {
Self {
buf: vec![0u8; capacity],
offset: 0,
}
}
pub fn alloc(&mut self, size: usize) -> Option<&mut [u8]> {
let aligned = (self.offset + 7) & !7;
if aligned + size > self.buf.len() {
return None;
}
self.offset = aligned + size;
Some(&mut self.buf[aligned..aligned + size])
}
pub fn reset(&mut self) {
self.offset = 0;
}
pub fn used(&self) -> usize {
self.offset
}
pub fn capacity(&self) -> usize {
self.buf.len()
}
pub fn remaining(&self) -> usize {
self.buf.len().saturating_sub(self.offset)
}
}
impl Default for Arena {
fn default() -> Self {
Self::new(64 * 1024) }
}
pub struct VecPool<T> {
pool: RefCell<Vec<Vec<T>>>,
}
impl<T> VecPool<T> {
pub fn new() -> Self {
Self {
pool: RefCell::new(Vec::new()),
}
}
pub fn get(&self) -> Vec<T> {
self.pool.borrow_mut().pop().unwrap_or_default()
}
pub fn put(&self, mut v: Vec<T>) {
v.clear();
self.pool.borrow_mut().push(v);
}
pub fn available(&self) -> usize {
self.pool.borrow().len()
}
}
impl<T> Default for VecPool<T> {
fn default() -> Self {
Self::new()
}
}
pub type InlineString = compact_str::CompactString;
pub fn reuse_string(s: &mut String) {
s.clear();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arena_alloc_and_reset() {
let mut arena = Arena::new(256);
let a = arena.alloc(32).unwrap();
assert_eq!(a.len(), 32);
assert!(arena.used() > 0);
let b = arena.alloc(64).unwrap();
assert_eq!(b.len(), 64);
arena.reset();
assert_eq!(arena.used(), 0);
assert_eq!(arena.remaining(), 256);
}
#[test]
fn arena_overflow() {
let mut arena = Arena::new(16);
assert!(arena.alloc(8).is_some());
assert!(arena.alloc(100).is_none());
}
#[test]
fn vec_pool_reuse() {
let pool: VecPool<i32> = VecPool::new();
let mut v = pool.get();
v.push(1);
v.push(2);
v.push(3);
let cap = v.capacity();
pool.put(v);
assert_eq!(pool.available(), 1);
let v2 = pool.get();
assert!(v2.is_empty());
assert!(v2.capacity() >= cap); assert_eq!(pool.available(), 0);
}
}