Skip to content

Commit

Permalink
Add LruCache::pop_entry method
Browse files Browse the repository at this point in the history
  • Loading branch information
asyncth committed May 17, 2022
1 parent dc6a7c4 commit 1bd2214
Showing 1 changed file with 55 additions and 6 deletions.
61 changes: 55 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,9 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
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 });

Expand Down Expand Up @@ -354,8 +354,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
}
}



// 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<LruEntry<K, V>>) {
Expand Down Expand Up @@ -647,6 +645,39 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
}
}

/// 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<Q>(&mut self, k: &Q) -> Option<(K, V)>
where
KeyRef<K>: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
match self.map.remove(k) {
None => None,
Some(mut old_node) => {
let node_ptr: *mut LruEntry<K, V> = &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.
///
Expand Down Expand Up @@ -1102,14 +1133,14 @@ where
}

impl<K, V> ExactSizeIterator for IntoIter<K, V> where K: Hash + Eq {}
impl<K, V> FusedIterator for IntoIter<K, V> where K: Hash + Eq {}
impl<K, V> FusedIterator for IntoIter<K, V> where K: Hash + Eq {}

impl<K: Hash + Eq, V> IntoIterator for LruCache<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;

fn into_iter(self) -> IntoIter<K, V> {
IntoIter{cache: self}
IntoIter { cache: self }
}
}

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1bd2214

Please sign in to comment.