use core::{cmp::Ordering, mem};
#[cfg(feature = "alloc")]
macro_rules! find_n {
($t:ty, $slice:ident, $n:ident, $f: ident, $sort: expr) => {{
let iter = $slice.iter().map($f).enumerate().map(|(i, k)| (k, i as $t));
let mut sorted = $sort(iter, $n);
for i in 0..$n {
let mut idx = sorted[i].1;
while (idx as usize) < i {
idx = sorted[idx as usize].1;
}
sorted[i].1 = idx;
$slice.swap(i, idx as usize);
}
&mut $slice[..$n]
}};
}
pub fn max<T: Ord>(v: &mut [T], n: usize) -> &mut [T] {
max_by(v, n, T::cmp)
}
pub fn min<T: Ord>(v: &mut [T], n: usize) -> &mut [T] {
min_by(v, n, T::cmp)
}
pub fn max_by<T>(v: &mut [T], n: usize, mut cmp: impl FnMut(&T, &T) -> Ordering) -> &mut [T] {
if n == 0 {
return &mut [];
}
let (left, right) = v.split_at_mut(n);
crate::make_min_heap(left, &mut cmp);
for i in right {
let min = &mut left[0];
if cmp(i, min).is_gt() {
mem::swap(min, i);
crate::sift_down(left, 0, &mut cmp);
}
}
crate::sort_min_heap(left, &mut cmp);
left
}
pub fn min_by<T>(v: &mut [T], n: usize, mut cmp: impl FnMut(&T, &T) -> Ordering) -> &mut [T] {
max_by(v, n, |a, b| cmp(b, a))
}
pub fn max_by_key<T, K: Ord>(v: &mut [T], n: usize, mut f: impl FnMut(&T) -> K) -> &mut [T] {
max_by(v, n, |a, b| f(a).cmp(&f(b)))
}
pub fn min_by_key<T, K: Ord>(v: &mut [T], n: usize, mut f: impl FnMut(&T) -> K) -> &mut [T] {
min_by(v, n, |a, b| f(a).cmp(&f(b)))
}
#[cfg(feature = "alloc")]
pub fn max_by_cached_key<T, K: Ord>(v: &mut [T], n: usize, f: impl FnMut(&T) -> K) -> &mut [T] {
let sz_u8 = mem::size_of::<(K, u8)>();
let sz_u16 = mem::size_of::<(K, u16)>();
let sz_u32 = mem::size_of::<(K, u32)>();
let sz_usize = mem::size_of::<(K, usize)>();
if sz_u8 < sz_u16 && v.len() <= u8::MAX as usize {
find_n!(u8, v, n, f, crate::iter::max)
} else if sz_u16 < sz_u32 && v.len() <= u16::MAX as usize {
find_n!(u16, v, n, f, crate::iter::max)
} else if sz_u32 < sz_usize && v.len() <= u32::MAX as usize {
find_n!(u32, v, n, f, crate::iter::max)
} else {
find_n!(usize, v, n, f, crate::iter::max)
}
}
#[cfg(feature = "alloc")]
pub fn min_by_cached_key<T, K: Ord>(v: &mut [T], n: usize, f: impl FnMut(&T) -> K) -> &mut [T] {
let sz_u8 = mem::size_of::<(K, u8)>();
let sz_u16 = mem::size_of::<(K, u16)>();
let sz_u32 = mem::size_of::<(K, u32)>();
let sz_usize = mem::size_of::<(K, usize)>();
if sz_u8 < sz_u16 && v.len() <= u8::MAX as usize {
find_n!(u8, v, n, f, crate::iter::min)
} else if sz_u16 < sz_u32 && v.len() <= u16::MAX as usize {
find_n!(u16, v, n, f, crate::iter::min)
} else if sz_u32 < sz_usize && v.len() <= u32::MAX as usize {
find_n!(u32, v, n, f, crate::iter::min)
} else {
find_n!(usize, v, n, f, crate::iter::min)
}
}