| @@ -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 |
} |