@@ -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 probe_action < ' 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 . probe_action :: < 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 . probe_action:: <_>( 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 . probe_action :: <_> ( key, MakeEntry ) )
962
917
}
963
918
964
919
/// Return an iterator over the key-value pairs of the map, in their order
@@ -1451,11 +1406,11 @@ impl<K, V> OrderMapCore<K, V> {
1451
1406
Some ( self . swap_remove_found ( probe, found) )
1452
1407
}
1453
1408
1454
- // FIXME: reduce duplication (compare with insert)
1455
- fn entry_phase_1 < Sz > ( & mut self , hash : HashValue , key : K ) -> Entry < K , V >
1409
+ fn probe_action < ' a , Sz , A > ( & ' a mut self , hash : HashValue , key : K , action : A ) -> A :: Output
1456
1410
where
1457
1411
Sz : Size ,
1458
1412
K : Eq ,
1413
+ A : ProbeAction < ' a , Sz , K , V > ,
1459
1414
{
1460
1415
let mut probe = desired_pos ( self . mask , hash) ;
1461
1416
let mut dist = 0 ;
@@ -1467,14 +1422,14 @@ impl<K, V> OrderMapCore<K, V> {
1467
1422
let their_dist = probe_distance( self . mask, entry_hash. into_hash( ) , probe) ;
1468
1423
if their_dist < dist {
1469
1424
// robin hood: steal the spot if it's better for us
1470
- return Entry :: Vacant ( VacantEntry {
1425
+ return action . steal ( VacantEntry {
1471
1426
map: self ,
1472
1427
hash: hash,
1473
1428
key: key,
1474
1429
probe: probe,
1475
1430
} ) ;
1476
1431
} else if entry_hash == hash && self . entries[ i] . key == key {
1477
- return Entry :: Occupied ( OccupiedEntry {
1432
+ return action . hit ( OccupiedEntry {
1478
1433
map: self ,
1479
1434
key: key,
1480
1435
probe: probe,
@@ -1483,7 +1438,7 @@ impl<K, V> OrderMapCore<K, V> {
1483
1438
}
1484
1439
} else {
1485
1440
// empty bucket, insert here
1486
- return Entry :: Vacant ( VacantEntry {
1441
+ return action . empty ( VacantEntry {
1487
1442
map: self ,
1488
1443
hash: hash,
1489
1444
key: key,
@@ -1494,52 +1449,6 @@ impl<K, V> OrderMapCore<K, V> {
1494
1449
} ) ;
1495
1450
}
1496
1451
1497
- // First phase: Look for the preferred location for key.
1498
- //
1499
- // We will know if `key` is already in the map, before we need to insert it.
1500
- // When we insert they key, it might be that we need to continue displacing
1501
- // entries (robin hood hashing), in which case Inserted::RobinHood is returned
1502
- fn insert_phase_1 < Sz > ( & mut self , hash : HashValue , key : K , value : V ) -> Inserted < V >
1503
- where
1504
- Sz : Size ,
1505
- K : Eq ,
1506
- {
1507
- let mut probe = desired_pos ( self . mask , hash) ;
1508
- let mut dist = 0 ;
1509
- let insert_kind;
1510
- debug_assert ! ( self . len( ) < self . raw_capacity( ) ) ;
1511
- probe_loop ! ( probe < self . indices. len( ) , {
1512
- let pos = & mut self . indices[ probe] ;
1513
- if let Some ( ( i, hash_proxy) ) = pos. resolve:: <Sz >( ) {
1514
- let entry_hash = hash_proxy. get_short_hash( & self . entries, i) ;
1515
- // if existing element probed less than us, swap
1516
- let their_dist = probe_distance( self . mask, entry_hash. into_hash( ) , probe) ;
1517
- if their_dist < dist {
1518
- // robin hood: steal the spot if it's better for us
1519
- let index = self . entries. len( ) ;
1520
- insert_kind = Inserted :: RobinHood {
1521
- probe: probe,
1522
- old_pos: Pos :: with_hash:: <Sz >( index, hash) ,
1523
- } ;
1524
- break ;
1525
- } else if entry_hash == hash && self . entries[ i] . key == key {
1526
- return Inserted :: Swapped {
1527
- prev_value: replace( & mut self . entries[ i] . value, value) ,
1528
- } ;
1529
- }
1530
- } else {
1531
- // empty bucket, insert here
1532
- let index = self . entries. len( ) ;
1533
- * pos = Pos :: with_hash:: <Sz >( index, hash) ;
1534
- insert_kind = Inserted :: Done ;
1535
- break ;
1536
- }
1537
- dist += 1 ;
1538
- } ) ;
1539
- self . entries . push ( Bucket { hash, key, value } ) ;
1540
- insert_kind
1541
- }
1542
-
1543
1452
/// phase 2 is post-insert where we forward-shift `Pos` in the indices.
1544
1453
fn insert_phase_2 < Sz > ( & mut self , mut probe : usize , mut old_pos : Pos )
1545
1454
where
@@ -1785,6 +1694,59 @@ impl<K, V> OrderMapCore<K, V> {
1785
1694
}
1786
1695
}
1787
1696
1697
+ trait ProbeAction < ' a , Sz : Size , K , V > : Sized {
1698
+ type Output ;
1699
+ fn hit ( self , entry : OccupiedEntry < ' a , K , V > ) -> Self :: Output ;
1700
+ fn empty ( self , entry : VacantEntry < ' a , K , V > ) -> Self :: Output ;
1701
+ fn steal ( self , entry : VacantEntry < ' a , K , V > ) -> Self :: Output {
1702
+ self . empty ( entry)
1703
+ }
1704
+ }
1705
+
1706
+ struct InsertValue < V > ( V ) ;
1707
+
1708
+ impl < ' a , Sz : Size , K , V > ProbeAction < ' a , Sz , K , V > for InsertValue < V > {
1709
+ type Output = ( usize , Option < V > ) ;
1710
+ fn hit ( self , entry : OccupiedEntry < ' a , K , V > ) -> Self :: Output {
1711
+ let old = replace ( & mut entry. map . entries [ entry. index ] . value , self . 0 ) ;
1712
+ ( entry. index , Some ( old) )
1713
+ }
1714
+ fn empty ( self , entry : VacantEntry < ' a , K , V > ) -> Self :: Output {
1715
+ let pos = & mut entry. map . indices [ entry. probe ] ;
1716
+ let index = entry. map . entries . len ( ) ;
1717
+ * pos = Pos :: with_hash :: < Sz > ( index, entry. hash ) ;
1718
+ entry. map . entries . push ( Bucket {
1719
+ hash : entry. hash ,
1720
+ key : entry. key ,
1721
+ value : self . 0 ,
1722
+ } ) ;
1723
+ ( index, None )
1724
+ }
1725
+ fn steal ( self , entry : VacantEntry < ' a , K , V > ) -> Self :: Output {
1726
+ let index = entry. map . entries . len ( ) ;
1727
+ let old_pos = Pos :: with_hash :: < Sz > ( index, entry. hash ) ;
1728
+ entry. map . entries . push ( Bucket {
1729
+ hash : entry. hash ,
1730
+ key : entry. key ,
1731
+ value : self . 0 ,
1732
+ } ) ;
1733
+ entry. map . insert_phase_2 :: < Sz > ( entry. probe , old_pos) ;
1734
+ ( index, None )
1735
+ }
1736
+ }
1737
+
1738
+ struct MakeEntry ;
1739
+
1740
+ impl < ' a , Sz : Size , K : ' a , V : ' a > ProbeAction < ' a , Sz , K , V > for MakeEntry {
1741
+ type Output = Entry < ' a , K , V > ;
1742
+ fn hit ( self , entry : OccupiedEntry < ' a , K , V > ) -> Self :: Output {
1743
+ Entry :: Occupied ( entry)
1744
+ }
1745
+ fn empty ( self , entry : VacantEntry < ' a , K , V > ) -> Self :: Output {
1746
+ Entry :: Vacant ( entry)
1747
+ }
1748
+ }
1749
+
1788
1750
/// Find, in the indices, an entry that already exists at a known position
1789
1751
/// inside self.entries in the IndexMap.
1790
1752
///
0 commit comments