struct LessSwap<'a, T, L> {
data: &'a mut [T],
less: L,
}
struct ImmutableLessSwap<'a, T, L> {
data: &'a [T],
less: L,
}
impl<'a, T, L> IndexSort for ImmutableLessSwap<'a, T, L>
where
L: Fn(usize, usize) -> bool,
{
fn len(&self) -> usize {
self.data.len()
}
fn swap(&mut self, _i: usize, _j: usize) {
unreachable!()
}
fn less(&self, i: usize, j: usize) -> bool {
(self.less)(i, j)
}
}
impl<'a, T, L> IndexSort for LessSwap<'a, T, L>
where
L: Fn(&[T], usize, usize) -> bool,
{
fn len(&self) -> usize {
self.data.len()
}
fn swap(&mut self, i: usize, j: usize) {
self.data.swap(i, j);
}
fn less(&self, i: usize, j: usize) -> bool {
(self.less)(self.data, i, j)
}
}
pub trait SliceSortExt {
type Item;
#[inline]
fn sort_slice<L>(data: &mut [Self::Item], less: L)
where
L: Fn(&[Self::Item], usize, usize) -> bool,
{
let mut sorter = LessSwap { data, less };
sorter.sort()
}
#[inline]
fn sort_slice_stable<L>(data: &mut [Self::Item], less: L)
where
L: Fn(&[Self::Item], usize, usize) -> bool,
{
let mut sorter = LessSwap { data, less };
sorter.sort_stable()
}
#[inline]
fn slice_is_sorted<L>(data: &[Self::Item], less: L) -> bool
where
L: Fn(usize, usize) -> bool,
{
let sorter = ImmutableLessSwap { data, less };
sorter.is_sorted()
}
}
impl<T> SliceSortExt for T {
type Item = T;
}
#[inline]
pub fn sort_slice<T, L>(data: &mut [T], less: L)
where
L: Fn(&[T], usize, usize) -> bool,
{
let mut sorter = LessSwap { data, less };
sorter.sort()
}
#[inline]
pub fn sort_slice_stable<T, L>(data: &mut [T], less: L)
where
L: Fn(&[T], usize, usize) -> bool,
{
let mut sorter = LessSwap { data, less };
sorter.sort_stable()
}
#[inline]
pub fn slice_is_sorted<T, L>(data: &[T], less: L) -> bool
where
L: Fn(usize, usize) -> bool,
{
let sorter = ImmutableLessSwap { data, less };
sorter.is_sorted()
}
struct Reverse<'a, T>(&'a mut T);
impl<'a, T: IndexSort> IndexSort for Reverse<'a, T> {
fn len(&self) -> usize {
self.0.len()
}
fn swap(&mut self, i: usize, j: usize) {
self.0.swap(i, j);
}
fn less(&self, i: usize, j: usize) -> bool {
self.0.less(j, i)
}
}
struct ImmutableReverse<'a, T>(&'a T);
impl<'a, T: IndexSort> IndexSort for ImmutableReverse<'a, T> {
fn len(&self) -> usize {
self.0.len()
}
fn swap(&mut self, _i: usize, _j: usize) {
unreachable!()
}
fn less(&self, i: usize, j: usize) -> bool {
self.0.less(j, i)
}
}
#[allow(clippy::len_without_is_empty)]
pub trait IndexSort {
fn len(&self) -> usize;
fn less(&self, i: usize, j: usize) -> bool;
fn swap(&mut self, i: usize, j: usize);
#[inline]
fn sort(&mut self)
where
Self: Sized,
{
let n = self.len();
quick_sort(self, 0, n, max_depth(n));
}
#[inline]
fn sort_stable(&mut self)
where
Self: Sized,
{
let n = self.len();
stable(self, n);
}
#[inline]
fn is_sorted(&self) -> bool {
let len = self.len();
let n = (len >> 1) + 1;
for i in 1..n {
if self.less(i, i - 1) {
return false;
}
let tail_off = len - i;
if self.less(tail_off, tail_off - 1) {
return false;
}
}
true
}
#[inline]
fn is_reverse_sorted(&self) -> bool {
let n = self.len();
for i in (1..n).rev() {
if self.less(i - 1, i) {
return false;
}
}
true
}
#[inline]
fn sort_reverse(&mut self)
where
Self: Sized,
{
let n = self.len();
quick_sort(&mut Reverse(self), 0, n, max_depth(n));
}
#[inline]
fn sort_stable_reverse(&mut self)
where
Self: Sized,
{
let n = self.len();
stable(&mut Reverse(self), n);
}
}
#[inline]
fn __swap_slice<T>(data: &mut [T], i: usize, j: usize) {
data.swap(i, j)
}
#[inline]
const fn __slice_len<T>(data: &[T]) -> usize {
data.len()
}
#[cfg(feature = "alloc")]
impl<T: PartialOrd + core::fmt::Debug> IndexSort for ::alloc::vec::Vec<T> {
fn len(&self) -> usize {
__slice_len(self)
}
fn less(&self, i: usize, j: usize) -> bool {
self[i] < self[j]
}
fn swap(&mut self, i: usize, j: usize) {
__swap_slice(self, i, j);
}
}
impl<'a, T: PartialOrd + core::fmt::Debug> IndexSort for &'a mut [T] {
fn len(&self) -> usize {
__slice_len(self)
}
fn less(&self, i: usize, j: usize) -> bool {
self[i] < self[j]
}
fn swap(&mut self, i: usize, j: usize) {
__swap_slice(self, i, j);
}
}
impl<const N: usize, T: PartialOrd + core::fmt::Debug> IndexSort for [T; N] {
fn len(&self) -> usize {
__slice_len(self)
}
fn less(&self, i: usize, j: usize) -> bool {
self[i] < self[j]
}
fn swap(&mut self, i: usize, j: usize) {
__swap_slice(self, i, j);
}
}
#[cfg(feature = "alloc")]
impl<T: PartialOrd + core::fmt::Debug> IndexSort for ::alloc::boxed::Box<[T]> {
fn len(&self) -> usize {
__slice_len(self)
}
fn less(&self, i: usize, j: usize) -> bool {
self[i] < self[j]
}
fn swap(&mut self, i: usize, j: usize) {
__swap_slice(self, i, j);
}
}
#[inline]
fn insertion_sort(data: &mut impl IndexSort, a: usize, b: usize) {
for i in a + 1..b {
let mut j = i;
while j > a && data.less(j, j - 1) {
data.swap(j, j - 1);
j -= 1;
}
}
}
#[inline]
fn sift_down(data: &mut impl IndexSort, lo: usize, hi: usize, first: usize) {
let mut root = lo;
loop {
let mut child = 2 * root + 1;
if child >= hi {
break;
}
if child + 1 < hi && data.less(first + child, first + child + 1) {
child += 1;
}
if !data.less(first + root, first + child) {
return;
}
data.swap(first + root, first + child);
root = child;
}
}
#[inline]
fn heap_sort(data: &mut impl IndexSort, a: usize, b: usize) {
let first = a;
let lo = 0;
let hi = b - a;
let mut i = (hi - 1) / 2;
loop {
sift_down(data, i, hi, first);
match i.checked_sub(1) {
Some(v) => i = v,
None => break,
}
}
let mut i = hi - 1;
loop {
data.swap(first, first + i);
sift_down(data, lo, i, first);
match i.checked_sub(1) {
Some(v) => i = v,
None => break,
}
}
}
#[inline]
fn median_of_three(data: &mut impl IndexSort, m1: usize, m0: usize, m2: usize) {
if data.less(m1, m0) {
data.swap(m1, m0);
}
if data.less(m2, m1) {
data.swap(m2, m1);
if data.less(m1, m0) {
data.swap(m1, m0);
}
}
}
#[inline]
fn swap_range(data: &mut impl IndexSort, a: usize, b: usize, n: usize) {
for i in 0..n {
data.swap(a + i, b + i);
}
}
#[inline]
fn do_pivot(data: &mut impl IndexSort, lo: usize, hi: usize) -> (usize, usize) {
let m = (lo + hi) >> 1;
if hi - lo > 40 {
let s = (hi - lo) / 8;
median_of_three(data, lo, lo + s, lo + 2 * s);
median_of_three(data, m, m - s, m + s);
median_of_three(data, hi - 1, hi - 1 - s, hi - 1 - 2 * s);
}
median_of_three(data, lo, m, hi - 1);
let pivot = lo;
let (mut a, mut c) = (lo + 1, hi - 1);
while a < c && data.less(a, pivot) {
a += 1;
}
let mut b = a;
loop {
while b < c && !data.less(pivot, b) {
b += 1;
}
while b < c && data.less(pivot, c - 1) {
c -= 1;
}
if b >= c {
break;
}
data.swap(b, c - 1);
b += 1;
c -= 1;
}
let mut protect = hi - c < 5;
if !protect && hi - c < (hi - lo) / 4 {
let mut dups = 0;
if !data.less(pivot, hi - 1) {
data.swap(c, hi - 1);
c += 1;
dups += 1;
}
if !data.less(b - 1, pivot) {
b -= 1;
dups += 1;
}
if !data.less(m, pivot) {
data.swap(m, b - 1);
b -= 1;
dups += 1;
}
protect = dups > 1;
}
if protect {
loop {
while a < b && !data.less(b - 1, pivot) {
b -= 1;
}
while a < b && data.less(a, pivot) {
a += 1;
}
if a >= b {
break;
}
data.swap(a, b - 1);
a += 1;
b -= 1;
}
}
data.swap(pivot, b - 1);
(b - 1, c)
}
#[inline]
fn quick_sort(data: &mut impl IndexSort, mut a: usize, mut b: usize, mut max_depth: usize) {
while b - a > 12 {
if max_depth == 0 {
heap_sort(data, a, b);
return;
}
max_depth -= 1;
let (mlo, mhi) = do_pivot(data, a, b);
if mlo - a < b - mhi {
quick_sort(data, a, mlo, max_depth);
a = mhi; } else {
quick_sort(data, mhi, b, max_depth);
b = mlo; }
}
if b - a > 1 {
for i in a + 6..b {
if data.less(i, i - 6) {
data.swap(i, i - 6);
}
}
insertion_sort(data, a, b)
}
}
#[inline]
fn stable(data: &mut impl IndexSort, n: usize) {
let mut block_size = 5;
let (mut a, mut b) = (0, block_size);
while b <= n {
insertion_sort(data, a, b);
a = b;
b += block_size;
}
insertion_sort(data, a, n);
while block_size < n {
a = 0;
b = 2 * block_size;
while b <= n {
syn_merge(data, a, a + block_size, b);
a = b;
b += 2 * block_size;
}
let m = a + block_size;
if m < n {
syn_merge(data, a, m, n);
}
block_size *= 2;
}
}
#[inline]
fn syn_merge(data: &mut impl IndexSort, a: usize, m: usize, b: usize) {
if m - a == 1 {
let mut i = m;
let mut j = b;
while i < j {
let h = (i + j) >> 1;
if data.less(h, a) {
i = h + 1;
} else {
j = h;
}
}
for k in a..i - 1 {
data.swap(k, k + 1);
}
return;
}
if b - m == 1 {
let mut i = a;
let mut j = m;
while i < j {
let h = (i + j) >> 1;
if !data.less(m, h) {
i = h + 1;
} else {
j = h;
}
}
let mut k = m;
while k > i {
data.swap(k, k - 1);
k -= 1;
}
return;
}
let mid = (a + b) >> 1;
let n = mid + m;
let (mut start, mut r) = if m > mid { (n - b, mid) } else { (a, m) };
let p = n - 1;
while start < r {
let c = (start + r) >> 1;
if !data.less(p - c, c) {
start = c + 1;
} else {
r = c;
}
}
let end = n - start;
if start < m && m < end {
rotate(data, start, m, end);
}
if a < start && start < mid {
syn_merge(data, a, start, mid);
}
if mid < end && end < b {
syn_merge(data, mid, end, b);
}
}
#[inline]
fn rotate(data: &mut impl IndexSort, a: usize, m: usize, b: usize) {
let mut i = m - a;
let mut j = b - m;
while i != j {
if i > j {
swap_range(data, m - i, m, j);
i -= j;
} else {
swap_range(data, m - i, m + j - i, i);
j -= i;
}
}
swap_range(data, m - i, m, i);
}
#[inline]
fn max_depth(n: usize) -> usize {
let mut depth = 0;
let mut i = n;
while i > 0 {
depth += 1;
i >>= 1;
}
depth * 2
}
#[inline]
pub fn sort(data: &mut impl IndexSort) {
let n = data.len();
quick_sort(data, 0, n, max_depth(n));
}
#[inline]
pub fn sort_stable(data: &mut impl IndexSort) {
let n = data.len();
stable(data, n);
}
#[inline]
pub fn sort_reverse(data: &mut impl IndexSort) {
let n = data.len();
quick_sort(&mut Reverse(data), 0, n, max_depth(n));
}
#[inline]
pub fn sort_stable_reverse(data: &mut impl IndexSort) {
let n = data.len();
stable(&mut Reverse(data), n);
}
#[inline]
pub fn search<F>(n: usize, mut f: F) -> usize
where
F: FnMut(usize) -> bool,
{
let mut i = 0;
let mut j = n;
while i < j {
let h = (i + j) >> 1;
if !f(h) {
i = h + 1;
} else {
j = h;
}
}
i
}