use core::mem::{self, MaybeUninit};
use core::{ptr, slice};
use super::counting::{
Count, STACK_BYTES, Stack, bump, counters, in_order, key_slots, min_max, rewrite, scatter,
};
use super::key::IntegerKey;
use super::key::sealed::Bits;
use super::tim::Buffer;
pub fn radix<T: IntegerKey>(arr: &mut [T]) {
let len = arr.len();
if len < 2 {
return;
}
if in_order(arr, |x, y| y < x) {
return;
}
if in_order(arr, |x, y| y > x) {
arr.reverse();
return;
}
let first = arr[0].bits();
let varying = arr.iter().fold(<T::Bits as Bits>::ZERO, |acc, x| {
acc.or(x.bits().xor(first))
});
let plan = Plan::new(varying, len);
if plan.digits == 1 && plan.low == 0 {
let (min, max) = min_max(arr);
let k = max.offset(min) + 1;
if len <= u32::MAX as usize {
rewrite::<T, u32>(arr, min, k);
} else {
rewrite::<T, usize>(arr, min, k);
}
} else if len <= u32::MAX as usize {
sort_values::<T, u32>(arr, &plan);
} else {
sort_values::<T, usize>(arr, &plan);
}
}
pub fn radix_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::Bits>(len, &mut stack, &mut heap);
let first = key(&arr[0]).bits();
slots[0].write(first);
let mut varying = <K::Bits as Bits>::ZERO;
let mut prev = first;
let (mut descent, mut no_descent) = (false, false);
for (slot, x) in slots[1..].iter_mut().zip(&arr[1..]) {
let x = key(x).bits();
slot.write(x);
varying = varying.or(x.xor(first));
descent |= x < prev;
no_descent |= x >= prev;
prev = x;
}
if !descent {
return;
}
if !no_descent {
arr.reverse();
return;
}
let plan = Plan::new(varying, len);
if plan.digits == 1 {
let keys = unsafe { slice::from_raw_parts_mut(slots.as_mut_ptr().cast::<K::Bits>(), len) };
let (mut min, mut max) = (plan.mask(), 0);
for k in keys.iter_mut() {
let d = k.digit(plan.low, plan.mask());
min = min.min(d);
max = max.max(d);
*k = Bits::of(d);
}
let (min, k) = (<K::Bits as Bits>::of(min), max - min + 1);
if len <= u32::MAX as usize {
scatter::<T, K::Bits, u32>(arr, keys, min, k);
} else {
scatter::<T, K::Bits, usize>(arr, keys, min, k);
}
} else if len <= u32::MAX as usize {
sort_by_keys::<T, K::Bits, u32>(arr, slots, &plan);
} else {
sort_by_keys::<T, K::Bits, usize>(arr, slots, &plan);
}
}
struct Plan {
low: u32,
width: u32,
digits: usize,
}
const MAX_WIDTH: u32 = 12;
const MIN_WIDTH: u32 = 8;
const MIN_WIDTH_LEN: usize = 64;
const SMALLEST_WIDTH: u32 = 4;
impl Plan {
fn new<B: Bits>(varying: B, len: usize) -> Self {
let low = varying.trailing_zeros();
let span = B::BITS - varying.leading_zeros() - low;
let mut max = len.ilog2().clamp(SMALLEST_WIDTH, MAX_WIDTH);
if len >= MIN_WIDTH_LEN {
max = max.max(MIN_WIDTH);
}
let digits = span.div_ceil(max);
Self {
low,
width: span.div_ceil(digits),
digits: digits as usize,
}
}
fn radix(&self) -> usize {
1 << self.width
}
fn mask(&self) -> usize {
self.radix() - 1
}
fn shift(&self, d: usize) -> u32 {
self.low + d as u32 * self.width
}
}
fn histogram<T: IntegerKey, C: Count>(v: &[T], plan: &Plan, counts: &mut [C]) {
match plan.digits {
1 => count_digits::<T, C>(v, plan, 1, counts),
2 => count_digits::<T, C>(v, plan, 2, counts),
3 => count_digits::<T, C>(v, plan, 3, counts),
4 => count_digits::<T, C>(v, plan, 4, counts),
5 => count_digits::<T, C>(v, plan, 5, counts),
6 => count_digits::<T, C>(v, plan, 6, counts),
7 => count_digits::<T, C>(v, plan, 7, counts),
8 => count_digits::<T, C>(v, plan, 8, counts),
digits => count_digits::<T, C>(v, plan, digits, counts),
}
}
#[inline(always)]
fn count_digits<T: IntegerKey, C: Count>(v: &[T], plan: &Plan, digits: usize, counts: &mut [C]) {
debug_assert!(counts.len() == digits * plan.radix());
let c = counts.as_mut_ptr();
let mask = plan.mask();
for x in v {
let bits = x.bits();
for d in 0..digits {
unsafe { bump(c.add(d * plan.radix() + bits.digit(plan.shift(d), mask))) };
}
}
}
fn places<C: Count>(counts: &mut [C], len: usize) -> bool {
let mut sum = 0;
for c in counts.iter_mut() {
let count = c.get();
if count == len {
return true;
}
*c = C::ZERO.add(sum);
sum += count;
}
false
}
fn sort_values<T: IntegerKey, C: Count>(arr: &mut [T], plan: &Plan) {
let len = arr.len();
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let counts = counters::<C>(plan.digits * plan.radix(), &mut stack, &mut heap);
histogram(arr, plan, counts);
let mut buf = Buffer::<T>::new(len);
let mut src = arr.as_mut_ptr();
let mut dst = buf.get();
let mask = plan.mask();
for (d, counts) in counts.chunks_exact_mut(plan.radix()).enumerate() {
if places(counts, len) {
continue;
}
let shift = plan.shift(d);
let c = counts.as_mut_ptr();
for i in 0..len {
unsafe {
let x = *src.add(i);
let pos = bump(c.add(x.bits().digit(shift, mask)));
dst.add(pos).write(x);
}
}
mem::swap(&mut src, &mut dst);
}
if src != arr.as_mut_ptr() {
unsafe { ptr::copy_nonoverlapping(src, arr.as_mut_ptr(), len) };
}
}
const GATHER_MIN_PASS_BYTES: usize = 96;
const GATHER_MAX_BYTES: usize = 16 << 20;
const GATHER_MIN_LEN: usize = MIN_WIDTH_LEN;
fn sort_by_keys<T, B: Bits + IntegerKey, C: Count>(
arr: &mut [T],
keys: &mut [MaybeUninit<B>],
plan: &Plan,
) {
let len = arr.len();
let keys = unsafe { slice::from_raw_parts_mut(keys.as_mut_ptr().cast::<B>(), len) };
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let counts = counters::<C>(plan.digits * plan.radix(), &mut stack, &mut heap);
histogram(keys, plan, counts);
let size = mem::size_of::<T>();
if plan.digits * size >= GATHER_MIN_PASS_BYTES
&& len >= GATHER_MIN_LEN
&& len.saturating_mul(size) <= GATHER_MAX_BYTES
{
gather(arr, keys, plan, counts);
} else {
move_with_keys(arr, keys, plan, counts);
}
}
fn move_with_keys<T, B: Bits + IntegerKey, C: Count>(
arr: &mut [T],
keys: &mut [B],
plan: &Plan,
counts: &mut [C],
) {
let len = arr.len();
let mut buf = Buffer::<T>::new(len);
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let key_buf = key_slots::<B>(len, &mut stack, &mut heap);
let (mut src, mut dst) = (arr.as_mut_ptr(), buf.get());
let (mut ks, mut kd) = (keys.as_mut_ptr(), key_buf.as_mut_ptr().cast::<B>());
let mask = plan.mask();
let last = (0..plan.digits)
.rev()
.find(|&d| {
let c = &counts[d * plan.radix()..(d + 1) * plan.radix()];
!c.contains(&C::ZERO.add(len))
})
.unwrap_or(0);
for (d, counts) in counts.chunks_exact_mut(plan.radix()).enumerate() {
if places(counts, len) {
continue;
}
let shift = plan.shift(d);
let c = counts.as_mut_ptr();
let move_keys = d != last;
for i in 0..len {
unsafe {
let k = *ks.add(i);
let pos = bump(c.add(k.digit(shift, mask)));
if move_keys {
kd.add(pos).write(k);
}
ptr::copy_nonoverlapping(src.add(i), dst.add(pos), 1);
}
}
mem::swap(&mut src, &mut dst);
mem::swap(&mut ks, &mut kd);
}
if src != arr.as_mut_ptr() {
unsafe { ptr::copy_nonoverlapping(src, arr.as_mut_ptr(), len) };
}
}
fn gather<T, B: Bits + IntegerKey, C: Count>(
arr: &mut [T],
keys: &[B],
plan: &Plan,
counts: &mut [C],
) {
let len = arr.len();
let mut tagged: Vec<(B, u32)> = keys.iter().zip(0..).map(|(&k, i)| (k, i)).collect();
let mut other: Vec<(B, u32)> = Vec::with_capacity(len);
let (mut src, mut dst) = (tagged.as_mut_ptr(), other.as_mut_ptr());
let mask = plan.mask();
for (d, counts) in counts.chunks_exact_mut(plan.radix()).enumerate() {
if places(counts, len) {
continue;
}
let shift = plan.shift(d);
let c = counts.as_mut_ptr();
for i in 0..len {
unsafe {
let e = *src.add(i);
let pos = bump(c.add(e.0.digit(shift, mask)));
dst.add(pos).write(e);
}
}
mem::swap(&mut src, &mut dst);
}
let mut buf = Buffer::<T>::new(len);
let out = buf.get();
let base = arr.as_ptr();
for i in 0..len {
unsafe { ptr::copy_nonoverlapping(base.add((*src.add(i)).1 as usize), out.add(i), 1) };
}
unsafe { ptr::copy_nonoverlapping(out, arr.as_mut_ptr(), len) };
}