1use std::{
5 collections::VecDeque,
6 sync::atomic::{AtomicI8, Ordering},
7};
8
9mod key;
10pub use key::S3FIFOKey;
11
12pub struct S3FIFO<K, V> {
41 small: VecDeque<Item<K, V>>,
42 main: VecDeque<Item<K, V>>,
43 ghost: VecDeque<Key<K>>,
44}
45
46impl<K: PartialEq + Clone, V> S3FIFO<K, V> {
47 pub fn new(capacity: usize) -> Self {
55 let small_capacity = capacity / 10;
56 let main_capacity = capacity * 9 / 10;
57 S3FIFO {
58 small: VecDeque::with_capacity(small_capacity),
59 main: VecDeque::with_capacity(main_capacity),
60 ghost: VecDeque::with_capacity(main_capacity),
61 }
62 }
63
64 pub fn get(&self, key: &K) -> Option<&V> {
67 if let Some(item) = self.small.iter().find(|item| item.key == *key) {
69 let _ = item
70 .freq
71 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |x| {
72 if x > 2 {
73 Some(3)
74 } else {
75 Some(x + 1)
76 }
77 });
78 return Some(&item.value);
79 }
80
81 if let Some(item) = self.main.iter().find(|item| item.key == *key) {
83 let _ = item
84 .freq
85 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |x| {
86 if x > 2 {
87 Some(3)
88 } else {
89 Some(x + 1)
90 }
91 });
92 return Some(&item.value);
93 }
94
95 None
96 }
97
98 pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
101 if let Some(item) = self.small.iter_mut().find(|item| item.key == *key) {
103 let _ = item
104 .freq
105 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |x| {
106 if x > 2 {
107 Some(3)
108 } else {
109 Some(x + 1)
110 }
111 });
112 return Some(&mut item.value);
113 }
114
115 if let Some(item) = self.main.iter_mut().find(|item| item.key == *key) {
117 let _ = item
118 .freq
119 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |x| {
120 if x > 2 {
121 Some(3)
122 } else {
123 Some(x + 1)
124 }
125 });
126 return Some(&mut item.value);
127 }
128
129 None
130 }
131
132 pub fn put(&mut self, key: K, value: V) -> (&mut V, Option<V>) {
136 if let Some(item) = self.get_mut(&key) {
138 let item = item as *mut V;
143 return (unsafe { &mut *item }, None);
144 }
145
146 let mut evicted = None;
148 if let Some(key) = self.ghost.iter().find(|k| k.key == key) {
149 let item = Item {
150 key: key.key.clone(),
151 value,
152 freq: key.freq.load(Ordering::Relaxed).into(),
153 };
154 if self.main.capacity() == self.main.len() {
155 evicted = self.evict_main();
156 }
157 self.main.push_front(item);
158 return (&mut self.main.front_mut().unwrap().value, evicted);
159 } else {
160 let item = Item {
161 key,
162 value,
163 freq: 0.into(),
164 };
165 if self.small.capacity() == self.small.len() {
166 evicted = self.evict_small();
167 }
168 self.small.push_front(item);
169 return (&mut self.small.front_mut().unwrap().value, evicted);
170 }
171 }
172
173 pub fn pop(&mut self) -> Option<V> {
175 while !self.small.is_empty() {
177 if let Some(value) = self.evict_small() {
178 return Some(value);
179 }
180 }
181
182 self.evict_main()
184 }
185
186 pub fn drain(&mut self) -> Vec<V> {
188 self.ghost.clear();
189 let mut values = Vec::with_capacity(self.small.len() + self.main.len());
190 values.extend(self.small.drain(..).map(|item| item.value));
191 values.extend(self.main.drain(..).map(|item| item.value));
192 values
193 }
194
195 fn evict_small(&mut self) -> Option<V> {
196 if self.small.is_empty() {
197 return None;
198 }
199 let item = self.small.pop_back().unwrap();
200 let freq = item.freq.load(Ordering::Relaxed);
201 if freq > 1 {
202 let mut value = None;
203 if self.main.capacity() == self.main.len() {
204 value = self.evict_main();
205 }
206 self.main.push_front(item);
207 value
208 } else {
209 let Item { key, value, freq } = item;
210 if self.ghost.capacity() == self.ghost.len() {
211 self.ghost.pop_back();
212 }
213 self.ghost.push_front(Key { key, freq });
214 Some(value)
215 }
216 }
217
218 fn evict_main(&mut self) -> Option<V> {
219 let mut iters = (3 * self.main.len() + 1) as isize;
222 while iters > 0 {
223 let Some(item) = self.main.pop_back() else {
224 return None;
225 };
226 iters -= 1;
227 let freq = item.freq.load(Ordering::Relaxed);
228 if freq > 0 {
229 item.freq.fetch_sub(1, Ordering::Relaxed);
230 self.main.push_front(item);
231 } else {
232 return Some(item.value);
233 }
234 }
235 None
236 }
237}
238
239struct Item<K, V> {
240 key: K,
241 value: V,
242 freq: AtomicI8, }
244
245struct Key<K> {
246 key: K,
247 freq: AtomicI8, }
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253 use std::{
254 collections::hash_map::DefaultHasher,
255 hash::{Hash, Hasher},
256 };
257
258 #[derive(Hash, Clone)]
259 struct Abc {
260 a: u8,
261 b: u16,
262 c: u32,
263 }
264
265 #[test]
266 fn can_use_cache() {
267 let test_value = Abc { a: 1, b: 2, c: 3 };
268 let mut hasher = DefaultHasher::new();
269 test_value.hash(&mut hasher);
270 let test_key = hasher.finish();
271
272 let mut cache = S3FIFO::new(10);
274 cache.put(test_key, test_value);
275 assert!(cache.get(&test_key).is_some());
276 }
277
278 #[test]
279 fn can_fill_cache() {
280 let mut cache = S3FIFO::new(10);
282 for i in 0..10 {
283 let test_value = Abc {
284 a: i as u8,
285 b: i as u16,
286 c: i as u32,
287 };
288 let test_key = S3FIFOKey::new(&test_value);
289
290 assert!(cache.get(&test_key).is_none());
291 cache.put(test_key.clone(), test_value);
292 assert!(cache.get(&test_key).is_some());
293 }
294
295 assert_eq!(cache.small.len(), 1);
296 assert_eq!(cache.ghost.len(), 9);
297
298 let repeat_value = Abc { a: 0, b: 0, c: 0 };
300 let repeat_key = S3FIFOKey::new(&repeat_value);
301 assert!(cache.get(&repeat_key).is_none());
302 cache.put(repeat_key, repeat_value);
303
304 assert_eq!(cache.small.len(), 1);
305 assert_eq!(cache.ghost.len(), 9);
306 assert_eq!(cache.main.len(), 1);
307
308 let repeat_value = Abc { a: 0, b: 0, c: 0 };
310 let repeat_key = S3FIFOKey::new(&repeat_value);
311 assert!(cache.get(&repeat_key).is_some());
312 assert_eq!(cache.small.len(), 1);
316 assert_eq!(cache.ghost.len(), 9);
317 assert_eq!(cache.main.len(), 1);
318 }
319}