use core::mem::{self, MaybeUninit};
use core::{ptr, slice};
use super::tim::Buffer;
pub fn counting<T: CountingKey>(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);
return;
}
if in_order(arr, |x, y| y > x) {
range(arr[len - 1], arr[0], len);
arr.reverse();
return;
}
let (min, max) = min_max(arr);
let k = range(min, max, len);
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: CountingKey,
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);
if !descent {
return;
}
if !no_descent {
arr.reverse();
return;
}
if len <= u32::MAX as usize {
scatter::<T, K, u32>(arr, keys, min, k);
} else {
scatter::<T, K, usize>(arr, keys, min, k);
}
}
pub trait CountingKey: sealed::Key {}
mod sealed {
pub trait Key: Copy + Ord {
fn distance(self, min: Self) -> u128;
fn offset(self, min: Self) -> usize;
fn nth(min: Self, offset: usize) -> Self;
}
}
macro_rules! integer_key {
($($t:ty => $u:ty),* $(,)?) => {$(
impl sealed::Key for $t {
#[inline(always)]
fn distance(self, min: Self) -> u128 {
(self as $u).wrapping_sub(min as $u) as u128
}
#[inline(always)]
fn offset(self, min: Self) -> usize {
(self as $u).wrapping_sub(min as $u) as usize
}
#[inline(always)]
fn nth(min: Self, offset: usize) -> Self {
(min as $u).wrapping_add(offset as $u) as $t
}
}
impl CountingKey for $t {}
)*};
}
integer_key! {
u8 => u8, u16 => u16, u32 => u32, u64 => u64, u128 => u128, usize => usize,
i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128, isize => usize,
}
impl sealed::Key for char {
#[inline(always)]
fn distance(self, min: Self) -> u128 {
u128::from(self as u32 - min as u32)
}
#[inline(always)]
fn offset(self, min: Self) -> usize {
(self as u32).wrapping_sub(min as u32) as usize
}
#[inline(always)]
fn nth(min: Self, offset: usize) -> Self {
char::from_u32((min as u32).wrapping_add(offset as u32)).unwrap_or(min)
}
}
impl CountingKey for char {}
impl sealed::Key for bool {
#[inline(always)]
fn distance(self, min: Self) -> u128 {
u128::from(self as u8 - min as u8)
}
#[inline(always)]
fn offset(self, min: Self) -> usize {
usize::from(self).wrapping_sub(usize::from(min))
}
#[inline(always)]
fn nth(min: Self, offset: usize) -> Self {
usize::from(min) + offset != 0
}
}
impl CountingKey for bool {}
const RANGE_MIN: usize = 1 << 16;
const RANGE_PER_ELEMENT: usize = 4;
fn range<K: CountingKey>(min: K, max: K, len: usize) -> 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!(
"counting sort: {} possible values are too many for {len} elements (at most {limit})",
distance.saturating_add(1)
),
}
}
#[inline(always)]
fn in_order<T: CountingKey>(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]))
}
#[inline(always)]
fn min_max<T: CountingKey>(v: &[T]) -> (T, T) {
let first = v[0];
v.iter()
.fold((first, first), |(min, max), &x| (min.min(x), max.max(x)))
}
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 usize {
const ZERO: Self = 0;
#[inline(always)]
fn add(self, n: usize) -> Self {
self + n
}
#[inline(always)]
fn get(self) -> usize {
self
}
}
const STACK_BYTES: usize = 4096;
#[repr(C, align(16))]
struct Stack([MaybeUninit<u8>; STACK_BYTES]);
#[inline(always)]
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)]
fn key_slots<'a, K: CountingKey>(
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>() {
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;
fn rewrite<T: CountingKey, 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: CountingKey, 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();
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)]
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: CountingKey, 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: CountingKey, 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;
fn scatter<T, K: CountingKey, C: Count>(arr: &mut [T], keys: &[K], min: K, k: usize) {
let segments = if k <= SEGMENTS_MAX_RANGE && arr.len() >= SEGMENTS_MIN_PER_KEY * k {
SEGMENTS
} else {
1
};
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: CountingKey, 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();
for i in 0..seg {
for s in 0..S {
unsafe { bump(next.add(s * k + (*keys.add(s * seg + i)).offset(min))) };
}
}
for i in tail..len {
unsafe { bump(next.add((S - 1) * k + (*keys.add(i)).offset(min))) };
}
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();
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) };
}