@@ -464,10 +464,10 @@ fn break_patterns<T>(v: &mut [T]) {
464
464
}
465
465
}
466
466
467
- /// Chooses a pivot in `v` and returns it's index.
467
+ /// Chooses a pivot in `v` and returns the index and true if the slice is likely already sorted .
468
468
///
469
469
/// Elements in `v` might be reordered in the process.
470
- fn choose_pivot < T , F > ( v : & mut [ T ] , is_less : & mut F ) -> usize
470
+ fn choose_pivot < T , F > ( v : & mut [ T ] , is_less : & mut F ) -> ( usize , bool )
471
471
where F : FnMut ( & T , & T ) -> bool
472
472
{
473
473
// Minimal length to choose the median-of-medians method.
@@ -520,12 +520,12 @@ fn choose_pivot<T, F>(v: &mut [T], is_less: &mut F) -> usize
520
520
}
521
521
522
522
if swaps < MAX_SWAPS {
523
- b
523
+ ( b , swaps == 0 )
524
524
} else {
525
525
// The maximal number of swaps was performed. Chances are the slice is descending or mostly
526
526
// descending, so reversing will probably help sort it faster.
527
527
v. reverse ( ) ;
528
- len - 1 - b
528
+ ( len - 1 - b, true )
529
529
}
530
530
}
531
531
@@ -541,8 +541,10 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T
541
541
// Slices of up to this length get sorted using insertion sort.
542
542
const MAX_INSERTION : usize = 16 ;
543
543
544
- // This is `true` if the last partitioning was balanced.
544
+ // True if the last partitioning was reasonably balanced.
545
545
let mut was_balanced = true ;
546
+ // True if the last partitioning didn't shuffle elements (the slice was already partitioned).
547
+ let mut was_partitioned = true ;
546
548
547
549
loop {
548
550
let len = v. len ( ) ;
@@ -567,7 +569,17 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T
567
569
limit -= 1 ;
568
570
}
569
571
570
- let pivot = choose_pivot ( v, is_less) ;
572
+ // Choose a pivot and try guessing whether the slice is already sorted.
573
+ let ( pivot, likely_sorted) = choose_pivot ( v, is_less) ;
574
+
575
+ // If the last partitioning was decently balanced and didn't shuffle elements, and if pivot
576
+ // selection predicts the slice is likely already sorted...
577
+ if was_balanced && was_partitioned && likely_sorted {
578
+ // Check whether the slice really is sorted. If so, we're done.
579
+ if v. windows ( 2 ) . all ( |w| !is_less ( & w[ 1 ] , & w[ 0 ] ) ) {
580
+ return ;
581
+ }
582
+ }
571
583
572
584
// If the chosen pivot is equal to the predecessor, then it's the smallest element in the
573
585
// slice. Partition the slice into elements equal to and elements greater than the pivot.
@@ -582,14 +594,10 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T
582
594
}
583
595
}
584
596
585
- let ( mid, was_partitioned) = partition ( v, pivot, is_less) ;
597
+ // Partition the slice.
598
+ let ( mid, was_p) = partition ( v, pivot, is_less) ;
586
599
was_balanced = cmp:: min ( mid, len - mid) >= len / 8 ;
587
-
588
- // If the partitioning is decently balanced and the slice was already partitioned, there
589
- // are good chances it is also completely sorted. If so, we're done.
590
- if was_balanced && was_partitioned && v. windows ( 2 ) . all ( |w| !is_less ( & w[ 1 ] , & w[ 0 ] ) ) {
591
- return ;
592
- }
600
+ was_partitioned = was_p;
593
601
594
602
// Split the slice into `left`, `pivot`, and `right`.
595
603
let ( left, right) = { v} . split_at_mut ( mid) ;
0 commit comments