11//! This module contains an unstable quicksort and two partition implementations.
22
33use crate :: mem:: { self , ManuallyDrop } ;
4+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
45use crate :: slice:: sort:: shared:: pivot:: choose_pivot;
6+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
57use crate :: slice:: sort:: shared:: smallsort:: UnstableSmallSortTypeImpl ;
68use crate :: { intrinsics, ptr} ;
79
@@ -11,6 +13,7 @@ use crate::{intrinsics, ptr};
1113///
1214/// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero,
1315/// this function will immediately switch to heapsort.
16+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
1417pub ( crate ) fn quicksort < ' a , T , F > (
1518 mut v : & ' a mut [ T ] ,
1619 mut ancestor_pivot : Option < & ' a T > ,
@@ -138,7 +141,16 @@ const fn inst_partition<T, F: FnMut(&T, &T) -> bool>() -> fn(&mut [T], &T, &mut
138141 if mem:: size_of :: < T > ( ) <= MAX_BRANCHLESS_PARTITION_SIZE {
139142 // Specialize for types that are relatively cheap to copy, where branchless optimizations
140143 // have large leverage e.g. `u64` and `String`.
141- partition_lomuto_branchless_cyclic :: < T , F >
144+
145+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
146+ {
147+ partition_lomuto_branchless_cyclic :: < T , F >
148+ }
149+
150+ #[ cfg( feature = "optimize_for_size" ) ]
151+ {
152+ partition_lomuto_branchless_simple :: < T , F >
153+ }
142154 } else {
143155 partition_hoare_branchy_cyclic :: < T , F >
144156 }
@@ -224,6 +236,7 @@ where
224236 }
225237}
226238
239+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
227240struct PartitionState < T > {
228241 // The current element that is being looked at, scans left to right through slice.
229242 right : * mut T ,
@@ -234,6 +247,7 @@ struct PartitionState<T> {
234247 gap : GapGuardRaw < T > ,
235248}
236249
250+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
237251fn partition_lomuto_branchless_cyclic < T , F > ( v : & mut [ T ] , pivot : & T , is_less : & mut F ) -> usize
238252where
239253 F : FnMut ( & T , & T ) -> bool ,
@@ -325,6 +339,27 @@ where
325339 }
326340}
327341
342+ #[ cfg( feature = "optimize_for_size" ) ]
343+ fn partition_lomuto_branchless_simple < T , F : FnMut ( & T , & T ) -> bool > (
344+ v : & mut [ T ] ,
345+ pivot : & T ,
346+ is_less : & mut F ,
347+ ) -> usize {
348+ let mut left = 0 ;
349+
350+ for right in 0 ..v. len ( ) {
351+ // SAFETY: `left` can at max be incremented by 1 each loop iteration, which implies that
352+ // left <= right and that both are in-bounds.
353+ unsafe {
354+ let right_is_lt = is_less ( v. get_unchecked ( right) , pivot) ;
355+ v. swap_unchecked ( left, right) ;
356+ left += right_is_lt as usize ;
357+ }
358+ }
359+
360+ left
361+ }
362+
328363struct GapGuard < T > {
329364 pos : * mut T ,
330365 value : ManuallyDrop < T > ,
@@ -342,11 +377,13 @@ impl<T> Drop for GapGuard<T> {
342377
343378/// Ideally this wouldn't be needed and we could just use the regular GapGuard.
344379/// See comment in [`partition_lomuto_branchless_cyclic`].
380+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
345381struct GapGuardRaw < T > {
346382 pos : * mut T ,
347383 value : * mut T ,
348384}
349385
386+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
350387impl < T > Drop for GapGuardRaw < T > {
351388 fn drop ( & mut self ) {
352389 // SAFETY: `self` MUST be constructed in a way that makes copying the gap value into
0 commit comments