#![cfg(feature = "alloc")]
use crate::merge_sort::{merge_sort, TimSortRun};
use core::{alloc::Layout, mem};
use ndarray::ArrayViewMut1;
#[cfg(not(feature = "std"))]
extern crate alloc as no_std_alloc;
#[cfg(not(feature = "std"))]
use no_std_alloc::alloc::{alloc, dealloc};
#[cfg(feature = "std")]
use std::alloc::{alloc, dealloc};
#[inline]
pub fn stable_sort<T, F>(v: ArrayViewMut1<'_, T>, mut is_less: F)
where
F: FnMut(&T, &T) -> bool,
{
if mem::size_of::<T>() == 0 {
return;
}
let elem_alloc_fn = |len: usize| -> *mut T {
unsafe { alloc(Layout::array::<T>(len).unwrap_unchecked()) as *mut T }
};
let elem_dealloc_fn = |buf_ptr: *mut T, len: usize| {
unsafe {
dealloc(
buf_ptr as *mut u8,
Layout::array::<T>(len).unwrap_unchecked(),
);
}
};
let run_alloc_fn = |len: usize| -> *mut TimSortRun {
unsafe { alloc(Layout::array::<TimSortRun>(len).unwrap_unchecked()) as *mut TimSortRun }
};
let run_dealloc_fn = |buf_ptr: *mut TimSortRun, len: usize| {
unsafe {
dealloc(
buf_ptr as *mut u8,
Layout::array::<TimSortRun>(len).unwrap_unchecked(),
);
}
};
merge_sort(
v,
&mut is_less,
elem_alloc_fn,
elem_dealloc_fn,
run_alloc_fn,
run_dealloc_fn,
);
}
#[cfg(feature = "std")]
#[cfg(test)]
mod test {
use super::stable_sort;
use core::cmp::Ordering;
use ndarray::Array1;
use quickcheck_macros::quickcheck;
struct Item {
index: usize,
value: u32,
}
impl Eq for Item {}
impl PartialEq for Item {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl Ord for Item {
fn cmp(&self, other: &Self) -> Ordering {
self.value.cmp(&other.value)
}
}
impl PartialOrd for Item {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl From<(usize, u32)> for Item {
fn from((index, value): (usize, u32)) -> Self {
Self { index, value }
}
}
#[quickcheck]
fn stably_sorted(xs: Vec<u32>) {
let xs = xs
.into_iter()
.enumerate()
.map(Item::from)
.collect::<Vec<Item>>();
let mut array = Array1::from_vec(xs);
stable_sort(array.view_mut(), &mut Item::lt);
for i in 1..array.len() {
let [a, b] = [&array[i - 1], &array[i]];
if a.value == b.value {
assert!(a.index < b.index);
} else {
assert!(a.value < b.value);
}
}
}
}