use core::hint::select_unpredictable;
use core::mem::{self, MaybeUninit};
use core::ptr::{self, NonNull};
use core::slice;
use super::counting::{Count, STACK_BYTES, Stack, bump, counters, in_order, key_slots, min_max};
use super::key::BucketKey;
use super::key::sealed::{Bits, Bucket};
use super::tim::Buffer;
pub fn bucket<T: BucketKey>(arr: &mut [T]) {
const {
assert!(
mem::size_of::<T>() == mem::size_of::<T::Bits>()
&& mem::align_of::<T>() == mem::align_of::<T::Bits>()
)
};
let len = arr.len();
if len < 2 {
return;
}
if in_order(arr, |x, y| y.ordered() < x.ordered()) {
return;
}
if in_order(arr, |x, y| y.ordered() > x.ordered()) {
arr.reverse();
return;
}
let mut bounds = None;
let mut descents = None;
if !T::IDENTITY && len <= LEAF {
let (mut prev, mut n) = (arr[0].ordered(), 0);
for x in arr.iter_mut() {
let bits = x.ordered();
n += usize::from(bits < prev);
prev = bits;
unsafe { ptr::from_mut(x).cast::<T::Bits>().write(bits) };
}
descents = Some(n);
} else if !T::IDENTITY {
let first = arr[0].ordered();
let (mut min, mut max) = (first, first);
for x in arr.iter_mut() {
let bits = x.ordered();
min = min.min(bits);
max = max.max(bits);
unsafe { ptr::from_mut(x).cast::<T::Bits>().write(bits) };
}
bounds = Some((min, max));
}
let p = arr.as_mut_ptr();
let keys = p.cast::<T::Bits>();
let none = NonNull::<()>::dangling().as_ptr();
let v = Area { keys, elems: none };
if len <= LEAF {
unsafe { insertion(v, len, &mut small_mode(descents, len)) };
} else {
let mut buf = Buffer::<T::Bits>::new(len);
let scratch = Area {
keys: buf.get(),
elems: none,
};
unsafe {
if len <= u32::MAX as usize {
sort::<T, (), u32, false>(v, scratch, len, 0, &mut Mode::One, bounds);
} else {
sort::<T, (), usize, false>(v, scratch, len, 0, &mut Mode::One, bounds);
}
}
}
if !T::IDENTITY {
for i in 0..len {
unsafe {
let bits = keys.add(i).read();
p.add(i).write(T::from_ordered(bits));
}
}
}
}
pub fn bucket_by_key<T, K, F>(arr: &mut [T], key: F)
where
K: BucketKey,
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 descents = match read_keys(arr, slots, key) {
Order::Ascending => return,
Order::Descending => {
arr.reverse();
return;
}
Order::NonIncreasing => {
arr.reverse();
let keys = unsafe { slice::from_raw_parts(slots.as_ptr().cast::<K::Bits>(), len) };
let mut end = len;
for run in keys.chunk_by(|x, y| x == y) {
arr[end - run.len()..end].reverse();
end -= run.len();
}
return;
}
Order::Neither(descents) => descents,
};
if len <= LEAF {
let v = Area {
keys: slots.as_mut_ptr().cast::<K::Bits>(),
elems: arr.as_mut_ptr(),
};
unsafe { insertion(v, len, &mut small_mode(descents, len)) };
return;
}
let mut scratch_stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut scratch_heap = Vec::new();
let scratch_keys = key_slots::<K::Bits>(len, &mut scratch_stack, &mut scratch_heap);
if cycles::<T>(len) {
let keys = unsafe { slice::from_raw_parts(slots.as_ptr().cast::<K::Bits>(), len) };
let (min, max) = min_max(keys);
if min != max {
unsafe {
by_index::<K, T, u32>(
slots.as_mut_ptr().cast::<K::Bits>(),
arr.as_mut_ptr(),
scratch_keys.as_mut_ptr().cast::<K::Bits>(),
len,
0,
(min, max),
&mut Mode::One,
);
}
}
return;
}
let mut buf = Buffer::<T>::new(len);
let v = Area {
keys: slots.as_mut_ptr().cast::<K::Bits>(),
elems: arr.as_mut_ptr(),
};
let scratch = Area {
keys: scratch_keys.as_mut_ptr().cast::<K::Bits>(),
elems: buf.get(),
};
unsafe {
if len <= u32::MAX as usize {
sort::<K, T, u32, false>(v, scratch, len, 0, &mut Mode::One, None);
} else {
sort::<K, T, usize, false>(v, scratch, len, 0, &mut Mode::One, None);
}
}
}
enum Order {
Ascending,
Descending,
NonIncreasing,
Neither(Option<usize>),
}
const VECTOR_READ_MAX_BYTES: usize = 16;
#[inline(always)]
fn read_keys<T, K: Bucket, F: FnMut(&T) -> K>(
arr: &[T],
slots: &mut [MaybeUninit<K::Bits>],
mut key: F,
) -> Order {
let first = key(&arr[0]).ordered();
slots[0].write(first);
let mut prev = first;
let mut rest = slots[1..].iter_mut().zip(&arr[1..]);
if mem::size_of::<T>() <= VECTOR_READ_MAX_BYTES {
let (mut descents, mut no_descent) = (0, false);
if arr.len() <= LEAF {
for (slot, x) in rest {
let x = key(x).ordered();
slot.write(x);
descents += usize::from(x < prev);
no_descent |= x >= prev;
prev = x;
}
} else {
let mut descent = false;
for (slot, x) in rest {
let x = key(x).ordered();
slot.write(x);
descent |= x < prev;
no_descent |= x >= prev;
prev = x;
}
descents = usize::from(descent);
}
if descents == 0 {
return Order::Ascending;
}
if !no_descent {
return Order::Descending;
}
let keys = unsafe { slice::from_raw_parts(slots.as_ptr().cast::<K::Bits>(), arr.len()) };
return if in_order(keys, |x, y| y > x) {
Order::NonIncreasing
} else {
Order::Neither((arr.len() <= LEAF).then_some(descents))
};
}
let mut top = None;
for (slot, x) in rest.by_ref() {
let x = key(x).ordered();
slot.write(x);
if x < prev {
top = Some(prev);
prev = x;
break;
}
prev = x;
}
let Some(top) = top else {
return Order::Ascending;
};
if top == first {
let (mut non_increasing, mut equal) = (true, rest.len() + 2 < arr.len());
if !equal {
for (slot, x) in rest.by_ref() {
let x = key(x).ordered();
slot.write(x);
if x >= prev {
(non_increasing, equal) = (x == prev, x == prev);
prev = x;
break;
}
prev = x;
}
}
if equal {
for (slot, x) in rest.by_ref() {
let x = key(x).ordered();
slot.write(x);
if x > prev {
non_increasing = false;
break;
}
prev = x;
}
}
if non_increasing {
return if equal {
Order::NonIncreasing
} else {
Order::Descending
};
}
}
for (slot, x) in rest {
slot.write(key(x).ordered());
}
Order::Neither(None)
}
const CYCLE_MIN_BYTES: usize = 64;
const CYCLE_MIN_PART_BYTES: usize = 64 << 10;
const CYCLE_MAX_LEN: usize = 1 << 13;
#[inline(always)]
fn cycles<E>(len: usize) -> bool {
let size = mem::size_of::<E>();
size >= CYCLE_MIN_BYTES
&& len > LEAF
&& len * size >= CYCLE_MIN_PART_BYTES
&& len <= CYCLE_MAX_LEN
}
#[inline(never)]
unsafe fn by_index<K: Bucket, E, C: Count>(
keys: *mut K::Bits,
elems: *mut E,
scratch: *mut K::Bits,
len: usize,
depth: u32,
range: (K::Bits, K::Bits),
mode: &mut Mode,
) {
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let index = key_slots::<u32>(2 * len, &mut stack, &mut heap);
let (index, index_scratch) = index.split_at_mut(len);
for (i, slot) in (0..).zip(index.iter_mut()) {
slot.write(i);
}
let index = index.as_mut_ptr().cast::<u32>();
let v = Area { keys, elems: index };
let scratch = Area {
keys: scratch,
elems: index_scratch.as_mut_ptr().cast::<u32>(),
};
unsafe { sort::<K, u32, C, false>(v, scratch, len, depth, mode, Some(range)) };
let base = elems;
unsafe {
for start in 0..len {
let mut from = *index.add(start) as usize;
if from == start {
continue;
}
let first = ptr::read(base.add(start));
let mut gap = start;
loop {
*index.add(gap) = gap as u32;
if from == start {
break;
}
ptr::copy_nonoverlapping(base.add(from), base.add(gap), 1);
gap = from;
from = *index.add(gap) as usize;
}
base.add(gap).write(first);
}
}
}
const LEAF: usize = 16;
const LOAD: usize = 1;
const MAX_BUCKETS: usize = 1 << 12;
const FLOAT_LEVELS: u32 = 1;
const CROWD: usize = 2;
const FEW_MAGNITUDES: f64 = 16.0;
const FEW_LOAD: usize = 4;
const FEW_TABLES: usize = 4;
const MANY_LOAD: usize = 16;
const MANY_TABLES: usize = 8;
const CACHE_MAX: usize = STACK_BYTES / mem::size_of::<u16>();
const _: () = assert!(
MAX_BUCKETS <= 1 << 16,
"a bucket must fit in the cached `u16`"
);
trait Place<B, E>: Copy {
unsafe fn bucket(self, src: Area<B, E>, i: usize) -> usize;
}
#[derive(Clone, Copy)]
struct Mapped<I>(I);
impl<B: Bits, E, I: Index<B>> Place<B, E> for Mapped<I> {
#[inline(always)]
unsafe fn bucket(self, src: Area<B, E>, i: usize) -> usize {
self.0.of(unsafe { src.key(i) })
}
}
#[derive(Clone, Copy)]
struct Cached(*const u16);
impl<B, E> Place<B, E> for Cached {
#[inline(always)]
unsafe fn bucket(self, _: Area<B, E>, i: usize) -> usize {
usize::from(unsafe { *self.0.add(i) })
}
}
fn buckets(len: usize) -> usize {
(len / LOAD).clamp(2, MAX_BUCKETS)
}
struct Area<B, E> {
keys: *mut B,
elems: *mut E,
}
impl<B, E> Clone for Area<B, E> {
fn clone(&self) -> Self {
*self
}
}
impl<B, E> Copy for Area<B, E> {}
impl<B: Copy, E> Area<B, E> {
#[inline(always)]
fn with<F>(self, elems: *mut F) -> Area<B, F> {
Area {
keys: self.keys,
elems,
}
}
#[inline(always)]
unsafe fn at(self, i: usize) -> Self {
unsafe {
Self {
keys: self.keys.add(i),
elems: self.elems.add(i),
}
}
}
#[inline(always)]
unsafe fn key(self, i: usize) -> B {
unsafe { *self.keys.add(i) }
}
#[inline(always)]
unsafe fn move_to(self, i: usize, dst: Self, j: usize) {
unsafe {
dst.keys.add(j).write(*self.keys.add(i));
ptr::copy(self.elems.add(i), dst.elems.add(j), 1);
}
}
#[inline(always)]
unsafe fn move_all(self, dst: Self, len: usize) {
unsafe {
ptr::copy_nonoverlapping(self.keys, dst.keys, len);
ptr::copy_nonoverlapping(self.elems, dst.elems, len);
}
}
}
trait Index<B>: Copy {
const ONE_KEY: bool = false;
fn of(self, key: B) -> usize;
fn buckets(self) -> usize;
#[inline(always)]
fn crowd(self) -> Option<(usize, B, B)> {
None
}
}
#[derive(Clone, Copy)]
struct Direct<B> {
min: B,
buckets: usize,
}
impl<B: Bits> Index<B> for Direct<B> {
const ONE_KEY: bool = true;
#[inline(always)]
fn of(self, key: B) -> usize {
key.wrapping_sub(self.min).low64() as usize
}
#[inline(always)]
fn buckets(self) -> usize {
self.buckets
}
}
#[derive(Clone, Copy)]
struct Linear<B> {
min: B,
shift: u32,
m: u64,
buckets: usize,
}
impl<B: Bits> Index<B> for Linear<B> {
#[inline(always)]
fn of(self, key: B) -> usize {
let d = key.wrapping_sub(self.min);
let d = if B::BITS > 64 { d.shr(self.shift) } else { d };
((u128::from(d.low64()) * u128::from(self.m)) >> 64) as usize
}
#[inline(always)]
fn buckets(self) -> usize {
self.buckets
}
}
struct Float<K: Bucket> {
lo: f64,
scale: f64,
lo32: f32,
scale32: f32,
last: usize,
zero: Option<usize>,
min: K::Bits,
max: K::Bits,
}
impl<K: Bucket> Clone for Float<K> {
fn clone(&self) -> Self {
*self
}
}
impl<K: Bucket> Copy for Float<K> {}
impl<K: Bucket> Float<K> {
const NARROW: bool = <K::Bits as Bits>::BITS == 32;
fn new(min: K::Bits, max: K::Bits, buckets: usize) -> Option<Self> {
let (lo, hi) = (K::value(min), K::value(max));
let mut map = Self {
lo,
scale: 0.0,
lo32: 0.0,
scale32: 0.0,
last: buckets - 1,
zero: None,
min,
max,
};
if Self::NARROW {
let (lo, hi) = (K::value32(min), K::value32(max));
let width = hi - lo;
map.lo32 = lo;
map.scale32 = buckets as f32 / width;
if !(lo.is_finite() && width.is_finite() && width > 0.0 && map.scale32.is_finite()) {
return None;
}
} else {
let width = hi - lo;
map.scale = buckets as f64 / width;
if !(lo.is_finite() && width.is_finite() && width > 0.0 && map.scale.is_finite()) {
return None;
}
}
let few_magnitudes = lo == 0.0
|| hi == 0.0
|| (lo > 0.0 && hi <= lo * FEW_MAGNITUDES)
|| (hi < 0.0 && lo >= hi * FEW_MAGNITUDES);
if !few_magnitudes {
map.zero = Some(map.at(0.0));
}
Some(map)
}
#[inline(always)]
fn at(self, value: f64) -> usize {
if Self::NARROW {
(((value as f32 - self.lo32) * self.scale32) as usize).min(self.last)
} else {
(((value - self.lo) * self.scale) as usize).min(self.last)
}
}
}
impl<K: Bucket> Index<K::Bits> for Float<K> {
#[inline(always)]
fn of(self, key: K::Bits) -> usize {
if Self::NARROW {
(((K::value32(key) - self.lo32) * self.scale32) as usize).min(self.last)
} else {
self.at(K::value(key))
}
}
#[inline(always)]
fn buckets(self) -> usize {
self.last + 1
}
#[inline(always)]
fn crowd(self) -> Option<(usize, K::Bits, K::Bits)> {
self.zero.map(|zero| (zero, self.min, self.max))
}
}
#[inline(never)]
unsafe fn sort<K: Bucket, E, C: Count, const INTO: bool>(
src: Area<K::Bits, E>,
dst: Area<K::Bits, E>,
len: usize,
depth: u32,
mode: &mut Mode,
bounds: Option<(K::Bits, K::Bits)>,
) {
unsafe {
if len <= LEAF {
if INTO {
insertion_into(src, dst, len, mode);
} else {
insertion(src, len, mode);
}
return;
}
let (min, max) = match bounds {
Some(bounds) => bounds,
None => min_max(slice::from_raw_parts(src.keys, len)),
};
if min == max {
if INTO {
src.move_all(dst, len);
}
return;
}
if !INTO && cycles::<E>(len) {
let (keys, elems) = (src.keys, src.elems);
return by_index::<K, E, C>(keys, elems, dst.keys, len, depth, (min, max), mode);
}
if K::FLOAT
&& depth < FLOAT_LEVELS
&& let Some(map) = Float::<K>::new(min, max, buckets(len))
{
level::<K, E, C, _, INTO>(src, dst, len, map, depth, mode, usize::MAX);
return;
}
by_bits::<K, E, C, INTO>(src, dst, len, (min, max), depth, mode, usize::MAX);
}
}
#[inline(always)]
unsafe fn by_bits<K: Bucket, E, C: Count, const INTO: bool>(
src: Area<K::Bits, E>,
dst: Area<K::Bits, E>,
len: usize,
(min, max): (K::Bits, K::Bits),
depth: u32,
mode: &mut Mode,
most: usize,
) -> bool {
let buckets = buckets(len);
let span = max.wrapping_sub(min);
let width = <K::Bits as Bits>::BITS - span.leading_zeros();
unsafe {
if width < 64 && span.low64() < buckets as u64 {
let map = Direct {
min,
buckets: span.low64() as usize + 1,
};
level::<K, E, C, _, INTO>(src, dst, len, map, depth, mode, most)
} else {
let shift = width.saturating_sub(64);
let span = span.shr(shift).low64();
let m = ((buckets as u128) << 64) / (u128::from(span) + 1);
let map = Linear {
min,
shift,
m: m as u64,
buckets,
};
level::<K, E, C, _, INTO>(src, dst, len, map, depth, mode, most)
}
}
}
#[cold]
#[inline(never)]
unsafe fn by_bits_instead<K: Bucket, E, C: Count, const INTO: bool>(
src: Area<K::Bits, E>,
dst: Area<K::Bits, E>,
len: usize,
range: (K::Bits, K::Bits),
mode: &mut Mode,
most: usize,
) -> bool {
unsafe { by_bits::<K, E, C, INTO>(src, dst, len, range, FLOAT_LEVELS, mode, most) }
}
#[inline(always)]
unsafe fn level<K: Bucket, E, C: Count, I: Index<K::Bits>, const INTO: bool>(
src: Area<K::Bits, E>,
dst: Area<K::Bits, E>,
len: usize,
map: I,
depth: u32,
mode: &mut Mode,
most: usize,
) -> bool {
let buckets = map.buckets();
let tables = if len >= MANY_LOAD * buckets {
MANY_TABLES
} else if len >= FEW_LOAD * buckets {
FEW_TABLES
} else {
1
};
let mut stack = Stack([MaybeUninit::uninit(); STACK_BYTES]);
let mut heap = Vec::new();
let counts = counters::<C>(tables * buckets, &mut stack, &mut heap);
unsafe {
if let Some(most) = partition(src, dst, len, map, counts, tables, most) {
let Some((_, min, max)) = map.crowd() else {
return false;
};
if by_bits_instead::<K, E, C, INTO>(src, dst, len, (min, max), mode, most) {
return true;
}
scatter(src, dst, len, map, &mut counts[..buckets]);
}
let ends = &counts[..buckets];
if I::ONE_KEY {
if !INTO {
dst.move_all(src, len);
}
return true;
}
let (mut start, mut flushed) = (0, 0);
for end in ends.iter() {
let end = end.get();
if end - start > LEAF {
let (to, n) = (src.at(start), end - start);
if INTO {
insertion(dst.at(flushed), start - flushed, mode);
sort::<K, E, C, false>(dst.at(start), to, n, depth + 1, mode, None);
} else {
insertion_into(dst.at(flushed), src.at(flushed), start - flushed, mode);
sort::<K, E, C, true>(dst.at(start), to, n, depth + 1, mode, None);
}
flushed = end;
}
start = end;
}
if INTO {
insertion(dst.at(flushed), len - flushed, mode);
} else {
insertion_into(dst.at(flushed), src.at(flushed), len - flushed, mode);
}
}
true
}
#[inline(never)]
unsafe fn partition<B: Bits, E, C: Count, I: Index<B>>(
src: Area<B, E>,
dst: Area<B, E>,
len: usize,
map: I,
counts: &mut [C],
tables: usize,
most: usize,
) -> Option<usize> {
let buckets = counts.len() / tables;
unsafe {
if len <= CACHE_MAX {
let mut idx = [MaybeUninit::<u16>::uninit(); CACHE_MAX];
let idx = idx.as_mut_ptr().cast::<u16>();
match tables {
MANY_TABLES => count::<_, _, _, _, MANY_TABLES>(src, len, map, counts, idx),
FEW_TABLES => count::<_, _, _, _, FEW_TABLES>(src, len, map, counts, idx),
_ => count::<_, _, _, _, 1>(src, len, map, counts, idx),
}
let starts = &mut counts[..buckets];
if let Some(most) = gives_up(map, starts, len, most) {
return Some(most);
}
distribute(src, dst, len, Cached(idx), starts);
} else {
let idx = ptr::null_mut();
match tables {
MANY_TABLES => count::<_, _, _, _, MANY_TABLES>(src, len, map, counts, idx),
FEW_TABLES => count::<_, _, _, _, FEW_TABLES>(src, len, map, counts, idx),
_ => count::<_, _, _, _, 1>(src, len, map, counts, idx),
}
let starts = &mut counts[..buckets];
if let Some(most) = gives_up(map, starts, len, most) {
return Some(most);
}
distribute(src, dst, len, Mapped(map), starts);
}
}
None
}
#[inline(always)]
fn gives_up<B, C: Count, I: Index<B>>(
map: I,
starts: &[C],
len: usize,
most: usize,
) -> Option<usize> {
let buckets = starts.len();
let start = |b: usize| if b < buckets { starts[b].get() } else { len };
if let Some((zero, _, _)) = map.crowd() {
let (lo, hi) = (zero.saturating_sub(1), (zero + 2).min(buckets));
if start(hi) - start(lo) > len / CROWD {
let crowd = (lo..hi).map(|b| start(b + 1) - start(b)).max();
return Some(crowd.unwrap_or(0));
}
}
if most <= len && (0..buckets).any(|b| start(b + 1) - start(b) >= most) {
return Some(0);
}
None
}
#[cold]
#[inline(never)]
unsafe fn scatter<B: Bits, E, C: Count, I: Index<B>>(
src: Area<B, E>,
dst: Area<B, E>,
len: usize,
map: I,
starts: &mut [C],
) {
unsafe { distribute(src, dst, len, Mapped(map), starts) }
}
#[inline(always)]
fn places(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]),
]
}
#[inline(always)]
unsafe fn count<B: Bits, E, C: Count, I: Index<B>, const N: usize>(
src: Area<B, E>,
len: usize,
map: I,
counts: &mut [C],
idx: *mut u16,
) {
let buckets = counts.len() / N;
let c = counts.as_mut_ptr();
let cache = !idx.is_null();
unsafe {
let mut i = 0;
if N == 1 {
while i + 4 <= len {
let b = [0, 1, 2, 3].map(|j| map.of(src.key(i + j)));
if cache {
for (j, &b) in b.iter().enumerate() {
idx.add(i + j).write(b as u16);
}
}
let counted = places(b, b.map(|b| (*c.add(b)).get()));
for j in 0..4 {
*c.add(b[j]) = C::ZERO.add(counted[j] + 1);
}
i += 4;
}
} else {
while i + 8 <= len {
for j in 0..8 {
let b = map.of(src.key(i + j));
if cache {
idx.add(i + j).write(b as u16);
}
bump(c.add(b * N + j % N));
}
i += 8;
}
}
for i in i..len {
let b = map.of(src.key(i));
debug_assert!(b < buckets);
if cache {
idx.add(i).write(b as u16);
}
bump(c.add(b * N));
}
let mut sum = 0;
for b in 0..buckets {
let mut count = 0;
for t in 0..N {
count += (*c.add(b * N + t)).get();
}
*c.add(b) = C::ZERO.add(sum);
sum += count;
}
}
}
#[inline(always)]
unsafe fn distribute<B: Bits, E, C: Count, P: Place<B, E>>(
src: Area<B, E>,
dst: Area<B, E>,
len: usize,
place: P,
starts: &mut [C],
) {
let c = starts.as_mut_ptr();
unsafe {
let mut i = 0;
while i + 4 <= len {
let b = [0, 1, 2, 3].map(|j| place.bucket(src, i + j));
let p = places(b, b.map(|b| (*c.add(b)).get()));
debug_assert!(p.iter().all(|&p| p < len));
for j in 0..4 {
*c.add(b[j]) = C::ZERO.add(p[j] + 1);
}
for (j, &p) in p.iter().enumerate() {
src.move_to(i + j, dst, p);
}
i += 4;
}
for i in i..len {
let pos = bump(c.add(place.bucket(src, i)));
debug_assert!(pos < len);
src.move_to(i, dst, pos);
}
}
}
const SELECT_BYTES: usize = 16;
const CHUNK: usize = 32;
const FEW_MOVED: usize = 1;
const GATHER_PART: usize = 8;
const GATHER_BLOCK: usize = 256;
const TWO_BYTES: usize = 8;
const FAR_PART: usize = 8;
#[derive(Clone, Copy, PartialEq, Eq)]
enum Mode {
Branch,
One,
Two,
}
fn small_mode(descents: Option<usize>, len: usize) -> Mode {
match descents {
Some(d) if d * SMALL_DESCENTS_PART <= len => Mode::Branch,
_ => Mode::One,
}
}
const SMALL_DESCENTS_PART: usize = 8;
#[inline(always)]
unsafe fn insertion<B: Bits, E>(v: Area<B, E>, len: usize, mode: &mut Mode) {
unsafe { sweep::<B, E, true>(v, v, len, mode) }
}
#[inline(always)]
unsafe fn insertion_into<B: Bits, E>(
src: Area<B, E>,
dst: Area<B, E>,
len: usize,
mode: &mut Mode,
) {
if mem::size_of::<E>() > SELECT_BYTES
&& *mode != Mode::Branch
&& mem::size_of::<E>() >= 2 * mem::size_of::<usize>()
&& dst.elems.cast::<usize>().is_aligned()
&& unsafe { descents(src.keys, len) } * GATHER_PART > len
{
return unsafe { gather(src, dst, len, mode) };
}
unsafe { sweep::<B, E, false>(src, dst, len, mode) }
}
#[inline(never)]
unsafe fn gather<B: Bits, E>(src: Area<B, E>, dst: Area<B, E>, len: usize, mode: &mut Mode) {
let ix = dst.elems.cast::<usize>();
let mut block = [MaybeUninit::<usize>::uninit(); GATHER_BLOCK];
unsafe {
let ids = ix.add(len);
for i in 0..len {
ids.add(i).write(i);
}
sweep::<B, usize, false>(src.with(ids), dst.with(ix), len, mode);
let mut end = len;
while end > 0 {
let start = end.saturating_sub(GATHER_BLOCK);
let block = &mut block[..end - start];
ptr::copy_nonoverlapping(ix.add(start), block.as_mut_ptr().cast(), block.len());
for (j, i) in (start..).zip(block.iter()) {
ptr::copy_nonoverlapping(src.elems.add(i.assume_init()), dst.elems.add(j), 1);
}
end = start;
}
}
}
#[inline(always)]
unsafe fn descents<B: Bits>(keys: *const B, len: usize) -> usize {
let keys = unsafe { slice::from_raw_parts(keys, len) };
let mut n = 0;
for i in 1..len {
n += usize::from(keys[i] < keys[i - 1]);
}
n
}
#[inline(always)]
unsafe fn sweep<B: Bits, E, const IN_PLACE: bool>(
src: Area<B, E>,
dst: Area<B, E>,
len: usize,
mode: &mut Mode,
) {
if len == 0 {
return;
}
let select = mem::size_of::<E>() <= SELECT_BYTES;
unsafe {
if !IN_PLACE {
src.move_to(0, dst, 0);
}
let mut i = 1;
let mut now = if select { *mode } else { Mode::Branch };
while i < len {
let end = if select { (i + CHUNK).min(len) } else { len };
let chunk = end - i;
let (mut moved, mut far) = (0, 0);
match now {
Mode::Branch => {
while i < end {
let k = src.key(i);
if dst.key(i - 1) <= k {
if !IN_PLACE {
src.move_to(i, dst, i);
}
} else {
moved += 1;
let e = ptr::read(src.elems.add(i).cast::<MaybeUninit<E>>());
let mut j = i;
loop {
dst.move_to(j - 1, dst, j);
j -= 1;
if j == 0 || dst.key(j - 1) <= k {
break;
}
}
far += usize::from(j + 1 < i);
dst.keys.add(j).write(k);
ptr::copy_nonoverlapping(e.as_ptr(), dst.elems.add(j), 1);
}
i += 1;
}
}
Mode::One => {
let mut last = dst.key(i - 1);
let mut before = if i >= 2 { dst.key(i - 2) } else { B::ZERO };
while i < end {
let k = src.key(i);
let up = last > k;
moved += usize::from(up);
let tmp;
let e = if IN_PLACE {
tmp = ptr::read(src.elems.add(i).cast::<MaybeUninit<E>>());
tmp.as_ptr()
} else {
src.elems.add(i).cast_const()
};
let p1 = dst.elems.add(i - 1).cast_const();
ptr::copy(select_unpredictable(up, p1, e), dst.elems.add(i), 1);
ptr::copy(select_unpredictable(up, e, p1), dst.elems.add(i - 1), 1);
dst.keys.add(i).write(select_unpredictable(up, last, k));
dst.keys.add(i - 1).write(select_unpredictable(up, k, last));
if up & (before > k) {
far += 1;
let mut j = i - 1;
loop {
dst.move_to(j - 1, dst, j);
j -= 1;
if j == 0 || dst.key(j - 1) <= k {
break;
}
}
dst.keys.add(j).write(k);
ptr::copy_nonoverlapping(e, dst.elems.add(j), 1);
before = dst.key(i - 1);
} else {
before = select_unpredictable(up, k, last);
last = select_unpredictable(up, last, k);
}
i += 1;
}
}
Mode::Two => {
let mut last = dst.key(i - 1);
let mut before = if i >= 2 { dst.key(i - 2) } else { B::ZERO };
while i < end {
let k = src.key(i);
let up = last > k;
let up2 = before > k;
moved += usize::from(up);
far += usize::from(up2);
let tmp;
let e = if IN_PLACE {
tmp = ptr::read(src.elems.add(i).cast::<MaybeUninit<E>>());
tmp.as_ptr()
} else {
src.elems.add(i).cast_const()
};
let i2 = i.saturating_sub(2);
let p1 = dst.elems.add(i - 1).cast_const();
let p2 = dst.elems.add(i2).cast_const();
let mid = select_unpredictable(up, k, last);
dst.keys.add(i2).write(select_unpredictable(up2, k, before));
dst.keys
.add(i - 1)
.write(select_unpredictable(up2, before, mid));
dst.keys.add(i).write(select_unpredictable(up, last, k));
ptr::copy(select_unpredictable(up, p1, e), dst.elems.add(i), 1);
let pm = select_unpredictable(up, e, p1);
ptr::copy(select_unpredictable(up2, p2, pm), dst.elems.add(i - 1), 1);
ptr::copy(select_unpredictable(up2, e, p2), dst.elems.add(i2), 1);
if up2 & (dst.key(i.saturating_sub(3)) > k) {
let mut j = i2;
loop {
dst.move_to(j - 1, dst, j);
j -= 1;
if j == 0 || dst.key(j - 1) <= k {
break;
}
}
dst.keys.add(j).write(k);
ptr::copy_nonoverlapping(e, dst.elems.add(j), 1);
} else {
before = select_unpredictable(up2, before, mid);
last = select_unpredictable(up, last, k);
}
i += 1;
}
}
}
*mode = if moved * CHUNK <= FEW_MOVED * chunk {
Mode::Branch
} else if mem::size_of::<E>() <= TWO_BYTES && far * FAR_PART > chunk {
Mode::Two
} else {
Mode::One
};
now = if select { *mode } else { Mode::Branch };
}
}
}