Skip to content

Commit 3778560

Browse files
committed
Refactor fn robin_hood
1 parent f8b8c3a commit 3778560

File tree

2 files changed

+53
-28
lines changed

2 files changed

+53
-28
lines changed

src/libstd/collections/hash/map.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -421,39 +421,41 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) {
421421
/// to recalculate it.
422422
///
423423
/// `hash`, `k`, and `v` are the elements to "robin hood" into the hashtable.
424-
fn robin_hood<'a, K: 'a, V: 'a>(mut bucket: FullBucketMut<'a, K, V>,
424+
fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
425425
mut ib: usize,
426426
mut hash: SafeHash,
427-
mut k: K,
428-
mut v: V)
427+
mut key: K,
428+
mut val: V)
429429
-> &'a mut V {
430430
let starting_index = bucket.index();
431431
let size = {
432432
let table = bucket.table(); // FIXME "lifetime too short".
433433
table.size()
434434
};
435+
// Save the *starting point*.
436+
let mut bucket = bucket.stash();
435437
// There can be at most `size - dib` buckets to displace, because
436438
// in the worst case, there are `size` elements and we already are
437-
// `distance` buckets away from the initial one.
439+
// `displacement` buckets away from the initial one.
438440
let idx_end = starting_index + size - bucket.displacement();
439441

440442
loop {
441-
let (old_hash, old_key, old_val) = bucket.replace(hash, k, v);
443+
let (old_hash, old_key, old_val) = bucket.replace(hash, key, val);
444+
hash = old_hash;
445+
key = old_key;
446+
val = old_val;
447+
442448
loop {
443449
let probe = bucket.next();
444450
assert!(probe.index() != idx_end);
445451

446452
let full_bucket = match probe.peek() {
447453
Empty(bucket) => {
448454
// Found a hole!
449-
let b = bucket.put(old_hash, old_key, old_val);
455+
let bucket = bucket.put(hash, key, val);
450456
// Now that it's stolen, just read the value's pointer
451-
// right out of the table!
452-
return Bucket::at_index(b.into_table(), starting_index)
453-
.peek()
454-
.expect_full()
455-
.into_mut_refs()
456-
.1;
457+
// right out of the table! Go back to the *starting point*.
458+
return bucket.into_table().into_mut_refs().1;
457459
},
458460
Full(bucket) => bucket
459461
};
@@ -465,9 +467,6 @@ fn robin_hood<'a, K: 'a, V: 'a>(mut bucket: FullBucketMut<'a, K, V>,
465467
// Robin hood! Steal the spot.
466468
if ib < probe_ib {
467469
ib = probe_ib;
468-
hash = old_hash;
469-
k = old_key;
470-
v = old_val;
471470
break;
472471
}
473472
}

src/libstd/collections/hash/table.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,28 @@ impl<K, V, M> Bucket<K, V, M> {
220220
}
221221
}
222222

223+
impl<K, V, M> Deref for FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> {
224+
type Target = RawTable<K, V>;
225+
fn deref(&self) -> &RawTable<K, V> {
226+
&self.table
227+
}
228+
}
229+
230+
impl<K, V, M> DerefMut for FullBucket<K, V, M> where M: DerefMut<Target=RawTable<K, V>> {
231+
fn deref_mut(&mut self) -> &mut RawTable<K, V> {
232+
&mut self.table
233+
}
234+
}
235+
236+
237+
/// `Put` is implemented for types which provide access to a table and cannot be invalidated
238+
/// by filling a bucket. A similar implementation for `Take` is possible.
239+
pub trait Put {}
240+
impl<K, V> Put for RawTable<K, V> {}
241+
impl<'t, K, V> Put for &'t mut RawTable<K, V> {}
242+
impl<K, V, M: Put> Put for Bucket<K, V, M> {}
243+
impl<K, V, M: Put> Put for FullBucket<K, V, M> {}
244+
223245
impl<K, V, M: Deref<Target=RawTable<K, V>>> Bucket<K, V, M> {
224246
pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> {
225247
Bucket::at_index(table, hash.inspect() as usize)
@@ -320,7 +342,7 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> EmptyBucket<K, V, M> {
320342
}
321343
}
322344

323-
impl<K, V, M: Deref<Target=RawTable<K, V>> + DerefMut> EmptyBucket<K, V, M> {
345+
impl<K, V, M> EmptyBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + DerefMut + Put {
324346
/// Puts given key and value pair, along with the key's hash,
325347
/// into this bucket in the hashtable. Note how `self` is 'moved' into
326348
/// this function, because this slot will no longer be empty when
@@ -359,6 +381,16 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> FullBucket<K, V, M> {
359381
}
360382
}
361383

384+
/// Duplicates the current position. This can be useful for operations
385+
/// on two or more buckets.
386+
pub fn stash(self) -> FullBucket<K, V, Self> {
387+
FullBucket {
388+
raw: self.raw,
389+
idx: self.idx,
390+
table: self,
391+
}
392+
}
393+
362394
/// Get the distance between this bucket and the 'ideal' location
363395
/// as determined by the key's hash stored in it.
364396
///
@@ -389,12 +421,14 @@ impl<K, V, M: Deref<Target=RawTable<K, V>>> FullBucket<K, V, M> {
389421
}
390422
}
391423

392-
impl<K, V, M: Deref<Target=RawTable<K, V>> + DerefMut> FullBucket<K, V, M> {
424+
// We don't need a `Take` trait currently. This is why a mutable reference
425+
// to the table is required.
426+
impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
393427
/// Removes this bucket's key and value from the hashtable.
394428
///
395429
/// This works similarly to `put`, building an `EmptyBucket` out of the
396430
/// taken bucket.
397-
pub fn take(mut self) -> (EmptyBucket<K, V, M>, K, V) {
431+
pub fn take(mut self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
398432
self.table.size -= 1;
399433

400434
unsafe {
@@ -410,7 +444,9 @@ impl<K, V, M: Deref<Target=RawTable<K, V>> + DerefMut> FullBucket<K, V, M> {
410444
)
411445
}
412446
}
447+
}
413448

449+
impl<K, V, M> FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + DerefMut {
414450
pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
415451
unsafe {
416452
let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
@@ -455,16 +491,6 @@ impl<'t, K, V, M: Deref<Target=RawTable<K, V>> + DerefMut + 't> FullBucket<K, V,
455491
}
456492
}
457493

458-
impl<K, V, M> BucketState<K, V, M> {
459-
// For convenience.
460-
pub fn expect_full(self) -> FullBucket<K, V, M> {
461-
match self {
462-
Full(full) => full,
463-
Empty(..) => panic!("Expected full bucket")
464-
}
465-
}
466-
}
467-
468494
impl<K, V, M: Deref<Target=RawTable<K, V>>> GapThenFull<K, V, M> {
469495
#[inline]
470496
pub fn full(&self) -> &FullBucket<K, V, M> {

0 commit comments

Comments
 (0)