Skip to content

Commit 22ecbbb

Browse files
authored
Merge pull request #126 from mwillsey/master
Unify the entry and insert code
2 parents a2054dc + bb263ea commit 22ecbbb

File tree

1 file changed

+70
-104
lines changed

1 file changed

+70
-104
lines changed

src/map.rs

+70-104
Original file line numberDiff line numberDiff line change
@@ -351,12 +351,6 @@ fn probe_distance(mask: usize, hash: HashValue, current: usize) -> usize {
351351
current.wrapping_sub(desired_pos(mask, hash)) & mask
352352
}
353353

354-
enum Inserted<V> {
355-
Done,
356-
Swapped { prev_value: V },
357-
RobinHood { probe: usize, old_pos: Pos },
358-
}
359-
360354
impl<K, V, S> fmt::Debug for IndexMap<K, V, S>
361355
where
362356
K: fmt::Debug + Hash + Eq,
@@ -840,13 +834,13 @@ where
840834
K: Hash + Eq,
841835
S: BuildHasher,
842836
{
843-
// FIXME: reduce duplication (compare with insert)
844-
fn entry_phase_1<Sz>(&mut self, key: K) -> Entry<K, V>
837+
fn insert_phase_1<'a, Sz, A>(&'a mut self, key: K, action: A) -> A::Output
845838
where
846839
Sz: Size,
840+
A: ProbeAction<'a, Sz, K, V>,
847841
{
848842
let hash = hash_elem_using(&self.hash_builder, &key);
849-
self.core.entry_phase_1::<Sz>(hash, key)
843+
self.core.insert_phase_1::<Sz, A>(hash, key, action)
850844
}
851845

852846
/// Remove all key-value pairs in the map, while preserving its capacity.
@@ -865,24 +859,12 @@ where
865859
}
866860
}
867861

868-
// First phase: Look for the preferred location for key.
869-
//
870-
// We will know if `key` is already in the map, before we need to insert it.
871-
// When we insert they key, it might be that we need to continue displacing
872-
// entries (robin hood hashing), in which case Inserted::RobinHood is returned
873-
fn insert_phase_1<Sz>(&mut self, key: K, value: V) -> Inserted<V>
874-
where
875-
Sz: Size,
876-
{
877-
let hash = hash_elem_using(&self.hash_builder, &key);
878-
self.core.insert_phase_1::<Sz>(hash, key, value)
879-
}
880-
881862
fn reserve_one(&mut self) {
882863
if self.len() == self.capacity() {
883864
dispatch_32_vs_64!(self.double_capacity());
884865
}
885866
}
867+
886868
fn double_capacity<Sz>(&mut self)
887869
where
888870
Sz: Size,
@@ -904,26 +886,7 @@ where
904886
/// See also [`entry`](#method.entry) if you you want to insert *or* modify
905887
/// or if you need to get the index of the corresponding key-value pair.
906888
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
907-
self.reserve_one();
908-
if self.size_class_is_64bit() {
909-
match self.insert_phase_1::<u64>(key, value) {
910-
Inserted::Swapped { prev_value } => Some(prev_value),
911-
Inserted::Done => None,
912-
Inserted::RobinHood { probe, old_pos } => {
913-
self.core.insert_phase_2::<u64>(probe, old_pos);
914-
None
915-
}
916-
}
917-
} else {
918-
match self.insert_phase_1::<u32>(key, value) {
919-
Inserted::Swapped { prev_value } => Some(prev_value),
920-
Inserted::Done => None,
921-
Inserted::RobinHood { probe, old_pos } => {
922-
self.core.insert_phase_2::<u32>(probe, old_pos);
923-
None
924-
}
925-
}
926-
}
889+
self.insert_full(key, value).1
927890
}
928891

929892
/// Insert a key-value pair in the map, and get their index.
@@ -940,16 +903,8 @@ where
940903
/// See also [`entry`](#method.entry) if you you want to insert *or* modify
941904
/// or if you need to get the index of the corresponding key-value pair.
942905
pub fn insert_full(&mut self, key: K, value: V) -> (usize, Option<V>) {
943-
let entry = self.entry(key);
944-
let index = entry.index();
945-
946-
match entry {
947-
Entry::Occupied(mut entry) => (index, Some(entry.insert(value))),
948-
Entry::Vacant(entry) => {
949-
entry.insert(value);
950-
(index, None)
951-
}
952-
}
906+
self.reserve_one();
907+
dispatch_32_vs_64!(self.insert_phase_1::<_>(key, InsertValue(value)))
953908
}
954909

955910
/// Get the given key’s corresponding entry in the map for insertion and/or
@@ -958,7 +913,7 @@ where
958913
/// Computes in **O(1)** time (amortized average).
959914
pub fn entry(&mut self, key: K) -> Entry<K, V> {
960915
self.reserve_one();
961-
dispatch_32_vs_64!(self.entry_phase_1(key))
916+
dispatch_32_vs_64!(self.insert_phase_1::<_>(key, MakeEntry))
962917
}
963918

964919
/// Return an iterator over the key-value pairs of the map, in their order
@@ -1458,11 +1413,11 @@ impl<K, V> OrderMapCore<K, V> {
14581413
Some(self.swap_remove_found(probe, found))
14591414
}
14601415

1461-
// FIXME: reduce duplication (compare with insert)
1462-
fn entry_phase_1<Sz>(&mut self, hash: HashValue, key: K) -> Entry<K, V>
1416+
fn insert_phase_1<'a, Sz, A>(&'a mut self, hash: HashValue, key: K, action: A) -> A::Output
14631417
where
14641418
Sz: Size,
14651419
K: Eq,
1420+
A: ProbeAction<'a, Sz, K, V>,
14661421
{
14671422
let mut probe = desired_pos(self.mask, hash);
14681423
let mut dist = 0;
@@ -1474,14 +1429,14 @@ impl<K, V> OrderMapCore<K, V> {
14741429
let their_dist = probe_distance(self.mask, entry_hash.into_hash(), probe);
14751430
if their_dist < dist {
14761431
// robin hood: steal the spot if it's better for us
1477-
return Entry::Vacant(VacantEntry {
1432+
return action.steal(VacantEntry {
14781433
map: self,
14791434
hash: hash,
14801435
key: key,
14811436
probe: probe,
14821437
});
14831438
} else if entry_hash == hash && self.entries[i].key == key {
1484-
return Entry::Occupied(OccupiedEntry {
1439+
return action.hit(OccupiedEntry {
14851440
map: self,
14861441
key: key,
14871442
probe: probe,
@@ -1490,7 +1445,7 @@ impl<K, V> OrderMapCore<K, V> {
14901445
}
14911446
} else {
14921447
// empty bucket, insert here
1493-
return Entry::Vacant(VacantEntry {
1448+
return action.empty(VacantEntry {
14941449
map: self,
14951450
hash: hash,
14961451
key: key,
@@ -1501,52 +1456,6 @@ impl<K, V> OrderMapCore<K, V> {
15011456
});
15021457
}
15031458

1504-
// First phase: Look for the preferred location for key.
1505-
//
1506-
// We will know if `key` is already in the map, before we need to insert it.
1507-
// When we insert they key, it might be that we need to continue displacing
1508-
// entries (robin hood hashing), in which case Inserted::RobinHood is returned
1509-
fn insert_phase_1<Sz>(&mut self, hash: HashValue, key: K, value: V) -> Inserted<V>
1510-
where
1511-
Sz: Size,
1512-
K: Eq,
1513-
{
1514-
let mut probe = desired_pos(self.mask, hash);
1515-
let mut dist = 0;
1516-
let insert_kind;
1517-
debug_assert!(self.len() < self.raw_capacity());
1518-
probe_loop!(probe < self.indices.len(), {
1519-
let pos = &mut self.indices[probe];
1520-
if let Some((i, hash_proxy)) = pos.resolve::<Sz>() {
1521-
let entry_hash = hash_proxy.get_short_hash(&self.entries, i);
1522-
// if existing element probed less than us, swap
1523-
let their_dist = probe_distance(self.mask, entry_hash.into_hash(), probe);
1524-
if their_dist < dist {
1525-
// robin hood: steal the spot if it's better for us
1526-
let index = self.entries.len();
1527-
insert_kind = Inserted::RobinHood {
1528-
probe: probe,
1529-
old_pos: Pos::with_hash::<Sz>(index, hash),
1530-
};
1531-
break;
1532-
} else if entry_hash == hash && self.entries[i].key == key {
1533-
return Inserted::Swapped {
1534-
prev_value: replace(&mut self.entries[i].value, value),
1535-
};
1536-
}
1537-
} else {
1538-
// empty bucket, insert here
1539-
let index = self.entries.len();
1540-
*pos = Pos::with_hash::<Sz>(index, hash);
1541-
insert_kind = Inserted::Done;
1542-
break;
1543-
}
1544-
dist += 1;
1545-
});
1546-
self.entries.push(Bucket { hash, key, value });
1547-
insert_kind
1548-
}
1549-
15501459
/// phase 2 is post-insert where we forward-shift `Pos` in the indices.
15511460
fn insert_phase_2<Sz>(&mut self, mut probe: usize, mut old_pos: Pos)
15521461
where
@@ -1811,6 +1720,63 @@ impl<K, V> OrderMapCore<K, V> {
18111720
}
18121721
}
18131722

1723+
trait ProbeAction<'a, Sz: Size, K, V>: Sized {
1724+
type Output;
1725+
// handle an occupied spot in the map
1726+
fn hit(self, entry: OccupiedEntry<'a, K, V>) -> Self::Output;
1727+
// handle an empty spot in the map
1728+
fn empty(self, entry: VacantEntry<'a, K, V>) -> Self::Output;
1729+
// robin hood: handle a spot that you should steal because it's better for you
1730+
fn steal(self, entry: VacantEntry<'a, K, V>) -> Self::Output;
1731+
}
1732+
1733+
struct InsertValue<V>(V);
1734+
1735+
impl<'a, Sz: Size, K, V> ProbeAction<'a, Sz, K, V> for InsertValue<V> {
1736+
type Output = (usize, Option<V>);
1737+
1738+
fn hit(self, entry: OccupiedEntry<'a, K, V>) -> Self::Output {
1739+
let old = replace(&mut entry.map.entries[entry.index].value, self.0);
1740+
(entry.index, Some(old))
1741+
}
1742+
1743+
fn empty(self, entry: VacantEntry<'a, K, V>) -> Self::Output {
1744+
let pos = &mut entry.map.indices[entry.probe];
1745+
let index = entry.map.entries.len();
1746+
*pos = Pos::with_hash::<Sz>(index, entry.hash);
1747+
entry.map.entries.push(Bucket {
1748+
hash: entry.hash,
1749+
key: entry.key,
1750+
value: self.0,
1751+
});
1752+
(index, None)
1753+
}
1754+
1755+
fn steal(self, entry: VacantEntry<'a, K, V>) -> Self::Output {
1756+
let index = entry.map.entries.len();
1757+
entry.insert_impl::<Sz>(self.0);
1758+
(index, None)
1759+
}
1760+
}
1761+
1762+
struct MakeEntry;
1763+
1764+
impl<'a, Sz: Size, K: 'a, V: 'a> ProbeAction<'a, Sz, K, V> for MakeEntry {
1765+
type Output = Entry<'a, K, V>;
1766+
1767+
fn hit(self, entry: OccupiedEntry<'a, K, V>) -> Self::Output {
1768+
Entry::Occupied(entry)
1769+
}
1770+
1771+
fn empty(self, entry: VacantEntry<'a, K, V>) -> Self::Output {
1772+
Entry::Vacant(entry)
1773+
}
1774+
1775+
fn steal(self, entry: VacantEntry<'a, K, V>) -> Self::Output {
1776+
Entry::Vacant(entry)
1777+
}
1778+
}
1779+
18141780
/// Find, in the indices, an entry that already exists at a known position
18151781
/// inside self.entries in the IndexMap.
18161782
///

0 commit comments

Comments
 (0)