Skip to content

Commit f07ebd6

Browse files
committed
Simplify HashMap Bucket interface
* Store capacity_mask instead of capacity * Move bucket index into RawBucket * Bucket index is now always within [0..table_capacity) * Clone RawTable using RawBucket * Simplify iterators by moving logic into RawBuckets * Make retain aware of the number of elements
1 parent 5309a3e commit f07ebd6

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)