Skip to content

Commit 327b9be

Browse files
author
Ariel Ben-Yehuda
authored
Rollup merge of rust-lang#40561 - arthurprs:hm-adapt2, r=pczarn
Simplify HashMap Bucket interface > Simplify HashMap Bucket interface > > * Store capacity_mask instead of capacity > * Move bucket index into RawBucket > * Valid bucket index is now always within [0..table_capacity) > * Simplify iterators by moving logic into RawBuckets > * Clone RawTable using RawBucket > * Make retain aware of the number of elements The idea was to put idx in RawBucket instead of the other Bucket types and simplify next() and prev() as much as possible. The rest was a side-effect of that change, except maybe the last 2. This change makes iteration and other next/prev() heavy operations noticeably faster. Clone is way faster. ``` ➜ hashmap2 git:(adapt) ✗ cargo benchcmp pre:: adp:: bench.txt name pre:: ns/iter adp:: ns/iter diff ns/iter diff % clone_10_000 74,364 39,736 -34,628 -46.57% grow_100_000 8,343,553 8,233,785 -109,768 -1.32% grow_10_000 817,825 723,958 -93,867 -11.48% grow_big_value_100_000 18,418,979 17,906,186 -512,793 -2.78% grow_big_value_10_000 1,219,242 1,103,334 -115,908 -9.51% insert_1000 74,546 58,343 -16,203 -21.74% insert_100_000 6,743,770 6,238,017 -505,753 -7.50% insert_10_000 798,079 719,123 -78,956 -9.89% insert_1_000_000 275,215,605 266,975,875 -8,239,730 -2.99% insert_int_bigvalue_10_000 1,517,387 1,419,838 -97,549 -6.43% insert_str_10_000 316,179 278,896 -37,283 -11.79% insert_string_10_000 770,927 747,449 -23,478 -3.05% iter_keys_100_000 386,099 333,104 -52,995 -13.73% iterate_100_000 387,320 355,707 -31,613 -8.16% lookup_100_000 206,757 193,063 -13,694 -6.62% lookup_100_000_unif 219,366 193,180 -26,186 -11.94% lookup_1_000_000 206,456 205,716 -740 -0.36% lookup_1_000_000_unif 659,934 629,659 -30,275 -4.59% lru_sim 20,194,334 18,442,149 -1,752,185 -8.68% merge_shuffle 1,168,044 1,063,055 -104,989 -8.99% ``` Note 2: I may have messed up porting the diff, let's see what CI says.
2 parents 540fc2c + f07ebd6 commit 327b9be

File tree

2 files changed

+165
-191
lines changed

2 files changed

+165
-191
lines changed

src/libstd/collections/hash/map.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>)
472472
}
473473

474474
// Now we've done all our shifting. Return the value we grabbed earlier.
475-
(retkey, retval, gap.into_bucket().into_table())
475+
(retkey, retval, gap.into_table())
476476
}
477477

478478
/// Perform robin hood bucket stealing at the given `bucket`. You must
@@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
485485
mut key: K,
486486
mut val: V)
487487
-> FullBucketMut<'a, K, V> {
488-
let start_index = bucket.index();
489488
let size = bucket.table().size();
490-
// Save the *starting point*.
491-
let mut bucket = bucket.stash();
489+
let raw_capacity = bucket.table().capacity();
492490
// There can be at most `size - dib` buckets to displace, because
493491
// in the worst case, there are `size` elements and we already are
494492
// `displacement` buckets away from the initial one.
495-
let idx_end = start_index + size - bucket.displacement();
493+
let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity;
494+
// Save the *starting point*.
495+
let mut bucket = bucket.stash();
496496

497497
loop {
498498
let (old_hash, old_key, old_val) = bucket.replace(hash, key, val);
@@ -568,11 +568,8 @@ impl<K, V, S> HashMap<K, V, S>
568568
// The caller should ensure that invariants by Robin Hood Hashing hold
569569
// and that there's space in the underlying table.
570570
fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) {
571-
let raw_cap = self.raw_capacity();
572571
let mut buckets = Bucket::new(&mut self.table, hash);
573-
// note that buckets.index() keeps increasing
574-
// even if the pointer wraps back to the first bucket.
575-
let limit_bucket = buckets.index() + raw_cap;
572+
let start_index = buckets.index();
576573

577574
loop {
578575
// We don't need to compare hashes for value swap.
@@ -585,7 +582,7 @@ impl<K, V, S> HashMap<K, V, S>
585582
Full(b) => b.into_bucket(),
586583
};
587584
buckets.next();
588-
debug_assert!(buckets.index() < limit_bucket);
585+
debug_assert!(buckets.index() != start_index);
589586
}
590587
}
591588
}
@@ -1244,24 +1241,25 @@ impl<K, V, S> HashMap<K, V, S>
12441241
pub fn retain<F>(&mut self, mut f: F)
12451242
where F: FnMut(&K, &mut V) -> bool
12461243
{
1247-
if self.table.capacity() == 0 || self.table.size() == 0 {
1244+
if self.table.size() == 0 {
12481245
return;
12491246
}
1247+
let mut elems_left = self.table.size();
12501248
let mut bucket = Bucket::head_bucket(&mut self.table);
12511249
bucket.prev();
1252-
let tail = bucket.index();
1253-
loop {
1250+
let start_index = bucket.index();
1251+
while elems_left != 0 {
12541252
bucket = match bucket.peek() {
12551253
Full(mut full) => {
1254+
elems_left -= 1;
12561255
let should_remove = {
12571256
let (k, v) = full.read_mut();
12581257
!f(k, v)
12591258
};
12601259
if should_remove {
1261-
let prev_idx = full.index();
12621260
let prev_raw = full.raw();
12631261
let (_, _, t) = pop_internal(full);
1264-
Bucket::new_from(prev_raw, prev_idx, t)
1262+
Bucket::new_from(prev_raw, t)
12651263
} else {
12661264
full.into_bucket()
12671265
}
@@ -1271,9 +1269,7 @@ impl<K, V, S> HashMap<K, V, S>
12711269
}
12721270
};
12731271
bucket.prev(); // reverse iteration
1274-
if bucket.index() == tail {
1275-
break;
1276-
}
1272+
debug_assert!(elems_left == 0 || bucket.index() != start_index);
12771273
}
12781274
}
12791275
}

0 commit comments

Comments
 (0)