auto merge of #8400 : blake2-ppc/rust/seq-ord, r=cmr
Use Eq + Ord for lexicographical ordering of sequences. For each of <, <=, >= or > as R, use:: [x, ..xs] R [y, ..ys] = if x != y { x R y } else { xs R ys } Previous code using `a < b` and then `!(b < a)` for short-circuiting fails on cases such as [1.0, 2.0] < [0.0/0.0, 3.0], where the first element was effectively considered equal. Containers like &[T] did also implement only one comparison operator `<`, and derived the comparison results from this. This isn't correct either for Ord. Implement functions in `std::iterator::order::{lt,le,gt,ge,equal,cmp}` that all iterable containers can use for lexical order. We also visit tuple ordering, having the same problem and same solution (but differing implementation).
This commit is contained in:
commit
35040275b3
6 changed files with 308 additions and 73 deletions
|
@ -148,7 +148,7 @@ macro_rules! tuple_impls {
|
|||
$(fn $get_fn(&self) -> $T;)+
|
||||
}
|
||||
|
||||
impl<$($T:Clone),+> $cloneable_trait<$($T),+> for ($($T),+) {
|
||||
impl<$($T:Clone),+> $cloneable_trait<$($T),+> for ($($T,)+) {
|
||||
$(
|
||||
#[inline]
|
||||
fn $get_fn(&self) -> $T {
|
||||
|
@ -161,7 +161,7 @@ macro_rules! tuple_impls {
|
|||
$(fn $get_ref_fn<'a>(&'a self) -> &'a $T;)+
|
||||
}
|
||||
|
||||
impl<$($T),+> $immutable_trait<$($T),+> for ($($T),+) {
|
||||
impl<$($T),+> $immutable_trait<$($T),+> for ($($T,)+) {
|
||||
$(
|
||||
#[inline]
|
||||
fn $get_ref_fn<'a>(&'a self) -> &'a $T {
|
||||
|
@ -170,59 +170,65 @@ macro_rules! tuple_impls {
|
|||
)+
|
||||
}
|
||||
|
||||
impl<$($T:Clone),+> Clone for ($($T),+) {
|
||||
fn clone(&self) -> ($($T),+) {
|
||||
($(self.$get_ref_fn().clone()),+)
|
||||
impl<$($T:Clone),+> Clone for ($($T,)+) {
|
||||
fn clone(&self) -> ($($T,)+) {
|
||||
($(self.$get_ref_fn().clone(),)+)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
impl<$($T:Eq),+> Eq for ($($T),+) {
|
||||
impl<$($T:Eq),+> Eq for ($($T,)+) {
|
||||
#[inline]
|
||||
fn eq(&self, other: &($($T),+)) -> bool {
|
||||
fn eq(&self, other: &($($T,)+)) -> bool {
|
||||
$(*self.$get_ref_fn() == *other.$get_ref_fn())&&+
|
||||
}
|
||||
#[inline]
|
||||
fn ne(&self, other: &($($T),+)) -> bool {
|
||||
!(*self == *other)
|
||||
fn ne(&self, other: &($($T,)+)) -> bool {
|
||||
$(*self.$get_ref_fn() != *other.$get_ref_fn())||+
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
impl<$($T:TotalEq),+> TotalEq for ($($T),+) {
|
||||
impl<$($T:TotalEq),+> TotalEq for ($($T,)+) {
|
||||
#[inline]
|
||||
fn equals(&self, other: &($($T),+)) -> bool {
|
||||
fn equals(&self, other: &($($T,)+)) -> bool {
|
||||
$(self.$get_ref_fn().equals(other.$get_ref_fn()))&&+
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
impl<$($T:Ord),+> Ord for ($($T),+) {
|
||||
impl<$($T:Ord + Eq),+> Ord for ($($T,)+) {
|
||||
#[inline]
|
||||
fn lt(&self, other: &($($T),+)) -> bool {
|
||||
lexical_lt!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
||||
fn lt(&self, other: &($($T,)+)) -> bool {
|
||||
lexical_ord!(lt, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
||||
}
|
||||
#[inline]
|
||||
fn le(&self, other: &($($T),+)) -> bool { !(*other).lt(&(*self)) }
|
||||
fn le(&self, other: &($($T,)+)) -> bool {
|
||||
lexical_ord!(le, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
||||
}
|
||||
#[inline]
|
||||
fn ge(&self, other: &($($T),+)) -> bool { !(*self).lt(other) }
|
||||
fn ge(&self, other: &($($T,)+)) -> bool {
|
||||
lexical_ord!(ge, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
||||
}
|
||||
#[inline]
|
||||
fn gt(&self, other: &($($T),+)) -> bool { (*other).lt(&(*self)) }
|
||||
fn gt(&self, other: &($($T,)+)) -> bool {
|
||||
lexical_ord!(gt, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
impl<$($T:TotalOrd),+> TotalOrd for ($($T),+) {
|
||||
impl<$($T:TotalOrd),+> TotalOrd for ($($T,)+) {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &($($T),+)) -> Ordering {
|
||||
fn cmp(&self, other: &($($T,)+)) -> Ordering {
|
||||
lexical_cmp!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
impl<$($T:Zero),+> Zero for ($($T),+) {
|
||||
impl<$($T:Zero),+> Zero for ($($T,)+) {
|
||||
#[inline]
|
||||
fn zero() -> ($($T),+) {
|
||||
($(Zero::zero::<$T>()),+)
|
||||
fn zero() -> ($($T,)+) {
|
||||
($(Zero::zero::<$T>(),)+)
|
||||
}
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
|
@ -234,17 +240,16 @@ macro_rules! tuple_impls {
|
|||
}
|
||||
}
|
||||
|
||||
// Constructs an expression that performs a lexical less-than
|
||||
// ordering. The values are interleaved, so the macro invocation for
|
||||
// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_lt!(a1, b1, a2, b2,
|
||||
// Constructs an expression that performs a lexical ordering using method $rel.
|
||||
// The values are interleaved, so the macro invocation for
|
||||
// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
|
||||
// a3, b3)` (and similarly for `lexical_cmp`)
|
||||
macro_rules! lexical_lt {
|
||||
($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
|
||||
if *$a < *$b { true }
|
||||
else if !(*$b < *$a) { lexical_lt!($($rest_a, $rest_b),+) }
|
||||
else { false }
|
||||
macro_rules! lexical_ord {
|
||||
($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
|
||||
if *$a != *$b { lexical_ord!($rel, $a, $b) }
|
||||
else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
|
||||
};
|
||||
($a:expr, $b:expr) => { *$a < *$b };
|
||||
($rel: ident, $a:expr, $b:expr) => { (*$a) . $rel ($b) };
|
||||
}
|
||||
|
||||
macro_rules! lexical_cmp {
|
||||
|
@ -259,6 +264,10 @@ macro_rules! lexical_cmp {
|
|||
|
||||
|
||||
tuple_impls! {
|
||||
(CloneableTuple1, ImmutableTuple1) {
|
||||
(n0, n0_ref) -> A { (ref a,) => a }
|
||||
}
|
||||
|
||||
(CloneableTuple2, ImmutableTuple2) {
|
||||
(n0, n0_ref) -> A { (ref a,_) => a }
|
||||
(n1, n1_ref) -> B { (_,ref b) => b }
|
||||
|
@ -432,6 +441,8 @@ mod tests {
|
|||
fn test_tuple_cmp() {
|
||||
let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u));
|
||||
|
||||
let nan = 0.0/0.0;
|
||||
|
||||
// Eq
|
||||
assert_eq!(small, small);
|
||||
assert_eq!(big, big);
|
||||
|
@ -452,6 +463,13 @@ mod tests {
|
|||
assert!(big >= small);
|
||||
assert!(big >= big);
|
||||
|
||||
assert!(!((1.0, 2.0) < (nan, 3.0)));
|
||||
assert!(!((1.0, 2.0) <= (nan, 3.0)));
|
||||
assert!(!((1.0, 2.0) > (nan, 3.0)));
|
||||
assert!(!((1.0, 2.0) >= (nan, 3.0)));
|
||||
assert!(((1.0, 2.0) < (2.0, nan)));
|
||||
assert!(!((2.0, 2.0) < (2.0, nan)));
|
||||
|
||||
// TotalEq
|
||||
assert!(small.equals(&small));
|
||||
assert!(big.equals(&big));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue