From 1bd2214fd82445c7b6ab90e8d063698f69f694d8 Mon Sep 17 00:00:00 2001 From: asyncth Date: Tue, 17 May 2022 07:00:41 +0000 Subject: [PATCH] Add LruCache::pop_entry method --- src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d6f9411..8e224d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -318,9 +318,9 @@ impl LruCache { self.capturing_put(k, v, true) } - // Used internally by `put` and `push` to add a new entry to the lru. + // Used internally by `put` and `push` to add a new entry to the lru. // Takes ownership of and returns entries replaced due to the cache's capacity - // when `capture` is true. + // when `capture` is true. fn capturing_put(&mut self, k: K, mut v: V, capture: bool) -> Option<(K, V)> { let node_ref = self.map.get_mut(&KeyRef { k: &k }); @@ -354,8 +354,6 @@ impl LruCache { } } - - // Used internally to swap out a node if the cache is full or to create a new node if space // is available. Shared between `put`, `push`, and `get_or_insert`. fn replace_or_create_node(&mut self, k: K, v: V) -> (Option<(K, V)>, Box>) { @@ -647,6 +645,39 @@ impl LruCache { } } + /// Removes and returns the key and the value corresponding to the key from the cache or + /// `None` if it does not exist. + /// + /// # Example + /// + /// ``` + /// use lru::LruCache; + /// let mut cache = LruCache::new(2); + /// + /// cache.put(1, "a"); + /// cache.put(2, "a"); + /// + /// assert_eq!(cache.pop(&1), Some("a")); + /// assert_eq!(cache.pop_entry(&2), Some((2, "a"))); + /// assert_eq!(cache.pop(&1), None); + /// assert_eq!(cache.pop_entry(&2), None); + /// assert_eq!(cache.len(), 0); + /// ``` + pub fn pop_entry(&mut self, k: &Q) -> Option<(K, V)> + where + KeyRef: Borrow, + Q: Hash + Eq + ?Sized, + { + match self.map.remove(k) { + None => None, + Some(mut old_node) => { + let node_ptr: *mut LruEntry = &mut *old_node; + self.detach(node_ptr); + unsafe { Some((old_node.key.assume_init(), old_node.val.assume_init())) } + } + } + } + /// Removes and returns the key and value corresponding to the least recently /// used item or `None` if the cache is empty. /// @@ -1102,14 +1133,14 @@ where } impl ExactSizeIterator for IntoIter where K: Hash + Eq {} -impl FusedIterator for IntoIter where K: Hash + Eq {} +impl FusedIterator for IntoIter where K: Hash + Eq {} impl IntoIterator for LruCache { type Item = (K, V); type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { - IntoIter{cache: self} + IntoIter { cache: self } } } @@ -1360,6 +1391,24 @@ mod tests { assert_opt_eq(cache.get(&"banana"), "yellow"); } + #[test] + fn test_pop_entry() { + let mut cache = LruCache::new(2); + cache.put("apple", "red"); + cache.put("banana", "yellow"); + + assert_eq!(cache.len(), 2); + assert_opt_eq(cache.get(&"apple"), "red"); + assert_opt_eq(cache.get(&"banana"), "yellow"); + + let popped = cache.pop_entry(&"apple"); + assert!(popped.is_some()); + assert_eq!(popped.unwrap(), ("apple", "red")); + assert_eq!(cache.len(), 1); + assert!(cache.get(&"apple").is_none()); + assert_opt_eq(cache.get(&"banana"), "yellow"); + } + #[test] fn test_pop_lru() { let mut cache = LruCache::new(200);