use std::mem;
use std::ptr;
fn insertsort_impl<T, F>(ptr: *mut T, len: isize, lt: &F) where F: Fn(&T, &T) -> bool {
for i in 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(ptr.offset(j), ptr.offset(j + 1), (i - j) as usize);
ptr::copy_nonoverlapping(&tmp, ptr.offset(j), 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 isize, <);
}
pub fn insertsort<T: PartialOrd>(v: &mut[T]) {
insertsort_by(v, |a, b| a.lt(b));
}
fn heapify<T, F>(ptr: *mut T, len: isize, 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: isize, end: isize, 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: isize, 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 isize;
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));
}
#[inline]
fn lg(n: usize) -> usize {
mem::size_of::<usize>() * 8 - 1 - n.leading_zeros() as usize
}
#[inline]
fn ptr_distance<T>(last: *const T, first: *const T) -> isize {
((last as usize - first as usize) / mem::size_of::<T>()) as isize
}
#[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 usize) < (last as usize)) {
return first;
}
ptr::swap(first, last);
first = first.offset(1);
}
}
}
#[inline]
fn partition_pivot<T, F>(ptr: *mut T, len: isize, 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: usize, lt: &F) where F: Fn(&T, &T) -> bool {
const THRESHOLD: isize = 32;
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]
fn introsort_impl<T: PartialOrd, F>(v: &mut[T], lt: F) where F: Fn(&T, &T) -> bool {
let len = v.len() as isize;
if len > 0 {
let ptr = v.as_mut_ptr();
unsafe {
introsort_loop(ptr, ptr.offset(len), 2 * lg(len as usize), <);
}
insertsort_impl(ptr, len, <);
}
}
pub fn introsort_by<T: PartialOrd, F>(v: &mut[T], lt: F) where F: Fn(&T, &T) -> bool {
introsort_impl(v, lt);
}
pub fn introsort<T: PartialOrd>(v: &mut[T]) {
introsort_impl(v, |a, b| a.lt(b))
}