#![no_std]
#![doc = include_str!("../README.md")]
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::mem::MaybeUninit;
use core::ptr::{self, addr_of_mut};
use num_traits::{PrimInt, Unsigned};
mod entry;
mod errs;
mod iters;
pub use entry::*;
pub use errs::*;
pub use iters::into_iter::IntoIter;
pub use iters::iter::Iter;
pub use iters::iter_key_order::IterKeyOrder;
pub use iters::iter_key_order_mut::IterKeyOrderMut;
pub use iters::iter_mut::IterMut;
use iters::iter_key_order::IterIndexed;
use iters::iter_maybe_uninit::IterMaybeUninit;
#[derive(Debug)]
pub struct ConstLru<K, V, const CAP: usize, I: PrimInt + Unsigned = usize> {
len: I,
head: I,
tail: I,
bs_index: [I; CAP],
nexts: [I; CAP],
prevs: [I; CAP],
keys: [MaybeUninit<K>; CAP],
values: [MaybeUninit<V>; CAP],
}
impl<K, V, const CAP: usize, I: PrimInt + Unsigned> ConstLru<K, V, CAP, I> {
pub fn new() -> Self {
let mut res: MaybeUninit<Self> = MaybeUninit::uninit();
unsafe {
Self::init_at_alloc(res.as_mut_ptr());
res.assume_init()
}
}
pub unsafe fn init_at_alloc(ptr: *mut Self) {
let i_max = I::max_value()
.to_usize()
.unwrap_or_else(|| panic!("I::MAX > usize::MAX"));
if CAP > i_max {
panic!("CAP > I::MAX");
}
let cap = I::from(CAP).unwrap();
addr_of_mut!((*ptr).len).write(I::zero());
addr_of_mut!((*ptr).head).write(cap);
addr_of_mut!((*ptr).tail).write(I::zero());
for i in 0..CAP {
addr_of_mut!((*ptr).nexts[i]).write(I::from(i + 1).unwrap());
}
if CAP > 0 {
addr_of_mut!((*ptr).prevs[0]).write(cap);
for i in 1..CAP {
addr_of_mut!((*ptr).prevs[i]).write(I::from(i - 1).unwrap());
}
}
for i in 0..CAP {
addr_of_mut!((*ptr).bs_index[i]).write(cap);
}
}
fn unlink_node(&mut self, index: I) {
let i = index.to_usize().unwrap();
let next = self.nexts[i];
let prev = self.prevs[i];
if next != self.cap() {
self.prevs[next.to_usize().unwrap()] = prev;
}
if prev != self.cap() {
self.nexts[prev.to_usize().unwrap()] = next;
}
let is_one_elem_list = self.head == self.tail;
if self.head == index && !is_one_elem_list {
self.head = next;
}
if self.tail == index && !is_one_elem_list {
self.tail = prev;
}
}
fn move_to_head(&mut self, index: I) {
if self.head == index {
return;
}
self.unlink_node(index);
let i = index.to_usize().unwrap();
let head = self.head;
self.prevs[i] = self.cap();
self.nexts[i] = head;
self.prevs[head.to_usize().unwrap()] = index;
self.head = index;
}
fn drop_cleanup(&mut self) {
for (k, v) in IterMaybeUninit::new(self) {
unsafe {
k.assume_init_drop();
v.assume_init_drop();
}
}
}
pub fn iter(&self) -> Iter<K, V, CAP, I> {
Iter::new(self)
}
pub fn iter_mut(&mut self) -> IterMut<K, V, CAP, I> {
IterMut::new(self)
}
pub fn iter_key_order(&self) -> IterKeyOrder<K, V, CAP, I> {
IterKeyOrder::new(self)
}
pub fn iter_key_order_mut(&mut self) -> IterKeyOrderMut<K, V, CAP, I> {
IterKeyOrderMut::new(self)
}
pub fn clear(&mut self) {
self.drop_cleanup();
let ptr_to_self: *mut Self = self;
unsafe { Self::init_at_alloc(ptr_to_self) }
}
pub fn cap(&self) -> I {
I::from(CAP).unwrap()
}
pub fn is_empty(&self) -> bool {
self.len() == I::zero()
}
pub fn is_full(&self) -> bool {
self.len() == self.cap()
}
pub fn len(&self) -> I {
self.len
}
fn insert_replace_value(&mut self, index: I, replacement: V) -> V {
let old_v = unsafe { self.values[index.to_usize().unwrap()].assume_init_mut() };
let old_v_out = core::mem::replace(old_v, replacement);
self.move_to_head(index);
old_v_out
}
fn insert_alloc_new(&mut self, insert_bs_i: I, k: K, v: V) -> I {
let free_index = if self.is_empty() {
self.head = self.tail;
self.tail
} else {
self.nexts[self.tail.to_usize().unwrap()]
};
self.tail = free_index;
let f = free_index.to_usize().unwrap();
self.keys[f].write(k);
self.values[f].write(v);
if insert_bs_i < self.len {
unsafe {
let insert_bs_i_ptr = self
.bs_index
.as_mut_ptr()
.add(insert_bs_i.to_usize().unwrap());
ptr::copy(
insert_bs_i_ptr,
insert_bs_i_ptr.add(1),
(self.len - insert_bs_i).to_usize().unwrap(),
);
}
}
self.bs_index[insert_bs_i.to_usize().unwrap()] = free_index;
self.len = self.len + I::one();
self.move_to_head(self.tail);
free_index
}
fn remove_by_index(&mut self, (index, bs_i): (I, I)) -> (K, V) {
let i = index.to_usize().unwrap();
let key = unsafe { self.keys[i].assume_init_read() };
let val = unsafe { self.values[i].assume_init_read() };
if self.len() > I::one() {
self.unlink_node(index);
let t = self.tail.to_usize().unwrap();
let first_free = self.nexts[t];
if first_free < self.cap() {
self.prevs[first_free.to_usize().unwrap()] = index;
}
self.nexts[i] = first_free;
self.prevs[i] = self.tail;
self.nexts[t] = index;
}
unsafe {
let bs_i_ptr = self.bs_index.as_mut_ptr().add(bs_i.to_usize().unwrap());
ptr::copy(
bs_i_ptr.add(1),
bs_i_ptr,
(self.len - bs_i - I::one()).to_usize().unwrap(),
);
}
self.len = self.len - I::one();
(key, val)
}
fn get_by_index(&self, index: I) -> &V {
unsafe { self.values[index.to_usize().unwrap()].assume_init_ref() }
}
fn get_mut_by_index(&mut self, index: I) -> &mut V {
unsafe { self.values[index.to_usize().unwrap()].assume_init_mut() }
}
}
impl<K: Ord, V, const CAP: usize, I: PrimInt + Unsigned> ConstLru<K, V, CAP, I> {
pub fn insert(&mut self, k: K, v: V) -> Option<InsertReplaced<K, V>> {
if CAP == 0 {
return None;
}
let insert_bs_i = match self.get_index_of(&k) {
Ok((existing_index, _)) => {
return Some(InsertReplaced::OldValue(
self.insert_replace_value(existing_index, v),
))
}
Err(i) => i,
};
if self.is_full() {
let (_, (old_k, old_v)) = self.insert_evict_lru(insert_bs_i, k, v);
Some(InsertReplaced::LruEvicted(old_k, old_v))
} else {
self.insert_alloc_new(insert_bs_i, k, v);
None
}
}
fn insert_evict_lru(&mut self, insert_bs_i: I, k: K, v: V) -> (I, (K, V)) {
let i = self.tail;
let t = i.to_usize().unwrap();
let evicted_k = unsafe { self.keys[t].assume_init_read() };
let evicted_v = unsafe { self.values[t].assume_init_read() };
let Ok((_should_be_t, evicted_bs_i)) = self.get_index_of(&evicted_k) else { unreachable!() };
self.keys[t].write(k);
self.values[t].write(v);
match insert_bs_i.cmp(&evicted_bs_i) {
Ordering::Equal => (),
Ordering::Less => {
let b = insert_bs_i.to_usize().unwrap();
unsafe {
let bs_i_ptr = self.bs_index.as_mut_ptr().add(b);
ptr::copy(
bs_i_ptr,
bs_i_ptr.add(1),
(evicted_bs_i - insert_bs_i).to_usize().unwrap(),
);
}
self.bs_index[b] = self.tail;
}
Ordering::Greater => {
let inser_bs_i_sub_1 = insert_bs_i - I::one();
unsafe {
let evicted_bs_i_ptr = self
.bs_index
.as_mut_ptr()
.add(evicted_bs_i.to_usize().unwrap());
ptr::copy(
evicted_bs_i_ptr.add(1),
evicted_bs_i_ptr,
(inser_bs_i_sub_1 - evicted_bs_i).to_usize().unwrap(),
);
}
self.bs_index[inser_bs_i_sub_1.to_usize().unwrap()] = self.tail;
}
}
self.move_to_head(self.tail);
(i, (evicted_k, evicted_v))
}
pub fn remove<Q: Ord + ?Sized>(&mut self, k: &Q) -> Option<V>
where
K: Borrow<Q>,
{
let tup = self.get_index_of(k).ok()?;
Some(self.remove_by_index(tup).1)
}
pub fn get<Q: Ord + ?Sized>(&mut self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
{
let (index, _) = self.get_index_of(k).ok()?;
self.move_to_head(index);
Some(self.get_by_index(index))
}
pub fn get_mut<Q: Ord + ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
{
let (index, _) = self.get_index_of(k).ok()?;
self.move_to_head(index);
Some(self.get_mut_by_index(index))
}
fn get_index_of<Q: Ord + ?Sized>(&self, k: &Q) -> Result<(I, I), I>
where
K: Borrow<Q>,
{
let l = self.len().to_usize().unwrap();
let valid_bs_index = &self.bs_index[0..l];
valid_bs_index
.binary_search_by(|probe_index| {
let p = probe_index.to_usize().unwrap();
let probe = unsafe { self.keys[p].assume_init_ref() };
probe.borrow().cmp(k)
})
.map(|bs_i| (self.bs_index[bs_i], I::from(bs_i).unwrap()))
.map_err(|new_bsi| I::from(new_bsi).unwrap())
}
pub fn get_untouched<Q: Ord + ?Sized>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
{
let (index, _) = self.get_index_of(k).ok()?;
Some(self.get_by_index(index))
}
pub fn get_mut_untouched<Q: Ord + ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
{
let (index, _) = self.get_index_of(k).ok()?;
Some(self.get_mut_by_index(index))
}
pub fn entry(&mut self, k: K) -> Entry<'_, K, V, CAP, I> {
Entry::new(self, k)
}
}
impl<K: Clone, V: Clone, const CAP: usize, I: PrimInt + Unsigned> ConstLru<K, V, CAP, I> {
pub unsafe fn clone_to_alloc(&self, dst: *mut Self) {
addr_of_mut!((*dst).len).write(self.len);
addr_of_mut!((*dst).head).write(self.head);
addr_of_mut!((*dst).tail).write(self.tail);
ptr::copy(
self.nexts.as_ptr(),
addr_of_mut!((*dst).nexts) as *mut I,
CAP,
);
ptr::copy(
self.prevs.as_ptr(),
addr_of_mut!((*dst).prevs) as *mut I,
CAP,
);
ptr::copy(
self.bs_index.as_ptr(),
addr_of_mut!((*dst).bs_index) as *mut I,
CAP,
);
for (index, k, v) in IterIndexed::new(self) {
let i = index.to_usize().unwrap();
addr_of_mut!((*dst).keys[i]).write(MaybeUninit::new(k.clone()));
addr_of_mut!((*dst).values[i]).write(MaybeUninit::new(v.clone()));
}
}
}
impl<K: Clone, V: Clone, const CAP: usize, I: PrimInt + Unsigned> Clone for ConstLru<K, V, CAP, I> {
fn clone(&self) -> Self {
let mut res: MaybeUninit<Self> = MaybeUninit::uninit();
unsafe {
self.clone_to_alloc(res.as_mut_ptr());
res.assume_init()
}
}
}
impl<K, V, const CAP: usize, I: PrimInt + Unsigned> Default for ConstLru<K, V, CAP, I> {
fn default() -> Self {
Self::new()
}
}
impl<K, V, const CAP: usize, I: PrimInt + Unsigned> Drop for ConstLru<K, V, CAP, I> {
fn drop(&mut self) {
self.drop_cleanup();
}
}
impl<K, V, const CAP: usize, I: PrimInt + Unsigned> IntoIterator for ConstLru<K, V, CAP, I> {
type Item = <IntoIter<K, V, CAP, I> as Iterator>::Item;
type IntoIter = IntoIter<K, V, CAP, I>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InsertReplaced<K, V> {
LruEvicted(K, V),
OldValue(V),
}
impl<K: Ord, V, const CAP: usize, I: PrimInt + Unsigned> TryFrom<[(K, V); CAP]>
for ConstLru<K, V, CAP, I>
{
type Error = DuplicateKeysError<K>;
fn try_from(entries: [(K, V); CAP]) -> Result<Self, Self::Error> {
let mut res = Self::new();
res.len = res.cap();
res.head = I::zero();
res.tail = if CAP > 0 {
res.len - I::one()
} else {
I::zero()
};
for (i, (k, v)) in entries.into_iter().enumerate() {
res.keys[i].write(k);
res.values[i].write(v);
}
for (i, val) in res.bs_index.iter_mut().enumerate() {
*val = I::from(i).unwrap();
}
res.bs_index.sort_unstable_by(|a, b| {
let k_a = unsafe { res.keys[a.to_usize().unwrap()].assume_init_ref() };
let k_b = unsafe { res.keys[b.to_usize().unwrap()].assume_init_ref() };
k_a.cmp(k_b)
});
if CAP > 1 {
for w in res.bs_index.windows(2) {
let index_1 = w[0];
let i1 = index_1.to_usize().unwrap();
let i2 = w[1].to_usize().unwrap();
let k1 = unsafe { res.keys[i1].assume_init_ref() };
let k2 = unsafe { res.keys[i2].assume_init_ref() };
if k1 == k2 {
res.unlink_node(index_1);
res.len = res.len - I::one();
unsafe { res.values[i1].assume_init_drop() };
let k_copied_out = unsafe { res.keys[i1].assume_init_read() };
return Err(DuplicateKeysError(k_copied_out));
}
}
}
Ok(res)
}
}