Skip to content

Commit 9faef77

Browse files
committed
Eliminate the need for Options in LruEntry.
LruEntry nodes previously used Option to encapsulate the key and value fields. This was used merely as a way avoid having values for the sigil node. Apart from wasting a few bytes for the discriminant, this cluttered the rest of the code, since these fields always contained Some on regular nodes as a class invariant. The Option wrapping was removed, and the values in the sigil field are initialized using mem::init, so that they don't contain any real data.
1 parent ad4062e commit 9faef77

File tree

1 file changed

+21
-42
lines changed

1 file changed

+21
-42
lines changed

src/libcollections/lru_cache.rs

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,18 @@ use std::cast;
4141
use std::container::Container;
4242
use std::hash::Hash;
4343
use std::fmt;
44+
use std::mem;
4445
use std::ptr;
4546

4647
use HashMap;
4748

4849
struct KeyRef<K> { k: *K }
4950

5051
struct LruEntry<K, V> {
51-
key: Option<K>,
52-
value: Option<V>,
5352
next: *mut LruEntry<K, V>,
5453
prev: *mut LruEntry<K, V>,
54+
key: K,
55+
value: V,
5556
}
5657

5758
/// An LRU Cache.
@@ -76,19 +77,10 @@ impl<K: Eq> Eq for KeyRef<K> {
7677
impl<K: TotalEq> TotalEq for KeyRef<K> {}
7778

7879
impl<K, V> LruEntry<K, V> {
79-
fn new() -> LruEntry<K, V> {
80+
fn new(k: K, v: V) -> LruEntry<K, V> {
8081
LruEntry {
81-
key: None,
82-
value: None,
83-
next: ptr::mut_null(),
84-
prev: ptr::mut_null(),
85-
}
86-
}
87-
88-
fn with_key_value(k: K, v: V) -> LruEntry<K, V> {
89-
LruEntry {
90-
key: Some(k),
91-
value: Some(v),
82+
key: k,
83+
value: v,
9284
next: ptr::mut_null(),
9385
prev: ptr::mut_null(),
9486
}
@@ -101,7 +93,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
10193
let cache = LruCache {
10294
map: HashMap::new(),
10395
max_size: capacity,
104-
head: unsafe{ cast::transmute(~LruEntry::<K, V>::new()) },
96+
head: unsafe{ cast::transmute(~mem::uninit::<LruEntry<K, V>>()) },
10597
};
10698
unsafe {
10799
(*cache.head).next = cache.head;
@@ -114,23 +106,24 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
114106
pub fn put(&mut self, k: K, v: V) {
115107
let (node_ptr, node_opt) = match self.map.find_mut(&KeyRef{k: &k}) {
116108
Some(node) => {
117-
node.value = Some(v);
109+
node.value = v;
118110
let node_ptr: *mut LruEntry<K, V> = &mut **node;
119111
(node_ptr, None)
120112
}
121113
None => {
122-
let mut node = ~LruEntry::with_key_value(k, v);
114+
let mut node = ~LruEntry::new(k, v);
123115
let node_ptr: *mut LruEntry<K, V> = &mut *node;
124116
(node_ptr, Some(node))
125117
}
126118
};
127119
match node_opt {
128120
None => {
121+
// Existing node, just update LRU position
129122
self.detach(node_ptr);
130123
self.attach(node_ptr);
131124
}
132125
Some(node) => {
133-
let keyref = unsafe { (*node_ptr).key.as_ref().unwrap() };
126+
let keyref = unsafe { &(*node_ptr).key };
134127
self.map.swap(KeyRef{k: keyref}, node);
135128
self.attach(node_ptr);
136129
if self.len() > self.capacity() {
@@ -146,12 +139,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
146139
None => (None, None),
147140
Some(node) => {
148141
let node_ptr: *mut LruEntry<K, V> = &mut **node;
149-
unsafe {
150-
match (*node_ptr).value {
151-
None => (None, None),
152-
Some(ref value) => (Some(value), Some(node_ptr))
153-
}
154-
}
142+
(Some(unsafe { &(*node_ptr).value }), Some(node_ptr))
155143
}
156144
};
157145
match node_ptr_opt {
@@ -168,7 +156,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
168156
pub fn pop(&mut self, k: &K) -> Option<V> {
169157
match self.map.pop(&KeyRef{k: k}) {
170158
None => None,
171-
Some(lru_entry) => lru_entry.value
159+
Some(lru_entry) => Some(lru_entry.value)
172160
}
173161
}
174162

@@ -191,12 +179,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
191179
if self.len() > 0 {
192180
let lru = unsafe { (*self.head).prev };
193181
self.detach(lru);
194-
unsafe {
195-
match (*lru).key {
196-
None => (),
197-
Some(ref k) => { self.map.pop(&KeyRef{k: k}); }
198-
}
199-
}
182+
self.map.pop(&KeyRef{k: unsafe { &(*lru).key }});
200183
}
201184
}
202185

@@ -229,19 +212,11 @@ impl<A: fmt::Show + Hash + TotalEq, B: fmt::Show> fmt::Show for LruCache<A, B> {
229212
if i > 0 { try!(write!(f.buf, ", ")) }
230213
unsafe {
231214
cur = (*cur).next;
232-
match (*cur).key {
233-
// should never print nil
234-
None => try!(write!(f.buf, "nil")),
235-
Some(ref k) => try!(write!(f.buf, "{}", *k)),
236-
}
215+
try!(write!(f.buf, "{}", (*cur).key));
237216
}
238217
try!(write!(f.buf, ": "));
239218
unsafe {
240-
match (*cur).value {
241-
// should never print nil
242-
None => try!(write!(f.buf, "nil")),
243-
Some(ref value) => try!(write!(f.buf, "{}", *value)),
244-
}
219+
try!(write!(f.buf, "{}", (*cur).value));
245220
}
246221
}
247222
write!(f.buf, r"\}")
@@ -266,7 +241,11 @@ impl<K: Hash + TotalEq, V> Mutable for LruCache<K, V> {
266241
impl<K, V> Drop for LruCache<K, V> {
267242
fn drop(&mut self) {
268243
unsafe {
269-
let _: ~LruEntry<K, V> = cast::transmute(self.head);
244+
let node: ~LruEntry<K, V> = cast::transmute(self.head);
245+
// Prevent compiler from trying to drop the un-initialized field in the sigil node.
246+
let ~LruEntry { key: k, value: v, .. } = node;
247+
cast::forget(k);
248+
cast::forget(v);
270249
}
271250
}
272251
}

0 commit comments

Comments
 (0)