@@ -75,6 +75,7 @@ pub struct LruCache<
75
75
M : CountableMeter < K , V > = Count ,
76
76
> {
77
77
map : LinkedHashMap < K , V , S > ,
78
+ visited : LinkedHashMap < K , bool > ,
78
79
current_measure : M :: Measure ,
79
80
max_capacity : u64 ,
80
81
meter : M ,
@@ -92,6 +93,7 @@ impl<K: Eq + Hash, V> LruCache<K, V> {
92
93
pub fn new ( capacity : u64 ) -> Self {
93
94
LruCache {
94
95
map : LinkedHashMap :: new ( ) ,
96
+ visited : LinkedHashMap :: new ( ) ,
95
97
current_measure : ( ) ,
96
98
max_capacity : capacity,
97
99
meter : Count ,
@@ -136,6 +138,7 @@ impl<K: Eq + Hash, V, M: CountableMeter<K, V>> LruCache<K, V, DefaultHashBuilder
136
138
pub fn with_meter ( capacity : u64 , meter : M ) -> LruCache < K , V , DefaultHashBuilder , M > {
137
139
LruCache {
138
140
map : LinkedHashMap :: new ( ) ,
141
+ visited : LinkedHashMap :: new ( ) ,
139
142
current_measure : Default :: default ( ) ,
140
143
max_capacity : capacity,
141
144
meter,
@@ -148,13 +151,30 @@ impl<K: Eq + Hash, V, S: BuildHasher> LruCache<K, V, S, Count> {
148
151
pub fn with_hasher ( capacity : u64 , hash_builder : S ) -> LruCache < K , V , S , Count > {
149
152
LruCache {
150
153
map : LinkedHashMap :: with_hasher ( hash_builder) ,
154
+ visited : LinkedHashMap :: new ( ) ,
151
155
current_measure : ( ) ,
152
156
max_capacity : capacity,
153
157
meter : Count ,
154
158
}
155
159
}
156
160
}
157
161
162
+ impl < K : Eq + Hash , V , S : BuildHasher , M : CountableMeter < K , V > > LruCache < K , V , S , M > {
163
+ fn find_evict_candidate ( & mut self ) -> Option < K > {
164
+ let mut iter = self . visited . iter_mut ( ) ;
165
+ let mut p: Option < K > = None ;
166
+ while let Some ( ( key, value) ) = iter. next ( ) {
167
+ if * value == false && p. is_none ( ) {
168
+ p = Some ( unsafe { std:: ptr:: read ( key) } )
169
+ }
170
+ if * value == true {
171
+ * value = false ;
172
+ }
173
+ }
174
+ p
175
+ }
176
+ }
177
+
158
178
impl < K : Eq + Hash , V , S : BuildHasher , M : CountableMeter < K , V > > Cache < K , V , S , M >
159
179
for LruCache < K , V , S , M >
160
180
{
@@ -163,6 +183,7 @@ impl<K: Eq + Hash, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K, V, S, M>
163
183
fn with_meter_and_hasher ( capacity : u64 , meter : M , hash_builder : S ) -> Self {
164
184
LruCache {
165
185
map : LinkedHashMap :: with_hasher ( hash_builder) ,
186
+ visited : LinkedHashMap :: new ( ) ,
166
187
current_measure : Default :: default ( ) ,
167
188
max_capacity : capacity,
168
189
meter,
@@ -196,8 +217,14 @@ impl<K: Eq + Hash, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K, V, S, M>
196
217
Q : Hash + Eq + ?Sized ,
197
218
{
198
219
match self . map . raw_entry_mut ( ) . from_key ( k) {
199
- linked_hash_map:: RawEntryMut :: Occupied ( mut occupied) => {
200
- occupied. to_back ( ) ;
220
+ linked_hash_map:: RawEntryMut :: Occupied ( occupied) => {
221
+ match self . visited . raw_entry_mut ( ) . from_key ( k) {
222
+ // Since the element has been accessed, we set a flag.
223
+ linked_hash_map:: RawEntryMut :: Occupied ( mut occupied) => {
224
+ occupied. replace_value ( true ) ;
225
+ }
226
+ linked_hash_map:: RawEntryMut :: Vacant ( _) => ( ) ,
227
+ }
201
228
Some ( occupied. into_mut ( ) )
202
229
}
203
230
linked_hash_map:: RawEntryMut :: Vacant ( _) => None ,
@@ -244,7 +271,7 @@ impl<K: Eq + Hash, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K, V, S, M>
244
271
/// assert_eq!(cache.peek_by_policy(), Some((&1, &"a")));
245
272
/// ```
246
273
fn peek_by_policy ( & self ) -> Option < ( & K , & V ) > {
247
- self . map . front ( )
274
+ todo ! ( )
248
275
}
249
276
250
277
/// Checks if the map contains the given key.
@@ -286,11 +313,21 @@ impl<K: Eq + Hash, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K, V, S, M>
286
313
let new_size = self . meter . measure ( & k, & v) ;
287
314
self . current_measure = self . meter . add ( self . current_measure , new_size) ;
288
315
if let Some ( old) = self . map . get ( & k) {
316
+ match self . visited . raw_entry_mut ( ) . from_key ( & k) {
317
+ // Since the key has been accessed, we set a flag.
318
+ linked_hash_map:: RawEntryMut :: Occupied ( mut occupied) => {
319
+ occupied. replace_value ( true ) ;
320
+ }
321
+ linked_hash_map:: RawEntryMut :: Vacant ( _) => ( ) ,
322
+ }
289
323
self . current_measure = self
290
324
. meter
291
325
. sub ( self . current_measure , self . meter . measure ( & k, old) ) ;
326
+ } else {
327
+ let clone_k = unsafe { std:: ptr:: read ( & k) } ;
328
+ self . visited . replace ( clone_k, false ) ;
292
329
}
293
- let old_val = self . map . insert ( k, v) ;
330
+ let old_val = self . map . replace ( k, v) ;
294
331
while self . size ( ) > self . capacity ( ) {
295
332
self . pop_by_policy ( ) ;
296
333
}
@@ -319,6 +356,7 @@ impl<K: Eq + Hash, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K, V, S, M>
319
356
Q : Hash + Eq + ?Sized ,
320
357
{
321
358
self . map . remove ( k) . map ( |v| {
359
+ self . visited . remove ( k) ;
322
360
self . current_measure = self
323
361
. meter
324
362
. sub ( self . current_measure , self . meter . measure ( k, & v) ) ;
@@ -343,12 +381,23 @@ impl<K: Eq + Hash, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K, V, S, M>
343
381
/// ```
344
382
#[ inline]
345
383
fn pop_by_policy ( & mut self ) -> Option < ( K , V ) > {
346
- self . map . pop_front ( ) . map ( |( k, v) | {
347
- self . current_measure = self
348
- . meter
349
- . sub ( self . current_measure , self . meter . measure ( & k, & v) ) ;
350
- ( k, v)
351
- } )
384
+ if let Some ( old_key) = self . find_evict_candidate ( ) {
385
+ self . map . remove_entry ( & old_key) . map ( |( k, v) | {
386
+ self . visited . remove_entry ( & old_key) ;
387
+ self . current_measure = self
388
+ . meter
389
+ . sub ( self . current_measure , self . meter . measure ( & k, & v) ) ;
390
+ ( k, v)
391
+ } )
392
+ } else {
393
+ self . map . pop_front ( ) . map ( |( k, v) | {
394
+ self . visited . pop_front ( ) ;
395
+ self . current_measure = self
396
+ . meter
397
+ . sub ( self . current_measure , self . meter . measure ( & k, & v) ) ;
398
+ ( k, v)
399
+ } )
400
+ }
352
401
}
353
402
354
403
/// Sets the size of the key-value pairs the cache can hold, as measured by the `Meter` used by
@@ -427,6 +476,7 @@ impl<K: Eq + Hash, V, S: BuildHasher, M: CountableMeter<K, V>> Cache<K, V, S, M>
427
476
/// Removes all key-value pairs from the cache.
428
477
fn clear ( & mut self ) {
429
478
self . map . clear ( ) ;
479
+ self . visited . clear ( ) ;
430
480
self . current_measure = Default :: default ( ) ;
431
481
}
432
482
}
0 commit comments