1use lru::LruCache;
24
25use std::hash::Hash;
26use std::num::NonZeroUsize;
27
28const INITIAL_CAPACITY: Option<NonZeroUsize> = NonZeroUsize::new(4);
29
30pub trait ResidentSize {
32 fn resident_size(&self) -> usize;
35}
36
37pub struct MemoryLruCache<K, V> {
39 inner: LruCache<K, V>,
40 cur_size: usize,
41 max_size: usize,
42}
43
44impl<K: Eq + Hash, V: ResidentSize> MemoryLruCache<K, V> {
45 pub fn new(max_size: usize) -> Self {
47 MemoryLruCache {
48 inner: LruCache::new(INITIAL_CAPACITY.expect("4 != 0; qed")),
49 max_size: max_size,
50 cur_size: 0,
51 }
52 }
53
54 pub fn insert(&mut self, key: K, val: V) {
56 let cap = self.inner.cap().get();
57
58 if self.inner.len() == cap {
61 let next_cap = NonZeroUsize::new(cap.saturating_mul(2)).expect(
62 "only returns None if value is zero; cap is guaranteed to be non-zero; qed",
63 );
64 self.inner.resize(next_cap);
65 }
66
67 self.cur_size += val.resident_size();
68
69 if let Some(lru) = self.inner.put(key, val) {
71 self.cur_size -= lru.resident_size();
72 }
73
74 self.readjust_down();
75 }
76
77 pub fn get(&mut self, key: &K) -> Option<&V> {
80 self.inner.get(key)
81 }
82
83 pub fn with_mut<U>(&mut self, key: &K, with: impl FnOnce(Option<&mut V>) -> U) -> U {
85 let mut val = self.inner.get_mut(key);
86 let prev_size = val.as_ref().map_or(0, |v| v.resident_size());
87
88 let res = with(val.as_mut().map(|v: &mut &mut V| &mut **v));
89
90 let new_size = val.as_ref().map_or(0, |v| v.resident_size());
91
92 self.cur_size -= prev_size;
93 self.cur_size += new_size;
94
95 self.readjust_down();
96
97 res
98 }
99
100 pub fn current_size(&self) -> usize {
102 self.cur_size
103 }
104
105 pub fn len(&self) -> usize {
107 self.inner.len()
108 }
109
110 pub fn contains(&self, key: &K) -> bool {
113 self.inner.contains(key)
114 }
115
116 pub fn is_empty(&self) -> bool {
118 self.inner.is_empty()
119 }
120
121 pub fn peek(&self, key: &K) -> Option<&V> {
125 self.inner.peek(key)
126 }
127
128 fn readjust_down(&mut self) {
129 while self.cur_size > self.max_size {
131 match self.inner.pop_lru() {
132 Some((_, v)) => self.cur_size -= v.resident_size(),
133 _ => break,
134 }
135 }
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 impl ResidentSize for Vec<u8> {
144 fn resident_size(&self) -> usize {
145 self.len()
146 }
147 }
148
149 #[test]
150 fn it_works() {
151 let mut cache = MemoryLruCache::new(256);
152 let val1 = vec![0u8; 100];
153 let size1 = val1.resident_size();
154 assert_eq!(cache.len(), 0);
155 cache.insert("hello", val1);
156
157 assert_eq!(cache.current_size(), size1);
158
159 let val2 = vec![0u8; 210];
160 let size2 = val2.resident_size();
161 cache.insert("world", val2);
162
163 assert!(cache.get(&"hello").is_none());
164 assert!(cache.get(&"world").is_some());
165
166 assert_eq!(cache.current_size(), size2);
167 assert_eq!(cache.len(), 1);
168 }
169
170 #[test]
171 fn it_works_if_cur_size_equals_max_size() {
172 let mut cache = MemoryLruCache::new(8);
173 cache.insert(1, vec![0u8, 1u8]);
174 cache.insert(2, vec![2u8, 3u8]);
175 cache.insert(3, vec![4u8, 5u8]);
176 cache.insert(4, vec![6u8, 7u8]);
177 cache.insert(5, vec![8u8, 9u8]);
178
179 assert_eq!(Some(&vec![2u8, 3u8]), cache.get(&2));
180 }
181}