Skip to content

Commit 745229b

Browse files
committed
docs, refactored
1 parent 316b300 commit 745229b

File tree

2 files changed

+56
-29
lines changed

2 files changed

+56
-29
lines changed

src/libstd/collections/hash/map.rs

+49-29
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use fmt::{self, Debug};
2121
use hash::{Hash, SipHasher};
2222
use iter::{Iterator, ExactSizeIterator, IntoIterator, IteratorExt, FromIterator, Extend, Map};
2323
use marker::Sized;
24-
use mem::{self, replace};
24+
use mem::{self, swap, replace};
2525
use num::{Int, UnsignedInt};
2626
use ops::{Deref, DerefMut, Drop, FnMut, Index, IndexMut};
2727
use option::Option::{self, Some, None};
@@ -393,8 +393,8 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) {
393393
fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
394394
mut ib: usize,
395395
mut hash: SafeHash,
396-
mut k: K,
397-
mut v: V)
396+
mut key: K,
397+
mut val: V)
398398
-> &'a mut V {
399399
let starting_index = bucket.index();
400400
let size = {
@@ -408,9 +408,11 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
408408
let idx_end = starting_index + size - bucket.displacement();
409409

410410
loop {
411-
let (old_hash, old_key, old_val) = {
411+
{
412412
let (h_ref, k_ref, v_ref) = bucket.read_mut();
413-
(replace(h_ref, hash), replace(k_ref, k), replace(v_ref, v))
413+
swap(h_ref, &mut hash);
414+
swap(k_ref, &mut key);
415+
swap(v_ref, &mut val));
414416
};
415417
loop {
416418
let probe = bucket.into_next();
@@ -419,7 +421,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
419421
let full_bucket = match probe.peek() {
420422
Empty(bucket) => {
421423
// Found a hole!
422-
let b = bucket.put(old_hash, old_key, old_val);
424+
let b = bucket.put(hash, key, val);
423425
// Now that it's stolen, just read the value's pointer
424426
// right out of the table!
425427
return b.into_table().into_mut_refs().1;
@@ -434,9 +436,6 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
434436
// Robin hood! Steal the spot.
435437
if ib < probe_ib {
436438
ib = probe_ib;
437-
hash = old_hash;
438-
k = old_key;
439-
v = old_val;
440439
break;
441440
}
442441
}
@@ -478,24 +477,20 @@ impl<K, V, S> HashMap<K, V, S>
478477
/// Search for a key, yielding the index if it's found in the hashtable.
479478
/// If you already have the hash for the key lying around, use
480479
/// search_hashed.
481-
fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>>
480+
fn search<'a, Q: ?Sized>(&'a self, q: &Q)
481+
-> Option<InternalEntry<K, V, &'a RawTable<K, V>>>
482482
where K: Borrow<Q>, Q: Eq + Hash
483483
{
484484
let hash = self.make_hash(q);
485-
match search_hashed(&self.table, hash, |k| q.eq(k.borrow())) {
486-
InternalEntry::Occupied(bucket) => Some(bucket.elem),
487-
_ => None,
488-
}
485+
search_hashed(&self.table, hash, |k| q.eq(k.borrow()))
489486
}
490487

491-
fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>>
488+
fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q)
489+
-> Option<InternalEntry<K, V, &'a mut RawTable<K, V>>>
492490
where K: Borrow<Q>, Q: Eq + Hash
493491
{
494492
let hash = self.make_hash(q);
495-
match search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) {
496-
InternalEntry::Occupied(bucket) => Some(bucket.elem),
497-
_ => None,
498-
}
493+
search_hashed(&mut self.table, hash, |k| q.eq(k.borrow()))
499494
}
500495
}
501496

@@ -773,7 +768,15 @@ impl<K, V, S> HashMap<K, V, S>
773768

774769
// Shrink the table. Naive algorithm for resizing:
775770
while let Some((h, k, v)) = old_table.take_front() {
776-
self.insert_hashed_nocheck(h, k, v);
771+
match search_hashed(&mut self.table, hash, |key| *key == k) {
772+
InternalEntry::Vacant(entry) => {
773+
entry.insert(hash, k, v);
774+
}
775+
InternalEntry::Occupied(mut entry) => {
776+
entry.insert(v);
777+
}
778+
InternalEntry::TableIsEmpty => unreachable!()
779+
}
777780
}
778781

779782
debug_assert_eq!(self.table.size(), old_size);
@@ -935,8 +938,7 @@ impl<K, V, S> HashMap<K, V, S>
935938
// Gotta resize now.
936939
self.reserve(1);
937940

938-
let hash = self.make_hash(&key);
939-
match search_hashed(&mut self.table, hash, |k| *k == key) {
941+
match self.search_mut(&key) {
940942
InternalEntry::Occupied(state) => Occupied(state),
941943
InternalEntry::Vacant(bucket) => Vacant(VacantEntry {
942944
elem: bucket,
@@ -1045,7 +1047,7 @@ impl<K, V, S> HashMap<K, V, S>
10451047
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
10461048
where K: Borrow<Q>, Q: Hash + Eq
10471049
{
1048-
self.search(k).map(|bucket| bucket.into_refs().1)
1050+
self.search(k).into_option().map(|bucket| bucket.into_refs().1)
10491051
}
10501052

10511053
/// Returns true if the map contains a value for the specified key.
@@ -1068,7 +1070,7 @@ impl<K, V, S> HashMap<K, V, S>
10681070
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
10691071
where K: Borrow<Q>, Q: Hash + Eq
10701072
{
1071-
self.search(k).is_some()
1073+
self.search(k).into_option().is_some()
10721074
}
10731075

10741076
/// Returns a mutable reference to the value corresponding to the key.
@@ -1094,7 +1096,7 @@ impl<K, V, S> HashMap<K, V, S>
10941096
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
10951097
where K: Borrow<Q>, Q: Hash + Eq
10961098
{
1097-
self.search_mut(k).map(|bucket| bucket.into_mut_refs().1)
1099+
self.search_mut(k).into_option().map(|bucket| bucket.into_mut_refs().1)
10981100
}
10991101

11001102
/// Inserts a key-value pair from the map. If the key already had a value
@@ -1114,10 +1116,19 @@ impl<K, V, S> HashMap<K, V, S>
11141116
/// assert_eq!(map[37], "c");
11151117
/// ```
11161118
#[stable(feature = "rust1", since = "1.0.0")]
1117-
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
1118-
let hash = self.make_hash(&k);
1119+
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
11191120
self.reserve(1);
1120-
self.insert_hashed_nocheck(hash, k, v)
1121+
1122+
match self.search_mut(&key) {
1123+
InternalEntry::Vacant(entry) => {
1124+
entry.insert(hash, key, value);
1125+
return None;
1126+
}
1127+
InternalEntry::Occupied(mut entry) => {
1128+
return Some(entry.insert(value));
1129+
}
1130+
InternalEntry::TableIsEmpty => unreachable!()
1131+
}
11211132
}
11221133

11231134
/// Removes a key from the map, returning the value at the key if the key
@@ -1145,7 +1156,7 @@ impl<K, V, S> HashMap<K, V, S>
11451156
return None
11461157
}
11471158

1148-
self.search_mut(k).map(|bucket| pop_internal(bucket).1)
1159+
self.search_mut(k).into_option().map(|bucket| pop_internal(bucket).1)
11491160
}
11501161
}
11511162

@@ -1398,6 +1409,15 @@ enum InternalEntry<K, V, M> {
13981409
TableIsEmpty,
13991410
}
14001411

1412+
impl<K, V, M> InternalEntry<K, V, M> {
1413+
fn into_option(self) -> Option<FullBucket<K, V, M>> {
1414+
match self {
1415+
InternalEntry::Occupied(bucket) => Some(bucket.elem),
1416+
_ => None,
1417+
}
1418+
}
1419+
}
1420+
14011421
#[stable(feature = "rust1", since = "1.0.0")]
14021422
impl<'a, K, V> Iterator for Iter<'a, K, V> {
14031423
type Item = (&'a K, &'a V);

src/libstd/collections/hash/table.rs

+7
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ impl<K, V> RawTable<K, V> {
522522
}
523523
}
524524

525+
/// Grows a non-empty table in-place.
525526
pub fn grow_inplace(&mut self, capacity: uint) -> bool {
526527
assert!(capacity.is_power_of_two());
527528
assert!(capacity >= self.capacity);
@@ -691,6 +692,7 @@ impl<K, V> Drop for RawTable<K, V> {
691692
}
692693
}
693694

695+
/// A partial table provides safe and cheap draining and incremental construction.
694696
pub struct PartialRawTable<K, V> {
695697
table: RawTable<K, V>,
696698
front: RawBucket<K, V>,
@@ -700,6 +702,7 @@ pub struct PartialRawTable<K, V> {
700702
}
701703

702704
impl<K, V> PartialRawTable<K, V> {
705+
/// Turn a table into a partial table. All buckets are already initialized.
703706
pub fn new(table: RawTable<K, V>) -> PartialRawTable<K, V> {
704707
unsafe {
705708
PartialRawTable {
@@ -712,6 +715,7 @@ impl<K, V> PartialRawTable<K, V> {
712715
}
713716
}
714717

718+
/// Initialize a bucket. Has no effect if there are no uninitialized buckets at the back.
715719
pub fn push_back(&mut self, bucket: Option<(SafeHash, K, V)>) {
716720
unsafe {
717721
if self.back_num != 0 {
@@ -728,6 +732,7 @@ impl<K, V> PartialRawTable<K, V> {
728732
}
729733
}
730734

735+
/// Takes out an initialized bucket. Returns None if all buckets are uninitialized.
731736
pub fn take_front(&mut self) -> Option<(SafeHash, K, V)> {
732737
unsafe {
733738
while self.front.hash != self.back.hash {
@@ -744,6 +749,7 @@ impl<K, V> PartialRawTable<K, V> {
744749
None
745750
}
746751

752+
/// Unwrap the table by zeroing uninitialized ranges.
747753
pub fn unwrap(self) -> RawTable<K, V> {
748754
unsafe {
749755
zero_memory(self.table.first_bucket_raw().hash, self.front_num);
@@ -759,6 +765,7 @@ impl<K, V> PartialRawTable<K, V> {
759765
}
760766
}
761767

768+
/// Drops all initialized buckets in the partial table.
762769
#[unsafe_destructor]
763770
impl<K, V> Drop for PartialRawTable<K, V> {
764771
fn drop(&mut self) {

0 commit comments

Comments
 (0)