use super::RdxSort;
use core::ptr;
use std::cmp;
use std::mem;
pub trait RdxSortTemplate {
fn cfg_nbuckets() -> usize;
fn cfg_nrounds() -> usize;
fn get_bucket(&self, round: usize) -> usize;
fn reverse(round: usize, bucket: usize) -> bool;
}
#[macro_export]
macro_rules! rdxsort_template_alias {
($t1:ty = $t2:ty) => {
impl RdxSortTemplate for $t1 {
#[inline]
fn cfg_nbuckets() -> usize {
<$t2 as RdxSortTemplate>::cfg_nbuckets()
}
#[inline]
fn cfg_nrounds() -> usize {
<$t2 as RdxSortTemplate>::cfg_nrounds()
}
#[inline]
fn get_bucket(&self, round: usize) -> usize {
(*self as $t2).get_bucket(round)
}
#[inline]
fn reverse(round: usize, bucket: usize) -> bool {
<$t2 as RdxSortTemplate>::reverse(round, bucket)
}
}
}
}
#[inline]
fn helper_bucket<T, I>(buckets_b: &mut Vec<Vec<T>>, iter: I, cfg_nbuckets: usize, round: usize)
where T: RdxSortTemplate,
I: Iterator<Item = T>
{
for x in iter {
let b = x.get_bucket(round);
assert!(b < cfg_nbuckets,
"Your RdxSortTemplate implementation returns a bucket >= cfg_nbuckets()!");
unsafe {
buckets_b.get_unchecked_mut(b).push(x);
}
}
}
impl<T> RdxSort for [T] where T: RdxSortTemplate + Clone
{
fn rdxsort(&mut self) {
let cfg_nbuckets = T::cfg_nbuckets();
let cfg_nrounds = T::cfg_nrounds();
if cfg_nrounds == 0 {
return;
}
let n = self.len();
let presize = cmp::max(16, (n << 2) / cfg_nbuckets); let mut buckets_a: Vec<Vec<T>> = Vec::with_capacity(cfg_nbuckets);
let mut buckets_b: Vec<Vec<T>> = Vec::with_capacity(cfg_nbuckets);
for _ in 0..cfg_nbuckets {
buckets_a.push(Vec::with_capacity(presize));
buckets_b.push(Vec::with_capacity(presize));
}
helper_bucket(&mut buckets_a, self.iter().cloned(), cfg_nbuckets, 0);
for round in 1..cfg_nrounds {
for bucket in &mut buckets_b {
bucket.clear();
}
for (i, bucket) in buckets_a.iter().enumerate() {
if T::reverse(round - 1, i) {
helper_bucket(&mut buckets_b,
bucket.iter().rev().cloned(),
cfg_nbuckets,
round);
} else {
helper_bucket(&mut buckets_b, bucket.iter().cloned(), cfg_nbuckets, round);
}
}
mem::swap(&mut buckets_a, &mut buckets_b);
}
let mut pos = 0;
for (i, bucket) in buckets_a.iter_mut().enumerate() {
assert!(pos + bucket.len() <= self.len(),
"bug: a buckets got oversized");
if T::reverse(cfg_nrounds - 1, i) {
for x in bucket.iter().rev().cloned() {
unsafe {
*self.get_unchecked_mut(pos) = x;
}
pos += 1;
}
} else {
unsafe {
ptr::copy_nonoverlapping(bucket.as_ptr(),
self.get_unchecked_mut(pos),
bucket.len());
}
pos += bucket.len();
}
}
assert!(pos == self.len(), "bug: bucket size does not sum up");
}
}
impl<T> RdxSort for Vec<T> where [T]: RdxSort
{
fn rdxsort(&mut self) {
self.as_mut_slice().rdxsort();
}
}