Use last swap optimization in bubblesort · qinheping/verify-rust-std@ae57bdf (original) (raw)

Original file line number Diff line number Diff line change
@@ -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 }