pub mod displaced;
pub mod monotone;
pub mod partition;
pub mod radix_route;
pub mod runs;
pub mod scout;
use crate::view::{AllocError, Arr, AuxBuffer, AuxRaw, DepthScope, Elem, Hooks, Stat, insertion_sort};
use radix_route::HistStore;
pub const INSERTION_MAX: usize = 32;
pub const SPLIT_MIN: usize = 1024;
pub const MAX_RUNS: usize = 4;
pub const MAX_POP: usize = 4;
pub const RING: usize = 256;
pub const COMMIT_BLOCK: usize = 1024;
pub const SAMPLE: usize = 512;
struct Handle<V: Arr> {
p: core::ptr::NonNull<u8>,
_v: core::marker::PhantomData<V>,
}
impl<V: Arr> Handle<V> {
const BYTES: usize = 16;
fn new() -> Result<Self, AllocError> {
Ok(Handle { p: V::alloc_array::<u8>(Self::BYTES)?, _v: core::marker::PhantomData })
}
}
impl<V: Arr> Drop for Handle<V> {
fn drop(&mut self) {
unsafe { V::free_array(self.p, Self::BYTES) };
}
}
struct Owned<V: Arr, B> {
handle: Handle<V>,
array: core::mem::ManuallyDrop<B>,
}
impl<V: Arr, B> Owned<V, B> {
fn new(make: impl FnOnce() -> Result<B, AllocError>) -> Result<Self, AllocError> {
let handle = Handle::new()?;
let array = make()?;
Ok(Owned { handle, array: core::mem::ManuallyDrop::new(array) })
}
}
impl<V: Arr, B> Drop for Owned<V, B> {
fn drop(&mut self) {
unsafe { core::mem::ManuallyDrop::drop(&mut self.array) };
let _ = &self.handle;
}
}
impl<V: Arr, B> core::ops::Deref for Owned<V, B> {
type Target = B;
fn deref(&self) -> &B {
&self.array
}
}
impl<V: Arr, B> core::ops::DerefMut for Owned<V, B> {
fn deref_mut(&mut self) -> &mut B {
&mut self.array
}
}
pub struct Scratch<V: Arr> {
buf: Option<Owned<V, AuxBuffer<V>>>,
hist: Option<Owned<V, AuxRaw<u32, V>>>,
wc: Option<Owned<V, AuxRaw<u8, V>>>,
}
impl<V: Arr> Default for Scratch<V> {
fn default() -> Self {
Self::new()
}
}
impl<V: Arr> Scratch<V> {
pub fn new() -> Self {
Scratch { buf: None, hist: None, wc: None }
}
pub fn ensure(&mut self, like: V, k: usize) -> Result<V, AllocError> {
match &mut self.buf {
None => self.buf = Some(Owned::new(|| AuxBuffer::new(like, k))?),
Some(b) if b.size() < k => {
if let Err(e) = b.resize_discard(k) {
self.buf = None;
return Err(e);
}
}
_ => {}
}
Ok(self.buf.as_ref().unwrap().arr().sub(0, k))
}
pub fn capacity(&self) -> usize {
self.buf.as_ref().map_or(0, |b| b.size())
}
pub fn buffer(&self) -> Option<*mut V::T> {
self.buf.as_ref().map(|b| b.data())
}
pub fn hist(&mut self, entries: usize) -> Result<HistStore, AllocError> {
match &self.hist {
Some(h) if h.size() >= entries => {}
_ => {
self.hist = None;
self.hist = Some(Owned::new(|| AuxRaw::new(entries))?);
}
}
let h = self.hist.as_ref().unwrap();
Ok(HistStore { p: h.data() })
}
pub fn wc(&mut self, bytes: usize) -> Result<*mut u8, AllocError> {
match &self.wc {
Some(w) if w.size() >= bytes => {}
_ => {
self.wc = None;
self.wc = Some(Owned::new(|| AuxRaw::new(bytes))?);
}
}
Ok(self.wc.as_ref().unwrap().data())
}
}
pub fn sort_range<V: Arr>(mut a: V, scratch: &mut Scratch<V>, mut n: usize, mut chunk: i32, free: bool, ended_in_src: &mut bool, digit_bits: u32) -> Result<(), AllocError> {
let _depth = DepthScope::<V::H>::new();
*ended_in_src = true;
loop {
if n < 2 {
return Ok(());
}
if n <= INSERTION_MAX {
insertion_sort(a, 0, n);
return Ok(());
}
let s = scout::scout(a, n, chunk);
if !s.committed {
if s.descents == 0 {
if V::H::COUNTED {
V::H::note_route(1);
}
return Ok(());
}
if s.ascents == 0 {
if V::H::COUNTED {
V::H::note_route(2);
}
monotone::stable_reverse(a, n, &s);
return Ok(());
}
if s.tracking {
if V::H::COUNTED {
V::H::note_route(3);
}
return runs::sort_few_runs(a, scratch, n, &s);
}
if s.descents <= n / 16 {
if V::H::COUNTED {
V::H::note_route(4);
}
if displaced::sort_displaced(a, n)? {
return Ok(());
}
if V::H::COUNTED {
V::H::stat(Stat::Giveups, 1);
}
}
}
if V::H::COUNTED {
V::H::note_route(5);
}
let unordered = s.committed || s.descents * 4 >= n;
radix_route::radix_route(a, scratch, n, &mut chunk, s.mask, s.has_mask, unordered, free && !<V::T as Elem>::CHUNKED, ended_in_src, digit_bits)?;
if !<V::T as Elem>::CHUNKED {
return Ok(());
}
let (mut g, mut big_g, mut big_len) = (0usize, 0usize, 0usize);
while g < n {
let eg = a.get(g);
let k = V::key(eg, chunk);
let mut e = g + 1;
while e < n && V::key(a.get(e), chunk) == k {
e += 1;
}
if e - g > 1 && !<V::T as Elem>::chunk_ends(eg, chunk) {
if e - g > big_len {
if big_len > 1 {
sort_range(a.sub(big_g, big_len), scratch, big_len, chunk + 1, false, ended_in_src, digit_bits)?;
}
big_g = g;
big_len = e - g;
} else {
sort_range(a.sub(g, e - g), scratch, e - g, chunk + 1, false, ended_in_src, digit_bits)?;
}
}
g = e;
}
if big_len < 2 {
return Ok(());
}
a = a.sub(big_g, big_len); n = big_len;
chunk += 1;
}
}
pub fn brainsort_impl<V: Arr>(a: V, scratch: &mut Scratch<V>, free: bool, digit_bits: u32) -> Result<bool, AllocError> {
let n = a.size();
if n < 2 {
return Ok(true);
}
if n <= INSERTION_MAX {
insertion_sort(a, 0, n);
return Ok(true);
}
if n > 0xFFFF_FFFF {
crate::mergesort::merge_sort(a)?; return Ok(true);
}
let mut ended_in_src = true;
sort_range(a, scratch, n, 0, free, &mut ended_in_src, digit_bits)?;
Ok(ended_in_src)
}