#[derive(Copy, Clone, Default)]
struct LruNode {
prev: u8,
next: u8,
}
pub struct Lru<const N: usize> {
data: [LruNode; N],
head: u8,
}
impl<const N: usize> Lru<N> {
pub fn new() -> Self {
let mut out = Self {
data: [LruNode::default(); N],
head: 0,
};
for i in 0..N {
out.data[i].next = ((i + 1) % N) as u8;
out.data[i].prev = (i.checked_sub(1).unwrap_or(N - 1)) as u8;
}
out
}
#[inline]
fn remove(&mut self, i: u8) {
let node = self.data[i as usize];
self.data[node.prev as usize].next = self.data[i as usize].next;
self.data[node.next as usize].prev = self.data[i as usize].prev;
}
#[inline]
fn insert_before(&mut self, i: u8, next: u8) {
let prev = self.data[next as usize].prev;
self.data[prev as usize].next = i;
self.data[next as usize].prev = i;
self.data[i as usize] = LruNode { next, prev };
}
#[inline]
pub fn poke(&mut self, i: u8) {
let prev_newest = self.head;
if prev_newest == i {
return;
} else if self.data[prev_newest as usize].prev != i {
self.remove(i);
self.insert_before(i, self.head);
}
self.head = i; }
#[inline]
pub fn pop(&mut self) -> u8 {
let out = self.data[self.head as usize].prev;
self.head = out; out
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_tiny_lru() {
let mut lru: Lru<2> = Lru::new();
lru.poke(0);
assert!(lru.pop() == 1);
assert!(lru.pop() == 0);
lru.poke(1);
assert!(lru.pop() == 0);
assert!(lru.pop() == 1);
}
#[test]
fn test_medium_lru() {
let mut lru: Lru<10> = Lru::new();
lru.poke(0);
for _ in 0..9 {
assert!(lru.pop() != 0);
}
assert!(lru.pop() == 0);
lru.poke(1);
for _ in 0..9 {
assert!(lru.pop() != 1);
}
assert!(lru.pop() == 1);
lru.poke(4);
lru.poke(5);
for _ in 0..8 {
assert!(!matches!(lru.pop(), 4 | 5));
}
assert!(lru.pop() == 4);
assert!(lru.pop() == 5);
}
}