use std::{collections::HashMap, fmt::Debug, ptr::NonNull};
use super::common::EvictionPolicy;
pub struct LinkedListNode<K>
where
K: Eq + std::hash::Hash + Clone,
{
pub key: K,
pub pre: Option<*mut LinkedListNode<K>>,
pub next: Option<*mut LinkedListNode<K>>,
}
impl<K> LinkedListNode<K>
where
K: Eq + std::hash::Hash + Clone,
{
pub fn new(key_ref: K) -> Self {
Self {
key: key_ref,
pre: None,
next: None,
}
}
}
pub struct LRU<K>
where
K: Eq + std::hash::Hash + Clone,
{
map: HashMap<K, NonNull<LinkedListNode<K>>>,
head: Option<*mut LinkedListNode<K>>,
tail: Option<*mut LinkedListNode<K>>,
}
impl<K> LRU<K>
where
K: Eq + std::hash::Hash + Clone,
{
pub fn new() -> Self {
Self {
map: HashMap::new(),
head: None,
tail: None,
}
}
pub fn len(&self) -> usize {
return self.map.len();
}
fn remove_node(&mut self, node: &NonNull<LinkedListNode<K>>) {
let curr = node.as_ptr();
if let Some(pre) = unsafe { (*curr).pre } {
unsafe { (*pre).next = (*curr).next };
} else {
self.head = unsafe { (*curr).next };
}
if let Some(next) = unsafe { (*curr).next } {
unsafe { (*next).pre = (*curr).pre }
} else {
self.tail = unsafe { (*curr).pre };
}
if let Some(head) = self.head {
unsafe { (*head).pre = None };
};
if let Some(tail) = self.tail {
unsafe { (*tail).next = None };
};
}
fn insert_at_front(&mut self, node: &NonNull<LinkedListNode<K>>) {
let mut current = node.as_ptr();
unsafe {
(*current).next = self.head;
(*current).pre = None;
}
if let Some(head) = self.head {
unsafe {
(*head).pre = Some(current);
}
}
self.head = Some(current);
if self.tail.is_none() {
self.tail = Some(current);
};
unsafe {
self.map
.insert((*current).key.clone(), NonNull::new(current).unwrap());
}
}
pub fn move_to_front(&mut self, key: &K) {
if let Some(node) = self.map.remove(key) {
self.remove_node(&node);
self.insert_at_front(&node);
}
}
fn remove_from_last(&mut self) -> Option<K> {
if let Some(tail) = self.tail {
self.map.remove(unsafe { &(*tail).key });
if let Some(pre) = unsafe { (*tail).pre } {
unsafe {
(*pre).next = None;
self.tail = Some(pre);
}
} else {
self.tail = None;
self.head = None; };
return Some(unsafe { (*tail).key.clone() });
}
return None;
}
}
impl<K> EvictionPolicy<K> for LRU<K>
where
K: Eq + std::hash::Hash + Clone + Debug,
{
fn on_get(&mut self, key: &K) {
if self.map.contains_key(key) {
self.move_to_front(key);
}
}
fn on_set(&mut self, key: K) {
if let Some(node) = self.map.remove(&key) {
self.remove_node(&node);
}
self.insert_at_front(
&NonNull::new(Box::into_raw(Box::new(LinkedListNode::new(key)))).unwrap(),
);
}
fn evict(&mut self) -> Option<K> {
self.remove_from_last()
}
fn remove(&mut self, key: K) {
if let Some(removed) = self.map.remove(&key) {
self.remove_node(&removed);
}
}
}
unsafe impl<K: Eq + std::hash::Hash + Clone + Send> Send for LRU<K> {}
unsafe impl<K: Eq + std::hash::Hash + Clone + Sync> Sync for LRU<K> {}