use core::mem::{align_of, size_of};
use core::ptr::{addr_of_mut, null_mut, NonNull};
use super::header::HEADER_ALIGN;
pub const NODE_SIZE: usize = size_of::<Node>();
pub const NODE_ALIGN: usize = align_of::<Node>();
#[repr(C)]
pub struct Node {
pub next: *mut Node,
pub prev: *mut Node,
}
#[derive(Debug)]
#[repr(C)]
pub struct Freelist {
head: *mut Node,
}
impl Freelist {
#[inline]
pub const fn new() -> Self {
Freelist { head: null_mut() }
}
pub unsafe fn push_front(&mut self, p: *mut Node) {
let head: *mut *mut Node = addr_of_mut!(self.head);
debug_assert_eq!((*head) as usize % NODE_ALIGN, 0);
debug_assert_eq!((*head) as usize % HEADER_ALIGN, 0);
p.write(Node {
next: *head,
prev: null_mut(),
});
if !(*head).is_null() {
(**head).prev = p;
}
(*head) = p;
}
pub unsafe fn remove(&mut self, node: *const Node) {
let prev = (*node).prev;
let next = (*node).next;
match prev.is_null() {
true => self.head = next,
false => (*prev).next = next,
}
if !next.is_null() {
(*next).prev = prev;
}
}
#[inline]
pub fn head(&self) -> Option<NonNull<Node>> {
NonNull::new(self.head)
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::mem::MaybeUninit;
#[test]
fn test_1() {
assert!(Freelist::new().head().is_none(), "List should be empty");
}
#[test]
fn test_2() {
let mut list = Freelist::new();
let count = 1000;
let mut nodes: Vec<MaybeUninit<Node>> = (0..count).map(|_| MaybeUninit::uninit()).collect();
for i in 0..count {
unsafe {
list.push_front(nodes[i].as_mut_ptr());
}
}
for i in (0..count).rev() {
let Some(head) = list.head() else {
panic!("List should not be empty.");
};
let head = head.as_ptr();
unsafe {
assert_eq!(
head as usize,
nodes.as_ptr().add(i) as usize,
"The list head should be placed at nodes[{i}]."
);
list.remove(head);
}
}
}
#[test]
fn test_3() {
let mut list = Freelist::new();
let count = 20;
let mut nodes: Vec<MaybeUninit<Node>> = (0..count).map(|_| MaybeUninit::uninit()).collect();
for i in 0..count {
unsafe {
list.push_front(nodes[i].as_mut_ptr());
}
}
for i in 1..count - 1 {
assert!(list.head().is_some(), "List should not be empty.");
unsafe {
list.remove(nodes.as_ptr().add(i).cast());
}
}
let head = list.head().unwrap().as_ptr();
unsafe {
assert_eq!(
head as usize,
nodes.as_ptr().add(count - 1) as usize,
"The list head should be placed at nodes[{}].",
count - 1
);
list.remove(head);
}
let head = list.head().unwrap().as_ptr();
unsafe {
assert_eq!(
head as usize,
nodes.as_ptr() as usize,
"The list head should be placed at nodes[0]"
);
list.remove(head);
}
}
#[test]
fn test_4() {
let mut list = Freelist::new();
let count = 200;
let mut nodes: Vec<MaybeUninit<Node>> = (0..count).map(|_| MaybeUninit::uninit()).collect();
for i in 0..count {
unsafe {
list.push_front(nodes[i].as_mut_ptr());
}
}
let mut p: *mut Node = list.head().unwrap().as_ptr();
while !p.is_null() {
unsafe {
if (*p).next.is_null() {
assert_eq!(p, nodes.as_mut_ptr().cast());
} else {
assert_eq!((*p).next, p.sub(1));
}
if (*p).prev.is_null() {
assert_eq!(p, nodes.as_mut_ptr().add(count - 1).cast())
} else {
assert!((*p).prev == p.add(1));
}
p = (*p).next;
}
}
}
}