@@ -425,9 +425,10 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
425
425
}
426
426
}
427
427
428
- /// Return the value corresponding to the key in the map, or insert
429
- /// and return the value if it doesn't exist.
430
- pub fn find_or_insert < ' a > ( & ' a mut self , k : K , v : V ) -> & ' a V {
428
+ /// Modify and return the value corresponding to the key in the map, or
429
+ /// insert and return a new value if it doesn't exist.
430
+ pub fn mangle < ' a , A > ( & ' a mut self , k : K , a : A , not_found : & fn ( & K , A ) -> V ,
431
+ found : & fn ( & K , & mut V , A ) ) -> & ' a mut V {
431
432
if self . size >= self . resize_at {
432
433
// n.b.: We could also do this after searching, so
433
434
// that we do not resize if this call to insert is
@@ -441,46 +442,37 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
441
442
let hash = k. hash_keyed ( self . k0 , self . k1 ) as uint ;
442
443
let idx = match self . bucket_for_key_with_hash ( hash, & k) {
443
444
TableFull => fail ! ( "Internal logic error" ) ,
444
- FoundEntry ( idx) => idx,
445
+ FoundEntry ( idx) => { found ( & k , self . mut_value_for_bucket ( idx) , a ) ; idx }
445
446
FoundHole ( idx) => {
446
- self . buckets [ idx ] = Some ( Bucket { hash : hash , key : k ,
447
- value : v} ) ;
447
+ let v = not_found ( & k , a ) ;
448
+ self . buckets [ idx ] = Some ( Bucket { hash : hash , key : k , value : v} ) ;
448
449
self . size += 1 ;
449
450
idx
450
- } ,
451
+ }
451
452
} ;
452
453
453
- self . value_for_bucket ( idx)
454
+ self . mut_value_for_bucket ( idx)
455
+ }
456
+
457
+ /// Return the value corresponding to the key in the map, or insert
458
+ /// and return the value if it doesn't exist.
459
+ pub fn find_or_insert < ' a > ( & ' a mut self , k : K , v : V ) -> & ' a mut V {
460
+ self . mangle ( k, v, |_k, a| a, |_k, _v, _a| ( ) )
454
461
}
455
462
456
463
/// Return the value corresponding to the key in the map, or create,
457
464
/// insert, and return a new value if it doesn't exist.
458
465
pub fn find_or_insert_with < ' a > ( & ' a mut self , k : K , f : & fn ( & K ) -> V )
459
- -> & ' a V {
460
- if self . size >= self . resize_at {
461
- // n.b.: We could also do this after searching, so
462
- // that we do not resize if this call to insert is
463
- // simply going to update a key in place. My sense
464
- // though is that it's worse to have to search through
465
- // buckets to find the right spot twice than to just
466
- // resize in this corner case.
467
- self . expand ( ) ;
468
- }
469
-
470
- let hash = k. hash_keyed ( self . k0 , self . k1 ) as uint ;
471
- let idx = match self . bucket_for_key_with_hash ( hash, & k) {
472
- TableFull => fail ! ( "Internal logic error" ) ,
473
- FoundEntry ( idx) => idx,
474
- FoundHole ( idx) => {
475
- let v = f ( & k) ;
476
- self . buckets [ idx] = Some ( Bucket { hash : hash, key : k,
477
- value : v} ) ;
478
- self . size += 1 ;
479
- idx
480
- } ,
481
- } ;
466
+ -> & ' a mut V {
467
+ self . mangle ( k, ( ) , |k, _a| f ( k) , |_k, _v, _a| ( ) )
468
+ }
482
469
483
- self . value_for_bucket ( idx)
470
+ /// Insert a key-value pair into the map if the key is not already present.
471
+ /// Otherwise, modify the existing value for the key.
472
+ /// Returns the new or modified value for the key.
473
+ pub fn insert_or_update_with < ' a > ( & ' a mut self , k : K , v : V ,
474
+ f : & fn ( & K , & mut V ) ) -> & ' a mut V {
475
+ self . mangle ( k, v, |_k, a| a, |k, v, _a| f ( k, v) )
484
476
}
485
477
486
478
/// Calls a function on each element of a hash map, destroying the hash
@@ -763,15 +755,22 @@ mod test_map {
763
755
#[ test]
764
756
fn test_find_or_insert ( ) {
765
757
let mut m = HashMap :: new :: < int , int > ( ) ;
766
- assert_eq ! ( m. find_or_insert( 1 , 2 ) , & 2 ) ;
767
- assert_eq ! ( m. find_or_insert( 1 , 3 ) , & 2 ) ;
758
+ assert_eq ! ( * m. find_or_insert( 1 , 2 ) , 2 ) ;
759
+ assert_eq ! ( * m. find_or_insert( 1 , 3 ) , 2 ) ;
768
760
}
769
761
770
762
#[ test]
771
763
fn test_find_or_insert_with ( ) {
772
764
let mut m = HashMap :: new :: < int , int > ( ) ;
773
- assert_eq ! ( m. find_or_insert_with( 1 , |_| 2 ) , & 2 ) ;
774
- assert_eq ! ( m. find_or_insert_with( 1 , |_| 3 ) , & 2 ) ;
765
+ assert_eq ! ( * m. find_or_insert_with( 1 , |_| 2 ) , 2 ) ;
766
+ assert_eq ! ( * m. find_or_insert_with( 1 , |_| 3 ) , 2 ) ;
767
+ }
768
+
769
+ #[ test]
770
+ fn test_insert_or_update_with ( ) {
771
+ let mut m = HashMap :: new :: < int , int > ( ) ;
772
+ assert_eq ! ( * m. insert_or_update_with( 1 , 2 , |_, x| * x+=1 ) , 2 ) ;
773
+ assert_eq ! ( * m. insert_or_update_with( 1 , 2 , |_, x| * x+=1 ) , 3 ) ;
775
774
}
776
775
777
776
#[ test]
0 commit comments