use crate::dump::Dump;
use crate::iter::*;
use alloc::borrow::Borrow;
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::mem;
use core::ptr::{self, NonNull};
use core::usize;
use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
#[cfg(feature = "hashbrown")]
use hashbrown::HashMap as HashMapData;
#[cfg(not(feature = "hashbrown"))]
use std::collections::HashMap as HashMapData;
extern crate alloc;
pub(crate) struct KeyRef<K> {
k: *const K,
}
impl<K: Hash> Hash for KeyRef<K> {
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe { (*self.k).hash(state) }
}
}
impl<K: PartialEq> PartialEq for KeyRef<K> {
fn eq(&self, other: &KeyRef<K>) -> bool {
unsafe { (*self.k).eq(&*other.k) }
}
}
impl<K: Eq> Eq for KeyRef<K> {}
impl<K> Borrow<K> for KeyRef<K> {
fn borrow(&self) -> &K {
unsafe { &*self.k }
}
}
pub(crate) struct Node<K, V> {
pub(crate) key: mem::MaybeUninit<K>,
pub(crate) value: mem::MaybeUninit<V>,
pub(crate) prev: *mut Node<K, V>,
pub(crate) next: *mut Node<K, V>,
}
impl<K, V> Node<K, V> {
fn new(key: K, val: V) -> Self {
Node {
key: mem::MaybeUninit::new(key),
value: mem::MaybeUninit::new(val),
prev: ptr::null_mut(),
next: ptr::null_mut(),
}
}
fn new_sigil() -> Self {
Node {
key: mem::MaybeUninit::uninit(),
value: mem::MaybeUninit::uninit(),
prev: ptr::null_mut(),
next: ptr::null_mut(),
}
}
}
pub struct Cache<K, V>
where
K: Eq + Hash,
{
data: HashMapData<KeyRef<K>, NonNull<Node<K, V>>>,
capacity: usize,
head: *mut Node<K, V>,
tail: *mut Node<K, V>,
}
unsafe impl<K: Send, V: Send> Send for Cache<K, V> where K: Eq + Hash {}
unsafe impl<K: Sync, V: Sync> Sync for Cache<K, V> where K: Eq + Hash {}
pub const BUG_REPORT_URL: &str = "https://gitlab.com/liberecofr/hashlru/-/issues";
impl<K, V> fmt::Debug for Cache<K, V>
where
K: fmt::Debug + Hash + Eq,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut comma = false;
write!(f, "Cache [")?;
if self.len() == 0 {
return write!(f, "]");
} else {
write!(f, " ")?;
}
let iter = self.iter();
for kv in iter {
if comma {
write!(f, ", ")?;
} else {
comma = true;
}
write!(f, "({:?}, {:?})", kv.0, kv.1)?;
}
write!(f, " ]")
}
}
impl<K, V> fmt::Display for Cache<K, V>
where
K: fmt::Display + Hash + Eq + Clone,
V: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let items = if self.len() <= 5 {
self.iter()
.map(|x| format!("{}: {}", x.0, x.1))
.collect::<Vec<String>>()
} else {
let mut acc = self
.iter()
.take(2)
.map(|x| format!("{}: {}", x.0, x.1))
.collect::<Vec<String>>();
acc.push("...".to_string());
let mru = self.peek_mru().unwrap();
acc.push(format!("{}: {}", mru.0, mru.1));
acc
};
write!(f, "[{}]", items.join(", "))
}
}
impl<K, V> Cache<K, V>
where
K: Eq + Hash,
{
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn capacity(&self) -> usize {
self.capacity
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
pub fn is_full(&self) -> bool {
self.data.len() >= self.capacity
}
#[inline]
pub fn clear(&mut self) {
while self.pop_lru().is_some() {}
}
pub fn resize(&mut self, capacity: usize) -> usize {
if capacity == self.capacity {
return 0;
}
if capacity > self.capacity {
self.data.reserve(capacity - self.capacity);
}
let mut dropped = 0;
while self.len() > capacity {
self.pop_lru();
dropped += 1;
}
self.data.shrink_to_fit();
self.capacity = capacity;
dropped
}
pub fn new(capacity: usize) -> Cache<K, V> {
let cache = Cache {
data: HashMapData::with_capacity(capacity),
capacity,
head: Box::into_raw(Box::new(Node::new_sigil())),
tail: Box::into_raw(Box::new(Node::new_sigil())),
};
unsafe {
(*cache.head).next = cache.tail;
(*cache.tail).prev = cache.head;
}
cache
}
fn insert_non_0(&mut self, k: K, mut v: V) -> Option<V> {
let node_ref = self.data.get_mut(&KeyRef { k: &k });
match node_ref {
Some(node_ref) => {
let node_ptr: *mut Node<K, V> = node_ref.as_ptr();
let node_ref = unsafe { &mut (*(*node_ptr).value.as_mut_ptr()) };
mem::swap(&mut v, node_ref);
let _ = node_ref;
self.detach(node_ptr);
self.attach(node_ptr);
Some(v)
}
None => {
let (_replaced, node) = self.replace_or_create_node(k, v);
let node_ptr: *mut Node<K, V> = node.as_ptr();
self.attach(node_ptr);
let keyref = unsafe { (*node_ptr).key.as_ptr() };
self.data.insert(KeyRef { k: keyref }, node);
None
}
}
}
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
if self.capacity == 0 {
return None;
}
self.insert_non_0(k, v)
}
fn remove_first(&mut self) -> Option<Box<Node<K, V>>> {
let prev = unsafe { (*self.head).next };
if prev != self.head {
let old_key = KeyRef {
k: unsafe { &(*(*(*self.head).next).key.as_ptr()) },
};
let old_node = self.data.remove(&old_key).unwrap();
let node_ptr: *mut Node<K, V> = old_node.as_ptr();
self.detach(node_ptr);
unsafe { Some(Box::from_raw(node_ptr)) }
} else {
None
}
}
fn remove_last(&mut self) -> Option<Box<Node<K, V>>> {
let prev = unsafe { (*self.tail).prev };
if prev != self.tail {
let old_key = KeyRef {
k: unsafe { &(*(*(*self.tail).prev).key.as_ptr()) },
};
let old_node = self.data.remove(&old_key).unwrap();
let node_ptr: *mut Node<K, V> = old_node.as_ptr();
self.detach(node_ptr);
unsafe { Some(Box::from_raw(node_ptr)) }
} else {
None
}
}
fn detach(&mut self, node: *mut Node<K, V>) {
unsafe {
(*(*node).prev).next = (*node).next;
(*(*node).next).prev = (*node).prev;
}
}
fn attach(&mut self, node: *mut Node<K, V>) {
unsafe {
(*node).next = (*self.head).next;
(*node).prev = self.head;
(*self.head).next = node;
(*(*node).next).prev = node;
}
}
fn replace_or_create_node(&mut self, k: K, v: V) -> (Option<(K, V)>, NonNull<Node<K, V>>) {
if self.len() == self.capacity() {
let old_key = KeyRef {
k: unsafe { &(*(*(*self.tail).prev).key.as_ptr()) },
};
let old_node = self.data.remove(&old_key).unwrap();
let node_ptr: *mut Node<K, V> = old_node.as_ptr();
let replaced = unsafe {
(
mem::replace(&mut (*node_ptr).key, mem::MaybeUninit::new(k)).assume_init(),
mem::replace(&mut (*node_ptr).value, mem::MaybeUninit::new(v)).assume_init(),
)
};
self.detach(node_ptr);
(Some(replaced), old_node)
} else {
(None, unsafe {
NonNull::new_unchecked(Box::into_raw(Box::new(Node::new(k, v))))
})
}
}
fn push_non_0(&mut self, k: K, mut v: V) -> Option<(K, V)> {
let node_ref = self.data.get_mut(&KeyRef { k: &k });
match node_ref {
Some(node_ref) => {
let node_ptr: *mut Node<K, V> = node_ref.as_ptr();
let node_ref = unsafe { &mut (*(*node_ptr).value.as_mut_ptr()) };
mem::swap(&mut v, node_ref);
let _ = node_ref;
self.detach(node_ptr);
self.attach(node_ptr);
None
}
None => {
let (replaced, node) = self.replace_or_create_node(k, v);
let node_ptr: *mut Node<K, V> = node.as_ptr();
self.attach(node_ptr);
let keyref = unsafe { (*node_ptr).key.as_ptr() };
self.data.insert(KeyRef { k: keyref }, node);
replaced
}
}
}
pub fn push(&mut self, k: K, v: V) -> Option<(K, V)> {
if self.capacity == 0 {
return None;
}
self.push_non_0(k, v)
}
pub fn contains_key(&self, k: &K) -> bool {
self.data.contains_key(k)
}
pub fn peek(&self, k: &K) -> Option<&V> {
self.data
.get(k)
.map(|node| unsafe { &*node.as_ref().value.as_ptr() })
}
pub fn peek_mut(&mut self, k: &K) -> Option<&mut V> {
if let Some(node) = self.data.get(k) {
let node_ptr: *mut Node<K, V> = node.as_ptr();
Some(unsafe { &mut *(*node_ptr).value.as_mut_ptr() })
} else {
None
}
}
pub fn peek_key_value(&self, k: &K) -> Option<(&K, &V)> {
self.data
.get(k)
.map(|node| unsafe { (&*node.as_ref().key.as_ptr(), &*node.as_ref().value.as_ptr()) })
}
pub fn get(&mut self, k: &K) -> Option<&V> {
if let Some(node) = self.data.get(k) {
let node_ptr: *mut Node<K, V> = node.as_ptr();
self.detach(node_ptr);
self.attach(node_ptr);
Some(unsafe { &*(*node_ptr).value.as_ptr() })
} else {
None
}
}
pub fn get_mut(&mut self, k: &K) -> Option<&mut V> {
if let Some(node) = self.data.get(k) {
let node_ptr: *mut Node<K, V> = node.as_ptr();
self.detach(node_ptr);
self.attach(node_ptr);
Some(unsafe { &mut *(*node_ptr).value.as_mut_ptr() })
} else {
None
}
}
pub fn get_key_value(&mut self, k: &K) -> Option<(&K, &V)> {
self.get(k); self.peek_key_value(k) }
pub fn bump(&mut self, k: &K) {
if let Some(node) = self.data.get_mut(k) {
let node_ptr: *mut Node<K, V> = node.as_ptr();
self.detach(node_ptr);
self.attach(node_ptr);
}
}
pub fn pop(&mut self, k: &K) -> Option<(K, V)> {
match self.data.remove(k) {
None => None,
Some(old_node) => {
let mut old_node = unsafe { *Box::from_raw(old_node.as_ptr()) };
self.detach(&mut old_node);
let Node { key, value, .. } = old_node;
unsafe { Some((key.assume_init(), value.assume_init())) }
}
}
}
pub fn remove(&mut self, k: &K) -> Option<V> {
match self.data.remove(k) {
None => None,
Some(old_node) => {
let mut old_node = unsafe { *Box::from_raw(old_node.as_ptr()) };
self.detach(&mut old_node);
let Node { key: _, value, .. } = old_node;
unsafe { Some(value.assume_init()) }
}
}
}
pub fn delete(&mut self, k: &K) {
if let Some(old_node) = self.data.remove(k) {
let mut old_node = unsafe { *Box::from_raw(old_node.as_ptr()) };
self.detach(&mut old_node);
let Node {
key: _, value: _, ..
} = old_node;
}
}
pub fn lru(&self) -> Option<&K> {
if self.len() > 0 {
let key = unsafe { &(*(*(*self.tail).prev).key.as_ptr()) };
Some(key)
} else {
None
}
}
pub fn pop_lru(&mut self) -> Option<(K, V)> {
if self.len() == 0 {
return None;
}
let node = self.remove_last()?;
let node = *node;
let Node { key, value, .. } = node;
unsafe { Some((key.assume_init(), value.assume_init())) }
}
pub fn peek_lru(&self) -> Option<(&K, &V)> {
match self.lru() {
Some(tail) => self.peek_key_value(&tail),
None => None,
}
}
pub fn get_lru(&mut self) -> Option<(&K, &V)> {
if self.len() == 0 {
return None;
}
let node_ptr = unsafe { (*self.tail).prev };
self.detach(node_ptr);
self.attach(node_ptr);
Some(unsafe { (&*(*node_ptr).key.as_ptr(), &*(*node_ptr).value.as_ptr()) })
}
pub fn mru(&self) -> Option<&K> {
if self.len() > 0 {
let key = unsafe { &(*(*(*self.head).next).key.as_ptr()) };
Some(key)
} else {
None
}
}
pub fn pop_mru(&mut self) -> Option<(K, V)> {
if self.len() == 0 {
return None;
}
let node = self.remove_first()?;
let node = *node;
let Node { key, value, .. } = node;
unsafe { Some((key.assume_init(), value.assume_init())) }
}
pub fn peek_mru(&self) -> Option<(&K, &V)> {
match self.mru() {
Some(mru) => self.peek_key_value(&mru),
None => None,
}
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter {
done: 0,
len: self.len(),
forward: unsafe { (*self.head).next },
backward: unsafe { (*self.tail).prev },
phantom: PhantomData,
}
}
pub fn iter_mut(&self) -> IterMut<'_, K, V> {
IterMut {
done: 0,
len: self.len(),
forward: unsafe { (*self.head).next },
backward: unsafe { (*self.tail).prev },
phantom: PhantomData,
}
}
pub fn keys(&self) -> Keys<'_, K, V> {
self.iter().keys()
}
pub fn values(&self) -> Values<'_, K, V> {
self.iter().values()
}
pub fn into_keys(self) -> IntoKeys<K, V> {
self.into_iter().keys()
}
pub fn into_values(self) -> IntoValues<K, V> {
self.into_iter().values()
}
pub fn import<I>(&mut self, iter: I) -> usize
where
I: Iterator<Item = (K, V)>,
{
for i in iter {
self.insert(i.0, i.1);
}
self.len()
}
}
impl<K, V> Cache<K, V> where K: Hash + Eq + Clone {}
impl<K, V> std::iter::IntoIterator for Cache<K, V>
where
K: Eq + Hash,
{
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> IntoIter<K, V> {
IntoIter {
len: self.len(),
cache: self,
}
}
}
impl<K, V> FromIterator<(K, V)> for Cache<K, V>
where
K: Eq + Hash + Clone,
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut c = Cache::new(0);
for i in iter {
c.resize(c.len() + 1);
c.push(i.0, i.1);
}
c
}
}
impl<K, V> Cache<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
pub fn dump(&self) -> Dump<K, V> {
Dump {
capacity: self.capacity(),
data: self.to_vec(),
}
}
pub fn restore(&mut self, dump: &Dump<K, V>) -> usize {
self.clear();
self.resize(dump.capacity);
for i in dump.data.iter() {
self.insert(i.0.clone(), i.1.clone());
}
self.len()
}
pub fn import_iter<'a, I>(&mut self, iter: I) -> usize
where
K: 'a,
V: 'a,
I: Iterator<Item = (&'a K, &'a V)>,
{
for i in iter {
self.insert(i.0.clone(), i.1.clone());
}
self.len()
}
pub fn to_map(&self) -> HashMap<K, V> {
let mut map: HashMap<K, V> = HashMap::with_capacity(self.len());
for i in self.iter() {
map.insert(i.0.clone(), i.1.clone());
}
map
}
pub fn to_vec(&self) -> Vec<(K, V)> {
let mut vec: Vec<(K, V)> = Vec::with_capacity(self.len());
for i in self.iter() {
vec.push((i.0.clone(), i.1.clone()));
}
vec
}
}
impl<K, V> Clone for Cache<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
fn clone(&self) -> Self {
let mut cloned = Cache::new(self.capacity);
cloned.import_iter(self.iter());
cloned
}
}
impl<K, V> PartialEq<Cache<K, V>> for Cache<K, V>
where
K: Hash + Eq + Clone,
V: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
if self.capacity != other.capacity {
return false;
}
if self.len() != other.len() {
return false;
}
let mut iter_other = other.iter();
for self_v in self.iter() {
match iter_other.next() {
Some(other_v) => {
if self_v != other_v {
return false;
}
}
None => return false,
}
}
true
}
}
impl<K, V> Eq for Cache<K, V>
where
K: Hash + Eq + Clone,
V: Eq,
{
}
#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;
use std::collections::HashSet;
use std::fmt::Debug;
use std::hash::Hash;
impl<K, V> Cache<K, V>
where
K: Hash + Eq + Clone + Debug,
{
fn check_order(&self) {
let n = self.len();
if n > 0 {
let mut keys = HashSet::new();
let mut iter_keys = self.keys();
for _ in 0..n {
let k = iter_keys.next().unwrap();
keys.insert(k);
}
assert_eq!(n, keys.len());
keys.clear();
let mut iter_keys = self.keys();
for _ in 0..n {
let k = iter_keys.next_back().unwrap();
keys.insert(k);
}
assert_eq!(n, keys.len());
}
}
}
#[test]
fn test_debug() {
let mut lru = Cache::<i32, &str>::new(7);
lru.insert(1, "abc");
lru.insert(2, "def");
lru.insert(3, "fgh");
let debug = format!("{:?}", lru);
assert_eq!("Cache [ (1, \"abc\"), (2, \"def\"), (3, \"fgh\") ]", debug);
let mut iter = lru.iter();
iter.next();
iter.next();
let mut debug_iter = format!("{:?}", iter);
assert_eq!(
"Iter { done: 2, len: 3, next: 3, next_back: 3 }",
debug_iter
);
iter.next();
debug_iter = format!("{:?}", iter);
assert_eq!("Iter { done: 3, len: 3 }", debug_iter);
}
#[test]
fn test_display() {
let mut lru = Cache::<i32, &str>::new(7);
lru.insert(1, "abc");
lru.insert(2, "def");
lru.insert(3, "fgh");
let display = format!("{}", lru);
assert_eq!("[1: abc, 2: def, 3: fgh]", display);
let mut iter = lru.iter();
iter.next();
let display_iter = format!("{}", iter);
assert_eq!("1/3, next: 2, next_back: 3", display_iter);
}
#[test]
fn test_standard_map() {
let mut lru = Cache::new(1000); assert_eq!(None, lru.insert(1, "one"));
lru.check_order();
assert_eq!(None, lru.insert(2, "two"));
lru.check_order();
assert_eq!(None, lru.insert(3, "three"));
lru.check_order();
assert_eq!(3, lru.len());
assert_eq!(Some("one"), lru.insert(1, "ONE"));
assert_eq!(None, lru.remove(&4));
assert_eq!(Some("ONE"), lru.remove(&1));
lru.check_order();
assert_eq!(Some("two"), lru.remove(&2));
lru.check_order();
assert_eq!(Some("three"), lru.remove(&3));
lru.check_order();
assert_eq!(None, lru.remove(&1));
}
#[test]
fn test_pop() {
let mut cache: Cache<usize, usize> = Cache::new(10);
assert_eq!(None, cache.insert(1, 10));
assert_eq!(None, cache.insert(2, 20));
assert_eq!(None, cache.insert(3, 30));
assert_eq!(10, cache.capacity());
assert_eq!(3, cache.len());
assert_eq!(Some((2, 20)), cache.pop(&2));
assert_eq!(None, cache.pop(&2));
assert_eq!(Some(&1), cache.lru());
assert_eq!(Some(&3), cache.mru());
assert_eq!(Some((1, 10)), cache.pop(&1));
assert_eq!(Some((3, 30)), cache.pop(&3));
assert_eq!(0, cache.len());
assert_eq!(None, cache.pop(&3));
}
#[test]
fn test_lru0() {
let mut lru = Cache::new(0);
assert_eq!(0, lru.len());
assert_eq!(0, lru.capacity());
assert_eq!(None, lru.insert(1, "one"));
assert_eq!(0, lru.len());
assert_eq!(0, lru.capacity());
assert_eq!(None, lru.pop_lru());
assert_eq!(None, lru.remove(&1));
assert_eq!("Cache []", format!("{:?}", lru));
assert_eq!("[]", format!("{}", lru));
}
#[test]
fn test_lru1() {
let mut lru = Cache::new(1);
assert_eq!(0, lru.len());
assert_eq!(1, lru.capacity());
assert_eq!(None, lru.push(1, "two"));
assert_eq!(1, lru.len());
assert_eq!(Some(&"two"), lru.peek(&1));
assert_eq!(Some(&"two"), lru.get(&1));
assert_eq!(None, lru.push(1, "one")); assert_eq!(Some("one"), lru.insert(1, "ONE")); assert_eq!(Some((1, "ONE")), lru.push(2, "two")); assert_eq!(None, lru.insert(1, "one")); assert_eq!(1, lru.len());
assert_eq!("Cache [ (1, \"one\") ]", format!("{:?}", lru));
assert_eq!("[1: one]", format!("{}", lru));
}
#[test]
fn test_lru5() {
let mut lru = Cache::new(5);
assert_eq!(None, lru.insert(1, "one"));
assert_eq!(None, lru.insert(2, "two"));
assert_eq!(None, lru.insert(3, "three"));
assert_eq!(Some("three"), lru.insert(3, "THREE"));
assert_eq!(None, lru.insert(4, "four"));
assert_eq!(None, lru.insert(5, "five"));
assert_eq!(None, lru.insert(6, "six"));
assert_eq!(5, lru.len());
assert_eq!(None, lru.get(&1));
assert_eq!(None, lru.insert(7, "seven"));
assert_eq!(5, lru.len());
assert_eq!(Some(&"seven"), lru.get(&7));
assert_eq!(5, lru.len());
assert_eq!(None, lru.get(&1));
assert_eq!(None, lru.get(&2));
lru.check_order();
assert_eq!(Some(&"THREE"), lru.get(&3));
lru.check_order();
assert_eq!(Some(&"four"), lru.get(&4));
assert_eq!(None, lru.insert(8, "eight"));
assert_eq!(None, lru.insert(9, "nine"));
assert_eq!(None, lru.insert(10, "ten"));
assert_eq!(None, lru.insert(11, "eleven"));
assert_eq!(5, lru.len());
assert_eq!(
"Cache [ (4, \"four\"), (8, \"eight\"), (9, \"nine\"), (10, \"ten\"), (11, \"eleven\") ]",
format!("{:?}", lru)
);
assert_eq!(
"[4: four, 8: eight, 9: nine, 10: ten, 11: eleven]",
format!("{}", lru)
);
assert_eq!(Some(&"four"), lru.get(&4));
assert_eq!(None, lru.get(&3));
assert_eq!(Some("eight"), lru.remove(&8));
assert_eq!(Some("nine"), lru.remove(&9));
assert_eq!(Some("ten"), lru.remove(&10));
assert_eq!(Some("eleven"), lru.remove(&11));
assert_eq!(Some("four"), lru.remove(&4));
assert_eq!(0, lru.len());
}
#[test]
fn test_lru100() {
let mut lru = Cache::new(100);
for i in 0..1000 {
lru.push(i, format!("value_{}", i));
lru.check_order();
}
assert_eq!(100, lru.len());
assert!(format!("{:?}", lru).starts_with("Cache [ (900, \"value_900\"), "));
assert_eq!(
"[900: value_900, 901: value_901, ..., 999: value_999]",
format!("{}", lru)
);
assert_eq!(Some(&"value_950".to_string()), lru.get(&950));
assert_eq!(
Some((&950, &"value_950".to_string())),
lru.get_key_value(&950)
);
assert_eq!(Some((&950, &"value_950".to_string())), lru.peek_mru());
assert_eq!(Some(&950), lru.mru());
assert_eq!(Some((&900, &"value_900".to_string())), lru.get_lru());
assert_eq!(Some((&901, &"value_901".to_string())), lru.get_lru());
assert_eq!(Some((&902, &"value_902".to_string())), lru.peek_lru());
assert_eq!(Some((&902, &"value_902".to_string())), lru.peek_lru());
assert_eq!(
"[902: value_902, 903: value_903, ..., 901: value_901]",
format!("{}", lru)
);
assert_eq!(Some(&902), lru.lru());
assert_eq!(Some((&901, &"value_901".to_string())), lru.peek_mru());
assert_eq!(Some(&901), lru.mru());
}
#[derive(Debug, Eq, PartialEq, Clone)]
struct Coord {
x: i64,
y: i64,
}
#[test]
fn test_monkey() {
let mut cache: Cache<String, Coord> = Cache::new(50);
let mut rng = rand::thread_rng();
let mut dummy: i64 = 0;
for i in 0..1_000_000 {
if i % 1000 == 0 {
print!(".");
}
if i % 100_000 == 0 {
cache.clear();
continue;
}
let dice = rng.gen_range(0..=100);
if dice < 20 {
let key = format!("key_{}", i % 100);
let value = Coord {
x: i % 89,
y: i % 97,
};
cache.insert(key, value);
continue;
}
if dice < 40 {
let key = format!("key_{}", i % 100);
let value = Coord {
x: i % 89,
y: i % 97,
};
cache.push(key, value);
continue;
}
if dice < 50 {
let key = format!("key_{}", i % 10);
cache.get(&key);
continue;
}
if dice < 60 {
let key = format!("key_{}", i % 10);
cache.peek(&key);
continue;
}
if dice < 70 {
let key = format!("key_{}", i % 10);
cache.pop(&key);
continue;
}
if dice < 80 {
let key = format!("key_{}", i % 10);
cache.remove(&key);
continue;
}
if dice < 81 {
let dump = cache.dump();
let mut other: Cache<String, Coord> = Cache::new(100);
other.restore(&dump);
}
if dice < 83 {
for kv in cache.iter() {
dummy += kv.1.x * kv.1.y;
}
}
if dice < 85 {
for v in cache.values() {
dummy += v.x * v.y;
}
}
}
assert_ne!(0, dummy);
}
}