@@ -108,19 +108,17 @@ pub mod linear {
108108 }
109109
110110 #[ inline( always) ]
111- pure fn bucket_for_key ( & self , buckets : & [ Option < Bucket < K , V > > ] ,
112- k : & K ) -> SearchResult {
111+ pure fn bucket_for_key ( & self , k : & K ) -> SearchResult {
113112 let hash = k. hash_keyed ( self . k0 , self . k1 ) as uint ;
114- self . bucket_for_key_with_hash ( buckets , hash, k)
113+ self . bucket_for_key_with_hash ( hash, k)
115114 }
116115
117116 #[ inline( always) ]
118117 pure fn bucket_for_key_with_hash ( & self ,
119- buckets : & [ Option < Bucket < K , V > > ] ,
120118 hash : uint ,
121119 k : & K ) -> SearchResult {
122120 let _ = for self . bucket_sequence( hash) |i| {
123- match buckets[ i] {
121+ match self . buckets [ i] {
124122 Some ( ref bkt) => if bkt. hash == hash && * k == bkt. key {
125123 return FoundEntry ( i) ;
126124 } ,
@@ -157,11 +155,19 @@ pub mod linear {
157155 }
158156 }
159157
158+ #[ inline( always) ]
159+ pure fn value_for_bucket ( & self , idx : uint ) -> & self /V {
160+ match self . buckets [ idx] {
161+ Some ( ref bkt) => & bkt. value ,
162+ None => die ! ( ~"LinearMap :: find: internal logic error"),
163+ }
164+ }
165+
160166 /// Inserts the key value pair into the buckets.
161167 /// Assumes that there will be a bucket.
162168 /// True if there was no previous entry with that key
163169 fn insert_internal(&mut self, hash: uint, k: K, v: V) -> bool {
164- match self . bucket_for_key_with_hash ( self . buckets , hash, & k) {
170+ match self.bucket_for_key_with_hash(hash, &k) {
165171 TableFull => { die!(~" Internal logic error"); }
166172 FoundHole(idx) => {
167173 debug!(" insert fresh ( %?->%?) at idx %?, hash %?",
@@ -196,8 +202,7 @@ pub mod linear {
196202 //
197203 // I found this explanation elucidating:
198204 // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf
199- let mut idx = match self.bucket_for_key_with_hash(self.buckets,
200- hash, k) {
205+ let mut idx = match self.bucket_for_key_with_hash(hash, k) {
201206 TableFull | FoundHole(_) => return None,
202207 FoundEntry(idx) => idx
203208 };
@@ -273,7 +278,7 @@ pub mod linear {
273278 impl <K: Hash IterBytes Eq, V> LinearMap<K, V>: Map<K, V> {
274279 /// Return true if the map contains a value for the specified key
275280 pure fn contains_key(&self, k: &K) -> bool {
276- match self.bucket_for_key(self.buckets, k) {
281+ match self.bucket_for_key(k) {
277282 FoundEntry(_) => {true}
278283 TableFull | FoundHole(_) => {false}
279284 }
@@ -291,20 +296,9 @@ pub mod linear {
291296
292297 /// Return the value corresponding to the key in the map
293298 pure fn find(&self, k: &K) -> Option<&self/V> {
294- match self.bucket_for_key(self.buckets, k) {
295- FoundEntry(idx) => {
296- match self.buckets[idx] {
297- Some(ref bkt) => {
298- Some(&bkt.value)
299- }
300- None => {
301- die!(~" LinearMap :: find: internal logic error")
302- }
303- }
304- }
305- TableFull | FoundHole(_) => {
306- None
307- }
299+ match self.bucket_for_key(k) {
300+ FoundEntry(idx) => Some(self.value_for_bucket(idx)),
301+ TableFull | FoundHole(_) => None,
308302 }
309303 }
310304
@@ -364,6 +358,63 @@ pub mod linear {
364358 old_value
365359 }
366360
361+ /// Return the value corresponding to the key in the map, or insert
362+ /// and return the value if it doesn't exist.
363+ fn find_or_insert(&mut self, k: K, v: V) -> &self/V {
364+ if self.size >= self.resize_at {
365+ // n.b.: We could also do this after searching, so
366+ // that we do not resize if this call to insert is
367+ // simply going to update a key in place. My sense
368+ // though is that it's worse to have to search through
369+ // buckets to find the right spot twice than to just
370+ // resize in this corner case.
371+ self.expand();
372+ }
373+
374+ let hash = k.hash_keyed(self.k0, self.k1) as uint;
375+ let idx = match self.bucket_for_key_with_hash(hash, &k) {
376+ TableFull => die!(~" Internal logic error"),
377+ FoundEntry(idx) => idx,
378+ FoundHole(idx) => {
379+ self.buckets[idx] = Some(Bucket{hash: hash, key: k,
380+ value: v});
381+ self.size += 1;
382+ idx
383+ },
384+ };
385+
386+ self.value_for_bucket(idx)
387+ }
388+
389+ /// Return the value corresponding to the key in the map, or create,
390+ /// insert, and return a new value if it doesn't exist.
391+ fn find_or_insert_with(&mut self, k: K, f: fn(&K) -> V) -> &self/V {
392+ if self.size >= self.resize_at {
393+ // n.b.: We could also do this after searching, so
394+ // that we do not resize if this call to insert is
395+ // simply going to update a key in place. My sense
396+ // though is that it's worse to have to search through
397+ // buckets to find the right spot twice than to just
398+ // resize in this corner case.
399+ self.expand();
400+ }
401+
402+ let hash = k.hash_keyed(self.k0, self.k1) as uint;
403+ let idx = match self.bucket_for_key_with_hash(hash, &k) {
404+ TableFull => die!(~" Internal logic error"),
405+ FoundEntry(idx) => idx,
406+ FoundHole(idx) => {
407+ let v = f(&k);
408+ self.buckets[idx] = Some(Bucket{hash: hash, key: k,
409+ value: v});
410+ self.size += 1;
411+ idx
412+ },
413+ };
414+
415+ self.value_for_bucket(idx)
416+ }
417+
367418 fn consume(&mut self, f: fn(K, V)) {
368419 let mut buckets = ~[];
369420 self.buckets <-> buckets;
@@ -521,7 +572,7 @@ mod test_map {
521572 use uint;
522573
523574 #[ test]
524- pub fn inserts ( ) {
575+ pub fn test_insert ( ) {
525576 let mut m = LinearMap :: new ( ) ;
526577 assert m. insert ( 1 , 2 ) ;
527578 assert m. insert ( 2 , 4 ) ;
@@ -530,7 +581,7 @@ mod test_map {
530581 }
531582
532583 #[ test]
533- pub fn overwrite ( ) {
584+ pub fn test_insert_overwrite ( ) {
534585 let mut m = LinearMap :: new ( ) ;
535586 assert m. insert ( 1 , 2 ) ;
536587 assert * m. get ( & 1 ) == 2 ;
@@ -539,7 +590,7 @@ mod test_map {
539590 }
540591
541592 #[ test]
542- pub fn conflicts ( ) {
593+ pub fn test_insert_conflicts ( ) {
543594 let mut m = linear:: linear_map_with_capacity ( 4 ) ;
544595 assert m. insert ( 1 , 2 ) ;
545596 assert m. insert ( 5 , 3 ) ;
@@ -550,7 +601,7 @@ mod test_map {
550601 }
551602
552603 #[ test]
553- pub fn conflict_remove ( ) {
604+ pub fn test_conflict_remove ( ) {
554605 let mut m = linear:: linear_map_with_capacity ( 4 ) ;
555606 assert m. insert ( 1 , 2 ) ;
556607 assert m. insert ( 5 , 3 ) ;
@@ -561,7 +612,7 @@ mod test_map {
561612 }
562613
563614 #[ test]
564- pub fn empty ( ) {
615+ pub fn test_is_empty ( ) {
565616 let mut m = linear:: linear_map_with_capacity ( 4 ) ;
566617 assert m. insert ( 1 , 2 ) ;
567618 assert !m. is_empty ( ) ;
@@ -570,23 +621,37 @@ mod test_map {
570621 }
571622
572623 #[ test]
573- pub fn pops ( ) {
624+ pub fn test_pop ( ) {
574625 let mut m = LinearMap :: new ( ) ;
575626 m. insert ( 1 , 2 ) ;
576627 assert m. pop ( & 1 ) == Some ( 2 ) ;
577628 assert m. pop ( & 1 ) == None ;
578629 }
579630
580631 #[ test]
581- pub fn swaps ( ) {
632+ pub fn test_swap ( ) {
582633 let mut m = LinearMap :: new ( ) ;
583634 assert m. swap ( 1 , 2 ) == None ;
584635 assert m. swap ( 1 , 3 ) == Some ( 2 ) ;
585636 assert m. swap ( 1 , 4 ) == Some ( 3 ) ;
586637 }
587638
588639 #[ test]
589- pub fn consumes ( ) {
640+ pub fn test_find_or_insert ( ) {
641+ let mut m = LinearMap :: new :: < int , int > ( ) ;
642+ assert m. find_or_insert ( 1 , 2 ) == & 2 ;
643+ assert m. find_or_insert ( 1 , 3 ) == & 2 ;
644+ }
645+
646+ #[ test]
647+ pub fn test_find_or_insert_with ( ) {
648+ let mut m = LinearMap :: new :: < int , int > ( ) ;
649+ assert m. find_or_insert_with ( 1 , |_| 2 ) == & 2 ;
650+ assert m. find_or_insert_with ( 1 , |_| 3 ) == & 2 ;
651+ }
652+
653+ #[ test]
654+ pub fn test_consume ( ) {
590655 let mut m = LinearMap :: new ( ) ;
591656 assert m. insert ( 1 , 2 ) ;
592657 assert m. insert ( 2 , 3 ) ;
@@ -601,7 +666,7 @@ mod test_map {
601666 }
602667
603668 #[ test]
604- pub fn iterate ( ) {
669+ pub fn test_iterate ( ) {
605670 let mut m = linear:: linear_map_with_capacity ( 4 ) ;
606671 for uint:: range( 0 , 32 ) |i| {
607672 assert m. insert( i, i* 2 ) ;
@@ -615,7 +680,7 @@ mod test_map {
615680 }
616681
617682 #[ test]
618- pub fn find ( ) {
683+ pub fn test_find ( ) {
619684 let mut m = LinearMap :: new ( ) ;
620685 assert m. find ( & 1 ) . is_none ( ) ;
621686 m. insert ( 1 , 2 ) ;
0 commit comments