From 259660811054364c5ec94e7b05c5f403889c3d68 Mon Sep 17 00:00:00 2001 From: Emerentius Date: Fri, 26 Nov 2021 11:55:56 +0100 Subject: [PATCH 1/2] use string literal for panic --- src/slice_ext.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/slice_ext.rs b/src/slice_ext.rs index 59e3baa..1304ba1 100644 --- a/src/slice_ext.rs +++ b/src/slice_ext.rs @@ -4,11 +4,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ord_subset_trait::*; use core::cmp::Ordering::{self, Equal, Greater, Less}; +use ord_subset_trait::*; + +macro_rules! panic_binary_search_outside_order { + () => { + panic!("Attempted binary search for value outside total order") + }; +} -static ERROR_BINARY_SEARCH_OUTSIDE_ORDER: &str = - "Attempted binary search for value outside total order"; static ERROR_BINARY_SEARCH_EXPECT: &str = "Unexpected None for a.partial_cmp(b), a,b inside order. Violated OrdSubset contract or attempted binary search on unsorted data"; // Wrapper for comparison functions @@ -297,7 +301,7 @@ where T: OrdSubset, { if x.is_outside_order() { - panic!(ERROR_BINARY_SEARCH_OUTSIDE_ORDER) + panic_binary_search_outside_order!() }; self.ord_subset_binary_search_by(|other| { other.partial_cmp(x).expect(ERROR_BINARY_SEARCH_EXPECT) @@ -325,7 +329,7 @@ where F: FnMut(&T) -> B, { if b.is_outside_order() { - panic!(ERROR_BINARY_SEARCH_OUTSIDE_ORDER) + panic_binary_search_outside_order!() }; // compare ordered values as expected // wrap it in a function that deals with unordered, so this one never sees them @@ -340,7 +344,7 @@ where T: OrdSubset, { if x.is_outside_order() { - panic!(ERROR_BINARY_SEARCH_OUTSIDE_ORDER) + panic_binary_search_outside_order!() }; self.ord_subset_binary_search_by(|other| { x.partial_cmp(other).expect(ERROR_BINARY_SEARCH_EXPECT) From b6826c56c9b344f4649b17fb6d02770ef7b77739 Mon Sep 17 00:00:00 2001 From: Emerentius Date: Fri, 26 Nov 2021 13:08:03 +0100 Subject: [PATCH 2/2] add ord_subset_sort_by_cached_key --- src/slice_ext.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/slice_ext.rs b/src/slice_ext.rs index 1304ba1..1842588 100644 --- a/src/slice_ext.rs +++ b/src/slice_ext.rs @@ -34,6 +34,32 @@ where } } +struct CmpUnorderedGreaterAll(T); + +impl PartialEq for CmpUnorderedGreaterAll { + fn eq(&self, other: &Self) -> bool { + self.0.is_outside_order() && other.0.is_outside_order() || self.0 == other.0 + } +} + +impl PartialOrd for CmpUnorderedGreaterAll { + fn partial_cmp(&self, other: &Self) -> Option { + Some(cmp_unordered_greater_all( + &self.0, + &other.0, + CmpUnwrap::cmp_unwrap, + )) + } +} + +impl Eq for CmpUnorderedGreaterAll {} + +impl Ord for CmpUnorderedGreaterAll { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap() + } +} + pub trait OrdSubsetSliceExt { /// Sort the slice. Values outside the ordered subset are put at the end in their original order. /// @@ -202,6 +228,12 @@ pub trait OrdSubsetSliceExt { fn ord_subset_binary_search_rev(&self, x: &T) -> Result where T: OrdSubset; + + fn ord_subset_sort_by_cached_key(&mut self, f: F) + where + Self: AsMut<[T]>, + F: FnMut(&T) -> K, + K: OrdSubset; } impl OrdSubsetSliceExt for U @@ -350,4 +382,24 @@ where x.partial_cmp(other).expect(ERROR_BINARY_SEARCH_EXPECT) }) } + + fn ord_subset_sort_by_cached_key(&mut self, mut f: F) + where + U: AsMut<[T]>, + F: FnMut(&T) -> K, + K: OrdSubset, + { + let new_key_f = dummy(|val| CmpUnorderedGreaterAll(f(val))); + self.as_mut().sort_by_cached_key(new_key_f); + } +} + +// A function that just returns its argument, but serves as a type hint. +// Otherwise we get an error about the closure input lifetime not being general enough. +// Taken from user github.com/comex: https://github.com/rust-lang/rust/issues/70263#issuecomment-623169045 +fn dummy(f: F) -> F +where + F: for<'a> FnMut(&'a T) -> K, +{ + f }