@@ -1063,6 +1063,37 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
10631063 Some ( ( key, val) )
10641064 }
10651065
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+
10661097 /// Returns a bool indicating whether the given key is in the cache. Does not update the
10671098 /// LRU list.
10681099 ///
@@ -1194,6 +1225,34 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
11941225 unsafe { Some ( ( key. assume_init ( ) , val. assume_init ( ) ) ) }
11951226 }
11961227
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+
11971256 /// Marks the key as the most recently used one.
11981257 ///
11991258 /// # Example
@@ -1440,6 +1499,22 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
14401499 }
14411500 }
14421501
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+
14431518 fn remove_last ( & mut self ) -> Option < Box < LruEntry < K , V > > > {
14441519 let prev;
14451520 unsafe { prev = ( * self . tail ) . prev }
@@ -2095,6 +2170,23 @@ mod tests {
20952170 assert ! ( cache. peek_lru( ) . is_none( ) ) ;
20962171 }
20972172
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+
20982190 #[ test]
20992191 fn test_contains ( ) {
21002192 let mut cache = LruCache :: new ( NonZeroUsize :: new ( 2 ) . unwrap ( ) ) ;
@@ -2180,6 +2272,41 @@ mod tests {
21802272 }
21812273 }
21822274
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+
21832310 #[ test]
21842311 fn test_clear ( ) {
21852312 let mut cache = LruCache :: new ( NonZeroUsize :: new ( 2 ) . unwrap ( ) ) ;
0 commit comments