Skip to content

Commit bb44cf9

Browse files
committed
Add try_get_or_insert() method
1 parent b4cdf23 commit bb44cf9

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

src/lib.rs

+55
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,61 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
508508
}
509509
}
510510

511+
/// Returns a reference to the value of the key in the cache if it is
512+
/// present in the cache and moves the key to the head of the LRU list.
513+
/// If the key does not exist the provided `FnOnce` is used to populate
514+
/// the list and a reference is returned. If `FnOnce` returns `Err`,
515+
/// returns the `Err`.
516+
///
517+
/// # Example
518+
///
519+
/// ```
520+
/// use lru::LruCache;
521+
/// use std::num::NonZeroUsize;
522+
/// let mut cache = LruCache::new(NonZeroUsize::new(2).unwrap());
523+
///
524+
/// cache.put(1, "a");
525+
/// cache.put(2, "b");
526+
/// cache.put(2, "c");
527+
/// cache.put(3, "d");
528+
///
529+
/// let f = ||->Result<&str, String> {Err("failed".to_owned())};
530+
/// let a = ||->Result<&str, String> {Ok("a")};
531+
/// let b = ||->Result<&str, String> {Ok("b")};
532+
/// assert_eq!(cache.try_get_or_insert(2, a), Ok(&"c"));
533+
/// assert_eq!(cache.try_get_or_insert(3, a), Ok(&"d"));
534+
/// assert_eq!(cache.try_get_or_insert(1, f), Err("failed".to_owned()));
535+
/// assert_eq!(cache.try_get_or_insert(1, b), Ok(&"b"));
536+
/// assert_eq!(cache.try_get_or_insert(1, a), Ok(&"b"));
537+
/// ```
538+
pub fn try_get_or_insert<F, E>(&mut self, k: K, f: F) -> Result<&V, E>
539+
where
540+
F: FnOnce() -> Result<V, E>,
541+
{
542+
if let Some(node) = self.map.get_mut(&KeyRef { k: &k }) {
543+
let node_ptr: *mut LruEntry<K, V> = node.as_ptr();
544+
545+
self.detach(node_ptr);
546+
self.attach(node_ptr);
547+
548+
unsafe { Ok(&*(*node_ptr).val.as_ptr()) }
549+
} else {
550+
match f() {
551+
Err(e) => Err(e),
552+
Ok(v) => {
553+
let (_, node) = self.replace_or_create_node(k, v);
554+
let node_ptr: *mut LruEntry<K, V> = node.as_ptr();
555+
556+
self.attach(node_ptr);
557+
558+
let keyref = unsafe { (*node_ptr).key.as_ptr() };
559+
self.map.insert(KeyRef { k: keyref }, node);
560+
Ok(unsafe { &*(*node_ptr).val.as_ptr() })
561+
}
562+
}
563+
}
564+
}
565+
511566
/// Returns a mutable reference to the value of the key in the cache if it is
512567
/// present in the cache and moves the key to the head of the LRU list.
513568
/// If the key does not exist the provided `FnOnce` is used to populate

0 commit comments

Comments
 (0)