#![warn(missing_docs, rustdoc::missing_crate_level_docs)]
#![doc = include_str!("../README.md")]
use core::borrow::Borrow;
use core::hash::Hash;
use core::marker::PhantomData;
use indexmap::IndexMap;
use rand::prelude::*;
use replace_with::replace_with_or_abort;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CommonCache<K, V, R: Rng = StdRng> {
base: usize,
#[cfg_attr(
feature = "serde",
serde(bound(
deserialize = "K: Deserialize<'de> + Eq + Hash, V: Deserialize<'de>",
serialize = "K: Serialize + Eq + Hash, V: Serialize",
))
)]
levels: Vec<Level<K, V>>,
#[cfg_attr(
feature = "serde",
serde(skip, default = "SeedableRng::from_entropy", bound = "R: SeedableRng")
)]
rng: R,
max_size: usize,
generation: u64,
}
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(bound(
deserialize = "K: Deserialize<'de> + Eq + Hash, V: Deserialize<'de>",
serialize = "K: Serialize + Eq + Hash, V: Serialize",
))
)]
struct Level<K, V> {
items: IndexMap<K, V>,
rand_range: rand::distributions::Uniform<usize>,
}
impl<K, V> CommonCache<K, V> {
pub fn new(base: usize, max_size: Option<usize>) -> Self {
Self::new_with_rng(base, max_size, StdRng::from_entropy())
}
pub fn set_max_size(&mut self, max_size: usize) {
assert!(
max_size >= 2,
"max_size must be >=2 in CommonCache::set_max_size()"
);
if max_size >= self.max_size {
self.max_size = max_size;
return;
}
let mut sum = 0;
for (i, level) in self.levels.iter_mut().enumerate() {
if sum == max_size {
self.levels.truncate(i);
break;
}
sum += level.items.len();
if sum > max_size {
for _ in max_size..sum {
let to_remove = self.rng.gen_range(0..level.items.len());
level.items.swap_remove_index(to_remove);
}
self.levels.truncate(i + 1);
break;
}
}
self.generation += 1;
}
pub fn clear(&mut self) {
self.levels.clear();
self.generation += 1;
}
}
impl<K, V, R: Rng> CommonCache<K, V, R> {
pub fn new_with_rng(base: usize, max_size: Option<usize>, rng: R) -> Self {
let max_size = max_size.unwrap_or(usize::MAX);
assert!(max_size >= 2, "max_size in CommonCache must be >= 2");
assert!(base >= 2, "base in CommonCache must be >=2.");
Self {
base,
rng,
levels: Vec::new(),
max_size,
generation: 0,
}
}
pub fn size(&self) -> usize {
self.levels.iter().map(|x| x.items.len()).sum()
}
pub fn max_size(&self) -> usize {
self.max_size
}
}
impl<K, V, R> CommonCache<K, V, R>
where
K: Eq + Hash,
R: Rng,
{
pub fn insert(&mut self, key: K, value: V) -> Entry<'_, K, V, R> {
let insert_level = if let Some(entry) = self.entry(&key) {
let level = entry.level;
let _old_item = entry.remove();
level.saturating_sub(1)
} else {
self.levels.len().saturating_sub(2)
};
self.insert_at_level::<true>(key, value, insert_level)
}
fn insert_at_level<const CREATE_NEW_LEVEL_IF_NEEDED: bool>(
&mut self,
key: K,
value: V,
level: usize,
) -> Entry<'_, K, V, R> {
self.generation += 1;
if self.size() == self.max_size {
let last_level_items = &mut self.levels.last_mut().unwrap().items;
let to_remove = self.rng.gen_range(0..last_level_items.len());
last_level_items.swap_remove_index(to_remove);
if last_level_items.is_empty() {
self.levels.pop();
}
}
if self.levels.is_empty() {
self.levels.push(Level {
items: IndexMap::with_capacity(1),
rand_range: (0..1).into(),
});
}
for level in (level..self.levels.len()).rev() {
let current_level = &mut self.levels[level];
let i = current_level.rand_range.sample(&mut self.rng);
if let Some(move_down_item) = current_level.items.swap_remove_index(i) {
if level != self.levels.len() - 1 {
self.levels[level + 1]
.items
.insert(move_down_item.0, move_down_item.1);
} else if CREATE_NEW_LEVEL_IF_NEEDED {
let new_level_size = self
.base
.checked_pow((level + 1).try_into().unwrap_or(u32::MAX))
.unwrap_or(usize::MAX);
self.levels.push(Level {
items: IndexMap::from([move_down_item]),
rand_range: (0..new_level_size).into(),
});
}
}
}
let (idx, None) = self.levels[level].items.insert_full(key, value) else {
unreachable!()
};
Entry {
cache: self,
level,
idx,
}
}
pub fn entry<Q>(&mut self, key: &Q) -> Option<Entry<'_, K, V, R>>
where
K: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
if let Some((level, idx)) = self
.levels
.iter_mut()
.enumerate()
.filter_map(|(i, x)| x.items.get_index_of(key).map(|x| (i, x)))
.next()
{
Some(Entry {
cache: self,
level,
idx,
})
} else {
None
}
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (&'_ K, &'_ V)> + '_ {
self.levels.iter().flat_map(|x| x.items.iter())
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&'_ K, &'_ mut V)> {
self.levels.iter_mut().flat_map(|x| x.items.iter_mut())
}
pub fn iter_indices(&self) -> impl DoubleEndedIterator<Item = Index<K, V, R>> + '_ {
self.levels
.iter()
.enumerate()
.flat_map(move |(i, x)| (0..x.items.len()).map(move |j| Index::new(i, j, self)))
}
pub fn find_first(
&mut self,
mut pred: impl FnMut(&K, &V) -> bool,
) -> Option<Entry<'_, K, V, R>> {
if let Some((level, (idx, _))) = self
.levels
.iter()
.enumerate()
.flat_map(|(i, level)| level.items.iter().enumerate().map(move |x| (i, x)))
.find(|(_, (_, (key, val)))| pred(key, val))
{
Some(Entry {
cache: self,
level,
idx,
})
} else {
None
}
}
}
#[derive(Debug)]
pub struct Entry<'a, K, V, R: Rng = StdRng> {
cache: &'a mut CommonCache<K, V, R>,
level: usize,
idx: usize,
}
impl<'a, K: Eq + Hash, V, R: Rng> Entry<'a, K, V, R> {
pub fn peek_key_value(&self) -> (&K, &V) {
self.cache.levels[self.level]
.items
.get_index(self.idx)
.unwrap()
}
pub fn peek_key(&self) -> &K {
self.peek_key_value().0
}
pub fn peek_value(&self) -> &V {
self.peek_key_value().1
}
pub fn peek_key_value_mut(&mut self) -> (&K, &mut V) {
let (key, value) = self.cache.levels[self.level]
.items
.get_index_mut(self.idx)
.unwrap();
(key, value)
}
pub fn peek_value_mut(&mut self) -> &mut V {
self.peek_key_value_mut().1
}
pub fn peek_long(self) -> (&'a K, &'a mut V) {
let (key, value) = self.cache.levels[self.level]
.items
.get_index_mut(self.idx)
.unwrap();
(key, value)
}
pub fn get_key_value(&mut self) -> (&K, &mut V) {
replace_with_or_abort(self, |self_| {
let curr_level = self_.level;
let (index, cache) = self_.index_and_cache();
let (key, value) = index.remove_from(cache);
cache.insert_at_level::<false>(key, value, curr_level.saturating_sub(1))
});
self.peek_key_value_mut()
}
pub fn get_value(&mut self) -> &mut V {
self.get_key_value().1
}
pub fn get_long(mut self) -> (&'a K, &'a mut V) {
self.get_key_value();
self.peek_long()
}
pub fn remove(self) -> (K, V) {
let (index, cache) = self.index_and_cache();
index.remove_from(cache)
}
pub fn index(self) -> Index<K, V, R> {
self.index_and_cache().0
}
pub fn index_and_cache(self) -> (Index<K, V, R>, &'a mut CommonCache<K, V, R>) {
(Index::new(self.level, self.idx, self.cache), self.cache)
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Index<K, V, R: Rng = StdRng> {
level: usize,
idx: usize,
generation: u64,
_key_ty: PhantomData<K>,
_val_ty: PhantomData<V>,
_rng_ty: PhantomData<R>,
}
impl<K: Eq + Hash, V, R: Rng> Index<K, V, R> {
fn new(level: usize, idx: usize, in_cache: &CommonCache<K, V, R>) -> Self {
Self {
level,
idx,
generation: in_cache.generation,
_key_ty: PhantomData,
_val_ty: PhantomData,
_rng_ty: PhantomData,
}
}
fn assert_generation(&self, cache: &CommonCache<K, V, R>) {
assert_eq!(
self.generation, cache.generation,
"The generations of an `Index` and a `CommonCache` differs"
);
}
pub fn entry(self, cache: &mut CommonCache<K, V, R>) -> Entry<'_, K, V, R> {
self.assert_generation(cache);
Entry {
cache,
level: self.level,
idx: self.idx,
}
}
pub fn peek_key_value<'a>(&'a self, cache: &'a CommonCache<K, V, R>) -> (&'a K, &'a V) {
self.assert_generation(cache);
cache.levels[self.level].items.get_index(self.idx).unwrap()
}
pub fn peek_key<'a>(&'a self, cache: &'a CommonCache<K, V, R>) -> &'a K {
self.peek_key_value(cache).0
}
pub fn peek_value<'a>(&'a self, cache: &'a CommonCache<K, V, R>) -> &'a V {
self.peek_key_value(cache).1
}
pub fn peek_key_value_mut<'a>(
&'a self,
cache: &'a mut CommonCache<K, V, R>,
) -> (&'a K, &'a mut V) {
self.assert_generation(cache);
let (key, value) = cache.levels[self.level]
.items
.get_index_mut(self.idx)
.unwrap();
(key, value)
}
pub fn peek_value_mut<'a>(&'a self, cache: &'a mut CommonCache<K, V, R>) -> &'a mut V {
self.peek_key_value_mut(cache).1
}
pub fn get_key_value(self, cache: &mut CommonCache<K, V, R>) -> (&K, &mut V) {
let curr_level = self.level;
let (key, value) = self.remove_from(cache);
cache
.insert_at_level::<false>(key, value, curr_level.saturating_sub(1))
.peek_long()
}
pub fn get_value(self, cache: &mut CommonCache<K, V, R>) -> &mut V {
self.get_key_value(cache).1
}
fn remove_from(self, cache: &mut CommonCache<K, V, R>) -> (K, V) {
self.assert_generation(cache);
let level_items = &mut cache.levels[self.level].items;
let (key, value) = level_items.swap_remove_index(self.idx).unwrap();
if level_items.is_empty() && self.level == cache.levels.len() - 1 {
cache.levels.pop();
}
(key, value)
}
}