@@ -498,32 +498,40 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
498
498
#[ cold]
499
499
fn break_patterns < T > ( v : & mut [ T ] ) {
500
500
let len = v. len ( ) ;
501
-
502
501
if len >= 8 {
503
- // A random number will be taken modulo this one. The modulus is a power of two so that we
504
- // can simply take bitwise "and", thus avoiding costly CPU operations.
505
- let modulus = ( len / 4 ) . next_power_of_two ( ) ;
506
- debug_assert ! ( modulus >= 1 && modulus <= len / 2 ) ;
507
-
508
- // Pseudorandom number generation from the "Xorshift RNGs" paper by George Marsaglia.
509
- let mut random = len;
510
- random ^= random << 13 ;
511
- random ^= random >> 17 ;
512
- random ^= random << 5 ;
513
- random &= modulus - 1 ;
514
- debug_assert ! ( random < len / 2 ) ;
515
-
516
- // The first index.
517
- let a = len / 4 * 2 ;
518
- debug_assert ! ( a >= 1 && a < len - 2 ) ;
519
-
520
- // The second index.
521
- let b = len / 4 + random;
522
- debug_assert ! ( b >= 1 && b < len - 2 ) ;
523
-
524
- // Swap neighbourhoods of `a` and `b`.
502
+ // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia.
503
+ let mut random = len as u32 ;
504
+ let mut gen_u32 = || {
505
+ random ^= random << 13 ;
506
+ random ^= random >> 17 ;
507
+ random ^= random << 5 ;
508
+ random
509
+ } ;
510
+ let mut gen_usize = || {
511
+ if mem:: size_of :: < usize > ( ) <= 4 {
512
+ gen_u32 ( ) as usize
513
+ } else {
514
+ ( ( ( gen_u32 ( ) as u64 ) << 32 ) | ( gen_u32 ( ) as u64 ) ) as usize
515
+ }
516
+ } ;
517
+
518
+ // Take random numbers modulo this number.
519
+ // The number fits into `usize` because `len` is not greater than `isize::MAX`.
520
+ let modulus = len. next_power_of_two ( ) ;
521
+
522
+ // Some pivot candidates will be in the nearby of this index. Let's randomize them.
523
+ let pos = len / 4 * 2 ;
524
+
525
525
for i in 0 ..3 {
526
- v. swap ( a - 1 + i, b - 1 + i) ;
526
+ // Generate a random number modulo `len`. However, in order to avoid costly operations
527
+ // we first take it modulo a power of two, and then decrease by `len` until it fits
528
+ // into the range `[0, len - 1]`.
529
+ let mut other = gen_usize ( ) & ( modulus - 1 ) ;
530
+ while other >= len {
531
+ other -= len;
532
+ }
533
+
534
+ v. swap ( pos - 1 + i, other) ;
527
535
}
528
536
}
529
537
}
0 commit comments