Skip to content

Commit 06bc946

Browse files
committed
docs, refactored
1 parent 55ebbc9 commit 06bc946

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};
@@ -392,8 +392,8 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) {
392392
fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
393393
mut ib: usize,
394394
mut hash: SafeHash,
395-
mut k: K,
396-
mut v: V)
395+
mut key: K,
396+
mut val: V)
397397
-> &'a mut V {
398398
let starting_index = bucket.index();
399399
let size = {
@@ -407,9 +407,11 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
407407
let idx_end = starting_index + size - bucket.displacement();
408408

409409
loop {
410-
let (old_hash, old_key, old_val) = {
410+
{
411411
let (h_ref, k_ref, v_ref) = bucket.read_mut();
412-
(replace(h_ref, hash), replace(k_ref, k), replace(v_ref, v))
412+
swap(h_ref, &mut hash);
413+
swap(k_ref, &mut key);
414+
swap(v_ref, &mut val));
413415
};
414416
loop {
415417
let probe = bucket.into_next();
@@ -418,7 +420,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
418420
let full_bucket = match probe.peek() {
419421
Empty(bucket) => {
420422
// Found a hole!
421-
let b = bucket.put(old_hash, old_key, old_val);
423+
let b = bucket.put(hash, key, val);
422424
// Now that it's stolen, just read the value's pointer
423425
// right out of the table!
424426
return b.into_table().into_mut_refs().1;
@@ -433,9 +435,6 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
433435
// Robin hood! Steal the spot.
434436
if ib < probe_ib {
435437
ib = probe_ib;
436-
hash = old_hash;
437-
k = old_key;
438-
v = old_val;
439438
break;
440439
}
441440
}
@@ -477,24 +476,20 @@ impl<K, V, S> HashMap<K, V, S>
477476
/// Search for a key, yielding the index if it's found in the hashtable.
478477
/// If you already have the hash for the key lying around, use
479478
/// search_hashed.
480-
fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>>
479+
fn search<'a, Q: ?Sized>(&'a self, q: &Q)
480+
-> Option<InternalEntry<K, V, &'a RawTable<K, V>>>
481481
where K: Borrow<Q>, Q: Eq + Hash
482482
{
483483
let hash = self.make_hash(q);
484-
match search_hashed(&self.table, hash, |k| q.eq(k.borrow())) {
485-
InternalEntry::Occupied(bucket) => Some(bucket.elem),
486-
_ => None,
487-
}
484+
search_hashed(&self.table, hash, |k| q.eq(k.borrow()))
488485
}
489486

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

@@ -772,7 +767,15 @@ impl<K, V, S> HashMap<K, V, S>
772767

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

778781
debug_assert_eq!(self.table.size(), old_size);
@@ -934,8 +937,7 @@ impl<K, V, S> HashMap<K, V, S>
934937
// Gotta resize now.
935938
self.reserve(1);
936939

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

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

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

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

11221133
/// Removes a key from the map, returning the value at the key if the key
@@ -1144,7 +1155,7 @@ impl<K, V, S> HashMap<K, V, S>
11441155
return None
11451156
}
11461157

1147-
self.search_mut(k).map(|bucket| pop_internal(bucket).1)
1158+
self.search_mut(k).into_option().map(|bucket| pop_internal(bucket).1)
11481159
}
11491160
}
11501161

@@ -1397,6 +1408,15 @@ enum InternalEntry<K, V, M> {
13971408
TableIsEmpty,
13981409
}
13991410

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

src/libstd/collections/hash/table.rs

+7
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ impl<K, V> RawTable<K, V> {
503503
}
504504
}
505505

506+
/// Grows a non-empty table in-place.
506507
pub fn grow_inplace(&mut self, capacity: uint) -> bool {
507508
assert!(capacity.is_power_of_two());
508509
assert!(capacity >= self.capacity);
@@ -672,6 +673,7 @@ impl<K, V> Drop for RawTable<K, V> {
672673
}
673674
}
674675

676+
/// A partial table provides safe and cheap draining and incremental construction.
675677
pub struct PartialRawTable<K, V> {
676678
table: RawTable<K, V>,
677679
front: RawBucket<K, V>,
@@ -681,6 +683,7 @@ pub struct PartialRawTable<K, V> {
681683
}
682684

683685
impl<K, V> PartialRawTable<K, V> {
686+
/// Turn a table into a partial table. All buckets are already initialized.
684687
pub fn new(table: RawTable<K, V>) -> PartialRawTable<K, V> {
685688
unsafe {
686689
PartialRawTable {
@@ -693,6 +696,7 @@ impl<K, V> PartialRawTable<K, V> {
693696
}
694697
}
695698

699+
/// Initialize a bucket. Has no effect if there are no uninitialized buckets at the back.
696700
pub fn push_back(&mut self, bucket: Option<(SafeHash, K, V)>) {
697701
unsafe {
698702
if self.back_num != 0 {
@@ -709,6 +713,7 @@ impl<K, V> PartialRawTable<K, V> {
709713
}
710714
}
711715

716+
/// Takes out an initialized bucket. Returns None if all buckets are uninitialized.
712717
pub fn take_front(&mut self) -> Option<(SafeHash, K, V)> {
713718
unsafe {
714719
while self.front.hash != self.back.hash {
@@ -725,6 +730,7 @@ impl<K, V> PartialRawTable<K, V> {
725730
None
726731
}
727732

733+
/// Unwrap the table by zeroing uninitialized ranges.
728734
pub fn unwrap(self) -> RawTable<K, V> {
729735
unsafe {
730736
ptr::write_bytes(self.table.first_bucket_raw().hash, self.front_num);
@@ -740,6 +746,7 @@ impl<K, V> PartialRawTable<K, V> {
740746
}
741747
}
742748

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

0 commit comments

Comments
 (0)