@@ -17,6 +17,9 @@ pub trait SendMap<K:Eq Hash, V: Copy> {
17
17
18
18
fn insert ( & mut self , k : K , +v : V ) -> bool ;
19
19
fn remove ( & mut self , k : & K ) -> bool ;
20
+ fn pop ( & mut self , k : & K ) -> Option < V > ;
21
+ fn swap ( & mut self , k : K , +v : V ) -> Option < V > ;
22
+ fn consume ( & mut self , f : fn ( K , V ) ) ;
20
23
fn clear ( & mut self ) ;
21
24
pure fn len ( & const self ) -> uint ;
22
25
pure fn is_empty ( & const self ) -> bool ;
@@ -198,6 +201,52 @@ pub mod linear {
198
201
}
199
202
}
200
203
204
+ fn pop_internal ( & mut self , hash : uint , k : & K ) -> Option < V > {
205
+ // Removing from an open-addressed hashtable
206
+ // is, well, painful. The problem is that
207
+ // the entry may lie on the probe path for other
208
+ // entries, so removing it would make you think that
209
+ // those probe paths are empty.
210
+ //
211
+ // To address this we basically have to keep walking,
212
+ // re-inserting entries we find until we reach an empty
213
+ // bucket. We know we will eventually reach one because
214
+ // we insert one ourselves at the beginning (the removed
215
+ // entry).
216
+ //
217
+ // I found this explanation elucidating:
218
+ // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf
219
+ let mut idx = match self . bucket_for_key_with_hash ( self . buckets ,
220
+ hash, k) {
221
+ TableFull | FoundHole ( _) => return None ,
222
+ FoundEntry ( idx) => idx
223
+ } ;
224
+
225
+ let len_buckets = self . buckets . len ( ) ;
226
+ let mut bucket = None ;
227
+ self . buckets [ idx] <-> bucket;
228
+
229
+ let value = match move bucket {
230
+ None => None ,
231
+ Some ( move bucket) => {
232
+ let Bucket { value : move value, _ } = move bucket;
233
+ Some ( value)
234
+ } ,
235
+ } ;
236
+
237
+ idx = self . next_bucket ( idx, len_buckets) ;
238
+ while self . buckets [ idx] . is_some ( ) {
239
+ let mut bucket = None ;
240
+ bucket <-> self . buckets [ idx] ;
241
+ self . insert_opt_bucket ( move bucket) ;
242
+ idx = self . next_bucket ( idx, len_buckets) ;
243
+ }
244
+ self . size -= 1 ;
245
+
246
+ value
247
+
248
+ }
249
+
201
250
fn search ( & self ,
202
251
hash : uint ,
203
252
op : fn ( x : & Option < Bucket < K , V > > ) -> bool ) {
@@ -222,37 +271,55 @@ pub mod linear {
222
271
}
223
272
224
273
fn remove ( & mut self , k : & K ) -> bool {
225
- // Removing from an open-addressed hashtable
226
- // is, well, painful. The problem is that
227
- // the entry may lie on the probe path for other
228
- // entries, so removing it would make you think that
229
- // those probe paths are empty.
230
- //
231
- // To address this we basically have to keep walking,
232
- // re-inserting entries we find until we reach an empty
233
- // bucket. We know we will eventually reach one because
234
- // we insert one ourselves at the beginning (the removed
235
- // entry).
236
- //
237
- // I found this explanation elucidating:
238
- // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf
274
+ match self . pop ( k) {
275
+ Some ( _) => true ,
276
+ None => false ,
277
+ }
278
+ }
239
279
240
- let mut idx = match self . bucket_for_key ( self . buckets , k) {
241
- TableFull | FoundHole ( _ ) => return false ,
242
- FoundEntry ( idx ) => idx
243
- } ;
280
+ fn pop ( & mut self , k : & K ) -> Option < V > {
281
+ let hash = k . hash_keyed ( self . k0 , self . k1 ) as uint ;
282
+ self . pop_internal ( hash , k )
283
+ }
244
284
245
- let len_buckets = self . buckets . len ( ) ;
246
- self . buckets [ idx] = None ;
247
- idx = self . next_bucket ( idx, len_buckets) ;
248
- while self . buckets [ idx] . is_some ( ) {
249
- let mut bucket = None ;
250
- bucket <-> self . buckets [ idx] ;
251
- self . insert_opt_bucket ( move bucket) ;
252
- idx = self . next_bucket ( idx, len_buckets) ;
285
+ fn swap ( & mut self , k : K , v : V ) -> Option < V > {
286
+ // this could be faster.
287
+ let hash = k. hash_keyed ( self . k0 , self . k1 ) as uint ;
288
+ let old_value = self . pop_internal ( hash, & k) ;
289
+
290
+ if self . size >= self . resize_at {
291
+ // n.b.: We could also do this after searching, so
292
+ // that we do not resize if this call to insert is
293
+ // simply going to update a key in place. My sense
294
+ // though is that it's worse to have to search through
295
+ // buckets to find the right spot twice than to just
296
+ // resize in this corner case.
297
+ self . expand ( ) ;
298
+ }
299
+
300
+ self . insert_internal ( hash, k, v) ;
301
+
302
+ old_value
303
+ }
304
+
305
+ fn consume ( & mut self , f : fn ( K , V ) ) {
306
+ let mut buckets = ~[ ] ;
307
+ self . buckets <-> buckets;
308
+ self . size = 0 ;
309
+
310
+ do vec:: consume ( buckets) |_i, bucket| {
311
+ match move bucket {
312
+ None => { } ,
313
+ Some ( move bucket) => {
314
+ let Bucket {
315
+ key : move key,
316
+ value : move value,
317
+ _
318
+ } = move bucket;
319
+ f ( key, value)
320
+ }
321
+ }
253
322
}
254
- self . size -= 1 ;
255
- return true ;
256
323
}
257
324
258
325
fn clear ( & mut self ) {
@@ -350,7 +417,6 @@ pub mod linear {
350
417
}
351
418
option:: unwrap ( move value)
352
419
}
353
-
354
420
}
355
421
}
356
422
@@ -407,6 +473,37 @@ pub mod test {
407
473
assert m. is_empty ( ) ;
408
474
}
409
475
476
+ #[ test]
477
+ pub fn pops ( ) {
478
+ let mut m = ~LinearMap ( ) ;
479
+ m. insert ( 1 , 2 ) ;
480
+ assert m. pop ( & 1 ) == Some ( 2 ) ;
481
+ assert m. pop ( & 1 ) == None ;
482
+ }
483
+
484
+ #[ test]
485
+ pub fn swaps ( ) {
486
+ let mut m = ~LinearMap ( ) ;
487
+ assert m. swap ( 1 , 2 ) == None ;
488
+ assert m. swap ( 1 , 3 ) == Some ( 2 ) ;
489
+ assert m. swap ( 1 , 4 ) == Some ( 3 ) ;
490
+ }
491
+
492
+ #[ test]
493
+ pub fn consumes ( ) {
494
+ let mut m = ~LinearMap ( ) ;
495
+ assert m. insert ( 1 , 2 ) ;
496
+ assert m. insert ( 2 , 3 ) ;
497
+ let mut m2 = ~LinearMap ( ) ;
498
+ do m. consume |k, v| {
499
+ m2. insert ( k, v) ;
500
+ }
501
+ assert m. len ( ) == 0 ;
502
+ assert m2. len ( ) == 2 ;
503
+ assert m2. find ( & 1 ) == Some ( 2 ) ;
504
+ assert m2. find ( & 2 ) == Some ( 3 ) ;
505
+ }
506
+
410
507
#[ test]
411
508
pub fn iterate ( ) {
412
509
let mut m = linear:: linear_map_with_capacity ( 4 ) ;
0 commit comments