@@ -41,25 +41,25 @@ use std::cast;
41
41
use std:: container:: Container ;
42
42
use std:: hash:: Hash ;
43
43
use std:: fmt;
44
+ use std:: mem;
44
45
use std:: ptr;
45
46
46
47
use HashMap ;
47
48
48
49
struct KeyRef < K > { k : * K }
49
50
50
51
struct LruEntry < K , V > {
51
- key : Option < K > ,
52
- value : Option < V > ,
53
52
next : * mut LruEntry < K , V > ,
54
53
prev : * mut LruEntry < K , V > ,
54
+ key : K ,
55
+ value : V ,
55
56
}
56
57
57
58
/// An LRU Cache.
58
59
pub struct LruCache < K , V > {
59
60
map : HashMap < KeyRef < K > , ~LruEntry < K , V > > ,
60
61
max_size : uint ,
61
62
head : * mut LruEntry < K , V > ,
62
- tail : * mut LruEntry < K , V > ,
63
63
}
64
64
65
65
impl < S , K : Hash < S > > Hash < S > for KeyRef < K > {
@@ -77,19 +77,10 @@ impl<K: Eq> Eq for KeyRef<K> {
77
77
impl < K : TotalEq > TotalEq for KeyRef < K > { }
78
78
79
79
impl < K , V > LruEntry < K , V > {
80
- fn new ( ) -> LruEntry < K , V > {
80
+ fn new ( k : K , v : V ) -> LruEntry < K , V > {
81
81
LruEntry {
82
- key : None ,
83
- value : None ,
84
- next : ptr:: mut_null ( ) ,
85
- prev : ptr:: mut_null ( ) ,
86
- }
87
- }
88
-
89
- fn with_key_value ( k : K , v : V ) -> LruEntry < K , V > {
90
- LruEntry {
91
- key : Some ( k) ,
92
- value : Some ( v) ,
82
+ key : k,
83
+ value : v,
93
84
next : ptr:: mut_null ( ) ,
94
85
prev : ptr:: mut_null ( ) ,
95
86
}
@@ -102,41 +93,42 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
102
93
let cache = LruCache {
103
94
map : HashMap :: new ( ) ,
104
95
max_size : capacity,
105
- head : unsafe { cast:: transmute ( ~LruEntry :: < K , V > :: new ( ) ) } ,
106
- tail : unsafe { cast:: transmute ( ~LruEntry :: < K , V > :: new ( ) ) } ,
96
+ head : unsafe { cast:: transmute ( ~mem:: uninit :: < LruEntry < K , V > > ( ) ) } ,
107
97
} ;
108
98
unsafe {
109
- ( * cache. head ) . next = cache. tail ;
110
- ( * cache. tail ) . prev = cache. head ;
99
+ ( * cache. head ) . next = cache. head ;
100
+ ( * cache. head ) . prev = cache. head ;
111
101
}
112
102
return cache;
113
103
}
114
104
115
105
/// Put a key-value pair into cache.
116
106
pub fn put ( & mut self , k : K , v : V ) {
117
- let mut key_existed = false ;
118
107
let ( node_ptr, node_opt) = match self . map . find_mut ( & KeyRef { k : & k} ) {
119
108
Some ( node) => {
120
- key_existed = true ;
121
- node. value = Some ( v) ;
109
+ node. value = v;
122
110
let node_ptr: * mut LruEntry < K , V > = & mut * * node;
123
111
( node_ptr, None )
124
112
}
125
113
None => {
126
- let mut node = ~LruEntry :: with_key_value ( k, v) ;
114
+ let mut node = ~LruEntry :: new ( k, v) ;
127
115
let node_ptr: * mut LruEntry < K , V > = & mut * node;
128
116
( node_ptr, Some ( node) )
129
117
}
130
118
} ;
131
- if key_existed {
132
- self . detach ( node_ptr) ;
133
- self . attach ( node_ptr) ;
134
- } else {
135
- let keyref = unsafe { ( * node_ptr) . key . as_ref ( ) . unwrap ( ) } ;
136
- self . map . swap ( KeyRef { k : keyref} , node_opt. unwrap ( ) ) ;
137
- self . attach ( node_ptr) ;
138
- if self . len ( ) > self . capacity ( ) {
139
- self . remove_lru ( ) ;
119
+ match node_opt {
120
+ None => {
121
+ // Existing node, just update LRU position
122
+ self . detach ( node_ptr) ;
123
+ self . attach ( node_ptr) ;
124
+ }
125
+ Some ( node) => {
126
+ let keyref = unsafe { & ( * node_ptr) . key } ;
127
+ self . map . swap ( KeyRef { k : keyref} , node) ;
128
+ self . attach ( node_ptr) ;
129
+ if self . len ( ) > self . capacity ( ) {
130
+ self . remove_lru ( ) ;
131
+ }
140
132
}
141
133
}
142
134
}
@@ -147,12 +139,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
147
139
None => ( None , None ) ,
148
140
Some ( node) => {
149
141
let node_ptr: * mut LruEntry < K , V > = & mut * * node;
150
- unsafe {
151
- match ( * node_ptr) . value {
152
- None => ( None , None ) ,
153
- Some ( ref value) => ( Some ( value) , Some ( node_ptr) )
154
- }
155
- }
142
+ ( Some ( unsafe { & ( * node_ptr) . value } ) , Some ( node_ptr) )
156
143
}
157
144
} ;
158
145
match node_ptr_opt {
@@ -169,7 +156,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
169
156
pub fn pop ( & mut self , k : & K ) -> Option < V > {
170
157
match self . map . pop ( & KeyRef { k : k} ) {
171
158
None => None ,
172
- Some ( lru_entry) => lru_entry. value
159
+ Some ( lru_entry) => Some ( lru_entry. value )
173
160
}
174
161
}
175
162
@@ -190,14 +177,9 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
190
177
#[ inline]
191
178
fn remove_lru ( & mut self ) {
192
179
if self . len ( ) > 0 {
193
- let lru = unsafe { ( * self . tail ) . prev } ;
180
+ let lru = unsafe { ( * self . head ) . prev } ;
194
181
self . detach ( lru) ;
195
- unsafe {
196
- match ( * lru) . key {
197
- None => ( ) ,
198
- Some ( ref k) => { self . map . pop ( & KeyRef { k : k} ) ; }
199
- }
200
- }
182
+ self . map . pop ( & KeyRef { k : unsafe { & ( * lru) . key } } ) ;
201
183
}
202
184
}
203
185
@@ -230,19 +212,11 @@ impl<A: fmt::Show + Hash + TotalEq, B: fmt::Show> fmt::Show for LruCache<A, B> {
230
212
if i > 0 { try!( write ! ( f. buf, ", " ) ) }
231
213
unsafe {
232
214
cur = ( * cur) . next ;
233
- match ( * cur) . key {
234
- // should never print nil
235
- None => try!( write ! ( f. buf, "nil" ) ) ,
236
- Some ( ref k) => try!( write ! ( f. buf, "{}" , * k) ) ,
237
- }
215
+ try!( write ! ( f. buf, "{}" , ( * cur) . key) ) ;
238
216
}
239
217
try!( write ! ( f. buf, ": " ) ) ;
240
218
unsafe {
241
- match ( * cur) . value {
242
- // should never print nil
243
- None => try!( write ! ( f. buf, "nil" ) ) ,
244
- Some ( ref value) => try!( write ! ( f. buf, "{}" , * value) ) ,
245
- }
219
+ try!( write ! ( f. buf, "{}" , ( * cur) . value) ) ;
246
220
}
247
221
}
248
222
write ! ( f. buf, r"\}" )
@@ -267,8 +241,11 @@ impl<K: Hash + TotalEq, V> Mutable for LruCache<K, V> {
267
241
impl < K , V > Drop for LruCache < K , V > {
268
242
fn drop ( & mut self ) {
269
243
unsafe {
270
- let _: ~LruEntry < K , V > = cast:: transmute ( self . head ) ;
271
- let _: ~LruEntry < K , V > = cast:: transmute ( self . tail ) ;
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) ;
272
249
}
273
250
}
274
251
}
0 commit comments