@@ -1063,6 +1063,37 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
1063
1063
Some ( ( key, val) )
1064
1064
}
1065
1065
1066
+ /// Returns the value corresponding to the most recently used item or `None` if the
1067
+ /// cache is empty. Like `peek`, `peek_mru` does not update the LRU list so the item's
1068
+ /// position will be unchanged.
1069
+ ///
1070
+ /// # Example
1071
+ ///
1072
+ /// ```
1073
+ /// use lru::LruCache;
1074
+ /// use std::num::NonZeroUsize;
1075
+ /// let mut cache = LruCache::new(NonZeroUsize::new(2).unwrap());
1076
+ ///
1077
+ /// cache.put(1, "a");
1078
+ /// cache.put(2, "b");
1079
+ ///
1080
+ /// assert_eq!(cache.peek_mru(), Some((&2, &"b")));
1081
+ /// ```
1082
+ pub fn peek_mru ( & self ) -> Option < ( & K , & V ) > {
1083
+ if self . is_empty ( ) {
1084
+ return None ;
1085
+ }
1086
+
1087
+ let ( key, val) ;
1088
+ unsafe {
1089
+ let node: * mut LruEntry < K , V > = ( * self . head ) . next ;
1090
+ key = & ( * ( * node) . key . as_ptr ( ) ) as & K ;
1091
+ val = & ( * ( * node) . val . as_ptr ( ) ) as & V ;
1092
+ }
1093
+
1094
+ Some ( ( key, val) )
1095
+ }
1096
+
1066
1097
/// Returns a bool indicating whether the given key is in the cache. Does not update the
1067
1098
/// LRU list.
1068
1099
///
@@ -1194,6 +1225,34 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
1194
1225
unsafe { Some ( ( key. assume_init ( ) , val. assume_init ( ) ) ) }
1195
1226
}
1196
1227
1228
+ /// Removes and returns the key and value corresponding to the most recently
1229
+ /// used item or `None` if the cache is empty.
1230
+ ///
1231
+ /// # Example
1232
+ ///
1233
+ /// ```
1234
+ /// use lru::LruCache;
1235
+ /// use std::num::NonZeroUsize;
1236
+ /// let mut cache = LruCache::new(NonZeroUsize::new(2).unwrap());
1237
+ ///
1238
+ /// cache.put(2, "a");
1239
+ /// cache.put(3, "b");
1240
+ /// cache.put(4, "c");
1241
+ /// cache.get(&3);
1242
+ ///
1243
+ /// assert_eq!(cache.pop_mru(), Some((3, "b")));
1244
+ /// assert_eq!(cache.pop_mru(), Some((4, "c")));
1245
+ /// assert_eq!(cache.pop_mru(), None);
1246
+ /// assert_eq!(cache.len(), 0);
1247
+ /// ```
1248
+ pub fn pop_mru ( & mut self ) -> Option < ( K , V ) > {
1249
+ let node = self . remove_first ( ) ?;
1250
+ // N.B.: Can't destructure directly because of https://github.com/rust-lang/rust/issues/28536
1251
+ let node = * node;
1252
+ let LruEntry { key, val, .. } = node;
1253
+ unsafe { Some ( ( key. assume_init ( ) , val. assume_init ( ) ) ) }
1254
+ }
1255
+
1197
1256
/// Marks the key as the most recently used one.
1198
1257
///
1199
1258
/// # Example
@@ -1440,6 +1499,22 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
1440
1499
}
1441
1500
}
1442
1501
1502
+ fn remove_first ( & mut self ) -> Option < Box < LruEntry < K , V > > > {
1503
+ let next;
1504
+ unsafe { next = ( * self . head ) . next }
1505
+ if next != self . tail {
1506
+ let old_key = KeyRef {
1507
+ k : unsafe { & ( * ( * ( * self . head ) . next ) . key . as_ptr ( ) ) } ,
1508
+ } ;
1509
+ let old_node = self . map . remove ( & old_key) . unwrap ( ) ;
1510
+ let node_ptr: * mut LruEntry < K , V > = old_node. as_ptr ( ) ;
1511
+ self . detach ( node_ptr) ;
1512
+ unsafe { Some ( Box :: from_raw ( node_ptr) ) }
1513
+ } else {
1514
+ None
1515
+ }
1516
+ }
1517
+
1443
1518
fn remove_last ( & mut self ) -> Option < Box < LruEntry < K , V > > > {
1444
1519
let prev;
1445
1520
unsafe { prev = ( * self . tail ) . prev }
@@ -2095,6 +2170,23 @@ mod tests {
2095
2170
assert ! ( cache. peek_lru( ) . is_none( ) ) ;
2096
2171
}
2097
2172
2173
+ #[ test]
2174
+ fn test_peek_mru ( ) {
2175
+ let mut cache = LruCache :: new ( NonZeroUsize :: new ( 2 ) . unwrap ( ) ) ;
2176
+
2177
+ assert ! ( cache. peek_mru( ) . is_none( ) ) ;
2178
+
2179
+ cache. put ( "apple" , "red" ) ;
2180
+ cache. put ( "banana" , "yellow" ) ;
2181
+ assert_opt_eq_tuple ( cache. peek_mru ( ) , ( "banana" , "yellow" ) ) ;
2182
+
2183
+ cache. get ( & "apple" ) ;
2184
+ assert_opt_eq_tuple ( cache. peek_mru ( ) , ( "apple" , "red" ) ) ;
2185
+
2186
+ cache. clear ( ) ;
2187
+ assert ! ( cache. peek_mru( ) . is_none( ) ) ;
2188
+ }
2189
+
2098
2190
#[ test]
2099
2191
fn test_contains ( ) {
2100
2192
let mut cache = LruCache :: new ( NonZeroUsize :: new ( 2 ) . unwrap ( ) ) ;
@@ -2180,6 +2272,41 @@ mod tests {
2180
2272
}
2181
2273
}
2182
2274
2275
+ #[ test]
2276
+ fn test_pop_mru ( ) {
2277
+ let mut cache = LruCache :: new ( NonZeroUsize :: new ( 200 ) . unwrap ( ) ) ;
2278
+
2279
+ for i in 0 ..75 {
2280
+ cache. put ( i, "A" ) ;
2281
+ }
2282
+ for i in 0 ..75 {
2283
+ cache. put ( i + 100 , "B" ) ;
2284
+ }
2285
+ for i in 0 ..75 {
2286
+ cache. put ( i + 200 , "C" ) ;
2287
+ }
2288
+ assert_eq ! ( cache. len( ) , 200 ) ;
2289
+
2290
+ for i in 0 ..75 {
2291
+ assert_opt_eq ( cache. get ( & ( 74 - i + 100 ) ) , "B" ) ;
2292
+ }
2293
+ assert_opt_eq ( cache. get ( & 25 ) , "A" ) ;
2294
+
2295
+ assert_eq ! ( cache. pop_mru( ) , Some ( ( 25 , "A" ) ) ) ;
2296
+ for i in 0 ..75 {
2297
+ assert_eq ! ( cache. pop_mru( ) , Some ( ( i + 100 , "B" ) ) ) ;
2298
+ }
2299
+ for i in 0 ..75 {
2300
+ assert_eq ! ( cache. pop_mru( ) , Some ( ( 74 - i + 200 , "C" ) ) ) ;
2301
+ }
2302
+ for i in ( 26 ..75 ) . into_iter ( ) . rev ( ) {
2303
+ assert_eq ! ( cache. pop_mru( ) , Some ( ( i, "A" ) ) ) ;
2304
+ }
2305
+ for _ in 0 ..50 {
2306
+ assert_eq ! ( cache. pop_mru( ) , None ) ;
2307
+ }
2308
+ }
2309
+
2183
2310
#[ test]
2184
2311
fn test_clear ( ) {
2185
2312
let mut cache = LruCache :: new ( NonZeroUsize :: new ( 2 ) . unwrap ( ) ) ;
0 commit comments