use std::cell::Cell;
use std::mem::size_of;
const ARENA_BLOCK: usize = 64 * 1024;
pub struct Arena {
store: Cell<Vec<Vec<u8>>>,
ptr: Cell<*mut u8>,
offset: Cell<usize>,
}
impl Arena {
pub fn new() -> Self {
let mut store = vec![Vec::with_capacity(ARENA_BLOCK)];
let ptr = store[0].as_mut_ptr();
Arena {
store: Cell::new(store),
ptr: Cell::new(ptr),
offset: Cell::new(0),
}
}
pub fn alloc(&self, size: usize) -> *mut u8 {
if size > ARENA_BLOCK {
return self.alloc_bytes(size);
}
let size = match size % size_of::<usize>() {
0 => size,
n => size + (size_of::<usize>() - n),
};
let offset = self.offset.get();
let cap = offset + size;
if cap > ARENA_BLOCK {
self.grow();
self.offset.set(size);
self.ptr.get()
} else {
self.offset.set(cap);
unsafe { self.ptr.get().add(offset) }
}
}
#[inline]
fn alloc_byte_vec(&self, mut val: Vec<u8>) -> *mut u8 {
let ptr = val.as_mut_ptr();
let mut temp = self.store.replace(Vec::new());
temp.push(val);
self.store.replace(temp);
ptr
}
pub fn grow(&self) {
let ptr = self.alloc_byte_vec(Vec::with_capacity(ARENA_BLOCK));
self.ptr.set(ptr);
}
fn alloc_bytes(&self, size: usize) -> *mut u8 {
self.alloc_byte_vec(Vec::with_capacity(size))
}
#[doc(hidden)]
#[inline]
pub unsafe fn offset(&self) -> usize {
self.offset.get()
}
}
unsafe impl Send for Arena {}