use core::cmp::Ordering;
use core::mem;
use core::ptr;
#[inline(always)]
pub fn sort<T: Ord>(v: &mut [T]) {
unstable_sort(v, |a, b| a.lt(b))
}
#[inline(always)]
pub fn sort_by<T, F: FnMut(&T, &T) -> Ordering>(v: &mut [T], mut compare: F) {
unstable_sort(v, |a, b| compare(a, b) == Ordering::Less);
}
#[inline(always)]
pub fn sort_by_key<T, K, F>(v: &mut [T], mut f: F)
where
F: FnMut(&T) -> K,
K: Ord,
{
unstable_sort(v, |a, b| f(a).lt(&f(b)));
}
#[inline(always)]
fn unstable_sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], mut is_less: F) {
if mem::size_of::<T>() == 0 {
return;
}
let len = v.len();
if len < 2 {
return;
}
unsafe {
heapsort(v, &mut is_less);
}
}
#[inline(never)]
unsafe fn heapsort<T, F>(v: &mut [T], is_less: &mut F)
where
F: FnMut(&T, &T) -> bool,
{
if v.len() < 2 {
unsafe {
core::hint::unreachable_unchecked();
}
}
let len = v.len();
for i in (0..len / 2).rev() {
sift_down(v, i, is_less);
}
for i in (1..len).rev() {
v.swap(0, i);
sift_down(&mut v[..i], 0, is_less);
}
}
#[inline(never)]
unsafe fn sift_down<T, F>(v: &mut [T], mut node: usize, is_less: &mut F)
where
F: FnMut(&T, &T) -> bool,
{
if node >= v.len() {
unsafe {
core::hint::unreachable_unchecked();
}
}
let len = v.len();
let arr_ptr = v.as_mut_ptr();
loop {
let mut child = 2 * node + 1;
if child >= len {
break;
}
unsafe {
if child + 1 < len {
child += is_less(&*arr_ptr.add(child), &*arr_ptr.add(child + 1)) as usize;
}
if !is_less(&*arr_ptr.add(node), &*arr_ptr.add(child)) {
break;
}
ptr::swap(arr_ptr.add(node), arr_ptr.add(child));
}
node = child;
}
}