@@ -498,32 +498,40 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
498498#[ cold]
499499fn break_patterns < T > ( v : & mut [ T ] ) {
500500 let len = v. len ( ) ;
501-
502501 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+
525525 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) ;
527535 }
528536 }
529537}
0 commit comments