use core::cmp::Ordering;
pub(crate) fn stable_sort_by<T: Copy>(
items: &mut [T],
mut compare: impl FnMut(&T, &T) -> Ordering,
) {
for i in 1..items.len() {
let item = items[i];
let mut j = i;
while j > 0 && compare(&items[j - 1], &item).is_gt() {
items[j] = items[j - 1];
j -= 1;
}
items[j] = item;
}
}
pub(crate) fn sort_unstable_by<T>(items: &mut [T], mut compare: impl FnMut(&T, &T) -> Ordering) {
let len = items.len();
for root in (0..len / 2).rev() {
sift_down(items, root, len, &mut compare);
}
for end in (1..len).rev() {
items.swap(0, end);
sift_down(items, 0, end, &mut compare);
}
}
fn sift_down<T>(
items: &mut [T],
mut root: usize,
end: usize,
compare: &mut impl FnMut(&T, &T) -> Ordering,
) {
loop {
let mut child = 2 * root + 1;
if child >= end {
break;
}
if child + 1 < end && compare(&items[child], &items[child + 1]).is_lt() {
child += 1;
}
if !compare(&items[root], &items[child]).is_lt() {
break;
}
items.swap(root, child);
root = child;
}
}
#[inline]
pub const fn rb_flag(x: u32) -> u32 {
1 << x
}
#[inline]
pub fn rb_flag_unsafe(x: u32) -> u32 {
if x < 32 {
1 << x
} else {
0
}
}
#[inline]
pub const fn rb_flag64(x: u32) -> u64 {
1 << x as u64
}
#[inline]
pub fn rb_flag64_unsafe(x: u32) -> u64 {
if x < 64 {
1 << (x as u64)
} else {
0
}
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_ENCODE3(x: u32, y: u32, z: u32) -> u64 {
((x as u64) << 42) | ((y as u64) << 21) | (z as u64)
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_DECODE3_1(v: u64) -> u32 {
(v >> 42) as u32
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_DECODE3_2(v: u64) -> u32 {
((v >> 21) & 0x001F_FFFF) as u32
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_DECODE3_3(v: u64) -> u32 {
(v & 0x001F_FFFF) as u32
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_ENCODE3_11_7_14(x: u32, y: u32, z: u32) -> u32 {
((x & 0x07FF) << 21) | ((y & 0x007F) << 14) | (z & 0x3FFF)
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_DECODE3_11_7_14_1(v: u32) -> u32 {
v >> 21
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_DECODE3_11_7_14_2(v: u32) -> u32 {
((v >> 14) & 0x007F) | 0x0300
}
#[allow(non_snake_case, dead_code)]
pub const fn HB_CODEPOINT_DECODE3_11_7_14_3(v: u32) -> u32 {
v & 0x3FFF
}
#[cfg(test)]
mod tests {
use super::{sort_unstable_by, stable_sort_by};
use alloc::vec::Vec;
#[test]
fn heap_sort_matches_std_sort() {
for len in 0..200 {
let mut items: Vec<u32> = (0..len).map(|i| (i * 173 + 31) % 37).collect();
let mut expected = items.clone();
expected.sort_unstable();
sort_unstable_by(&mut items, Ord::cmp);
assert_eq!(items, expected);
}
}
#[test]
fn insertion_sort_is_stable() {
for len in 0..64 {
let mut items: Vec<(u32, u32)> = (0..len).map(|i| ((i * 7 + 3) % 5, i)).collect();
let mut expected = items.clone();
expected.sort_by_key(|item| item.0);
stable_sort_by(&mut items, |a, b| a.0.cmp(&b.0));
assert_eq!(items, expected);
}
}
}