@@ -317,23 +317,32 @@ fn median_idx<T, F: FnMut(&T, &T) -> bool>(
317
317
318
318
// It's possible to re-use the insertion sort in the smallsort module, but with optimize_for_size it
319
319
// would clutter that module with cfg statements and make it generally harder to read and develop.
320
- // So to decouple things and simplify it, we use a an even smaller bubble sort.
320
+ // So to decouple things and simplify it, we use an even smaller bubble sort.
321
321
#[ cfg( feature = "optimize_for_size" ) ]
322
322
fn bubble_sort < T , F : FnMut ( & T , & T ) -> bool > ( v : & mut [ T ] , is_less : & mut F ) {
323
+ use crate :: ptr;
324
+
323
325
let mut n = v. len ( ) ;
324
- let mut did_swap = true ;
325
326
326
- while did_swap && n > 1 {
327
- did_swap = false ;
328
- for i in 1 ..n {
327
+ let v_base = v. as_mut_ptr ( ) ;
328
+
329
+ while n > 1 {
330
+ let loop_n = n;
331
+ n = 0 ;
332
+ for i in 1 ..loop_n {
329
333
// SAFETY: The loop construction implies that `i` and `i - 1` will always be in-bounds.
330
334
unsafe {
331
- if is_less ( v. get_unchecked ( i) , v. get_unchecked ( i - 1 ) ) {
332
- v. swap_unchecked ( i - 1 , i) ;
333
- did_swap = true ;
335
+ // Even if `is_less` erroneously always returns true, we are guaranteed that `n`
336
+ // reduces by one each out loop iteration, because `1..n` is exclusive. This
337
+ // guarantees a bounded run-time should `Ord` be implemented incorrectly.
338
+ let v_i = v_base. add ( i) ;
339
+ let v_i_minus_one = v_base. add ( i - 1 ) ;
340
+
341
+ if is_less ( & * v_i, & * v_i_minus_one) {
342
+ ptr:: swap_nonoverlapping ( v_i, v_i_minus_one, 1 ) ;
343
+ n = i;
334
344
}
335
345
}
336
346
}
337
- n -= 1 ;
338
347
}
339
348
}
0 commit comments