From 1c1e2b96d82007d6827bab7cdda5b51ae5265056 Mon Sep 17 00:00:00 2001 From: Jerome Froelich Date: Mon, 2 Jan 2017 12:27:15 -0500 Subject: [PATCH] Added peek and contains functions --- CHANGELOG.md | 4 +++ Cargo.toml | 2 +- src/lib.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 87 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7681b4..3954689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [v0.1.2](https://github.com/jeromefroe/lru-rs/tree/0.1.2) - 2017-01-02 + +* Add `peek` and `contains` functions. + ## [v0.1.1](https://github.com/jeromefroe/lru-rs/tree/0.1.1) - 2016-12-31 * Fix documentation link in Cargo.toml. diff --git a/Cargo.toml b/Cargo.toml index 6a9b585..6d3a13a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lru" -version = "0.1.1" +version = "0.1.2" authors = ["Jerome Froelich "] description = "A LRU cache implementation" homepage = "https://github.com/jeromefroe/lru-rs" diff --git a/src/lib.rs b/src/lib.rs index 481e5f5..1913e13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,7 +184,7 @@ impl LruCache { } /// Return the value corresponding to the key in the cache or `None` if it is not - /// present in the cache. + /// present in the cache. Moves the key to the head of the LRU list if it exists. /// /// # Example /// @@ -207,6 +207,9 @@ impl LruCache { None => (None, None), Some(node) => { let node_ptr: *mut LruEntry = &mut **node; + // we need to use node_ptr to get a reference to val here because + // detach and attach require a mutable reference to self here which + // would be disallowed if we set value equal to &node.val (Some(node_ptr), Some(unsafe { &(*node_ptr).val })) } }; @@ -222,6 +225,52 @@ impl LruCache { value } + /// Return the value corresponding to the key in the cache or `None` if it is not + /// present in the cache. Unlike `get`, `peek` does not update the LRU list so key's + /// position will be unchanged. + /// + /// # Example + /// + /// ``` + /// use lru::LruCache; + /// let mut cache = LruCache::new(2); + /// + /// cache.put(1, "a"); + /// cache.put(2, "b"); + /// + /// assert_eq!(cache.peek(&1), Some(&"a")); + /// assert_eq!(cache.peek(&2), Some(&"b")); + /// ``` + pub fn peek<'a>(&'a self, k: &K) -> Option<&'a V> { + let key = KeyRef { k: k }; + match self.map.get(&key) { + None => None, + Some(node) => Some(&node.val), + } + } + + /// Return a bool indicating whether the given key is in the cache. Does not update the + /// LRU list. + /// + /// # Example + /// + /// ``` + /// use lru::LruCache; + /// let mut cache = LruCache::new(2); + /// + /// cache.put(1, "a"); + /// cache.put(2, "b"); + /// cache.put(3, "c"); + /// + /// assert!(!cache.contains(&1)); + /// assert!(cache.contains(&2)); + /// assert!(cache.contains(&3)); + /// ``` + pub fn contains(&self, k: &K) -> bool { + let key = KeyRef { k: k }; + self.map.contains_key(&key) + } + /// Remove and return the value corresponding to the key from the cache or /// `None` if it does not exist. /// @@ -348,8 +397,6 @@ mod tests { #[test] fn test_put_update() { - println!("testing put update"); - let mut cache = LruCache::new(1); cache.put("apple".to_string(), "red".to_string()); @@ -360,7 +407,7 @@ mod tests { } #[test] - fn test_remove_oldest() { + fn test_put_removes_oldest() { let mut cache = LruCache::new(2); cache.put("apple".to_string(), "red".to_string()); @@ -380,7 +427,37 @@ mod tests { } #[test] - fn test_remove() { + fn test_peek() { + let mut cache: LruCache = LruCache::new(2); + + cache.put("apple".to_string(), "red".to_string()); + cache.put("banana".to_string(), "yellow".to_string()); + + assert_opt_eq(cache.peek(&"banana".to_string()), "yellow".to_string()); + assert_opt_eq(cache.peek(&"apple".to_string()), "red".to_string()); + + cache.put("pear".to_string(), "green".to_string()); + + assert!(cache.peek(&"apple".to_string()).is_none()); + assert_opt_eq(cache.peek(&"banana".to_string()), "yellow".to_string()); + assert_opt_eq(cache.peek(&"pear".to_string()), "green".to_string()); + } + + #[test] + fn test_contains() { + let mut cache = LruCache::new(2); + + cache.put("apple".to_string(), "red".to_string()); + cache.put("banana".to_string(), "yellow".to_string()); + cache.put("pear".to_string(), "green".to_string()); + + assert!(!cache.contains(&"apple".to_string())); + assert!(cache.contains(&"banana".to_string())); + assert!(cache.contains(&"pear".to_string())); + } + + #[test] + fn test_pop() { let mut cache = LruCache::new(2); cache.put("apple".to_string(), "red".to_string());