use core::mem::{self, MaybeUninit};
use core::{ptr, slice};
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],
}
pub(super) fn sort<T: Ord>(v: &mut [T], buf: *mut T) {
let len = v.len();
if len <= RUN {
unsafe { sort_run::<T, true>(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) }
}
pub(super) const PINGPONG_MAX: usize = 64;
pub(super) fn descents<T: Ord>(v: &[T]) -> u64 {
debug_assert!(v.len() <= PINGPONG_MAX);
let mut mask = 0u64;
for i in 1..v.len() {
mask |= u64::from(v[i] < v[i - 1]) << i;
}
mask
}
pub(super) unsafe fn sort_pingpong<T: Ord>(v: &mut [T], buf: *mut T, descents: u64) {
debug_assert!(v.len() <= PINGPONG_MAX);
unsafe { pingpong::<T, true>(v.as_mut_ptr(), v.len(), buf, descents) }
}
unsafe fn pingpong<T: Ord, const IN_V: bool>(v: *mut T, len: usize, buf: *mut T, descents: u64) {
unsafe {
if descents == 0 {
if !IN_V {
ptr::copy_nonoverlapping(v, buf, len);
}
return;
}
if len <= RUN {
if IN_V {
sort_run::<T, false>(slice::from_raw_parts_mut(v, len), buf);
return;
}
let mid = len / 2;
if len <= 4 {
sort_at_most_4(v, len, buf);
return;
}
let mut tmp = MaybeUninit::<[T; RUN]>::uninit();
let tmp = tmp.as_mut_ptr().cast::<T>();
sort_at_most_4(v, mid, tmp);
sort_at_most_4(v.add(mid), len - mid, tmp.add(mid));
let restore = Restore {
src: tmp,
dst: v,
len,
};
merge_from_buffer(tmp, buf, len);
mem::forget(restore);
return;
}
let mid = len / 2;
let (left, right) = (descents & ((1u64 << mid) - 1), (descents >> mid) & !1);
if IN_V {
if left == 0 && right == 0 {
merge_halves(slice::from_raw_parts_mut(v, len), buf);
return;
}
pingpong::<T, false>(v, mid, buf, left);
let mut restore = Restore {
src: buf,
dst: v,
len: mid,
};
pingpong::<T, false>(v.add(mid), len - mid, buf.add(mid), right);
restore.len = len;
if *buf.add(mid) >= *buf.add(mid - 1) {
drop(restore);
return;
}
mem::forget(restore);
merge_from_buffer(buf, v, len);
} else {
pingpong::<T, true>(v, mid, buf, left);
pingpong::<T, true>(v.add(mid), len - mid, buf.add(mid), right);
if *v.add(mid) >= *v.add(mid - 1) {
ptr::copy_nonoverlapping(v, buf, len);
return;
}
merge_from_buffer(v, buf, len);
}
}
}
pub(super) unsafe fn sort_run<T: Ord, const SCAN: bool>(v: &mut [T], buf: *mut T) {
if SCAN && 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);
}
}
pub(super) 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);
}
}
const GATHER_MAX: usize = 16;
const TRACKED_MAX_SIZE: usize = 8;
unsafe fn merge_from_buffer<T: Ord>(src: *const T, dst: *mut T, len: usize) {
unsafe {
if len <= GATHER_MAX {
merge_gather(src, dst, len);
} else if mem::size_of::<T>() <= TRACKED_MAX_SIZE {
merge_tracked(src, dst, len);
} else {
merge_checked(src, dst, len);
}
}
}
unsafe fn merge_checked<T: Ord>(src: *const T, dst: *mut T, len: usize) {
let mid = len / 2;
unsafe {
let restore = Restore { src, dst, len };
let (mut left, mut right) = (0, mid);
let (mut left_end, mut right_end) = (mid, len);
let (mut out, mut out_end) = (0, len);
for _ in 0..mid / 2 {
let take_right = *src.add(right) < *src.add(left);
ptr::copy_nonoverlapping(
src.add(if take_right { right } else { left }),
dst.add(out),
1,
);
out += 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 = *src.add(last_right) < *src.add(last_left);
out_end -= 1;
ptr::copy_nonoverlapping(
src.add(if take_left { last_left } else { last_right }),
dst.add(out_end),
1,
);
left_end -= usize::from(take_left);
right_end -= usize::from(!take_left);
}
while left < left_end && right < right_end {
let take_right = *src.add(right) < *src.add(left);
ptr::copy_nonoverlapping(
src.add(if take_right { right } else { left }),
dst.add(out),
1,
);
out += 1;
right += usize::from(take_right);
left += usize::from(!take_right);
if left == left_end || right == right_end {
break;
}
let (last_left, last_right) = (left_end - 1, right_end - 1);
let take_left = *src.add(last_right) < *src.add(last_left);
out_end -= 1;
ptr::copy_nonoverlapping(
src.add(if take_left { last_left } else { last_right }),
dst.add(out_end),
1,
);
left_end -= usize::from(take_left);
right_end -= usize::from(!take_left);
}
let rest_left = left_end - left;
debug_assert_eq!(out + rest_left + (right_end - right), out_end);
ptr::copy_nonoverlapping(src.add(left), dst.add(out), rest_left);
ptr::copy_nonoverlapping(src.add(right), dst.add(out + rest_left), right_end - right);
mem::forget(restore);
}
}
unsafe fn merge_tracked<T: Ord>(src: *const T, dst: *mut T, len: usize) {
let mid = len / 2;
unsafe {
let restore = Restore { src, dst, len };
let (mut left, mut right) = (0, mid);
let (mut left_end, mut right_end) = (mid, len);
let (mut front_left_i, mut front_right_i) = (usize::MAX, usize::MAX);
let (mut back_left_i, mut back_right_i) = (usize::MAX, usize::MAX);
for i in 0..mid {
let take_right = *src.add(right) < *src.add(left);
let from = src.add(if take_right { right } else { left });
ptr::copy_nonoverlapping(from, dst.add(i), 1);
let mask = usize::from(take_right).wrapping_neg();
front_right_i ^= (front_right_i ^ i) & mask;
front_left_i ^= (front_left_i ^ i) & !mask;
right += usize::from(take_right);
left += usize::from(!take_right);
let (last_left, last_right) = (left_end - 1, right_end - 1);
let take_left = *src.add(last_right) < *src.add(last_left);
let from = src.add(if take_left { last_left } else { last_right });
ptr::copy_nonoverlapping(from, dst.add(len - 1 - i), 1);
let mask = usize::from(take_left).wrapping_neg();
back_left_i ^= (back_left_i ^ (len - 1 - i)) & mask;
back_right_i ^= (back_right_i ^ (len - 1 - i)) & !mask;
left_end -= usize::from(take_left);
right_end -= usize::from(!take_left);
}
let mut spare = MaybeUninit::<T>::uninit();
let spare = spare.as_mut_ptr();
let slot = |k: usize| if k == usize::MAX { spare } else { dst.add(k) };
ptr::copy_nonoverlapping(src.add(left.max(1) - 1), slot(front_left_i), 1);
ptr::copy_nonoverlapping(src.add(right - 1), slot(front_right_i), 1);
ptr::copy_nonoverlapping(src.add(left_end), slot(back_left_i), 1);
ptr::copy_nonoverlapping(src.add(right_end.min(len - 1)), slot(back_right_i), 1);
if len % 2 == 1 {
let take_left =
left < left_end && !(right < right_end && *src.add(right) < *src.add(left));
let from = src.add(if take_left { left } else { right });
ptr::copy_nonoverlapping(from, dst.add(mid), 1);
left += usize::from(take_left);
right += usize::from(!take_left);
}
if left == left_end && right == right_end {
mem::forget(restore);
}
}
}
unsafe fn merge_gather<T: Ord>(src: *const T, dst: *mut T, len: usize) {
debug_assert!(len <= GATHER_MAX);
let mid = len / 2;
unsafe {
let restore = Restore { src, dst, len };
let mut order = MaybeUninit::<[u8; GATHER_MAX]>::uninit();
let order = order.as_mut_ptr().cast::<u8>();
let (mut left, mut right) = (0, mid);
let (mut left_end, mut right_end) = (mid, len);
for i in 0..mid {
let take_right = *src.add(right) < *src.add(left);
*order.add(i) = (if take_right { right } else { left }) as u8;
right += usize::from(take_right);
left += usize::from(!take_right);
let (last_left, last_right) = (left_end - 1, right_end - 1);
let take_left = *src.add(last_right) < *src.add(last_left);
*order.add(len - 1 - i) = (if take_left { last_left } else { last_right }) as u8;
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 && *src.add(right) < *src.add(left));
*order.add(mid) = (if take_left { left } else { right }) as u8;
left += usize::from(take_left);
right += usize::from(!take_left);
}
if left == left_end && right == right_end {
for k in 0..len {
ptr::copy_nonoverlapping(src.add(usize::from(*order.add(k))), dst.add(k), 1);
}
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) }
}
}