@@ -41,25 +41,25 @@ use std::cast;
4141use std:: container:: Container ;
4242use std:: hash:: Hash ;
4343use std:: fmt;
44+ use std:: mem;
4445use std:: ptr;
4546
4647use HashMap ;
4748
4849struct KeyRef < K > { k : * K }
4950
5051struct 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.
5859pub struct LruCache < K , V > {
5960 map : HashMap < KeyRef < K > , ~LruEntry < K , V > > ,
6061 max_size : uint ,
6162 head : * mut LruEntry < K , V > ,
62- tail : * mut LruEntry < K , V > ,
6363}
6464
6565impl < S , K : Hash < S > > Hash < S > for KeyRef < K > {
@@ -77,19 +77,10 @@ impl<K: Eq> Eq for KeyRef<K> {
7777impl < K : TotalEq > TotalEq for KeyRef < K > { }
7878
7979impl < K , V > LruEntry < K , V > {
80- fn new ( ) -> LruEntry < K , V > {
80+ fn new ( k : K , v : V ) -> LruEntry < K , V > {
8181 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,
9384 next : ptr:: mut_null ( ) ,
9485 prev : ptr:: mut_null ( ) ,
9586 }
@@ -102,41 +93,42 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
10293 let cache = LruCache {
10394 map : HashMap :: new ( ) ,
10495 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 > > ( ) ) } ,
10797 } ;
10898 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 ;
111101 }
112102 return cache;
113103 }
114104
115105 /// Put a key-value pair into cache.
116106 pub fn put ( & mut self , k : K , v : V ) {
117- let mut key_existed = false ;
118107 let ( node_ptr, node_opt) = match self . map . find_mut ( & KeyRef { k : & k} ) {
119108 Some ( node) => {
120- key_existed = true ;
121- node. value = Some ( v) ;
109+ node. value = v;
122110 let node_ptr: * mut LruEntry < K , V > = & mut * * node;
123111 ( node_ptr, None )
124112 }
125113 None => {
126- let mut node = ~LruEntry :: with_key_value ( k, v) ;
114+ let mut node = ~LruEntry :: new ( k, v) ;
127115 let node_ptr: * mut LruEntry < K , V > = & mut * node;
128116 ( node_ptr, Some ( node) )
129117 }
130118 } ;
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+ }
140132 }
141133 }
142134 }
@@ -147,12 +139,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
147139 None => ( None , None ) ,
148140 Some ( node) => {
149141 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) )
156143 }
157144 } ;
158145 match node_ptr_opt {
@@ -169,7 +156,7 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
169156 pub fn pop ( & mut self , k : & K ) -> Option < V > {
170157 match self . map . pop ( & KeyRef { k : k} ) {
171158 None => None ,
172- Some ( lru_entry) => lru_entry. value
159+ Some ( lru_entry) => Some ( lru_entry. value )
173160 }
174161 }
175162
@@ -190,14 +177,9 @@ impl<K: Hash + TotalEq, V> LruCache<K, V> {
190177 #[ inline]
191178 fn remove_lru ( & mut self ) {
192179 if self . len ( ) > 0 {
193- let lru = unsafe { ( * self . tail ) . prev } ;
180+ let lru = unsafe { ( * self . head ) . prev } ;
194181 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 } } ) ;
201183 }
202184 }
203185
@@ -230,19 +212,11 @@ impl<A: fmt::Show + Hash + TotalEq, B: fmt::Show> fmt::Show for LruCache<A, B> {
230212 if i > 0 { try!( write ! ( f. buf, ", " ) ) }
231213 unsafe {
232214 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) ) ;
238216 }
239217 try!( write ! ( f. buf, ": " ) ) ;
240218 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) ) ;
246220 }
247221 }
248222 write ! ( f. buf, r"\}" )
@@ -267,8 +241,11 @@ impl<K: Hash + TotalEq, V> Mutable for LruCache<K, V> {
267241impl < K , V > Drop for LruCache < K , V > {
268242 fn drop ( & mut self ) {
269243 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) ;
272249 }
273250 }
274251}
0 commit comments