|
1 | 1 | //! This module contains a branchless heapsort as fallback for unstable quicksort.
|
2 | 2 |
|
3 |
| -use crate::{intrinsics, ptr}; |
| 3 | +use crate::{cmp, intrinsics, ptr}; |
4 | 4 |
|
5 | 5 | /// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case.
|
6 | 6 | ///
|
7 | 7 | /// Never inline this, it sits the main hot-loop in `recurse` and is meant as unlikely algorithmic
|
8 | 8 | /// fallback.
|
9 |
| -/// |
10 |
| -/// SAFETY: The caller has to guarantee that `v.len()` >= 2. |
11 | 9 | #[inline(never)]
|
12 |
| -pub(crate) unsafe fn heapsort<T, F>(v: &mut [T], is_less: &mut F) |
| 10 | +pub(crate) fn heapsort<T, F>(v: &mut [T], is_less: &mut F) |
13 | 11 | where
|
14 | 12 | F: FnMut(&T, &T) -> bool,
|
15 | 13 | {
|
16 |
| - // SAFETY: See function safety. |
17 |
| - unsafe { |
18 |
| - intrinsics::assume(v.len() >= 2); |
19 |
| - |
20 |
| - // Build the heap in linear time. |
21 |
| - for i in (0..v.len() / 2).rev() { |
22 |
| - sift_down(v, i, is_less); |
23 |
| - } |
| 14 | + let len = v.len(); |
24 | 15 |
|
25 |
| - // Pop maximal elements from the heap. |
26 |
| - for i in (1..v.len()).rev() { |
| 16 | + for i in (0..len + len / 2).rev() { |
| 17 | + let sift_idx = if i >= len { |
| 18 | + i - len |
| 19 | + } else { |
27 | 20 | v.swap(0, i);
|
28 |
| - sift_down(&mut v[..i], 0, is_less); |
| 21 | + 0 |
| 22 | + }; |
| 23 | + |
| 24 | + // SAFETY: The above calculation ensures that `sift_idx` is either 0 or |
| 25 | + // `(len..(len + (len / 2))) - len`, which simplifies to `0..(len / 2)`. |
| 26 | + // This guarantees the required `sift_idx <= len`. |
| 27 | + unsafe { |
| 28 | + sift_down(&mut v[..cmp::min(i, len)], sift_idx, is_less); |
29 | 29 | }
|
30 | 30 | }
|
31 | 31 | }
|
32 | 32 |
|
33 | 33 | // This binary heap respects the invariant `parent >= child`.
|
34 | 34 | //
|
35 |
| -// SAFETY: The caller has to guarantee that node < `v.len()`. |
36 |
| -#[inline(never)] |
| 35 | +// SAFETY: The caller has to guarantee that `node <= v.len()`. |
| 36 | +#[inline(always)] |
37 | 37 | unsafe fn sift_down<T, F>(v: &mut [T], mut node: usize, is_less: &mut F)
|
38 | 38 | where
|
39 | 39 | F: FnMut(&T, &T) -> bool,
|
40 | 40 | {
|
41 | 41 | // SAFETY: See function safety.
|
42 | 42 | unsafe {
|
43 |
| - intrinsics::assume(node < v.len()); |
| 43 | + intrinsics::assume(node <= v.len()); |
44 | 44 | }
|
45 | 45 |
|
46 | 46 | let len = v.len();
|
|
0 commit comments