Skip to content

Commit

Permalink
Specialize ordering() for Ord types
Browse files Browse the repository at this point in the history
  • Loading branch information
coolreader18 committed May 5, 2022
1 parent 235bc0c commit 607edb8
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 35 deletions.
4 changes: 2 additions & 2 deletions src/find_run/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{comparator, never};
use crate::{comparator, never, ord_t_comparator};

#[test]
fn empty() {
Expand Down Expand Up @@ -76,5 +76,5 @@ fn find_run<T: Ord>(list: &[T]) -> (bool, usize) {

/// With comparator.
fn get_run<T: Ord>(list: &mut [T]) -> usize {
super::get_run(list, &comparator(|a, b| Ok(a > b))).unwrap_or_else(never)
super::get_run(list, &ord_t_comparator()).unwrap_or_else(never)
}
17 changes: 3 additions & 14 deletions src/gallop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub(crate) fn gallop_left<T, C: Comparator<T>>(
let (mut base, mut lim) = gallop(key, list, mode, cmp)?;
while lim != 0 {
let ix = base + (lim / 2);
match ordering(cmp, &list[ix], key)? {
match cmp.ordering(&list[ix], key)? {
Ordering::Less => {
base = ix + 1;
lim -= 1;
Expand Down Expand Up @@ -53,7 +53,7 @@ pub(crate) fn gallop_right<T, C: Comparator<T>>(
let (mut base, mut lim) = gallop(key, list, mode, cmp)?;
while lim != 0 {
let ix = base + (lim / 2);
match ordering(cmp, &list[ix], key)? {
match cmp.ordering(&list[ix], key)? {
Ordering::Less => {
base = ix + 1;
lim -= 1;
Expand Down Expand Up @@ -88,7 +88,7 @@ fn gallop<T, C: Comparator<T>>(
let mut prev_val = 0;
let mut next_val = 1;
while next_val < list_len {
match ordering(cmp, &list[next_val], key)? {
match cmp.ordering(&list[next_val], key)? {
Ordering::Less => {
prev_val = next_val;
next_val = ((next_val + 1) * 2) - 1;
Expand Down Expand Up @@ -124,14 +124,3 @@ fn gallop<T, C: Comparator<T>>(
};
Ok(ret)
}

fn ordering<T, C: Comparator<T>>(cmp: &C, a: &T, b: &T) -> Result<Ordering, C::Error> {
let ord = if cmp.is_gt(a, b)? {
Ordering::Greater
} else if cmp.is_gt(b, a)? {
Ordering::Less
} else {
Ordering::Equal
};
Ok(ord)
}
6 changes: 3 additions & 3 deletions src/gallop/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::Mode;
use crate::{comparator, never};
use crate::{never, ord_t_comparator};

macro_rules! test_both {
($v:ident, $($x:expr);*) => {{
Expand Down Expand Up @@ -182,9 +182,9 @@ fn gallop_large_end_greater() {
}

fn gallop_left<T: Ord>(key: &T, list: &[T], mode: Mode) -> usize {
super::gallop_left(key, list, mode, &comparator(|a, b| Ok(a > b))).unwrap_or_else(never)
super::gallop_left(key, list, mode, &ord_t_comparator()).unwrap_or_else(never)
}

fn gallop_right<T: Ord>(key: &T, list: &[T], mode: Mode) -> usize {
super::gallop_right(key, list, mode, &comparator(|a, b| Ok(a > b))).unwrap_or_else(never)
super::gallop_right(key, list, mode, &ord_t_comparator()).unwrap_or_else(never)
}
4 changes: 2 additions & 2 deletions src/insort/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{comparator, never};
use crate::{comparator, never, ord_t_comparator};

/// Test the insertion sort implementation with an empty list
#[test]
Expand Down Expand Up @@ -80,5 +80,5 @@ fn stable() {

/// Insertion sort implementation convenience used for tests.
fn sort<T: Ord>(list: &mut [T]) {
super::sort(list, &comparator(|a, b| Ok(a > b))).unwrap_or_else(never);
super::sort(list, &ord_t_comparator()).unwrap_or_else(never);
}
47 changes: 41 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod insort;
mod merge;
mod sort;

pub use sort::try_sort_by as try_sort_by_gt;
use sort::try_sort_by as try_sort_by_cmp;
use std::cmp::Ordering;
use std::convert::Infallible;

Expand All @@ -19,14 +19,19 @@ fn never<T>(x: Infallible) -> T {
match x {}
}

pub fn try_sort_by_gt<T, E, C: Fn(&T, &T) -> Result<bool, E>>(
list: &mut [T],
cmp: C,
) -> Result<(), E> {
try_sort_by_cmp(list, cmp)
}

#[inline]
pub fn try_sort_by<T, E, C: Fn(&T, &T) -> Result<Ordering, E>>(
list: &mut [T],
cmp: C,
) -> Result<(), E> {
try_sort_by_gt(list, move |a, b| {
cmp(a, b).map(|ord| ord == Ordering::Greater)
})
try_sort_by_cmp(list, ord_comparator(cmp))
}

#[inline]
Expand All @@ -41,13 +46,23 @@ pub fn sort_by<T, C: Fn(&T, &T) -> Ordering>(list: &mut [T], cmp: C) {
}

#[inline]
pub fn sort<T: PartialOrd>(list: &mut [T]) {
sort_by_gt(list, |a, b| a > b)
pub fn sort<T: Ord>(list: &mut [T]) {
sort_by(list, Ord::cmp)
}

trait Comparator<T> {
type Error;
fn is_gt(&self, lhs: &T, rhs: &T) -> Result<bool, Self::Error>;
fn ordering(&self, lhs: &T, rhs: &T) -> Result<Ordering, Self::Error> {
let ord = if self.is_gt(lhs, rhs)? {
Ordering::Greater
} else if self.is_gt(rhs, lhs)? {
Ordering::Less
} else {
Ordering::Equal
};
Ok(ord)
}
}

impl<F, T, E> Comparator<T> for F
Expand All @@ -67,3 +82,23 @@ pub(crate) fn comparator<T>(
) -> impl Comparator<T, Error = Infallible> {
f
}
#[cfg(test)]
pub(crate) fn ord_t_comparator<T: Ord>() -> impl Comparator<T, Error = Infallible> {
ord_comparator(|a: &T, b| Ok(a.cmp(b)))
}

pub(crate) fn ord_comparator<T, E, F: Fn(&T, &T) -> Result<Ordering, E>>(
f: F,
) -> impl Comparator<T, Error = E> {
struct OrdComparator<F>(F);
impl<T, E, F: Fn(&T, &T) -> Result<Ordering, E>> Comparator<T> for OrdComparator<F> {
type Error = E;
fn is_gt(&self, lhs: &T, rhs: &T) -> Result<bool, E> {
(self.0)(lhs, rhs).map(|ord| ord == Ordering::Greater)
}
fn ordering(&self, lhs: &T, rhs: &T) -> Result<Ordering, Self::Error> {
(self.0)(lhs, rhs)
}
}
OrdComparator(f)
}
4 changes: 2 additions & 2 deletions src/merge/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! sized temporary slice of the same type. Naturally, it can only merge slices
//! that are themselves already sorted.
use crate::{comparator, never};
use crate::{comparator, never, ord_t_comparator};

/// Test mergeing two empty slices.
#[test]
Expand Down Expand Up @@ -244,5 +244,5 @@ fn hi_gallop_stress() {

/// Merge convenience used for tests.
fn merge<T: Ord>(list: &mut [T], first_len: usize) {
super::merge(list, first_len, &comparator(|a, b| Ok(a > b))).unwrap_or_else(never)
super::merge(list, first_len, &ord_t_comparator()).unwrap_or_else(never)
}
5 changes: 1 addition & 4 deletions src/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,7 @@ impl<'a, T, C: Comparator<T>> SortState<'a, T, C> {
}

/// Sorts the list using merge sort.
pub fn try_sort_by<T, E, C: Fn(&T, &T) -> Result<bool, E>>(
list: &mut [T],
cmp: C,
) -> Result<(), E> {
pub(crate) fn try_sort_by<T, C: Comparator<T>>(list: &mut [T], cmp: C) -> Result<(), C::Error> {
if list.len() < MIN_MERGE {
insort::sort(list, &cmp)
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/sort/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! The top sorting algorithm; that is, the modified merge sort we keep
//! talking about.
use crate::{comparator, never};
use crate::{never, ord_t_comparator};

/// Test the sort implementation with an empty list
#[test]
Expand Down Expand Up @@ -109,7 +109,7 @@ fn stable() {

/// Sort implementation convenience used for tests.
fn sort<T: Ord>(list: &mut [T]) {
super::SortState::new(list, &comparator(|a, b| Ok(a > b)))
super::SortState::new(list, &ord_t_comparator())
.sort()
.unwrap_or_else(never)
}

0 comments on commit 607edb8

Please sign in to comment.