associative_cache/replacement/
lru.rs1use super::*;
5use std::cell::Cell;
6use std::ops::{Deref, DerefMut};
7use std::time::Instant;
8
9pub trait LruTimestamp {
16 type Timestamp<'a>: PartialOrd
21 where
22 Self: 'a;
23
24 fn get_timestamp(&self) -> Self::Timestamp<'_>;
26
27 fn update_timestamp(&self);
34}
35
36#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
62pub struct WithLruTimestamp<T> {
63 timestamp: Cell<Instant>,
64 inner: T,
65}
66
67impl<T> Default for WithLruTimestamp<T>
68where
69 T: Default,
70{
71 #[inline]
72 fn default() -> Self {
73 WithLruTimestamp {
74 timestamp: Cell::new(Instant::now()),
75 inner: Default::default(),
76 }
77 }
78}
79
80impl<T> AsRef<T> for WithLruTimestamp<T> {
81 #[inline]
82 fn as_ref(&self) -> &T {
83 &self.inner
84 }
85}
86
87impl<T> AsMut<T> for WithLruTimestamp<T> {
88 #[inline]
89 fn as_mut(&mut self) -> &mut T {
90 &mut self.inner
91 }
92}
93
94impl<T> Deref for WithLruTimestamp<T> {
95 type Target = T;
96
97 #[inline]
98 fn deref(&self) -> &T {
99 &self.inner
100 }
101}
102
103impl<T> DerefMut for WithLruTimestamp<T> {
104 #[inline]
105 fn deref_mut(&mut self) -> &mut T {
106 &mut self.inner
107 }
108}
109
110impl<T> From<T> for WithLruTimestamp<T> {
111 #[inline]
112 fn from(inner: T) -> WithLruTimestamp<T> {
113 WithLruTimestamp::new(inner)
114 }
115}
116
117impl<T> WithLruTimestamp<T> {
118 #[inline]
129 pub fn new(inner: T) -> WithLruTimestamp<T> {
130 WithLruTimestamp {
131 timestamp: Cell::new(Instant::now()),
132 inner,
133 }
134 }
135
136 #[inline]
148 pub fn into_inner(outer: WithLruTimestamp<T>) -> T {
149 outer.inner
150 }
151}
152
153impl<T> LruTimestamp for WithLruTimestamp<T> {
154 type Timestamp<'a> = &'a Cell<Instant> where T: 'a;
155
156 #[inline]
157 fn get_timestamp(&self) -> Self::Timestamp<'_> {
158 &self.timestamp
159 }
160
161 #[inline]
162 fn update_timestamp(&self) {
163 self.timestamp.set(Instant::now());
164 }
165}
166
167#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
174pub struct LruReplacement {
175 _private: (),
176}
177
178impl<V, C> Replacement<V, C> for LruReplacement
179where
180 C: Capacity,
181 V: LruTimestamp,
182{
183 #[inline]
184 fn choose_for_replacement<'a>(
185 &mut self,
186 candidates: impl ExactSizeIterator<Item = (usize, &'a V)>,
187 ) -> usize
188 where
189 V: 'a,
190 {
191 let mut lru = None;
192 for (index, value) in candidates {
193 let timestamp = value.get_timestamp();
194 lru = match lru {
195 Some((t, i)) if t < timestamp => Some((t, i)),
196 _ => Some((timestamp, index)),
197 };
198 }
199 lru.unwrap().1
200 }
201
202 #[inline]
203 fn on_hit(&self, value: &V) {
204 value.update_timestamp();
205 }
206
207 #[inline]
208 fn on_insert(&self, value: &V) {
209 value.update_timestamp();
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use crate::Capacity4;
217 use std::time::Duration;
218
219 #[test]
220 fn lru_replacement() {
221 let now = Instant::now();
222 let candidates = vec![
223 now,
224 now - Duration::from_secs(1),
225 now - Duration::from_secs(2),
226 now - Duration::from_secs(3),
227 ]
228 .into_iter()
229 .map(|t| WithLruTimestamp {
230 timestamp: Cell::new(t),
231 inner: (),
232 })
233 .collect::<Vec<_>>();
234
235 let replacement = &mut LruReplacement::default();
236
237 let index = <LruReplacement as Replacement<_, Capacity4>>::choose_for_replacement(
238 replacement,
239 candidates.iter().enumerate(),
240 );
241
242 assert_eq!(index, 3);
243 }
244
245 #[test]
246 fn lru_timestamp_ref() {
247 struct Wrap {
248 timestamp: Instant,
249 }
250 impl LruTimestamp for Wrap {
251 type Timestamp<'a> = &'a Instant;
252 fn get_timestamp(&self) -> Self::Timestamp<'_> {
253 &self.timestamp
254 }
255 fn update_timestamp(&self) {}
256 }
257 let now = Instant::now();
258 let candidates = vec![
259 now,
260 now - Duration::from_secs(1),
261 now - Duration::from_secs(2),
262 now - Duration::from_secs(3),
263 ]
264 .into_iter()
265 .map(|t| Wrap { timestamp: t })
266 .collect::<Vec<_>>();
267
268 let replacement = &mut LruReplacement::default();
269
270 let index = <LruReplacement as Replacement<_, Capacity4>>::choose_for_replacement(
271 replacement,
272 candidates.iter().enumerate(),
273 );
274
275 assert_eq!(index, 3);
276 }
277
278 #[test]
279 fn lru_timestamp_owned() {
280 #[repr(packed)]
281 struct Wrap {
282 timestamp: Instant,
283 }
284 impl LruTimestamp for Wrap {
285 type Timestamp<'a> = Instant;
286 fn get_timestamp(&self) -> Self::Timestamp<'_> {
287 self.timestamp
288 }
289 fn update_timestamp(&self) {}
290 }
291 let now = Instant::now();
292 let candidates = vec![
293 now,
294 now - Duration::from_secs(1),
295 now - Duration::from_secs(2),
296 now - Duration::from_secs(3),
297 ]
298 .into_iter()
299 .map(|t| Wrap { timestamp: t })
300 .collect::<Vec<_>>();
301
302 let replacement = &mut LruReplacement::default();
303
304 let index = <LruReplacement as Replacement<_, Capacity4>>::choose_for_replacement(
305 replacement,
306 candidates.iter().enumerate(),
307 );
308
309 assert_eq!(index, 3);
310 }
311}