use std::cell::{Cell, RefCell};
use std::mem::MaybeUninit;
use super::builder::NodeAlloc;
use super::char_trait::DawgChar;
use super::children::DawgNode;
const CHUNK_CAP: usize = 64;
pub(crate) struct NodeArena<T> {
chunks: RefCell<Vec<Box<[MaybeUninit<T>; CHUNK_CAP]>>>,
len: Cell<usize>,
}
impl<T> NodeArena<T> {
pub fn new() -> Self {
NodeArena {
chunks: RefCell::new(Vec::new()),
len: Cell::new(0),
}
}
pub fn alloc(&self, value: T) -> &T {
let len = self.len.get();
let chunk_idx = len / CHUNK_CAP;
let offset = len % CHUNK_CAP;
let mut chunks = self.chunks.borrow_mut();
if chunk_idx == chunks.len() {
chunks.push(Box::new([const { MaybeUninit::uninit() }; CHUNK_CAP]));
}
let slot_ptr: *mut MaybeUninit<T> = &mut chunks[chunk_idx][offset];
self.len.set(len + 1);
unsafe {
(*slot_ptr).write(value);
(*slot_ptr).assume_init_ref()
}
}
pub fn len(&self) -> usize {
self.len.get()
}
}
impl<T> Drop for NodeArena<T> {
fn drop(&mut self) {
let chunks = self.chunks.get_mut();
let len = *self.len.get_mut();
for i in 0..len {
let chunk_idx = i / CHUNK_CAP;
let offset = i % CHUNK_CAP;
unsafe {
chunks[chunk_idx][offset].assume_init_drop();
}
}
}
}
impl<'w, C: DawgChar> NodeAlloc<'w, C> for NodeArena<DawgNode<'w, C>> {
fn alloc_node(&'w self, node: DawgNode<'w, C>) -> &'w DawgNode<'w, C> {
unsafe { &*(self.alloc(node) as *const DawgNode<'w, C>) }
}
}