use core::mem::{self, MaybeUninit};
use core::{hint, 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();
let base = v.as_mut_ptr();
unsafe {
if !sort_where(base, buf, len, true) {
ptr::copy_nonoverlapping(buf, base, len);
}
}
}
unsafe fn sort_where<T: Ord>(v: *mut T, buf: *mut T, len: usize, in_v: bool) -> bool {
unsafe {
if is_leaf::<T>(len) {
return sort_leaf(v, buf, len, in_v);
}
sort_node(v, buf, len, in_v)
}
}
#[inline(always)]
fn is_leaf<T>(len: usize) -> bool {
if mem::size_of::<T>() <= PINGPONG_SIZE {
len <= PINGPONG_MAX
} else {
len <= RUN
}
}
#[inline(always)]
unsafe fn sort_leaf<T: Ord>(v: *mut T, buf: *mut T, len: usize, in_v: bool) -> bool {
unsafe {
if mem::size_of::<T>() <= PINGPONG_SIZE {
let descents = descents(slice::from_raw_parts(v, len));
if descents == 0 {
return true;
}
if descents == (u64::MAX >> (PINGPONG_MAX - len)) & !1 {
slice::from_raw_parts_mut(v, len).reverse();
return true;
}
if in_v {
pingpong::<T, true>(v, len, buf, descents);
} else {
pingpong::<T, false>(v, len, buf, descents);
}
return in_v;
}
sort_run::<T, true>(slice::from_raw_parts_mut(v, len), buf);
true
}
}
unsafe fn sort_node<T: Ord>(v: *mut T, buf: *mut T, len: usize, in_v: bool) -> bool {
unsafe {
let half = |v: *mut T, buf: *mut T, len: usize| {
if is_leaf::<T>(len) {
sort_leaf(v, buf, len, !in_v)
} else {
sort_node(v, buf, len, !in_v)
}
};
let mid = len / 2;
let left_in_v = half(v, buf, mid);
let mut restore = Restore {
src: buf,
dst: v,
len: if left_in_v { 0 } else { mid },
};
let right_in_v = half(v.add(mid), buf.add(mid), len - mid);
let halves_in_v = if left_in_v == right_in_v {
left_in_v
} else {
!in_v
};
if left_in_v != halves_in_v {
if halves_in_v {
ptr::copy_nonoverlapping(buf, v, mid);
} else {
ptr::copy_nonoverlapping(v, buf, mid);
}
}
if right_in_v != halves_in_v {
if halves_in_v {
ptr::copy_nonoverlapping(buf.add(mid), v.add(mid), len - mid);
} else {
ptr::copy_nonoverlapping(v.add(mid), buf.add(mid), len - mid);
}
}
let (src, dst) = if halves_in_v { (v, buf) } else { (buf, v) };
restore.len = if halves_in_v { 0 } else { len };
if *src.add(mid) >= *src.add(mid - 1) {
mem::forget(restore);
return halves_in_v;
}
if *src.add(len - 1) < *src {
mem::forget(restore);
ptr::copy_nonoverlapping(src.add(mid), dst, len - mid);
ptr::copy_nonoverlapping(src, dst.add(len - mid), mid);
return !halves_in_v;
}
mem::forget(restore);
merge_from_buffer(src, dst, len);
!halves_in_v
}
}
const PINGPONG_SIZE: usize = 8;
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 len >= SPLIT_MIN {
merge_split(src, dst, len);
} else if mem::size_of::<T>() <= TRACKED_MAX_SIZE {
merge_tracked(src, dst, len);
} else {
merge_checked(src, dst, len);
}
}
}
const SPLIT_MIN: usize = 128;
const SELECT_ADVANCE_MAX_SIZE: usize = 8;
#[inline(always)]
unsafe fn advance<T>(p: *const T, cond: bool) -> *const T {
unsafe {
if mem::size_of::<T>() <= SELECT_ADVANCE_MAX_SIZE {
hint::select_unpredictable(cond, p.add(1), p)
} else {
p.add(usize::from(cond))
}
}
}
#[inline(always)]
unsafe fn retreat<T>(p: *const T, cond: bool) -> *const T {
unsafe {
if mem::size_of::<T>() <= SELECT_ADVANCE_MAX_SIZE {
hint::select_unpredictable(cond, p.sub(1), p)
} else {
p.sub(usize::from(cond))
}
}
}
struct Part<T> {
a: *const T,
a_end: *const T,
b: *const T,
b_end: *const T,
out: *mut T,
out_end: *mut T,
}
impl<T: Ord> Part<T> {
#[inline(always)]
unsafe fn safe(&self) -> usize {
unsafe {
self.a_end
.offset_from_unsigned(self.a)
.min(self.b_end.offset_from_unsigned(self.b))
/ 2
}
}
#[inline(always)]
unsafe fn step(&mut self) {
unsafe {
let take_b = *self.b < *self.a;
let src = hint::select_unpredictable(take_b, self.b, self.a);
ptr::copy_nonoverlapping(src, self.out, 1);
self.out = self.out.add(1);
self.b = advance(self.b, take_b);
self.a = advance(self.a, !take_b);
let (last_a, last_b) = (self.a_end.sub(1), self.b_end.sub(1));
let take_a = *last_b < *last_a;
self.out_end = self.out_end.sub(1);
let src = hint::select_unpredictable(take_a, last_a, last_b);
ptr::copy_nonoverlapping(src, self.out_end, 1);
self.a_end = retreat(self.a_end, take_a);
self.b_end = retreat(self.b_end, !take_a);
}
}
#[inline(always)]
unsafe fn finish(mut self) {
unsafe {
loop {
let n = self.safe();
if n == 0 {
break;
}
for _ in 0..n {
self.step();
}
}
let rest_a = self.a_end.offset_from_unsigned(self.a);
let rest_b = self.b_end.offset_from_unsigned(self.b);
if rest_a == 1 && rest_b > 0 {
let (mut lo, mut hi) = (0, rest_b);
while lo < hi {
let m = lo + (hi - lo) / 2;
if *self.b.add(m) < *self.a {
lo = m + 1;
} else {
hi = m;
}
}
ptr::copy_nonoverlapping(self.b, self.out, lo);
ptr::copy_nonoverlapping(self.a, self.out.add(lo), 1);
ptr::copy_nonoverlapping(self.b.add(lo), self.out.add(lo + 1), rest_b - lo);
} else if rest_b == 1 && rest_a > 0 {
let (mut lo, mut hi) = (0, rest_a);
while lo < hi {
let m = lo + (hi - lo) / 2;
if *self.a.add(m) <= *self.b {
lo = m + 1;
} else {
hi = m;
}
}
ptr::copy_nonoverlapping(self.a, self.out, lo);
ptr::copy_nonoverlapping(self.b, self.out.add(lo), 1);
ptr::copy_nonoverlapping(self.a.add(lo), self.out.add(lo + 1), rest_a - lo);
} else {
ptr::copy_nonoverlapping(self.a, self.out, rest_a);
ptr::copy_nonoverlapping(self.b, self.out.add(rest_a), rest_b);
}
}
}
}
unsafe fn merge_split<T: Ord>(src: *const T, dst: *mut T, len: usize) {
unsafe {
if len >= SPLIT4_MIN && mem::size_of::<T>() <= SPLIT4_MAX_SIZE {
merge_parts::<T, 4>(src, dst, len)
} else {
merge_parts::<T, 2>(src, dst, len)
}
}
}
const SPLIT4_MAX_SIZE: usize = 32;
const SPLIT4_MIN: usize = 4096;
#[inline(always)]
unsafe fn co_rank<T: Ord>(a: *const T, na: usize, b: *const T, nb: usize, k: usize) -> usize {
let (mut lo, mut hi) = (k.saturating_sub(nb), k.min(na));
unsafe {
while lo < hi {
let m = lo + (hi - lo) / 2;
if *b.add(k - m - 1) >= *a.add(m) {
lo = m + 1;
} else {
hi = m;
}
}
}
lo
}
unsafe fn merge_parts<T: Ord, const P: usize>(src: *const T, dst: *mut T, len: usize) {
let mid = len / 2;
unsafe {
let restore = Restore { src, dst, len };
let a = src;
let b = src.add(mid);
let (na, nb) = (mid, len - mid);
let mut cuts = [(0usize, 0usize); P];
let mut prev = (0, 0);
for (p, cut) in cuts.iter_mut().enumerate().skip(1) {
let k = len * p / P;
let i = co_rank(a, na, b, nb, k).max(prev.0).min(k - prev.1);
*cut = (i, k - i);
prev = *cut;
}
let mut parts: [Part<T>; P] = core::array::from_fn(|p| {
let (i0, j0) = cuts[p];
let (i1, j1) = if p + 1 < P { cuts[p + 1] } else { (na, nb) };
Part {
a: a.add(i0),
a_end: a.add(i1),
b: b.add(j0),
b_end: b.add(j1),
out: dst.add(i0 + j0),
out_end: dst.add(i1 + j1),
}
});
loop {
let mut n = usize::MAX;
for part in &parts {
n = n.min(part.safe());
}
if n == 0 {
break;
}
for _ in 0..n {
for part in &mut parts {
part.step();
}
}
}
for part in parts {
part.finish();
}
mem::forget(restore);
}
}
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) }
}
}