#![cfg(test)]
extern crate test;
use std::mem;
use std::num::Int;
use std::ptr;
fn insertsort_impl<T, F>(ptr: *mut T, len: int, lt: &F) where F: Fn(&T, &T) -> bool {
for i in range(1, len) {
let mut j = i;
unsafe {
let read_ptr = ptr.offset(i) as *const T;
while j > 0 &&
lt(&*read_ptr, &*ptr.offset(j - 1)) {
j -= 1;
}
if i != j {
let tmp = ptr::read(read_ptr);
ptr::copy_memory(ptr.offset(j + 1),
&*ptr.offset(j),
(i - j) as uint);
ptr::copy_nonoverlapping_memory(ptr.offset(j),
&tmp as *const T,
1);
mem::forget(tmp);
}
}
}
}
pub fn insertsort_by<T: PartialOrd, F>(v: &mut[T], lt: F) where F: Fn(&T, &T) -> bool {
insertsort_impl(v.as_mut_ptr(), v.len() as int, <);
}
pub fn insertsort<T: PartialOrd>(v: &mut[T]) {
insertsort_by(v, |a, b| a.lt(b));
}
fn heapify<T, F>(ptr: *mut T, len: int, lt: &F) where F: Fn(&T, &T) -> bool {
let mut start = (len - 2) / 2;
let end = len - 1;
while start >= 0 {
shift_down(ptr, start, end, lt);
start = start - 1;
}
}
fn shift_down<T, F>(ptr: *mut T, start: int, end: int, lt: &F) where F: Fn(&T, &T) -> bool {
let mut root = start;
let mut next_root = root * 2;
while next_root < end {
let left_child = next_root + 1;
let mut swap = root;
unsafe {
if lt(&*ptr.offset(swap), &*ptr.offset(left_child)) {
swap = left_child;
}
let right_child = left_child + 1;
if right_child <= end && lt(&*ptr.offset(swap), &*ptr.offset(right_child)) {
swap = right_child;
}
if swap == root {
return;
}
ptr::swap(ptr.offset(root), ptr.offset(swap));
}
root = swap;
next_root = root * 2;
}
}
fn heapsort_impl<T, F>(ptr: *mut T, len: int, lt: &F) where F: Fn(&T, &T) -> bool {
heapify(ptr, len, lt);
let mut end = len - 1;
while end > 0 {
unsafe { ptr::swap(ptr.offset(end), ptr); }
end = end - 1;
shift_down(ptr, 0, end, lt);
}
}
pub fn heapsort_by<T: PartialOrd, F>(v: &mut[T], lt: F) where F: Fn(&T, &T) -> bool {
let len = v.len() as int;
if len > 0 {
let ptr = v.as_mut_ptr();
heapsort_impl(ptr, len, <);
}
}
pub fn heapsort<T: PartialOrd>(v: &mut[T]) {
heapsort_by(v, |a, b| a.lt(b));
}
const THRESHOLD: int = 16;
#[inline]
fn lg(n: uint) -> uint {
mem::size_of::<uint>() * 8 - 1 - n.leading_zeros()
}
#[inline]
fn ptr_distance<T>(last: *const T, first: *const T) -> int {
((last as uint - first as uint) / mem::size_of::<T>()) as int
}
#[inline]
fn median_3<T, F>(a: *mut T, b: *mut T, c: *mut T, lt: &F) -> *mut T where F: Fn(&T, &T) -> bool {
unsafe {
if lt(&*a, &*b) {
if lt(&*b, &*c) {
b
}
else if lt(&*a, &*c) {
c
}
else {
a
}
}
else if lt(&*a, &*c) {
a
}
else if lt(&*b, &*c) {
c
}
else {
b
}
}
}
#[inline]
fn partition<T, F>(mut first: *mut T, mut last: *mut T, pivot: *mut T, lt: &F) -> *mut T
where F: Fn(&T, &T) -> bool {
unsafe {
loop {
while lt(&*first, &*pivot) {
first = first.offset(1);
}
last = last.offset(-1);
while lt(&*pivot, &*last) {
last = last.offset(-1);
}
if !((first as uint) < (last as uint)) {
return first;
}
ptr::swap(first, last);
first = first.offset(1);
}
}
}
#[inline]
fn partition_pivot<T, F>(ptr: *mut T, len: int, lt: &F) -> *mut T where F: Fn(&T, &T) -> bool {
unsafe {
let pivot = median_3(ptr.offset(1), ptr.offset(len / 2), ptr.offset(len - 1), lt);
ptr::swap(ptr, pivot);
return partition(ptr.offset(1), ptr.offset(len), ptr, lt);
}
}
fn introsort_loop<T, F>(ptr: *mut T, mut last: *mut T, mut depth_limit: uint, lt: &F) where F: Fn(&T, &T) -> bool {
let mut len = ptr_distance(last, ptr);
while len > THRESHOLD {
if depth_limit == 0 {
heapsort_impl(ptr, len, lt);
return;
}
depth_limit -= 1;
let pivot = partition_pivot(ptr, len, lt);
introsort_loop(pivot, last, depth_limit, lt);
len = ptr_distance(pivot, ptr);
last = pivot;
}
}
#[inline]
pub fn introsort_impl<T: PartialOrd, F>(v: &mut[T], lt: F) where F: Fn(&T, &T) -> bool {
let len = v.len() as int;
if len > 0 {
let ptr = v.as_mut_ptr();
unsafe {
introsort_loop(ptr, ptr.offset(len), 2 * lg(len as uint), <);
}
insertsort_impl(ptr, len, <);
}
}
#[inline]
pub fn introsort_by<T: PartialOrd, F>(v: &mut[T], lt: F) where F: Fn(&T, &T) -> bool {
introsort_impl(v, lt);
}
#[inline]
pub fn introsort<T: PartialOrd>(v: &mut[T]) {
introsort_impl(v, |a, b| a.lt(b))
}
#[cfg(test)]
mod tests {
use std::rand::{Rng, thread_rng};
use insertsort;
use insertsort_by;
use heapsort;
use heapsort_by;
use introsort;
use introsort_by;
#[test]
fn test_insertsort() {
for len in range(4u, 25) {
for _ in range(0i, 100) {
let mut v = thread_rng().gen_iter::<uint>().take(len)
.collect::<Vec<uint>>();
let mut v1 = v.clone();
insertsort(v.as_mut_slice());
assert!(v.as_slice().windows(2).all(|w| w[0] <= w[1]));
insertsort_by(v1.as_mut_slice(), |a, b| a.lt(b));
assert!(v1.as_slice().windows(2).all(|w| w[0] <= w[1]));
insertsort_by(v1.as_mut_slice(), |a, b| b.lt(a));
assert!(v1.as_slice().windows(2).all(|w| w[0] >= w[1]));
}
}
let mut v: [uint; 0] = [];
insertsort(v.as_mut_slice());
let mut v = [0xDEADBEEFu];
insertsort(v.as_mut_slice());
assert!(v == [0xDEADBEEF]);
}
#[test]
fn test_heapsort() {
for len in range(4u, 25) {
for _ in range(0i, 100) {
let mut v = thread_rng().gen_iter::<uint>().take(len)
.collect::<Vec<uint>>();
let mut v1 = v.clone();
heapsort(v.as_mut_slice());
assert!(v.as_slice().windows(2).all(|w| w[0] <= w[1]));
heapsort_by(v1.as_mut_slice(), |a, b| a.lt(b));
assert!(v1.as_slice().windows(2).all(|w| w[0] <= w[1]));
heapsort_by(v1.as_mut_slice(), |a, b| b.lt(a));
assert!(v1.as_slice().windows(2).all(|w| w[0] >= w[1]));
}
}
let mut v: [uint; 0] = [];
heapsort(v.as_mut_slice());
let mut v = [0xDEADBEEFu];
heapsort(v.as_mut_slice());
assert!(v == [0xDEADBEEF]);
}
#[test]
fn test_introsort() {
for len in range(4u, 25) {
for _ in range(0i, 100) {
let mut v = thread_rng().gen_iter::<uint>().take(len)
.collect::<Vec<uint>>();
let mut v1 = v.clone();
introsort(v.as_mut_slice());
assert!(v.as_slice().windows(2).all(|w| w[0] <= w[1]));
introsort_by(v1.as_mut_slice(), |a, b| a.lt(b));
assert!(v1.as_slice().windows(2).all(|w| w[0] <= w[1]));
introsort_by(v1.as_mut_slice(), |a, b| b.lt(a));
assert!(v1.as_slice().windows(2).all(|w| w[0] >= w[1]));
}
}
let mut v: [uint; 0] = [];
introsort(v.as_mut_slice());
let mut v = [0xDEADBEEFu];
introsort(v.as_mut_slice());
assert!(v == [0xDEADBEEF]);
}
}
#[cfg(test)]
mod bench {
use heapsort;
use insertsort;
use introsort;
use std::mem;
use std::rand::{weak_rng, Rng};
use test::{ Bencher };
type BigSortable = (u64,u64,u64,u64);
fn bench_random_small<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [u64]) {
let mut rng = weak_rng();
b.iter(|| {
let mut v = rng.gen_iter::<u64>().take(5).collect::<Vec<u64>>();
sortfn(v.as_mut_slice());
});
b.bytes = 5 * mem::size_of::<u64>() as u64;
}
fn bench_random_medium<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [u64]) {
let mut rng = weak_rng();
b.iter(|| {
let mut v = rng.gen_iter::<u64>().take(100).collect::<Vec<u64>>();
sortfn(v.as_mut_slice());
});
b.bytes = 100 * mem::size_of::<u64>() as u64;
}
fn bench_random_large<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [u64]) {
let mut rng = weak_rng();
b.iter(|| {
let mut v = rng.gen_iter::<u64>().take(10000).collect::<Vec<u64>>();
sortfn(v.as_mut_slice());
});
b.bytes = 10000 * mem::size_of::<u64>() as u64;
}
fn bench_sorted<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [uint]) {
let mut v = range(0u, 10000).collect::<Vec<_>>();
b.iter(|| {
sortfn(v.as_mut_slice());
});
b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64;
}
fn bench_big_random_small<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [BigSortable]) {
let mut rng = weak_rng();
b.iter(|| {
let mut v = rng.gen_iter::<BigSortable>().take(5)
.collect::<Vec<BigSortable>>();
sortfn(v.as_mut_slice());
});
b.bytes = 5 * mem::size_of::<BigSortable>() as u64;
}
fn bench_big_random_medium<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [BigSortable]) {
let mut rng = weak_rng();
b.iter(|| {
let mut v = rng.gen_iter::<BigSortable>().take(100)
.collect::<Vec<BigSortable>>();
sortfn(v.as_mut_slice());
});
b.bytes = 100 * mem::size_of::<BigSortable>() as u64;
}
fn bench_big_random_large<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [BigSortable]) {
let mut rng = weak_rng();
b.iter(|| {
let mut v = rng.gen_iter::<BigSortable>().take(10000)
.collect::<Vec<BigSortable>>();
sortfn(v.as_mut_slice());
});
b.bytes = 10000 * mem::size_of::<BigSortable>() as u64;
}
fn bench_big_sorted<F>(b: &mut Bencher, sortfn: F) where F: Fn(&mut [BigSortable]) {
let mut v = range(0, 10000u64).map(|i| (i, i, i, i)).collect::<Vec<_>>();
b.iter(|| {
sortfn(v.as_mut_slice());
});
b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64;
}
#[bench]
fn introsort_random_small(b: &mut Bencher) {
bench_random_small(b, introsort);
}
#[bench]
fn introsort_random_medium(b: &mut Bencher) {
bench_random_medium(b, introsort);
}
#[bench]
fn introsort_random_large(b: &mut Bencher) {
bench_random_large(b, introsort);
}
#[bench]
fn introsort_sorted(b: &mut Bencher) {
bench_sorted(b, introsort);
}
#[bench]
fn introsort_big_random_small(b: &mut Bencher) {
bench_big_random_small(b, introsort);
}
#[bench]
fn introsort_big_random_medium(b: &mut Bencher) {
bench_big_random_medium(b, introsort);
}
#[bench]
fn introsort_big_random_large(b: &mut Bencher) {
bench_big_random_large(b, introsort);
}
#[bench]
fn introsort_big_sorted(b: &mut Bencher) {
bench_big_sorted(b, introsort);
}
#[bench]
fn insertsort_random_small(b: &mut Bencher) {
bench_random_small(b, insertsort);
}
#[bench]
fn insertsort_random_medium(b: &mut Bencher) {
bench_random_medium(b, insertsort);
}
#[bench]
fn insertsort_sorted(b: &mut Bencher) {
bench_sorted(b, insertsort);
}
#[bench]
fn insertsort_big_random_small(b: &mut Bencher) {
bench_big_random_small(b, insertsort);
}
#[bench]
fn insertsort_big_random_medium(b: &mut Bencher) {
bench_big_random_medium(b, insertsort);
}
#[bench]
fn insertsort_big_sorted(b: &mut Bencher) {
bench_big_sorted(b, insertsort);
}
#[bench]
fn heapsort_random_small(b: &mut Bencher) {
bench_random_small(b, heapsort);
}
#[bench]
fn heapsort_random_medium(b: &mut Bencher) {
bench_random_medium(b, heapsort);
}
#[bench]
fn heapsort_random_large(b: &mut Bencher) {
bench_random_large(b, heapsort);
}
#[bench]
fn heapsort_sorted(b: &mut Bencher) {
bench_sorted(b, heapsort);
}
#[bench]
fn heapsort_big_random_small(b: &mut Bencher) {
bench_big_random_small(b, heapsort);
}
#[bench]
fn heapsort_big_random_medium(b: &mut Bencher) {
bench_big_random_medium(b, heapsort);
}
#[bench]
fn heapsort_big_random_large(b: &mut Bencher) {
bench_big_random_large(b, heapsort);
}
#[bench]
fn heapsort_big_sorted(b: &mut Bencher) {
bench_big_sorted(b, heapsort);
}
fn mergesort<T: Ord>(v: &mut[T]) { v.sort(); }
#[bench]
fn stdsort_random_small(b: &mut Bencher) {
bench_random_small(b, mergesort);
}
#[bench]
fn stdsort_random_medium(b: &mut Bencher) {
bench_random_medium(b, mergesort);
}
#[bench]
fn stdsort_random_large(b: &mut Bencher) {
bench_random_large(b, mergesort);
}
#[bench]
fn stdsort_sorted(b: &mut Bencher) {
bench_sorted(b, mergesort);
}
#[bench]
fn stdsort_big_random_small(b: &mut Bencher) {
bench_big_random_small(b, mergesort);
}
#[bench]
fn stdsort_big_random_medium(b: &mut Bencher) {
bench_big_random_medium(b, mergesort);
}
#[bench]
fn stdsort_big_random_large(b: &mut Bencher) {
bench_big_random_large(b, mergesort);
}
#[bench]
fn stdsort_big_sorted(b: &mut Bencher) {
bench_big_sorted(b, mergesort);
}
}