#![no_std]
extern crate arrayvec;
use arrayvec::{Array, ArrayVec};
#[cfg(test)] mod tests;
pub struct LRUCache<A: Array> {
entries: ArrayVec<A>,
head: u16,
tail: u16,
}
pub struct CacheIndex(u16);
pub struct Entry<T> {
val: T,
prev: u16,
next: u16,
}
impl<A: Array> Default for LRUCache<A> {
fn default() -> Self {
let cache = LRUCache {
entries: ArrayVec::new(),
head: 0,
tail: 0,
};
assert!(cache.entries.capacity() < u16::max_value() as usize, "Capacity overflow");
cache
}
}
impl<T, A: Array<Item=Entry<T>>> LRUCache<A> {
pub fn num_entries(&self) -> usize {
self.entries.len()
}
#[inline]
pub fn touch(&mut self, idx: CacheIndex) {
if idx.0 != self.head {
self.remove(idx.0);
self.push_front(idx.0);
}
}
pub fn front(&self) -> Option<&T> {
self.entries.get(self.head as usize).map(|e| &e.val)
}
pub fn front_mut(&mut self) -> Option<&mut T> {
self.entries.get_mut(self.head as usize).map(|e| &mut e.val)
}
pub fn iter(&self) -> LRUCacheIterator<A> {
LRUCacheIterator {
pos: self.head,
done: self.entries.len() == 0,
cache: self,
}
}
pub fn iter_mut(&mut self) -> LRUCacheMutIterator<A> {
LRUCacheMutIterator {
pos: self.head,
done: self.entries.len() == 0,
cache: self,
}
}
pub fn lookup<F, R>(&mut self, mut test_one: F) -> Option<R>
where
F: FnMut(&mut T) -> Option<R>
{
let mut result = None;
for (i, candidate) in self.iter_mut() {
if let Some(r) = test_one(candidate) {
result = Some((i, r));
break;
}
};
match result {
None => None,
Some((i, r)) => {
self.touch(i);
Some(r)
}
}
}
pub fn find<F>(&mut self, mut pred: F) -> Option<&mut T>
where
F: FnMut(&T) -> bool
{
match self.iter_mut().find(|&(_, ref x)| pred(x)) {
Some((i, _)) => {
self.touch(i);
self.front_mut()
}
None => None
}
}
pub 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);
}
fn remove(&mut self, i: u16) {
let prev = self.entries[i as usize].prev;
let next = self.entries[i as usize].next;
if i == self.head {
self.head = next;
} else {
self.entries[prev as usize].next = next;
}
if i == self.tail {
self.tail = prev;
} else {
self.entries[next as usize].prev = prev;
}
}
fn push_front(&mut self, i: u16) {
if self.entries.len() == 1 {
self.tail = i;
} else {
self.entries[i as usize].next = self.head;
self.entries[self.head as usize].prev = i;
}
self.head = i;
}
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 fn evict_all(&mut self) {
self.entries.clear();
}
}
pub struct LRUCacheIterator<'a, A: 'a + Array> {
cache: &'a LRUCache<A>,
pos: u16,
done: bool,
}
impl<'a, T, A> Iterator for LRUCacheIterator<'a, A>
where T: 'a,
A: 'a + Array<Item=Entry<T>>
{
type Item = (CacheIndex, &'a T);
fn next(&mut self) -> Option<Self::Item> {
if self.done { return None }
let entry = &self.cache.entries[self.pos as usize];
let index = CacheIndex(self.pos);
if self.pos == self.cache.tail {
self.done = true;
}
self.pos = entry.next;
Some((index, &entry.val))
}
}
pub struct LRUCacheMutIterator<'a, A: 'a + Array> {
cache: &'a mut LRUCache<A>,
pos: u16,
done: bool,
}
impl<'a, T, A> Iterator for LRUCacheMutIterator<'a, A>
where T: 'a,
A: 'a + Array<Item=Entry<T>>
{
type Item = (CacheIndex, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
if self.done { return None }
let entry = unsafe {
&mut *(&mut self.cache.entries[self.pos as usize] as *mut Entry<T>)
};
let index = CacheIndex(self.pos);
if self.pos == self.cache.tail {
self.done = true;
}
self.pos = entry.next;
Some((index, &mut entry.val))
}
}