@@ -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-
360354impl < K , V , S > fmt:: Debug for IndexMap < K , V , S >
361355where
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