use crate::tape::Tape;
use crate::MemError;
use crossbeam_queue::SegQueue;
use std::marker::PhantomData;
pub struct Grid<const CELL_SIZE: usize, const CELLS: usize> {
tape: Tape,
free: SegQueue<usize>,
}
pub struct Cell<'a> {
ptr: *mut u8,
index: usize,
_grid: PhantomData<&'a ()>,
}
impl<const CELL_SIZE: usize, const CELLS: usize> Grid<CELL_SIZE, CELLS> {
pub fn new() -> Result<Self, MemError> {
assert!(CELL_SIZE > 0, "CELL_SIZE must be > 0");
assert!(
CELL_SIZE.is_multiple_of(64),
"CELL_SIZE must be multiple of 64"
);
assert!(CELLS > 0, "CELLS must be > 0");
let tape = Tape::start(CELL_SIZE * CELLS)?;
let free = SegQueue::new();
for i in 0..CELLS {
let _ = tape.take(CELL_SIZE, 64);
free.push(i);
}
Ok(Grid { tape, free })
}
#[inline]
pub fn take(&self) -> Option<Cell<'_>> {
let index = self.free.pop()?;
let base = self.tape.block().address();
let ptr = unsafe { base.add(index * CELL_SIZE) };
Some(Cell {
ptr,
index,
_grid: PhantomData,
})
}
#[inline]
pub fn give(&self, cell: Cell<'_>) {
self.free.push(cell.index);
}
pub fn free(&self) -> usize {
self.free.len()
}
#[inline]
pub const fn total(&self) -> usize {
CELLS
}
#[inline]
pub fn tape(&self) -> &Tape {
&self.tape
}
}
impl<'a> Cell<'a> {
#[inline(always)]
pub fn address(&self) -> *mut u8 {
self.ptr
}
#[inline]
pub unsafe fn bytes(&mut self, len: usize) -> &mut [u8] {
std::slice::from_raw_parts_mut(self.ptr, len)
}
#[inline]
pub fn id(&self) -> usize {
self.index
}
}