@@ -912,92 +912,25 @@ impl<T, A: Allocator + Clone> RawTable<T, A> {
912
912
}
913
913
}
914
914
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
-
948
915
/// Searches for an element in the table,
949
916
/// or a potential slot where that element could be inserted.
950
917
#[ inline]
951
918
pub fn find_potential (
952
919
& self ,
953
920
hash : u64 ,
954
- eq : impl FnMut ( & T ) -> bool ,
921
+ mut eq : impl FnMut ( & T ) -> bool ,
955
922
) -> Result < Bucket < T > , usize > {
956
923
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
+ } ) ;
981
929
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
+ }
1001
934
}
1002
935
}
1003
936
@@ -1288,6 +1221,93 @@ impl<A: Allocator + Clone> RawTableInner<A> {
1288
1221
}
1289
1222
}
1290
1223
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
+
1291
1311
/// Searches for an empty or deleted bucket which is suitable for inserting
1292
1312
/// a new element and sets the hash for that slot.
1293
1313
///
0 commit comments