@@ -351,12 +351,6 @@ fn probe_distance(mask: usize, hash: HashValue, current: usize) -> usize {
351
351
current. wrapping_sub ( desired_pos ( mask, hash) ) & mask
352
352
}
353
353
354
- enum Inserted < V > {
355
- Done ,
356
- Swapped { prev_value : V } ,
357
- RobinHood { probe : usize , old_pos : Pos } ,
358
- }
359
-
360
354
impl < K , V , S > fmt:: Debug for IndexMap < K , V , S >
361
355
where
362
356
K : fmt:: Debug + Hash + Eq ,
@@ -840,13 +834,13 @@ where
840
834
K : Hash + Eq ,
841
835
S : BuildHasher ,
842
836
{
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
845
838
where
846
839
Sz : Size ,
840
+ A : ProbeAction < ' a , Sz , K , V > ,
847
841
{
848
842
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 )
850
844
}
851
845
852
846
/// Remove all key-value pairs in the map, while preserving its capacity.
@@ -865,24 +859,12 @@ where
865
859
}
866
860
}
867
861
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
-
881
862
fn reserve_one ( & mut self ) {
882
863
if self . len ( ) == self . capacity ( ) {
883
864
dispatch_32_vs_64 ! ( self . double_capacity( ) ) ;
884
865
}
885
866
}
867
+
886
868
fn double_capacity < Sz > ( & mut self )
887
869
where
888
870
Sz : Size ,
@@ -904,26 +886,7 @@ where
904
886
/// See also [`entry`](#method.entry) if you you want to insert *or* modify
905
887
/// or if you need to get the index of the corresponding key-value pair.
906
888
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
927
890
}
928
891
929
892
/// Insert a key-value pair in the map, and get their index.
@@ -940,16 +903,8 @@ where
940
903
/// See also [`entry`](#method.entry) if you you want to insert *or* modify
941
904
/// or if you need to get the index of the corresponding key-value pair.
942
905
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) ) )
953
908
}
954
909
955
910
/// Get the given key’s corresponding entry in the map for insertion and/or
@@ -958,7 +913,7 @@ where
958
913
/// Computes in **O(1)** time (amortized average).
959
914
pub fn entry ( & mut self , key : K ) -> Entry < K , V > {
960
915
self . reserve_one ( ) ;
961
- dispatch_32_vs_64 ! ( self . entry_phase_1 ( key) )
916
+ dispatch_32_vs_64 ! ( self . insert_phase_1 :: <_> ( key, MakeEntry ) )
962
917
}
963
918
964
919
/// Return an iterator over the key-value pairs of the map, in their order
@@ -1458,11 +1413,11 @@ impl<K, V> OrderMapCore<K, V> {
1458
1413
Some ( self . swap_remove_found ( probe, found) )
1459
1414
}
1460
1415
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
1463
1417
where
1464
1418
Sz : Size ,
1465
1419
K : Eq ,
1420
+ A : ProbeAction < ' a , Sz , K , V > ,
1466
1421
{
1467
1422
let mut probe = desired_pos ( self . mask , hash) ;
1468
1423
let mut dist = 0 ;
@@ -1474,14 +1429,14 @@ impl<K, V> OrderMapCore<K, V> {
1474
1429
let their_dist = probe_distance( self . mask, entry_hash. into_hash( ) , probe) ;
1475
1430
if their_dist < dist {
1476
1431
// robin hood: steal the spot if it's better for us
1477
- return Entry :: Vacant ( VacantEntry {
1432
+ return action . steal ( VacantEntry {
1478
1433
map: self ,
1479
1434
hash: hash,
1480
1435
key: key,
1481
1436
probe: probe,
1482
1437
} ) ;
1483
1438
} else if entry_hash == hash && self . entries[ i] . key == key {
1484
- return Entry :: Occupied ( OccupiedEntry {
1439
+ return action . hit ( OccupiedEntry {
1485
1440
map: self ,
1486
1441
key: key,
1487
1442
probe: probe,
@@ -1490,7 +1445,7 @@ impl<K, V> OrderMapCore<K, V> {
1490
1445
}
1491
1446
} else {
1492
1447
// empty bucket, insert here
1493
- return Entry :: Vacant ( VacantEntry {
1448
+ return action . empty ( VacantEntry {
1494
1449
map: self ,
1495
1450
hash: hash,
1496
1451
key: key,
@@ -1501,52 +1456,6 @@ impl<K, V> OrderMapCore<K, V> {
1501
1456
} ) ;
1502
1457
}
1503
1458
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
-
1550
1459
/// phase 2 is post-insert where we forward-shift `Pos` in the indices.
1551
1460
fn insert_phase_2 < Sz > ( & mut self , mut probe : usize , mut old_pos : Pos )
1552
1461
where
@@ -1811,6 +1720,63 @@ impl<K, V> OrderMapCore<K, V> {
1811
1720
}
1812
1721
}
1813
1722
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
+
1814
1780
/// Find, in the indices, an entry that already exists at a known position
1815
1781
/// inside self.entries in the IndexMap.
1816
1782
///
0 commit comments