use bytemuck::{Pod, Zeroable};
use crate::{get_mut_helper, DataIndex, Get, NIL};
const END: u32 = u32::MAX;
pub struct FreeList<'a, T: Pod> {
head_index: DataIndex,
data: &'a mut [u8],
phantom: std::marker::PhantomData<&'a T>,
}
#[derive(Default, Copy, Clone, Zeroable)]
#[repr(C)]
pub struct FreeListNode<T> {
next_index: DataIndex,
node_inner: T,
}
unsafe impl<T: Pod> Pod for FreeListNode<T> {}
impl<T: Pod> Get for FreeListNode<T> {}
impl<T: Pod> FreeListNode<T> {
pub fn has_next(&self) -> bool {
self.next_index != NIL
}
}
impl<'a, T: Pod> FreeList<'a, T> {
pub fn new(data: &'a mut [u8], head_index: DataIndex) -> Self {
FreeList {
head_index,
data,
phantom: std::marker::PhantomData,
}
}
pub fn get_head(&self) -> DataIndex {
self.head_index
}
pub fn add(&mut self, index: DataIndex) {
let node: &mut FreeListNode<T> = get_mut_helper::<FreeListNode<T>>(self.data, index);
node.node_inner = T::zeroed();
node.next_index = self.head_index;
self.head_index = index;
}
pub fn remove(&mut self) -> DataIndex {
if self.head_index == END {
return END;
}
let free_node_index: DataIndex = self.head_index;
let head: &mut FreeListNode<T> =
get_mut_helper::<FreeListNode<T>>(self.data, free_node_index);
self.head_index = head.next_index;
head.next_index = 0;
free_node_index
}
}
mod test {
use super::*;
#[repr(C, packed)]
#[derive(Default, Copy, Clone, Pod, Zeroable)]
struct UnusedFreeListPadding1 {
_padding: [u8; 1],
}
#[test]
fn test_free_list_basic() {
let mut data: [u8; 100000] = [0; 100000];
let mut free_list: FreeList<UnusedFreeListPadding1> = FreeList::new(&mut data, END);
free_list.add(64);
free_list.add(128);
assert_eq!(128, free_list.remove());
assert_eq!(64, free_list.remove());
assert_eq!(END, free_list.remove());
}
}