Skip to content

Commit 91c59f5

Browse files
committed
auto merge of #4880 : erickt/rust/hashmap-cleanup, r=catamorphism
2 parents bc2d147 + 4fb4a4b commit 91c59f5

File tree

1 file changed

+98
-33
lines changed

1 file changed

+98
-33
lines changed

src/libcore/hashmap.rs

+98-33
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)