extern crate rand;
extern crate rdxsort;
use std::collections;
use std::hash;
use std::hash::Hash;
use std::hash::Hasher;
use std::iter;
use std::mem;
use std::ops;
use rand::{Rand, Rng, XorShiftRng};
use rdxsort::*;
pub static CFG_N: usize = 10_000;
fn is_sorted<T>(data: &Vec<T>) -> bool
where T: Clone,
T: PartialOrd
{
let mut last_entry: Option<T> = None;
for x in data.iter().cloned() {
match last_entry {
Some(l) => {
if !(l.le(&x)) {
return false;
}
}
None => {}
}
last_entry = Some(x);
}
return true;
}
pub trait MyHash {
fn hash_it<H>(&self, state: &mut H) where H: Hasher;
}
macro_rules! trivial_myhash {
($t:ty) => {
impl MyHash for $t {
fn hash_it<H>(&self, state: &mut H) where H: Hasher {
self.hash(state);
}
}
}
}
trivial_myhash!([u8; 0]);
trivial_myhash!([u8; 4]);
trivial_myhash!((u8,));
trivial_myhash!((u8, i32));
trivial_myhash!((u8, i32, char));
trivial_myhash!(bool);
trivial_myhash!(char);
trivial_myhash!(i8);
trivial_myhash!(i16);
trivial_myhash!(i32);
trivial_myhash!(i64);
trivial_myhash!(isize);
trivial_myhash!(u8);
trivial_myhash!(u16);
trivial_myhash!(u32);
trivial_myhash!(u64);
trivial_myhash!(usize);
impl MyHash for f32 {
fn hash_it<H>(&self, state: &mut H) where H: Hasher {
let alias = unsafe {mem::transmute_copy::<f32, u32>(self)};
alias.hash(state);
}
}
impl MyHash for f64 {
fn hash_it<H>(&self, state: &mut H) where H: Hasher {
let alias = unsafe {mem::transmute_copy::<f64, u64>(self)};
alias.hash(state);
}
}
fn guess_entropy<T>(data: &Vec<T>) -> f64 where T: MyHash {
let mut counter = collections::HashMap::<u64, usize>::new();
for x in data {
let mut hasher = hash::SipHasher::new();
x.hash_it(&mut hasher);
let key = hasher.finish();
let state = counter.entry(key).or_insert(0);
*state += 1;
}
counter.values().map(|&x| x as f64 / data.len() as f64).map(|x| -x * x.log2()).fold(0f64, |a, b| a + b)
}
pub fn test_generic<T>(data: Vec<T>)
where T: Clone + PartialOrd,
Vec<T>: RdxSort
{
let mut data = data;
let n = data.len();
let mut data_sorted_ref = data.clone();
data_sorted_ref.sort_by(|a, b| a.partial_cmp(b).unwrap());
data.rdxsort();
assert!(data.len() == n, "sorted data has wrong lenght!");
assert!(is_sorted(&data), "data is not sorted!");
for (x, y) in data.iter().zip(data_sorted_ref.iter()) {
assert!(x == y, "sortd data does not match the reference!");
}
}
pub fn test_empty_generic<T>()
where T: Clone + PartialOrd,
Vec<T>: RdxSort
{
let data: Vec<T> = vec![];
test_generic(data);
}
pub fn test_rnd_generic<T>(vspecial: Vec<T>)
where T: Clone + PartialOrd + Rand + MyHash,
Vec<T>: RdxSort
{
let entropy_threshold = 0.5f64;
let mut rng = XorShiftRng::new_unseeded();
let mut data: Vec<T> = rng.gen_iter::<T>().take(CFG_N).collect();
let mut positions: Vec<usize> = (0..(CFG_N + 1)).collect();
rng.shuffle(&mut positions[..]);
assert!(vspecial.len() < CFG_N, "to many special values to test!");
for (i, x) in positions.into_iter().zip(vspecial.into_iter()) {
data[i] = x;
}
assert!(data.len() == CFG_N, "generated data has wrong length!");
assert!(guess_entropy(&data) >= entropy_threshold, "generated data does not contain enough entropy!");
test_generic(data);
}
pub fn test_single_generic<T>(x: T)
where T: Clone + PartialOrd,
Vec<T>: RdxSort
{
let data: Vec<T> = vec![x];
test_generic(data);
}
pub fn test_full_generic<T>(vmin: T, vmax: T)
where T: Clone+ PartialOrd + ops::Add,
ops::Range<T>: iter::Iterator,
Vec<T>: iter::FromIterator<<ops::Range<T> as iter::Iterator>::Item>,
Vec<T>: RdxSort
{
let mut data: Vec<T> = (vmin.clone()..vmax.clone()).collect();
data.push(vmax);
let mut rng = XorShiftRng::new_unseeded();
rng.shuffle(&mut data[..]);
test_generic(data);
}
mod sub_array {
use super::*;
#[test]
fn test_empty_array0() {
test_empty_generic::<[u8; 0]>();
}
#[test]
fn test_single_array0() {
test_single_generic::<[u8; 0]>([]);
}
#[test]
fn test_rnd_array4() {
test_rnd_generic::<[u8; 4]>(vec![]);
}
#[test]
fn test_empty_array4() {
test_empty_generic::<[u8; 4]>();
}
#[test]
fn test_single_array4() {
test_single_generic::<[u8; 4]>([1, 2, 3, 4]);
}
}
mod sub_bool {
use super::*;
#[test]
fn test_rnd_bool() {
test_rnd_generic::<bool>(vec![false, true]);
}
#[test]
fn test_empty_bool() {
test_empty_generic::<bool>();
}
#[test]
fn test_single_bool() {
test_single_generic::<bool>(true);
}
}
mod sub_char {
use super::*;
use std::char;
#[test]
fn test_rnd_char() {
test_rnd_generic::<char>(vec!['\0', char::MAX]);
}
#[test]
fn test_empty_char() {
test_empty_generic::<char>();
}
#[test]
fn test_single_char() {
test_single_generic::<char>('x');
}
}
mod sub_i8 {
use super::*;
#[test]
fn test_rnd_i8() {
test_rnd_generic::<i8>(vec![i8::min_value(), i8::min_value() + 1, -1i8, 0i8, 1i8, i8::max_value() - 1, i8::max_value()]);
}
#[test]
fn test_full_i8() {
test_full_generic::<i8>(i8::min_value(), i8::max_value());
}
#[test]
fn test_empty_i8() {
test_empty_generic::<i8>();
}
#[test]
fn test_single_i8() {
test_single_generic::<i8>(3i8);
}
}
mod sub_i16 {
use super::*;
#[test]
fn test_rnd_i16() {
test_rnd_generic::<i16>(vec![i16::min_value(), i16::min_value() + 1, -1i16, 0i16, 1i16, i16::max_value() - 1, i16::max_value()]);
}
#[test]
fn test_full_i16() {
test_full_generic::<i16>(i16::min_value(), i16::max_value());
}
#[test]
fn test_empty_i16() {
test_empty_generic::<i16>();
}
#[test]
fn test_single_i16() {
test_single_generic::<i16>(3i16);
}
}
mod sub_i32 {
use super::*;
#[test]
fn test_rnd_i32() {
test_rnd_generic::<i32>(vec![i32::min_value(), i32::min_value() + 1, -1i32, 0i32, 1i32, i32::max_value() - 1, i32::max_value()]);
}
#[test]
fn test_empty_i32() {
test_empty_generic::<i32>();
}
#[test]
fn test_single_i32() {
test_single_generic::<i32>(3i32);
}
}
mod sub_i64 {
use super::*;
#[test]
fn test_rnd_i64() {
test_rnd_generic::<i64>(vec![i64::min_value(), i64::min_value() + 1, -1i64, 0i64, 1i64, i64::max_value() - 1, i64::max_value()]);
}
#[test]
fn test_empty_i64() {
test_empty_generic::<i64>();
}
#[test]
fn test_single_i64() {
test_single_generic::<i64>(3i64);
}
}
mod sub_isize {
use super::*;
#[test]
fn test_rnd_isize() {
test_rnd_generic::<isize>(vec![isize::min_value(), isize::min_value() + 1, -1, 0, 1, isize::max_value() - 1, isize::max_value()]);
}
#[test]
fn test_empty_isize() {
test_empty_generic::<isize>();
}
#[test]
fn test_single_isize() {
test_single_generic::<isize>(3);
}
}
mod sub_u8 {
use super::*;
#[test]
fn test_rnd_u8() {
test_rnd_generic::<u8>(vec![0u8, 1u8, u8::max_value() - 1, u8::max_value()]);
}
#[test]
fn test_full_u8() {
test_full_generic::<u8>(u8::min_value(), u8::max_value());
}
#[test]
fn test_empty_u8() {
test_empty_generic::<u8>();
}
#[test]
fn test_single_u8() {
test_single_generic::<u8>(3u8);
}
}
mod sub_u16 {
use super::*;
#[test]
fn test_rnd_u16() {
test_rnd_generic::<u16>(vec![0u16, 1u16, u16::max_value() - 1, u16::max_value()]);
}
#[test]
fn test_full_u16() {
test_full_generic::<u16>(u16::min_value(), u16::max_value());
}
#[test]
fn test_empty_u16() {
test_empty_generic::<u16>();
}
#[test]
fn test_single_u16() {
test_single_generic::<u16>(3u16);
}
}
mod sub_u32 {
use super::*;
#[test]
fn test_rnd_u32() {
test_rnd_generic::<u32>(vec![0u32, 1u32, u32::max_value() - 1, u32::max_value()]);
}
#[test]
fn test_empty_u32() {
test_empty_generic::<u32>();
}
#[test]
fn test_single_u32() {
test_single_generic::<u32>(3u32);
}
}
mod sub_u64 {
use super::*;
#[test]
fn test_rnd_u64() {
test_rnd_generic::<u64>(vec![0u64, 1u64, u64::max_value() - 1, u64::max_value()]);
}
#[test]
fn test_empty_u64() {
test_empty_generic::<u64>();
}
#[test]
fn test_single_u64() {
test_single_generic::<u64>(3u64);
}
}
mod sub_usize {
use super::*;
#[test]
fn test_rnd_usize() {
test_rnd_generic::<usize>(vec![0, 1, usize::max_value() - 1, usize::max_value()]);
}
#[test]
fn test_empty_usize() {
test_empty_generic::<usize>();
}
#[test]
fn test_single_usize() {
test_single_generic::<usize>(3);
}
}
mod sub_f32 {
use super::*;
use std::f32;
#[test]
fn test_rnd_f32() {
test_rnd_generic::<f32>(vec![-f32::INFINITY, -0f32, 0f32, f32::INFINITY]);
}
#[test]
fn test_empty_f32() {
test_empty_generic::<f32>();
}
#[test]
fn test_single_f32() {
test_single_generic::<f32>(3f32);
}
}
mod sub_f64 {
use super::*;
use std::f64;
#[test]
fn test_rnd_f64() {
test_rnd_generic::<f64>(vec![-f64::INFINITY, -0f64, 0f64, f64::INFINITY]);
}
#[test]
fn test_empty_f64() {
test_empty_generic::<f64>();
}
#[test]
fn test_single_f64() {
test_single_generic::<f64>(3f64);
}
}
mod sub_tuple {
use super::*;
#[test]
fn test_empty_tuple0() {
test_empty_generic::<()>();
}
#[test]
fn test_single_tuple0() {
test_single_generic::<()>(());
}
#[test]
fn test_rnd_tuple1() {
test_rnd_generic::<(u8,)>(vec![]);
}
#[test]
fn test_empty_tuple1() {
test_empty_generic::<(u8,)>();
}
#[test]
fn test_single_tuple1() {
test_single_generic::<(u8,)>((1u8,));
}
#[test]
fn test_rnd_tuple2() {
test_rnd_generic::<(u8, i32)>(vec![]);
}
#[test]
fn test_empty_tuple2() {
test_empty_generic::<(u8, i32)>();
}
#[test]
fn test_single_tuple2() {
test_single_generic::<(u8, i32)>((1u8, 1337i32));
}
#[test]
fn test_rnd_tuple3() {
test_rnd_generic::<(u8, i32, char)>(vec![]);
}
#[test]
fn test_empty_tuple3() {
test_empty_generic::<(u8, i32, char)>();
}
#[test]
fn test_single_tuple3() {
test_single_generic::<(u8, i32, char)>((1u8, 1337i32, 'x'));
}
}