use core::mem::{self, MaybeUninit};
use core::ptr;
use super::insertion;
pub fn merge<T: Ord>(arr: &mut [T]) {
let len = arr.len();
let size = mem::size_of::<T>();
if size > 0 && len <= STACK_BYTES / size {
let mut stack = StackBuffer::<T> {
_align: [],
bytes: [MaybeUninit::uninit(); STACK_BYTES],
};
sort(arr, stack.bytes.as_mut_ptr().cast::<T>());
return;
}
if len <= RUN {
insertion(arr);
return;
}
let mut buf: Vec<T> = Vec::with_capacity(len);
sort(arr, buf.as_mut_ptr());
}
const RUN: usize = 8;
const STACK_BYTES: usize = 4096;
#[repr(C)]
struct StackBuffer<T> {
_align: [T; 0],
bytes: [MaybeUninit<u8>; STACK_BYTES],
}
fn sort<T: Ord>(v: &mut [T], buf: *mut T) {
let len = v.len();
if len <= RUN {
unsafe { sort_run(v, buf) };
return;
}
let mid = len / 2;
let (left, right) = v.split_at_mut(mid);
sort(left, buf);
sort(right, buf);
unsafe { merge_halves(v, buf) }
}
unsafe fn sort_run<T: Ord>(v: &mut [T], buf: *mut T) {
if v.windows(2).all(|w| w[1] >= w[0]) {
return;
}
let len = v.len();
let mid = len / 2;
let src = v.as_mut_ptr();
unsafe {
if len <= 4 {
sort_at_most_4(src, len, buf);
ptr::copy_nonoverlapping(buf, src, len);
return;
}
sort_at_most_4(src, mid, buf);
sort_at_most_4(src.add(mid), len - mid, buf.add(mid));
merge_from_buffer(buf, src, len);
}
}
unsafe fn merge_halves<T: Ord>(v: &mut [T], buf: *mut T) {
let len = v.len();
let mid = len / 2;
if v[mid] >= v[mid - 1] {
return;
}
if v[len - 1] < v[0] {
let dst = v.as_mut_ptr();
unsafe {
ptr::copy_nonoverlapping(dst, buf, mid);
ptr::copy(dst.add(mid), dst, len - mid);
ptr::copy_nonoverlapping(buf, dst.add(len - mid), mid);
}
return;
}
let dst = v.as_mut_ptr();
unsafe {
ptr::copy_nonoverlapping(dst, buf, len);
merge_from_buffer(buf, dst, len);
}
}
unsafe fn merge_from_buffer<T: Ord>(buf: *mut T, dst: *mut T, len: usize) {
let mid = len / 2;
unsafe {
let restore = Restore { src: buf, dst, len };
let (mut left, mut right) = (0, mid);
let (mut left_end, mut right_end) = (mid, len);
for i in 0..mid {
let take_right = *buf.add(right) < *buf.add(left);
let src = buf.add(if take_right { right } else { left });
ptr::copy_nonoverlapping(src, dst.add(i), 1);
right += usize::from(take_right);
left += usize::from(!take_right);
let (last_left, last_right) = (left_end - 1, right_end - 1);
let take_left = *buf.add(last_right) < *buf.add(last_left);
let src = buf.add(if take_left { last_left } else { last_right });
ptr::copy_nonoverlapping(src, dst.add(len - 1 - i), 1);
left_end -= usize::from(take_left);
right_end -= usize::from(!take_left);
}
if len % 2 == 1 {
let take_left =
left < left_end && !(right < right_end && *buf.add(right) < *buf.add(left));
let src = buf.add(if take_left { left } else { right });
ptr::copy_nonoverlapping(src, dst.add(mid), 1);
left += usize::from(take_left);
right += usize::from(!take_left);
}
if left == left_end && right == right_end {
mem::forget(restore);
}
}
}
#[inline(always)]
unsafe fn sort_at_most_4<T: Ord>(src: *const T, len: usize, dst: *mut T) {
unsafe {
match len {
0 => {}
1 => ptr::copy_nonoverlapping(src, dst, 1),
2 => {
let swap = *src.add(1) < *src;
ptr::copy_nonoverlapping(src.add(usize::from(swap)), dst, 1);
ptr::copy_nonoverlapping(src.add(usize::from(!swap)), dst.add(1), 1);
}
3 => {
let swap = *src.add(1) < *src;
let (lo, hi) = (src.add(usize::from(swap)), src.add(usize::from(!swap)));
let last = src.add(2);
let before_hi = *last < *hi;
let before_lo = before_hi & (*last < *lo);
let first = if before_lo { last } else { lo };
let second = if before_lo {
lo
} else if before_hi {
last
} else {
hi
};
let third = if before_hi { hi } else { last };
ptr::copy_nonoverlapping(first, dst, 1);
ptr::copy_nonoverlapping(second, dst.add(1), 1);
ptr::copy_nonoverlapping(third, dst.add(2), 1);
}
_ => {
let swap_left = *src.add(1) < *src;
let swap_right = *src.add(3) < *src.add(2);
let a = src.add(usize::from(swap_left));
let b = src.add(usize::from(!swap_left));
let c = src.add(2 + usize::from(swap_right));
let d = src.add(2 + usize::from(!swap_right));
let c_first = *c < *a;
let b_last = *d < *b;
let min = if c_first { c } else { a };
let max = if b_last { b } else { d };
let unknown_left = if c_first {
a
} else if b_last {
c
} else {
b
};
let unknown_right = if b_last {
d
} else if c_first {
b
} else {
c
};
let swap_middle = *unknown_right < *unknown_left;
let lo = if swap_middle {
unknown_right
} else {
unknown_left
};
let hi = if swap_middle {
unknown_left
} else {
unknown_right
};
ptr::copy_nonoverlapping(min, dst, 1);
ptr::copy_nonoverlapping(lo, dst.add(1), 1);
ptr::copy_nonoverlapping(hi, dst.add(2), 1);
ptr::copy_nonoverlapping(max, dst.add(3), 1);
}
}
}
}
struct Restore<T> {
src: *const T,
dst: *mut T,
len: usize,
}
impl<T> Drop for Restore<T> {
fn drop(&mut self) {
unsafe { ptr::copy_nonoverlapping(self.src, self.dst, self.len) }
}
}