use crate::{
memory::AllocSet,
word::{ByWordType, Shape, Word, WordIdx},
};
use alloc::vec::Vec;
use core::fmt::Debug;
pub trait RefCount: Sized + Copy + Debug {
const ZERO: Self;
fn increase(&mut self);
fn decrease(&mut self);
fn is_zero(&self) -> bool;
}
macro_rules! impl_RefCount {
($ty: ty) => {
impl RefCount for $ty {
const ZERO: Self = 0;
fn increase(&mut self) {
*self += 1;
}
fn decrease(&mut self) {
if *self == 0 {
panic!("Reference count underflow detected.");
}
*self -= 1;
}
fn is_zero(&self) -> bool {
return *self == 0;
}
}
};
}
impl_RefCount!(u8);
impl_RefCount!(u16);
impl_RefCount!(u32);
impl_RefCount!(u64);
impl_RefCount!(u128);
impl_RefCount!(usize);
pub trait MemoryManager: Sized + Debug {
fn new() -> Self;
fn alloc<W: Word, const N: usize>(&mut self) -> (WordIdx<W, N>, usize);
fn increase_refcount<W: Word, const N: usize>(&mut self, idx: WordIdx<W, N>);
fn decrease_refcount<W: Word, const N: usize>(&mut self, idx: WordIdx<W, N>);
fn clear(&mut self);
}
#[derive(Debug)]
pub struct FlexibleMemoryManager<RC: RefCount> {
refcounts: ByWordType<Vec<RC>>,
alloc_set: ByWordType<AllocSet>,
}
impl<RC: RefCount> FlexibleMemoryManager<RC> {
pub fn refcounts(&self) -> &ByWordType<Vec<RC>> {
return &self.refcounts;
}
pub fn alloc_set(&self) -> &ByWordType<AllocSet> {
return &self.alloc_set;
}
pub fn shape(&self) -> Shape {
return self.refcounts.map(|refcounts| refcounts.len());
}
pub fn capacity(&self) -> Shape {
return self.refcounts.map(|refcounts| refcounts.capacity());
}
fn extend_recounts_vec_if_needed<W: Word, const N: usize>(
&mut self,
idx: WordIdx<W, N>,
) -> usize {
let refcounts = self.refcounts.as_vec_mut::<W>();
let idxs: [usize; N] = idx.into();
let max_idx = idxs.into_iter().max();
if let Some(max_idx) = max_idx {
if max_idx >= refcounts.len() {
refcounts.resize(max_idx + 1, RC::ZERO);
}
}
return refcounts.len();
}
}
impl<RC: RefCount> MemoryManager for FlexibleMemoryManager<RC> {
fn new() -> Self {
return FlexibleMemoryManager {
refcounts: ByWordType::new(),
alloc_set: ByWordType::default(),
};
}
fn alloc<W: Word, const N: usize>(&mut self) -> (WordIdx<W, N>, usize) {
let alloc_set = self.alloc_set.as_value_mut::<W>();
let idxs: [usize; N] = core::array::from_fn(|_| alloc_set.alloc());
let idx = WordIdx::new(idxs);
let vec_len = self.extend_recounts_vec_if_needed(idx);
return (idx, vec_len);
}
fn increase_refcount<W: Word, const N: usize>(&mut self, idx: WordIdx<W, N>) {
let refcounts = self.refcounts.as_vec_mut::<W>();
let idxs: [usize; _] = idx.into();
for i in idxs {
refcounts[i].increase();
}
}
fn decrease_refcount<W: Word, const N: usize>(&mut self, idx: WordIdx<W, N>) {
let refcounts = self.refcounts.as_vec_mut::<W>();
let alloc_set = self.alloc_set.as_value_mut::<W>();
let idxs: [usize; _] = idx.into();
for i in idxs {
refcounts[i].decrease();
if refcounts[i].is_zero() {
alloc_set.free(i);
}
}
}
fn clear(&mut self) {
self.refcounts.map_mut(|refcounts| refcounts.clear());
self.alloc_set.map_mut(|alloc_set| alloc_set.clear());
}
}