use core::mem::{self, MaybeUninit};
use core::{ptr, slice};
use super::key::IntegerKey;
use super::tim::Buffer;
pub fn counting<T: IntegerKey>(arr: &mut [T]) {
let len = arr.len();
if len < 2 {
return;
}
if in_order(arr, |x, y| y < x) {
range(arr[0], arr[len - 1], len, SORT);
return;
}
if in_order(arr, |x, y| y > x) {
range(arr[len - 1], arr[0], len, SORT);
arr.reverse();
return;
}
let (min, max) = min_max(arr);
let k = range(min, max, len, SORT);
if len <= u16::MAX as usize {
rewrite::<T, u16>(arr, min, k);
} else if len <= u32::MAX as usize {
rewrite::<T, u32>(arr, min, k);
} else {
rewrite::<T, usize>(arr, min, k);
}
}
pub fn counting_by_key<T, K, F>(arr: &mut [T], mut key: F)
where
K: IntegerKey,
F: FnMut(&T) -> K,
{
let len = arr.len();
if len < 2 || mem::size_of::<T>() == 0 {
return;
}
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let slots = key_slots::<K>(len, &mut stack, &mut heap);
let first = key(&arr[0]);
slots[0].write(first);
let (mut min, mut max, mut prev) = (first, first, first);
let (mut descent, mut no_descent) = (false, false);
for (slot, x) in slots[1..].iter_mut().zip(&arr[1..]) {
let x = key(x);
slot.write(x);
min = min.min(x);
max = max.max(x);
descent |= x < prev;
no_descent |= x >= prev;
prev = x;
}
let keys = unsafe { slice::from_raw_parts(slots.as_ptr().cast::<K>(), len) };
let k = range(min, max, len, SORT);
if !descent {
return;
}
if !no_descent {
arr.reverse();
return;
}
scatter(arr, keys, min, k);
}
const SORT: &str = "counting sort";
const RANGE_MIN: usize = 1 << 16;
const RANGE_PER_ELEMENT: usize = 4;
pub(super) fn range<K: IntegerKey>(min: K, max: K, len: usize, sort: &str) -> usize {
let limit = RANGE_MIN.max(len.saturating_mul(RANGE_PER_ELEMENT));
let distance = max.distance(min);
match usize::try_from(distance) {
Ok(d) if d < limit => d + 1,
_ => panic!(
"{sort}: {} possible values are too many for {len} elements (at most {limit})",
distance.saturating_add(1)
),
}
}
#[inline(always)]
pub(super) fn in_order<T: Copy>(v: &[T], out: impl Fn(T, T) -> bool) -> bool {
const BLOCK: usize = 16;
let mut i = 0;
while i + BLOCK < v.len() {
let b = &v[i..i + BLOCK + 1];
let mut any = false;
for j in 0..BLOCK {
any |= out(b[j], b[j + 1]);
}
if any {
return false;
}
i += BLOCK;
}
v[i..].windows(2).all(|w| !out(w[0], w[1]))
}
const HEAD: usize = 64;
const HEAD_DESCENTS_PART: usize = 16;
#[inline(always)]
pub(super) fn in_order_at_first<T: Copy + Ord>(v: &[T]) -> bool {
let head = &v[..v.len().min(HEAD)];
let descents: usize = head.windows(2).map(|w| usize::from(w[1] < w[0])).sum();
descents * HEAD_DESCENTS_PART <= head.len()
}
#[inline(always)]
pub(super) fn min_max<T: IntegerKey>(v: &[T]) -> (T, T) {
let first = v[0];
v.iter()
.fold((first, first), |(min, max), &x| (min.min(x), max.max(x)))
}
pub(super) unsafe trait Count: Copy + Eq {
const ZERO: Self;
fn add(self, n: usize) -> Self;
fn get(self) -> usize;
}
unsafe impl Count for u32 {
const ZERO: Self = 0;
#[inline(always)]
fn add(self, n: usize) -> Self {
self + n as u32
}
#[inline(always)]
fn get(self) -> usize {
self as usize
}
}
unsafe impl Count for u16 {
const ZERO: Self = 0;
#[inline(always)]
fn add(self, n: usize) -> Self {
self + n as u16
}
#[inline(always)]
fn get(self) -> usize {
self as usize
}
}
unsafe impl Count for usize {
const ZERO: Self = 0;
#[inline(always)]
fn add(self, n: usize) -> Self {
self + n
}
#[inline(always)]
fn get(self) -> usize {
self
}
}
pub(super) const STACK_BYTES: usize = 4096;
#[repr(C, align(16))]
pub(super) struct Stack(pub(super) [MaybeUninit<u8>; STACK_BYTES]);
#[inline(always)]
pub(super) fn counters<'a, C: Count>(
len: usize,
stack: &'a mut Stack,
heap: &'a mut Vec<C>,
) -> &'a mut [C] {
if len <= STACK_BYTES / mem::size_of::<C>() {
let p = stack.0.as_mut_ptr().cast::<C>();
unsafe {
ptr::write_bytes(p, 0, len);
slice::from_raw_parts_mut(p, len)
}
} else {
*heap = vec![C::ZERO; len];
heap
}
}
#[inline(always)]
pub(super) fn key_slots<'a, K: Copy>(
len: usize,
stack: &'a mut Stack,
heap: &'a mut Vec<K>,
) -> &'a mut [MaybeUninit<K>] {
const { assert!(mem::align_of::<K>() <= mem::align_of::<Stack>()) };
if len <= STACK_BYTES / mem::size_of::<K>().max(1) {
unsafe { slice::from_raw_parts_mut(stack.0.as_mut_ptr().cast(), len) }
} else {
*heap = Vec::with_capacity(len);
&mut heap.spare_capacity_mut()[..len]
}
}
const TABLES_MAX_RANGE: usize = 2048;
const TABLES_MIN_PER_VALUE: usize = 16;
const TABLES: usize = 8;
const SPARSE_PER_ELEMENT: usize = 32;
#[inline(never)]
pub(super) fn rewrite<T: IntegerKey, C: Count>(arr: &mut [T], min: T, k: usize) {
let len = arr.len();
let tables = if k <= TABLES_MAX_RANGE && len >= TABLES_MIN_PER_VALUE * k {
TABLES
} else {
1
};
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let counts = counters::<C>(tables * k, &mut stack, &mut heap);
if tables == TABLES {
count::<T, C, TABLES>(arr, min, counts, k);
} else {
count::<T, C, 1>(arr, min, counts, k);
}
let counts = &counts[..k];
if k >= SPARSE_PER_ELEMENT.saturating_mul(len) {
write_sparse(arr, min, counts);
} else if mem::size_of::<T>() <= 2 {
write_ahead::<T, C, 8>(arr, min, counts);
} else {
write_ahead::<T, C, 4>(arr, min, counts);
}
}
#[inline(always)]
fn count<T: IntegerKey, C: Count, const N: usize>(v: &[T], min: T, counts: &mut [C], k: usize) {
const STEP: usize = 8;
debug_assert!(STEP.is_multiple_of(N) && counts.len() == N * k);
let c = counts.as_mut_ptr();
if N == 1 && mem::size_of::<C>() == 2 {
return unsafe { by_quarters(v, min, c) };
}
if N == 1 && v.len() >= QUARTERS_MIN_LEN && in_order_at_first(v) {
return count_by_quarters(v, min, counts);
}
let (chunks, rest) = v.as_chunks::<STEP>();
for chunk in chunks {
for (j, x) in chunk.iter().enumerate() {
unsafe { bump(c.add(j % N * k + x.offset(min))) };
}
}
for x in rest {
unsafe { bump(c.add(x.offset(min))) };
}
if N > 1 {
let (first, rest) = counts.split_at_mut(k);
for table in rest.chunks_exact(k) {
for (sum, &c) in first.iter_mut().zip(table) {
*sum = sum.add(c.get());
}
}
}
}
#[inline(always)]
pub(super) fn exclusive_scan<C: Count>(counts: &mut [C]) {
let mut sum = 0;
let (chunks, rest) = counts.as_chunks_mut::<4>();
for chunk in chunks {
let [a, b, c, d] = chunk.map(|c| c.get());
let (ab, abc) = (a + b, a + b + c);
*chunk = [sum, sum + a, sum + ab, sum + abc].map(|s| C::ZERO.add(s));
sum += abc + d;
}
for c in rest {
let count = c.get();
*c = C::ZERO.add(sum);
sum += count;
}
}
#[inline(always)]
pub(super) fn places4(b: [usize; 4], next: [usize; 4]) -> [usize; 4] {
[
next[0],
next[1] + usize::from(b[1] == b[0]),
next[2] + usize::from(b[2] == b[0]) + usize::from(b[2] == b[1]),
next[3] + usize::from(b[3] == b[0]) + usize::from(b[3] == b[1]) + usize::from(b[3] == b[2]),
]
}
const QUARTERS_MIN_LEN: usize = 1024;
#[inline(never)]
fn count_by_quarters<T: IntegerKey, C: Count>(v: &[T], min: T, counts: &mut [C]) {
unsafe { by_quarters(v, min, counts.as_mut_ptr()) }
}
#[inline(always)]
unsafe fn by_quarters<T: IntegerKey, C: Count>(v: &[T], min: T, c: *mut C) {
let quarter = v.len() / 4;
let (a, rest) = v.split_at(quarter);
let (b, rest) = rest.split_at(quarter);
let (d, rest) = rest.split_at(quarter);
let (e, rest) = rest.split_at(quarter);
for (((a, b), d), e) in a.iter().zip(b).zip(d).zip(e) {
for x in [a, b, d, e] {
unsafe { bump(c.add(x.offset(min))) };
}
}
for x in rest {
unsafe { bump(c.add(x.offset(min))) };
}
}
#[inline(always)]
pub(super) unsafe fn bump<C: Count>(c: *mut C) -> usize {
unsafe {
let before = *c;
*c = before.add(1);
before.get()
}
}
#[inline(always)]
fn write_ahead<T: IntegerKey, C: Count, const W: usize>(v: &mut [T], min: T, counts: &[C]) {
let len = v.len();
let base = v.as_mut_ptr();
let mut pos = 0;
let mut o = 0;
while o < counts.len() && pos + W <= len {
let c = counts[o].get();
let x = T::nth(min, o);
unsafe {
for j in 0..W {
base.add(pos + j).write(x);
}
if c > W {
slice::from_raw_parts_mut(base.add(pos + W), c - W).fill(x);
}
}
pos += c;
o += 1;
}
for (o, &c) in counts.iter().enumerate().skip(o) {
let c = c.get();
v[pos..pos + c].fill(T::nth(min, o));
pos += c;
}
}
#[inline(always)]
fn write_sparse<T: IntegerKey, C: Count>(v: &mut [T], min: T, counts: &[C]) {
const BLOCK: usize = 8;
let mut pos = 0;
let (blocks, rest) = counts.as_chunks::<BLOCK>();
let mut o = 0;
for block in blocks {
if block.iter().fold(false, |any, &c| any | (c != C::ZERO)) {
for (j, &c) in block.iter().enumerate() {
let c = c.get();
v[pos..pos + c].fill(T::nth(min, o + j));
pos += c;
}
}
o += BLOCK;
}
for (j, &c) in rest.iter().enumerate() {
let c = c.get();
v[pos..pos + c].fill(T::nth(min, o + j));
pos += c;
}
}
const SEGMENTS: usize = 8;
const SEGMENTS_MAX_RANGE: usize = 256;
const SEGMENTS_MIN_PER_KEY: usize = 16;
pub(super) fn scatter<T, K: IntegerKey>(arr: &mut [T], keys: &[K], min: K, k: usize) {
let len = arr.len();
let segments = k <= SEGMENTS_MAX_RANGE && len >= SEGMENTS_MIN_PER_KEY * k;
if !segments && len <= u16::MAX as usize {
scatter_in::<T, K, u16>(arr, keys, min, k, 1);
} else if len <= u32::MAX as usize {
scatter_in::<T, K, u32>(arr, keys, min, k, if segments { SEGMENTS } else { 1 });
} else {
scatter_in::<T, K, usize>(arr, keys, min, k, if segments { SEGMENTS } else { 1 });
}
}
fn scatter_in<T, K: IntegerKey, C: Count>(
arr: &mut [T],
keys: &[K],
min: K,
k: usize,
segments: usize,
) {
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let next = counters::<C>(segments * k, &mut stack, &mut heap);
if segments == SEGMENTS {
place::<T, K, C, SEGMENTS>(arr, keys, min, k, next);
} else {
place::<T, K, C, 1>(arr, keys, min, k, next);
}
}
#[inline(always)]
fn place<T, K: IntegerKey, C: Count, const S: usize>(
arr: &mut [T],
keys: &[K],
min: K,
k: usize,
next: &mut [C],
) {
let len = arr.len();
let seg = len / S;
let tail = S * seg;
let next = next.as_mut_ptr();
let keys = keys.as_ptr();
let (quarters, quarter) = if S == 1 { (4, len / 4) } else { (S, seg) };
for i in 0..quarter {
for q in 0..quarters {
unsafe {
let t = if S == 1 { 0 } else { q };
bump(next.add(t * k + (*keys.add(q * quarter + i)).offset(min)));
}
}
}
for i in quarters * quarter..len {
unsafe { bump(next.add((S - 1) * k + (*keys.add(i)).offset(min))) };
}
if S == 1 {
exclusive_scan(unsafe { slice::from_raw_parts_mut(next, k) });
} else {
let mut sum = 0;
for o in 0..k {
for s in 0..S {
unsafe {
let c = next.add(s * k + o);
let count = (*c).get();
*c = C::ZERO.add(sum);
sum += count;
}
}
}
}
let mut buf = Buffer::<T>::new(len);
let dst = buf.get();
let base = arr.as_ptr();
if S == 1 {
let mut i = 0;
while i + 4 <= len {
unsafe {
let b = [0, 1, 2, 3].map(|j| (*keys.add(i + j)).offset(min));
let p = places4(b, b.map(|b| (*next.add(b)).get()));
for j in 0..4 {
*next.add(b[j]) = C::ZERO.add(p[j] + 1);
}
for (j, &p) in p.iter().enumerate() {
ptr::copy_nonoverlapping(base.add(i + j), dst.add(p), 1);
}
}
i += 4;
}
for i in i..len {
unsafe {
let pos = bump(next.add((*keys.add(i)).offset(min)));
ptr::copy_nonoverlapping(base.add(i), dst.add(pos), 1);
}
}
unsafe { ptr::copy_nonoverlapping(dst, arr.as_mut_ptr(), len) };
return;
}
for i in 0..seg {
for s in 0..S {
unsafe {
let j = s * seg + i;
let pos = bump(next.add(s * k + (*keys.add(j)).offset(min)));
ptr::copy_nonoverlapping(base.add(j), dst.add(pos), 1);
}
}
}
for i in tail..len {
unsafe {
let pos = bump(next.add((S - 1) * k + (*keys.add(i)).offset(min)));
ptr::copy_nonoverlapping(base.add(i), dst.add(pos), 1);
}
}
unsafe { ptr::copy_nonoverlapping(dst, arr.as_mut_ptr(), len) };
}