31
31
#![ feature( hashmap_hasher) ]
32
32
#![ feature( box_raw) ]
33
33
#![ feature( iter_order) ]
34
+ #![ cfg_attr( test, feature( test) ) ]
34
35
35
36
use std:: borrow:: Borrow ;
36
37
use std:: cmp:: Ordering ;
@@ -57,6 +58,7 @@ struct LinkedHashMapEntry<K, V> {
57
58
pub struct LinkedHashMap < K , V , S = hash_map:: RandomState > {
58
59
map : HashMap < KeyRef < K > , Box < LinkedHashMapEntry < K , V > > , S > ,
59
60
head : * mut LinkedHashMapEntry < K , V > ,
61
+ free : * mut LinkedHashMapEntry < K , V > ,
60
62
}
61
63
62
64
impl < K : Hash > Hash for KeyRef < K > {
@@ -117,11 +119,26 @@ impl<K: Hash + Eq, V> LinkedHashMap<K, V> {
117
119
}
118
120
}
119
121
122
+ impl < K , V , S > LinkedHashMap < K , V , S > {
123
+ fn clear_free_list ( & mut self ) {
124
+ unsafe {
125
+ let mut free = self . free ;
126
+ while ! free. is_null ( ) {
127
+ let next_free = ( * free) . next ;
128
+ drop_empty_entry_box ( free) ;
129
+ free = next_free;
130
+ }
131
+ self . free = ptr:: null_mut ( ) ;
132
+ }
133
+ }
134
+ }
135
+
120
136
impl < K : Hash + Eq , V , S : HashState > LinkedHashMap < K , V , S > {
121
137
fn with_map ( map : HashMap < KeyRef < K > , Box < LinkedHashMapEntry < K , V > > , S > ) -> LinkedHashMap < K , V , S > {
122
138
LinkedHashMap {
123
139
map : map,
124
140
head : ptr:: null_mut ( ) ,
141
+ free : ptr:: null_mut ( ) ,
125
142
}
126
143
}
127
144
@@ -146,7 +163,10 @@ impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
146
163
/// Shrinks the capacity of the map as much as possible. It will drop down as much as possible
147
164
/// while maintaining the internal rules and possibly leaving some space in accordance with the
148
165
/// resize policy.
149
- pub fn shrink_to_fit ( & mut self ) { self . map . shrink_to_fit ( ) ; }
166
+ pub fn shrink_to_fit ( & mut self ) {
167
+ self . map . shrink_to_fit ( ) ;
168
+ self . clear_free_list ( ) ;
169
+ }
150
170
151
171
/// Inserts a key-value pair into the map. If the key already existed, the old value is
152
172
/// returned.
@@ -178,7 +198,17 @@ impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
178
198
( node_ptr, None , Some ( old_val) )
179
199
}
180
200
None => {
181
- let mut node = Box :: new ( LinkedHashMapEntry :: new ( k, v) ) ;
201
+ let mut node = if self . free . is_null ( ) {
202
+ Box :: new ( LinkedHashMapEntry :: new ( k, v) )
203
+ } else {
204
+ // use a recycled box
205
+ unsafe {
206
+ let free = self . free ;
207
+ self . free = ( * free) . next ;
208
+ ptr:: write ( free, LinkedHashMapEntry :: new ( k, v) ) ;
209
+ Box :: from_raw ( free)
210
+ }
211
+ } ;
182
212
let node_ptr: * mut LinkedHashMapEntry < K , V > = & mut * node;
183
213
( node_ptr, Some ( node) , None )
184
214
}
@@ -295,7 +325,15 @@ impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
295
325
removed. map ( |mut node| {
296
326
let node_ptr: * mut LinkedHashMapEntry < K , V > = & mut * node;
297
327
self . detach ( node_ptr) ;
298
- node. value
328
+ unsafe {
329
+ // add to free list
330
+ ( * node_ptr) . next = self . free ;
331
+ self . free = node_ptr;
332
+ // forget the box but drop the key and return the value
333
+ mem:: forget ( node) ;
334
+ drop ( ptr:: read ( & ( * node_ptr) . key ) ) ;
335
+ ptr:: read ( & ( * node_ptr) . value )
336
+ }
299
337
} )
300
338
}
301
339
@@ -675,6 +713,7 @@ impl<K, V, S> Drop for LinkedHashMap<K, V, S> {
675
713
if ! self . head . is_null ( ) {
676
714
drop_empty_entry_box ( self . head ) ;
677
715
}
716
+ self . clear_free_list ( ) ;
678
717
}
679
718
}
680
719
}
@@ -1059,4 +1098,40 @@ mod tests {
1059
1098
assert_eq ! ( map. remove( & Foo ( Bar ( 1 ) ) ) , None ) ;
1060
1099
assert_eq ! ( map. remove( & Foo ( Bar ( 2 ) ) ) , None ) ;
1061
1100
}
1101
+
1102
+ extern crate test;
1103
+
1104
+ #[ bench]
1105
+ fn not_recycled_cycling ( b : & mut test:: Bencher ) {
1106
+ let mut hash_map = LinkedHashMap :: with_capacity ( 1000 ) ;
1107
+ for i in ( 0usize ..1000 ) {
1108
+ hash_map. insert ( i, i) ;
1109
+ }
1110
+ b. iter ( || {
1111
+ for i in ( 0usize ..1000 ) {
1112
+ hash_map. remove ( & i) ;
1113
+ }
1114
+ hash_map. clear_free_list ( ) ;
1115
+ for i in ( 0usize ..1000 ) {
1116
+ hash_map. insert ( i, i) ;
1117
+ }
1118
+ } )
1119
+ }
1120
+
1121
+ #[ bench]
1122
+ fn recycled_cycling ( b : & mut test:: Bencher ) {
1123
+ let mut hash_map = LinkedHashMap :: with_capacity ( 1000 ) ;
1124
+ for i in ( 0usize ..1000 ) {
1125
+ hash_map. insert ( i, i) ;
1126
+ }
1127
+ b. iter ( || {
1128
+ for i in ( 0usize ..1000 ) {
1129
+ hash_map. remove ( & i) ;
1130
+ }
1131
+ for i in ( 0usize ..1000 ) {
1132
+ hash_map. insert ( i, i) ;
1133
+ }
1134
+ } )
1135
+ }
1136
+
1062
1137
}
0 commit comments