@@ -912,92 +912,25 @@ impl<T, A: Allocator + Clone> RawTable<T, A> {
912912 }
913913 }
914914
915- /// Searches for an element in the table, stopping at the group where `stop` returns `Some` and
916- /// no elements matched. Returns the bucket that matches or the result of `stop`.
917- #[ inline]
918- unsafe fn search < R > (
919- & self ,
920- hash : u64 ,
921- mut eq : impl FnMut ( & T ) -> bool ,
922- mut stop : impl FnMut ( & Group , & ProbeSeq ) -> Option < R > ,
923- ) -> Result < Bucket < T > , R > {
924- let h2_hash = h2 ( hash) ;
925- let mut probe_seq = self . table . probe_seq ( hash) ;
926-
927- loop {
928- let group = Group :: load ( self . table . ctrl ( probe_seq. pos ) ) ;
929-
930- for bit in group. match_byte ( h2_hash) . into_iter ( ) {
931- let index = ( probe_seq. pos + bit) & self . table . bucket_mask ;
932-
933- let bucket = self . bucket ( index) ;
934- let elm = self . bucket ( index) . as_ref ( ) ;
935- if likely ( eq ( elm) ) {
936- return Ok ( bucket) ;
937- }
938- }
939-
940- if let Some ( stop) = stop ( & group, & probe_seq) {
941- return Err ( stop) ;
942- }
943-
944- probe_seq. move_next ( self . table . bucket_mask ) ;
945- }
946- }
947-
948915 /// Searches for an element in the table,
949916 /// or a potential slot where that element could be inserted.
950917 #[ inline]
951918 pub fn find_potential (
952919 & self ,
953920 hash : u64 ,
954- eq : impl FnMut ( & T ) -> bool ,
921+ mut eq : impl FnMut ( & T ) -> bool ,
955922 ) -> Result < Bucket < T > , usize > {
956923 unsafe {
957- let mut tombstone = None ;
958- self . search ( hash, eq, |group, probe_seq| {
959- let bit = group. match_empty_or_deleted ( ) . lowest_set_bit ( ) ;
960-
961- if likely ( bit. is_some ( ) ) {
962- let mut index = ( probe_seq. pos + bit. unwrap ( ) ) & self . table . bucket_mask ;
963-
964- // In tables smaller than the group width, trailing control
965- // bytes outside the range of the table are filled with
966- // EMPTY entries. These will unfortunately trigger a
967- // match, but once masked may point to a full bucket that
968- // is already occupied. We detect this situation here and
969- // perform a second scan starting at the begining of the
970- // table. This second scan is guaranteed to find an empty
971- // slot (due to the load factor) before hitting the trailing
972- // control bytes (containing EMPTY).
973- if unlikely ( is_full ( * self . table . ctrl ( index) ) ) {
974- debug_assert ! ( self . table. bucket_mask < Group :: WIDTH ) ;
975- debug_assert_ne ! ( probe_seq. pos, 0 ) ;
976-
977- index = Group :: load_aligned ( self . table . ctrl ( 0 ) )
978- . match_empty_or_deleted ( )
979- . lowest_set_bit_nonzero ( )
980- }
924+ let result = self . table . find_potential_inner ( hash, & mut |index| {
925+ let bucket = self . bucket ( index) ;
926+ let elm = bucket. as_ref ( ) ;
927+ eq ( elm)
928+ } ) ;
981929
982- // Only stop the search if the group is empty. The element might be
983- // in a following group.
984- if likely ( group. match_empty ( ) . any_bit_set ( ) ) {
985- // Use a tombstone if we found one
986- if unlikely ( tombstone. is_some ( ) ) {
987- tombstone
988- } else {
989- Some ( index)
990- }
991- } else {
992- // We found a tombstone, record it so we can return it as a potential
993- // insertion location.
994- tombstone = Some ( index) ;
995- None
996- }
997- } else {
998- None
999- }
1000- } )
930+ match result {
931+ Ok ( index) => Ok ( self . bucket ( index) ) ,
932+ Err ( index) => Err ( index) ,
933+ }
1001934 }
1002935 }
1003936
@@ -1288,6 +1221,93 @@ impl<A: Allocator + Clone> RawTableInner<A> {
12881221 }
12891222 }
12901223
1224+ /// Searches for an element in the table, stopping at the group where `stop` returns `Some` and
1225+ /// no elements matched. Returns the bucket that matches or the result of `stop`.
1226+ #[ inline]
1227+ unsafe fn search < R > (
1228+ & self ,
1229+ hash : u64 ,
1230+ eq : & mut dyn FnMut ( usize ) -> bool ,
1231+ mut stop : impl FnMut ( & Group , & ProbeSeq ) -> Option < R > ,
1232+ ) -> Result < usize , R > {
1233+ let h2_hash = h2 ( hash) ;
1234+ let mut probe_seq = self . probe_seq ( hash) ;
1235+
1236+ loop {
1237+ let group = Group :: load ( self . ctrl ( probe_seq. pos ) ) ;
1238+
1239+ for bit in group. match_byte ( h2_hash) . into_iter ( ) {
1240+ let index = ( probe_seq. pos + bit) & self . bucket_mask ;
1241+
1242+ if likely ( eq ( index) ) {
1243+ return Ok ( index) ;
1244+ }
1245+ }
1246+
1247+ if let Some ( stop) = stop ( & group, & probe_seq) {
1248+ return Err ( stop) ;
1249+ }
1250+
1251+ probe_seq. move_next ( self . bucket_mask ) ;
1252+ }
1253+ }
1254+
1255+ /// Searches for an element in the table,
1256+ /// or a potential slot where that element could be inserted.
1257+ #[ inline]
1258+ pub fn find_potential_inner (
1259+ & self ,
1260+ hash : u64 ,
1261+ eq : & mut dyn FnMut ( usize ) -> bool ,
1262+ ) -> Result < usize , usize > {
1263+ unsafe {
1264+ let mut tombstone = None ;
1265+ self . search ( hash, eq, |group, probe_seq| {
1266+ let bit = group. match_empty_or_deleted ( ) . lowest_set_bit ( ) ;
1267+
1268+ if likely ( bit. is_some ( ) ) {
1269+ let mut index = ( probe_seq. pos + bit. unwrap ( ) ) & self . bucket_mask ;
1270+
1271+ // In tables smaller than the group width, trailing control
1272+ // bytes outside the range of the table are filled with
1273+ // EMPTY entries. These will unfortunately trigger a
1274+ // match, but once masked may point to a full bucket that
1275+ // is already occupied. We detect this situation here and
1276+ // perform a second scan starting at the begining of the
1277+ // table. This second scan is guaranteed to find an empty
1278+ // slot (due to the load factor) before hitting the trailing
1279+ // control bytes (containing EMPTY).
1280+ if unlikely ( is_full ( * self . ctrl ( index) ) ) {
1281+ debug_assert ! ( self . bucket_mask < Group :: WIDTH ) ;
1282+ debug_assert_ne ! ( probe_seq. pos, 0 ) ;
1283+
1284+ index = Group :: load_aligned ( self . ctrl ( 0 ) )
1285+ . match_empty_or_deleted ( )
1286+ . lowest_set_bit_nonzero ( )
1287+ }
1288+
1289+ // Only stop the search if the group is empty. The element might be
1290+ // in a following group.
1291+ if likely ( group. match_empty ( ) . any_bit_set ( ) ) {
1292+ // Use a tombstone if we found one
1293+ if unlikely ( tombstone. is_some ( ) ) {
1294+ tombstone
1295+ } else {
1296+ Some ( index)
1297+ }
1298+ } else {
1299+ // We found a tombstone, record it so we can return it as a potential
1300+ // insertion location.
1301+ tombstone = Some ( index) ;
1302+ None
1303+ }
1304+ } else {
1305+ None
1306+ }
1307+ } )
1308+ }
1309+ }
1310+
12911311 /// Searches for an empty or deleted bucket which is suitable for inserting
12921312 /// a new element and sets the hash for that slot.
12931313 ///
0 commit comments