@@ -114,22 +114,14 @@ fn special_is_empty(ctrl: u8) -> bool {
114
114
ctrl & 0x01 != 0
115
115
}
116
116
117
- /// Primary hash function, used to select the initial bucket to probe from.
118
- #[ inline]
119
- #[ allow( clippy:: cast_possible_truncation) ]
120
- fn h1 ( hash : u64 ) -> usize {
121
- // On 32-bit platforms we simply ignore the higher hash bits.
122
- hash as usize
123
- }
124
-
125
117
/// Secondary hash function, saved in the low 7 bits of the control byte.
126
118
#[ inline]
127
119
#[ allow( clippy:: cast_possible_truncation) ]
128
120
fn h2 ( hash : u64 ) -> u8 {
129
121
// Grab the top 7 bits of the hash. While the hash is normally a full 64-bit
130
122
// value, some hash functions (such as FxHash) produce a usize result
131
123
// instead, which means that the top 32 bits are 0 on 32-bit platforms.
132
- let hash_len = usize :: min ( mem:: size_of :: < usize > ( ) , mem :: size_of :: < u64 > ( ) ) ;
124
+ let hash_len = mem:: size_of :: < usize > ( ) ;
133
125
let top7 = hash >> ( hash_len * 8 - 7 ) ;
134
126
( top7 & 0x7f ) as u8 // truncation
135
127
}
@@ -327,9 +319,8 @@ impl<T> Bucket<T> {
327
319
328
320
/// A raw hash table with an unsafe API.
329
321
pub struct RawTable < T > {
330
- // Mask to get an index from a hash value. The value is one less than the
331
- // number of buckets in the table.
332
- bucket_mask : usize ,
322
+ // Log2 of the table capacity (which is always a power of 2)
323
+ capacity_log2 : u8 ,
333
324
334
325
// Pointer to the array of control bytes
335
326
ctrl : NonNull < u8 > ,
@@ -358,7 +349,7 @@ impl<T> RawTable<T> {
358
349
Self {
359
350
data : NonNull :: dangling ( ) ,
360
351
ctrl : NonNull :: from ( & Group :: static_empty ( ) [ 0 ] ) ,
361
- bucket_mask : 0 ,
352
+ capacity_log2 : 0 ,
362
353
items : 0 ,
363
354
growth_left : 0 ,
364
355
marker : PhantomData ,
@@ -380,13 +371,31 @@ impl<T> RawTable<T> {
380
371
Ok ( Self {
381
372
data,
382
373
ctrl,
383
- bucket_mask : buckets - 1 ,
374
+ capacity_log2 : if buckets == 0 { 0 } else { buckets . trailing_zeros ( ) as u8 } ,
384
375
items : 0 ,
385
376
growth_left : bucket_mask_to_capacity ( buckets - 1 ) ,
386
377
marker : PhantomData ,
387
378
} )
388
379
}
389
380
381
+ // Mask to get an index from a hash value. The value is one less than the
382
+ // number of buckets in the table.
383
+ #[ inline]
384
+ fn bucket_mask ( & self ) -> usize {
385
+ ( 1 << self . capacity_log2 as usize ) - 1
386
+ }
387
+
388
+ // Number of bits to shift to extract the index from the hash.
389
+ #[ inline]
390
+ fn bucket_shift ( & self ) -> u32 {
391
+ // The secondary hash in h2 takes the top 7 bits, this extracts the
392
+ // primary hash from the high bits just under those.
393
+ // The default FxHasher does not mix in low bits as well, so we only
394
+ // use high bits.
395
+ let hash_len = mem:: size_of :: < usize > ( ) ;
396
+ 8 * hash_len as u32 - 7 - self . capacity_log2 as u32
397
+ }
398
+
390
399
/// Attempts to allocate a new hash table with at least enough capacity
391
400
/// for inserting the given number of elements without reallocating.
392
401
fn try_with_capacity (
@@ -442,7 +451,7 @@ impl<T> RawTable<T> {
442
451
/// Returns a pointer to an element in the table.
443
452
#[ inline]
444
453
pub unsafe fn bucket ( & self , index : usize ) -> Bucket < T > {
445
- debug_assert_ne ! ( self . bucket_mask, 0 ) ;
454
+ debug_assert_ne ! ( self . bucket_mask( ) , 0 ) ;
446
455
debug_assert ! ( index < self . buckets( ) ) ;
447
456
Bucket :: from_base_index ( self . data . as_ptr ( ) , index)
448
457
}
@@ -451,7 +460,7 @@ impl<T> RawTable<T> {
451
460
#[ inline]
452
461
pub unsafe fn erase_no_drop ( & mut self , item : & Bucket < T > ) {
453
462
let index = self . bucket_index ( item) ;
454
- let index_before = index. wrapping_sub ( Group :: WIDTH ) & self . bucket_mask ;
463
+ let index_before = index. wrapping_sub ( Group :: WIDTH ) & self . bucket_mask ( ) ;
455
464
let empty_before = Group :: load ( self . ctrl ( index_before) ) . match_empty ( ) ;
456
465
let empty_after = Group :: load ( self . ctrl ( index) ) . match_empty ( ) ;
457
466
@@ -481,8 +490,8 @@ impl<T> RawTable<T> {
481
490
#[ inline]
482
491
fn probe_seq ( & self , hash : u64 ) -> ProbeSeq {
483
492
ProbeSeq {
484
- bucket_mask : self . bucket_mask ,
485
- pos : h1 ( hash) & self . bucket_mask ,
493
+ bucket_mask : self . bucket_mask ( ) ,
494
+ pos : ( hash as usize ) . wrapping_shr ( self . bucket_shift ( ) ) & self . bucket_mask ( ) ,
486
495
stride : 0 ,
487
496
}
488
497
}
@@ -494,7 +503,7 @@ impl<T> RawTable<T> {
494
503
// Replicate the first Group::WIDTH control bytes at the end of
495
504
// the array without using a branch:
496
505
// - If index >= Group::WIDTH then index == index2.
497
- // - Otherwise index2 == self.bucket_mask + 1 + index.
506
+ // - Otherwise index2 == self.bucket_mask() + 1 + index.
498
507
//
499
508
// The very last replicated control byte is never actually read because
500
509
// we mask the initial index for unaligned loads, but we write it
@@ -509,7 +518,7 @@ impl<T> RawTable<T> {
509
518
// ---------------------------------------------
510
519
// | [A] | [B] | [EMPTY] | [EMPTY] | [A] | [B] |
511
520
// ---------------------------------------------
512
- let index2 = ( ( index. wrapping_sub ( Group :: WIDTH ) ) & self . bucket_mask ) + Group :: WIDTH ;
521
+ let index2 = ( ( index. wrapping_sub ( Group :: WIDTH ) ) & self . bucket_mask ( ) ) + Group :: WIDTH ;
513
522
514
523
* self . ctrl ( index) = ctrl;
515
524
* self . ctrl ( index2) = ctrl;
@@ -525,7 +534,7 @@ impl<T> RawTable<T> {
525
534
unsafe {
526
535
let group = Group :: load ( self . ctrl ( pos) ) ;
527
536
if let Some ( bit) = group. match_empty_or_deleted ( ) . lowest_set_bit ( ) {
528
- let result = ( pos + bit) & self . bucket_mask ;
537
+ let result = ( pos + bit) & self . bucket_mask ( ) ;
529
538
530
539
// In tables smaller than the group width, trailing control
531
540
// bytes outside the range of the table are filled with
@@ -537,7 +546,7 @@ impl<T> RawTable<T> {
537
546
// slot (due to the load factor) before hitting the trailing
538
547
// control bytes (containing EMPTY).
539
548
if unlikely ( is_full ( * self . ctrl ( result) ) ) {
540
- debug_assert ! ( self . bucket_mask < Group :: WIDTH ) ;
549
+ debug_assert ! ( self . bucket_mask( ) < Group :: WIDTH ) ;
541
550
debug_assert_ne ! ( pos, 0 ) ;
542
551
return Group :: load_aligned ( self . ctrl ( 0 ) )
543
552
. match_empty_or_deleted ( )
@@ -562,7 +571,7 @@ impl<T> RawTable<T> {
562
571
}
563
572
}
564
573
self . items = 0 ;
565
- self . growth_left = bucket_mask_to_capacity ( self . bucket_mask ) ;
574
+ self . growth_left = bucket_mask_to_capacity ( self . bucket_mask ( ) ) ;
566
575
}
567
576
568
577
/// Removes all elements from the table without freeing the backing memory.
@@ -653,7 +662,7 @@ impl<T> RawTable<T> {
653
662
654
663
// Rehash in-place without re-allocating if we have plenty of spare
655
664
// capacity that is locked up due to DELETED entries.
656
- if new_items < bucket_mask_to_capacity ( self . bucket_mask ) / 2 {
665
+ if new_items < bucket_mask_to_capacity ( self . bucket_mask ( ) ) / 2 {
657
666
self . rehash_in_place ( hasher) ;
658
667
Ok ( ( ) )
659
668
} else {
@@ -700,7 +709,7 @@ impl<T> RawTable<T> {
700
709
}
701
710
}
702
711
}
703
- self_. growth_left = bucket_mask_to_capacity ( self_. bucket_mask ) - self_. items ;
712
+ self_. growth_left = bucket_mask_to_capacity ( self_. bucket_mask ( ) ) - self_. items ;
704
713
} ) ;
705
714
706
715
// At this point, DELETED elements are elements that we haven't
@@ -724,7 +733,7 @@ impl<T> RawTable<T> {
724
733
// same unaligned group, then there is no benefit in moving
725
734
// it and we can just continue to the next item.
726
735
let probe_index = |pos : usize | {
727
- ( pos. wrapping_sub ( guard. probe_seq ( hash) . pos ) & guard. bucket_mask )
736
+ ( pos. wrapping_sub ( guard. probe_seq ( hash) . pos ) & guard. bucket_mask ( ) )
728
737
/ Group :: WIDTH
729
738
} ;
730
739
if likely ( probe_index ( i) == probe_index ( new_i) ) {
@@ -755,7 +764,7 @@ impl<T> RawTable<T> {
755
764
}
756
765
}
757
766
758
- guard. growth_left = bucket_mask_to_capacity ( guard. bucket_mask ) - guard. items ;
767
+ guard. growth_left = bucket_mask_to_capacity ( guard. bucket_mask ( ) ) - guard. items ;
759
768
mem:: forget ( guard) ;
760
769
}
761
770
}
@@ -851,7 +860,7 @@ impl<T> RawTable<T> {
851
860
for pos in self . probe_seq ( hash) {
852
861
let group = Group :: load ( self . ctrl ( pos) ) ;
853
862
for bit in group. match_byte ( h2 ( hash) ) {
854
- let index = ( pos + bit) & self . bucket_mask ;
863
+ let index = ( pos + bit) & self . bucket_mask ( ) ;
855
864
let bucket = self . bucket ( index) ;
856
865
if likely ( eq ( bucket. as_ref ( ) ) ) {
857
866
return Some ( bucket) ;
@@ -885,20 +894,20 @@ impl<T> RawTable<T> {
885
894
/// Returns the number of buckets in the table.
886
895
#[ inline]
887
896
pub fn buckets ( & self ) -> usize {
888
- self . bucket_mask + 1
897
+ self . bucket_mask ( ) + 1
889
898
}
890
899
891
900
/// Returns the number of control bytes in the table.
892
901
#[ inline]
893
902
fn num_ctrl_bytes ( & self ) -> usize {
894
- self . bucket_mask + 1 + Group :: WIDTH
903
+ self . bucket_mask ( ) + 1 + Group :: WIDTH
895
904
}
896
905
897
906
/// Returns whether this table points to the empty singleton with a capacity
898
907
/// of 0.
899
908
#[ inline]
900
909
fn is_empty_singleton ( & self ) -> bool {
901
- self . bucket_mask == 0
910
+ self . capacity_log2 == 0
902
911
}
903
912
904
913
/// Returns an iterator over every element in the table. It is up to
0 commit comments