#![allow(unsafe_code)]
use std::{cell::UnsafeCell, ptr};
use super::CacheAccess;
#[derive(Debug)]
pub(crate) struct Node {
pub inner: UnsafeCell<CacheAccess>,
next: *mut Node,
prev: *mut Node,
}
impl std::ops::Deref for Node {
type Target = CacheAccess;
fn deref(&self) -> &CacheAccess {
unsafe { &(*self.inner.get()) }
}
}
impl Node {
fn unwire(&mut self) {
unsafe {
if !self.prev.is_null() {
(*self.prev).next = self.next;
}
if !self.next.is_null() {
(*self.next).prev = self.prev;
}
}
self.next = ptr::null_mut();
self.prev = ptr::null_mut();
}
}
pub struct DoublyLinkedList {
head: *mut Node,
tail: *mut Node,
len: usize,
}
unsafe impl Send for DoublyLinkedList {}
impl Drop for DoublyLinkedList {
fn drop(&mut self) {
let mut cursor = self.head;
while !cursor.is_null() {
unsafe {
let node = Box::from_raw(cursor);
cursor = node.prev;
drop(node);
}
}
}
}
impl Default for DoublyLinkedList {
fn default() -> Self {
Self {
head: ptr::null_mut(),
tail: ptr::null_mut(),
len: 0,
}
}
}
impl DoublyLinkedList {
pub(crate) const fn len(&self) -> usize {
self.len
}
pub(crate) fn push_head(&mut self, item: CacheAccess) -> *mut Node {
self.len += 1;
let node = Node {
inner: UnsafeCell::new(item),
next: ptr::null_mut(),
prev: self.head,
};
let ptr = Box::into_raw(Box::new(node));
self.push_head_ptr(ptr);
ptr
}
fn push_head_ptr(&mut self, ptr: *mut Node) {
if !self.head.is_null() {
unsafe {
(*self.head).next = ptr;
(*ptr).prev = self.head;
}
}
if self.tail.is_null() {
self.tail = ptr;
}
self.head = ptr;
}
pub(crate) fn unwire(&mut self, ptr: *mut Node) {
unsafe {
if self.tail == ptr {
self.tail = (*ptr).next;
}
if self.head == ptr {
self.head = (*ptr).prev;
}
(*ptr).unwire();
}
self.len -= 1;
}
pub(crate) fn install(&mut self, ptr: *mut Node) {
self.len += 1;
self.push_head_ptr(ptr);
}
pub(crate) fn pop_tail(&mut self) -> Option<*mut Node> {
if self.tail.is_null() {
return None;
}
self.len -= 1;
let tail_ptr = self.tail;
if self.head == self.tail {
self.head = ptr::null_mut();
}
unsafe {
self.tail = (*tail_ptr).next;
(*tail_ptr).unwire();
}
Some(tail_ptr)
}
}