#![warn(missing_docs)]
#![no_std]
extern crate alloc;
use alloc::boxed::Box;
use core::{fmt, iter::FusedIterator, marker::PhantomData, ptr::addr_of_mut};
#[derive(Clone)]
pub struct LruSlab<T> {
slots: Box<[Slot<T>]>,
head: u32,
tail: u32,
free: u32,
len: u32,
}
impl<T> LruSlab<T> {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: u32) -> Self {
assert!(capacity != u32::MAX, "capacity too large");
Self {
slots: (0..capacity)
.map(|n| Slot {
value: None,
prev: NONE,
next: if n + 1 == capacity { NONE } else { n + 1 },
})
.collect(),
head: NONE,
tail: NONE,
free: if capacity == 0 { NONE } else { 0 },
len: 0,
}
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn len(&self) -> u32 {
self.len
}
pub fn capacity(&self) -> u32 {
self.slots.len() as u32
}
pub fn vacant_key(&self) -> u32 {
match self.free {
NONE => self.capacity(),
_ => self.free,
}
}
pub fn insert(&mut self, value: T) -> u32 {
let id = match self.alloc() {
Some(id) => id,
None => {
let len = self.capacity();
let cap = 2u32.saturating_mul(len.max(2)).min(u32::MAX - 1);
if cap == len {
panic!("cannot store more than 2^32-2 elements");
}
self.slots = self
.slots
.iter_mut()
.map(|x| Slot {
value: x.value.take(),
next: x.next,
prev: x.prev,
})
.chain((len..cap).map(|n| Slot {
value: None,
prev: NONE,
next: if n + 1 == cap { NONE } else { n + 1 },
}))
.collect();
self.free = len + 1;
len
}
};
let idx = id as usize;
debug_assert!(self.slots[idx].value.is_none(), "corrupt free list");
self.slots[idx].value = Some(value);
self.link_at_head(id);
self.len += 1;
id
}
pub fn lru(&self) -> Option<u32> {
if self.tail == NONE {
debug_assert_eq!(self.head, NONE);
None
} else {
Some(self.tail)
}
}
pub fn remove(&mut self, slot: u32) -> T {
self.unlink(slot);
self.slots[slot as usize].next = self.free;
self.slots[slot as usize].prev = NONE;
self.free = slot;
self.len -= 1;
self.slots[slot as usize]
.value
.take()
.expect("removing empty slot")
}
pub fn get_mut(&mut self, slot: u32) -> &mut T {
self.freshen(slot);
self.peek_mut(slot)
}
pub fn peek(&self, slot: u32) -> &T {
self.slots[slot as usize].value.as_ref().unwrap()
}
pub fn peek_mut(&mut self, slot: u32) -> &mut T {
self.slots[slot as usize].value.as_mut().unwrap()
}
pub fn iter(&self) -> Iter<'_, T> {
let state = IterState::new(self);
Iter {
slots: &self.slots[..],
state,
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
let state = IterState::new(self);
IterMut {
slots: self.slots[..].as_mut_ptr().cast(),
state,
_marker: PhantomData,
}
}
fn alloc(&mut self) -> Option<u32> {
if self.free == NONE {
return None;
}
let slot = self.free;
self.free = self.slots[slot as usize].next;
Some(slot)
}
fn freshen(&mut self, slot: u32) {
if self.slots[slot as usize].prev == NONE {
debug_assert_eq!(self.head, slot, "corrupt LRU list");
return;
}
self.unlink(slot);
self.link_at_head(slot);
}
fn link_at_head(&mut self, slot: u32) {
let idx = slot as usize;
if self.head == NONE {
self.slots[idx].next = NONE;
self.tail = slot;
} else {
self.slots[idx].next = self.head;
self.slots[self.head as usize].prev = slot;
}
self.slots[idx].prev = NONE;
self.head = slot;
}
fn unlink(&mut self, slot: u32) {
let idx = slot as usize;
if self.slots[idx].prev != NONE {
self.slots[self.slots[idx].prev as usize].next = self.slots[idx].next;
} else {
self.head = self.slots[idx].next;
}
if self.slots[idx].next != NONE {
self.slots[self.slots[idx].next as usize].prev = self.slots[idx].prev;
} else {
self.tail = self.slots[idx].prev;
}
}
}
impl<T> Default for LruSlab<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> FromIterator<T> for LruSlab<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let iter = iter.into_iter();
let mut slab = LruSlab::with_capacity(u32::try_from(iter.size_hint().0).unwrap());
for x in iter {
slab.insert(x);
}
slab
}
}
impl<'a, T> IntoIterator for &'a LruSlab<T> {
type Item = (u32, &'a T);
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut LruSlab<T> {
type Item = (u32, &'a mut T);
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T: fmt::Debug> fmt::Debug for LruSlab<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self).finish()
}
}
#[derive(Clone)]
struct Slot<T> {
value: Option<T>,
next: u32,
prev: u32,
}
const NONE: u32 = u32::MAX;
pub struct Iter<'a, T> {
slots: &'a [Slot<T>],
state: IterState,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (u32, &'a T);
fn next(&mut self) -> Option<(u32, &'a T)> {
let idx = self.state.next(|i| self.slots[i as usize].next)?;
let result = self.slots[idx as usize]
.value
.as_ref()
.expect("corrupt LRU list");
Some((idx, result))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.state.len as usize, Some(self.state.len as usize))
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<(u32, &'a T)> {
let idx = self.state.next_back(|i| self.slots[i as usize].prev)?;
let result = self.slots[idx as usize]
.value
.as_ref()
.expect("corrupt LRU list");
Some((idx, result))
}
}
impl<T> ExactSizeIterator for Iter<'_, T> {
fn len(&self) -> usize {
self.state.len as usize
}
}
impl<T> FusedIterator for Iter<'_, T> {}
pub struct IterMut<'a, T> {
slots: *mut Slot<T>,
state: IterState,
_marker: PhantomData<&'a mut [Slot<T>]>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = (u32, &'a mut T);
fn next(&mut self) -> Option<(u32, &'a mut T)> {
unsafe {
let idx = self
.state
.next(|i| *addr_of_mut!((*self.slots.add(i as usize)).next))?;
let result = (*addr_of_mut!((*self.slots.add(idx as usize)).value))
.as_mut()
.expect("corrupt LRU list");
Some((idx, result))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.state.len as usize, Some(self.state.len as usize))
}
}
impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
fn next_back(&mut self) -> Option<(u32, &'a mut T)> {
unsafe {
let idx = self
.state
.next_back(|i| *addr_of_mut!((*self.slots.add(i as usize)).prev))?;
let result = (*addr_of_mut!((*self.slots.add(idx as usize)).value))
.as_mut()
.expect("corrupt LRU list");
Some((idx, result))
}
}
}
impl<T> ExactSizeIterator for IterMut<'_, T> {
fn len(&self) -> usize {
self.state.len as usize
}
}
impl<T> FusedIterator for IterMut<'_, T> {}
struct IterState {
head: u32,
tail: u32,
len: u32,
}
impl IterState {
fn new<T>(slab: &LruSlab<T>) -> Self {
Self {
head: slab.head,
tail: slab.tail,
len: slab.len,
}
}
fn next(&mut self, get_next: impl Fn(u32) -> u32) -> Option<u32> {
if self.len == 0 {
return None;
}
let idx = self.head;
self.head = get_next(idx);
self.len -= 1;
Some(idx)
}
fn next_back(&mut self, get_prev: impl Fn(u32) -> u32) -> Option<u32> {
if self.len == 0 {
return None;
}
let idx = self.tail;
self.tail = get_prev(idx);
self.len -= 1;
Some(idx)
}
}
#[cfg(test)]
mod tests {
use alloc::{format, string::String, vec::Vec};
use super::*;
#[test]
fn lru_order() {
let mut cache = LruSlab::new();
let b = cache.insert('b');
assert_eq!(cache.iter().map(|(_, x)| x).collect::<String>(), "b");
let _a = cache.insert('a');
assert_eq!(cache.iter().map(|(_, x)| x).collect::<String>(), "ab");
let d = cache.insert('d');
assert_eq!(cache.iter().map(|(_, x)| x).collect::<String>(), "dab");
let c = cache.insert('c');
assert_eq!(cache.iter().map(|(_, x)| x).collect::<String>(), "cdab");
let e = cache.insert('e');
assert_eq!(cache.iter().map(|(_, x)| x).collect::<String>(), "ecdab");
cache.get_mut(b);
cache.get_mut(c);
cache.get_mut(d);
cache.get_mut(e);
assert_eq!(cache.remove(cache.lru().unwrap()), 'a');
assert_eq!(cache.remove(cache.lru().unwrap()), 'b');
assert_eq!(cache.remove(cache.lru().unwrap()), 'c');
assert_eq!(cache.remove(cache.lru().unwrap()), 'd');
assert_eq!(cache.remove(cache.lru().unwrap()), 'e');
assert!(cache.lru().is_none());
}
#[test]
fn slot_reuse() {
let mut cache = LruSlab::new();
let a = cache.insert('a');
cache.remove(a);
let a_prime = cache.insert('a');
assert_eq!(a, a_prime);
assert_eq!(cache.len(), 1);
}
#[test]
fn debug() {
let slab = ['a', 'b'].into_iter().collect::<LruSlab<_>>();
assert_eq!(format!("{:?}", slab), "{1: 'b', 0: 'a'}");
}
#[test]
fn iter_reverse() {
let slab = ['a', 'b'].into_iter().collect::<LruSlab<_>>();
let mut double_reversed = slab.iter().rev().collect::<Vec<_>>();
double_reversed.reverse();
assert_eq!(slab.iter().collect::<Vec<_>>(), double_reversed);
}
#[test]
fn vacant_key() {
let mut slab = LruSlab::new();
assert_eq!(slab.vacant_key(), 0);
slab.insert(());
assert_eq!(slab.vacant_key(), 1);
slab.remove(0);
assert_eq!(slab.vacant_key(), 0);
}
}