diff --git a/src/libcollections/lru_cache.rs b/src/libcollections/lru_cache.rs index fc95ba6d95a6..097513c6c570 100644 --- a/src/libcollections/lru_cache.rs +++ b/src/libcollections/lru_cache.rs @@ -41,6 +41,7 @@ use std::cast; use std::container::Container; use std::hash::Hash; use std::fmt; +use std::mem; use std::ptr; use HashMap; @@ -48,10 +49,10 @@ use HashMap; struct KeyRef { k: *K } struct LruEntry { - key: Option, - value: Option, next: *mut LruEntry, prev: *mut LruEntry, + key: K, + value: V, } /// An LRU Cache. @@ -59,7 +60,6 @@ pub struct LruCache { map: HashMap, ~LruEntry>, max_size: uint, head: *mut LruEntry, - tail: *mut LruEntry, } impl> Hash for KeyRef { @@ -77,19 +77,10 @@ impl Eq for KeyRef { impl TotalEq for KeyRef {} impl LruEntry { - fn new() -> LruEntry { + fn new(k: K, v: V) -> LruEntry { LruEntry { - key: None, - value: None, - next: ptr::mut_null(), - prev: ptr::mut_null(), - } - } - - fn with_key_value(k: K, v: V) -> LruEntry { - LruEntry { - key: Some(k), - value: Some(v), + key: k, + value: v, next: ptr::mut_null(), prev: ptr::mut_null(), } @@ -102,41 +93,42 @@ impl LruCache { let cache = LruCache { map: HashMap::new(), max_size: capacity, - head: unsafe{ cast::transmute(~LruEntry::::new()) }, - tail: unsafe{ cast::transmute(~LruEntry::::new()) }, + head: unsafe{ cast::transmute(~mem::uninit::>()) }, }; unsafe { - (*cache.head).next = cache.tail; - (*cache.tail).prev = cache.head; + (*cache.head).next = cache.head; + (*cache.head).prev = cache.head; } return cache; } /// Put a key-value pair into cache. pub fn put(&mut self, k: K, v: V) { - let mut key_existed = false; let (node_ptr, node_opt) = match self.map.find_mut(&KeyRef{k: &k}) { Some(node) => { - key_existed = true; - node.value = Some(v); + node.value = v; let node_ptr: *mut LruEntry = &mut **node; (node_ptr, None) } None => { - let mut node = ~LruEntry::with_key_value(k, v); + let mut node = ~LruEntry::new(k, v); let node_ptr: *mut LruEntry = &mut *node; (node_ptr, Some(node)) } }; - if key_existed { - self.detach(node_ptr); - self.attach(node_ptr); - } else { - let keyref = unsafe { (*node_ptr).key.as_ref().unwrap() }; - self.map.swap(KeyRef{k: keyref}, node_opt.unwrap()); - self.attach(node_ptr); - if self.len() > self.capacity() { - self.remove_lru(); + match node_opt { + None => { + // Existing node, just update LRU position + self.detach(node_ptr); + self.attach(node_ptr); + } + Some(node) => { + let keyref = unsafe { &(*node_ptr).key }; + self.map.swap(KeyRef{k: keyref}, node); + self.attach(node_ptr); + if self.len() > self.capacity() { + self.remove_lru(); + } } } } @@ -147,12 +139,7 @@ impl LruCache { None => (None, None), Some(node) => { let node_ptr: *mut LruEntry = &mut **node; - unsafe { - match (*node_ptr).value { - None => (None, None), - Some(ref value) => (Some(value), Some(node_ptr)) - } - } + (Some(unsafe { &(*node_ptr).value }), Some(node_ptr)) } }; match node_ptr_opt { @@ -169,7 +156,7 @@ impl LruCache { pub fn pop(&mut self, k: &K) -> Option { match self.map.pop(&KeyRef{k: k}) { None => None, - Some(lru_entry) => lru_entry.value + Some(lru_entry) => Some(lru_entry.value) } } @@ -190,14 +177,9 @@ impl LruCache { #[inline] fn remove_lru(&mut self) { if self.len() > 0 { - let lru = unsafe { (*self.tail).prev }; + let lru = unsafe { (*self.head).prev }; self.detach(lru); - unsafe { - match (*lru).key { - None => (), - Some(ref k) => { self.map.pop(&KeyRef{k: k}); } - } - } + self.map.pop(&KeyRef{k: unsafe { &(*lru).key }}); } } @@ -230,19 +212,11 @@ impl fmt::Show for LruCache { if i > 0 { try!(write!(f.buf, ", ")) } unsafe { cur = (*cur).next; - match (*cur).key { - // should never print nil - None => try!(write!(f.buf, "nil")), - Some(ref k) => try!(write!(f.buf, "{}", *k)), - } + try!(write!(f.buf, "{}", (*cur).key)); } try!(write!(f.buf, ": ")); unsafe { - match (*cur).value { - // should never print nil - None => try!(write!(f.buf, "nil")), - Some(ref value) => try!(write!(f.buf, "{}", *value)), - } + try!(write!(f.buf, "{}", (*cur).value)); } } write!(f.buf, r"\}") @@ -267,8 +241,11 @@ impl Mutable for LruCache { impl Drop for LruCache { fn drop(&mut self) { unsafe { - let _: ~LruEntry = cast::transmute(self.head); - let _: ~LruEntry = cast::transmute(self.tail); + let node: ~LruEntry = cast::transmute(self.head); + // Prevent compiler from trying to drop the un-initialized field in the sigil node. + let ~LruEntry { key: k, value: v, .. } = node; + cast::forget(k); + cast::forget(v); } } }