#![deny(unsafe_code)]
extern crate arrayvec;
use arrayvec::ArrayVec;
#[derive(Debug)]
pub(crate) struct Cache<T, const N: usize> {
pub(crate) entries: ArrayVec<Entry<T>, N>,
pub(crate) head: u16,
pub(crate) tail: u16
}
#[derive(Debug, Clone)]
pub(crate) struct Entry<T> {
pub(crate) val: T,
prev: u16,
next: u16,
}
impl<T, const N: usize> Default for Cache<T, N> {
fn default() -> Self {
let cache = Cache {
entries: ArrayVec::new(),
head: 0,
tail: 0,
};
assert!(
cache.entries.capacity() < u16::max_value() as usize,
"Capacity overflow"
);
cache
}
}
impl<T, const N: usize> Cache<T, N> {
pub(crate) fn insert(&mut self, val: T) {
let entry = Entry {
val,
prev: 0,
next: 0,
};
let new_head = if self.entries.len() == self.entries.capacity() {
let i = self.pop_back();
self.entries[i as usize] = entry;
i
} else {
self.entries.push(entry);
self.entries.len() as u16 -1
};
self.push_front(new_head);
}
#[inline]
pub(crate) fn touch_index(&mut self, idx: u16) {
if idx != self.head {
self.remove(idx);
self.push_front(idx);
}
}
#[inline]
pub(crate) fn len(&self) -> usize {
self.entries.len()
}
#[inline]
pub(crate) fn clear(&mut self) {
self.entries.clear();
}
pub(crate) fn remove(&mut self, idx: u16) {
let prev = self.entries[idx as usize].prev;
let next = self.entries[idx as usize].next;
if idx == self.head {
self.head = next;
} else {
self.entries[prev as usize].next = next;
}
if idx == self.tail {
self.tail = prev;
} else {
self.entries[next as usize].prev = prev;
}
}
pub(crate) fn push_front(&mut self, idx: u16) {
if self.entries.len() == 1 {
self.tail = idx;
} else {
self.entries[idx as usize].next = self.head;
self.entries[self.head as usize].prev = idx;
}
self.head = idx;
}
pub(crate) fn pop_back(&mut self) -> u16 {
let old_tail = self.tail;
let new_tail = self.entries[old_tail as usize].prev;
self.tail = new_tail;
old_tail
}
pub(crate) fn replace(&mut self, idx: u16, val: T) -> T {
self.touch_index(idx);
let entry = &mut self.entries[idx as usize];
std::mem::replace(&mut entry.val, val)
}
pub(crate) fn get(&mut self, idx: u16) -> &T {
self.touch_index(idx);
&self.entries[idx as usize].val
}
pub(crate) fn get_mut(&mut self, idx: u16) -> &mut T {
self.touch_index(idx);
&mut self.entries[idx as usize].val
}
pub(crate) fn iter(&self) -> Iter<T, N> {
Iter {
cache: self,
pos: self.head,
}
}
}
impl<T, const N: usize> Clone for Cache<T, N>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
entries: self.entries.clone(),
head: self.head,
tail: self.tail,
}
}
}
pub struct Iter<'a, T, const N: usize> {
cache: &'a Cache<T, N>,
pos: u16,
}
impl<'a, T, const N: usize> Iterator for Iter<'a, T, N> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
let entry = self.cache.entries.get(self.pos as usize)?;
self.pos = if self.pos == self.cache.tail {
N as u16 } else {
entry.next
};
Some(&entry.val)
}
}