1use core::hash::Hash;
4use std::collections::HashMap;
5use std::num::NonZeroUsize;
6use std::sync::Mutex;
7
8use crate::cache::Cache;
9use crate::error::CacheError;
10use crate::util::MutexExt;
11
12pub struct LruCache<K, V> {
40 capacity: NonZeroUsize,
41 inner: Mutex<Inner<K, V>>,
42}
43
44struct Node<K, V> {
45 key: K,
46 value: V,
47 prev: Option<usize>,
48 next: Option<usize>,
49}
50
51struct Inner<K, V> {
52 nodes: Vec<Option<Node<K, V>>>,
54 free: Vec<usize>,
56 head: Option<usize>,
58 tail: Option<usize>,
60 map: HashMap<K, usize>,
62}
63
64impl<K, V> Inner<K, V>
65where
66 K: Eq + Hash + Clone,
67{
68 fn with_capacity(cap: usize) -> Self {
69 Self {
70 nodes: Vec::with_capacity(cap),
71 free: Vec::new(),
72 head: None,
73 tail: None,
74 map: HashMap::with_capacity(cap),
75 }
76 }
77
78 fn alloc(&mut self, node: Node<K, V>) -> usize {
80 if let Some(idx) = self.free.pop() {
81 self.nodes[idx] = Some(node);
82 idx
83 } else {
84 self.nodes.push(Some(node));
85 self.nodes.len() - 1
86 }
87 }
88
89 fn dealloc(&mut self, idx: usize) -> Node<K, V> {
91 let node = self.nodes[idx]
92 .take()
93 .unwrap_or_else(|| unreachable!("arena slot must be occupied to be deallocated"));
94 self.free.push(idx);
95 node
96 }
97
98 fn unlink(&mut self, idx: usize) {
101 let (prev, next) = {
102 let n = self.nodes[idx]
103 .as_ref()
104 .unwrap_or_else(|| unreachable!("unlink target must be occupied"));
105 (n.prev, n.next)
106 };
107 match prev {
108 Some(p) => {
109 self.nodes[p]
110 .as_mut()
111 .unwrap_or_else(|| unreachable!())
112 .next = next
113 }
114 None => self.head = next,
115 }
116 match next {
117 Some(n) => {
118 self.nodes[n]
119 .as_mut()
120 .unwrap_or_else(|| unreachable!())
121 .prev = prev
122 }
123 None => self.tail = prev,
124 }
125 if let Some(n) = self.nodes[idx].as_mut() {
126 n.prev = None;
127 n.next = None;
128 }
129 }
130
131 fn push_front(&mut self, idx: usize) {
133 let old_head = self.head;
134 if let Some(n) = self.nodes[idx].as_mut() {
135 n.prev = None;
136 n.next = old_head;
137 }
138 if let Some(h) = old_head {
139 if let Some(n) = self.nodes[h].as_mut() {
140 n.prev = Some(idx);
141 }
142 } else {
143 self.tail = Some(idx);
145 }
146 self.head = Some(idx);
147 }
148
149 fn promote(&mut self, idx: usize) {
151 if self.head == Some(idx) {
152 return;
153 }
154 self.unlink(idx);
155 self.push_front(idx);
156 }
157}
158
159impl<K, V> LruCache<K, V>
160where
161 K: Eq + Hash + Clone,
162 V: Clone,
163{
164 pub fn new(capacity: usize) -> Result<Self, CacheError> {
176 let cap = NonZeroUsize::new(capacity).ok_or(CacheError::InvalidCapacity)?;
177 Ok(Self::with_capacity(cap))
178 }
179
180 pub fn with_capacity(capacity: NonZeroUsize) -> Self {
192 let cap = capacity.get();
193 Self {
194 capacity,
195 inner: Mutex::new(Inner::with_capacity(cap)),
196 }
197 }
198}
199
200impl<K, V> Cache<K, V> for LruCache<K, V>
201where
202 K: Eq + Hash + Clone,
203 V: Clone,
204{
205 fn get(&self, key: &K) -> Option<V> {
206 let mut inner = self.inner.lock_recover();
207 let idx = *inner.map.get(key)?;
208 inner.promote(idx);
209 let value = inner.nodes[idx]
210 .as_ref()
211 .map(|n| n.value.clone())
212 .unwrap_or_else(|| unreachable!("promoted node must be occupied"));
213 Some(value)
214 }
215
216 fn insert(&self, key: K, value: V) -> Option<V> {
217 let mut inner = self.inner.lock_recover();
218
219 if let Some(&idx) = inner.map.get(&key) {
220 let old = inner.nodes[idx]
222 .as_mut()
223 .map(|n| core::mem::replace(&mut n.value, value))
224 .unwrap_or_else(|| unreachable!("mapped index must be occupied"));
225 inner.promote(idx);
226 return Some(old);
227 }
228
229 if inner.map.len() >= self.capacity.get() {
231 if let Some(tail_idx) = inner.tail {
232 inner.unlink(tail_idx);
233 let evicted = inner.dealloc(tail_idx);
234 let _ = inner.map.remove(&evicted.key);
235 }
236 }
237
238 let idx = inner.alloc(Node {
239 key: key.clone(),
240 value,
241 prev: None,
242 next: None,
243 });
244 inner.push_front(idx);
245 let _ = inner.map.insert(key, idx);
246 None
247 }
248
249 fn remove(&self, key: &K) -> Option<V> {
250 let mut inner = self.inner.lock_recover();
251 let idx = inner.map.remove(key)?;
252 inner.unlink(idx);
253 let node = inner.dealloc(idx);
254 Some(node.value)
255 }
256
257 fn contains_key(&self, key: &K) -> bool {
258 self.inner.lock_recover().map.contains_key(key)
259 }
260
261 fn len(&self) -> usize {
262 self.inner.lock_recover().map.len()
263 }
264
265 fn clear(&self) {
266 let mut inner = self.inner.lock_recover();
267 inner.nodes.clear();
268 inner.free.clear();
269 inner.head = None;
270 inner.tail = None;
271 inner.map.clear();
272 }
273
274 fn capacity(&self) -> usize {
275 self.capacity.get()
276 }
277}