@@ -155,6 +155,14 @@ pub mod linear {
155
155
}
156
156
}
157
157
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
+
158
166
/// Inserts the key value pair into the buckets.
159
167
/// Assumes that there will be a bucket.
160
168
/// True if there was no previous entry with that key
@@ -289,19 +297,8 @@ pub mod linear {
289
297
/// Return the value corresponding to the key in the map
290
298
pure fn find(&self, k: &K) -> Option<&self/V> {
291
299
match self.bucket_for_key(k) {
292
- FoundEntry(idx) => {
293
- match self.buckets[idx] {
294
- Some(ref bkt) => {
295
- Some(&bkt.value)
296
- }
297
- None => {
298
- die!(~" LinearMap :: find: internal logic error")
299
- }
300
- }
301
- }
302
- TableFull | FoundHole(_) => {
303
- None
304
- }
300
+ FoundEntry(idx) => Some(self.value_for_bucket(idx)),
301
+ TableFull | FoundHole(_) => None,
305
302
}
306
303
}
307
304
@@ -361,6 +358,63 @@ pub mod linear {
361
358
old_value
362
359
}
363
360
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
+
364
418
fn consume(&mut self, f: fn(K, V)) {
365
419
let mut buckets = ~[];
366
420
self.buckets <-> buckets;
@@ -582,6 +636,20 @@ mod test_map {
582
636
assert m. swap ( 1 , 4 ) == Some ( 3 ) ;
583
637
}
584
638
639
+ #[ test]
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
+
585
653
#[ test]
586
654
pub fn test_consume ( ) {
587
655
let mut m = LinearMap :: new ( ) ;
0 commit comments