From 5d9fd882b7ebb911daf0f21ca81f4acc599c2686 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 22:07:21 +0200 Subject: [PATCH 1/9] Add std::iterator::order with lexical ordering functions for sequences 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. --- src/libstd/iterator.rs | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 29f54bd10fba1..3d56149fdbaeb 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -1591,6 +1591,116 @@ impl RandomAccessIterator for Repeat { fn idx(&self, _: uint) -> Option { Some(self.element.clone()) } } +/// Functions for lexicographical ordering of sequences. +/// +/// Lexicographical ordering through `<`, `<=`, `>=`, `>` requires +/// that the elements implement both `Eq` and `Ord`. +/// +/// If two sequences are equal up until the point where one ends, +/// the shorter sequence compares less. +pub mod order { + use cmp; + use cmp::{TotalEq, TotalOrd, Ord, Eq}; + use option::{Some, None}; + use super::Iterator; + + /// Compare `a` and `b` for equality using `TotalOrd` + pub fn equals>(mut a: T, mut b: T) -> bool { + loop { + match (a.next(), b.next()) { + (None, None) => return true, + (None, _) | (_, None) => return false, + (Some(x), Some(y)) => if !x.equals(&y) { return false }, + } + } + } + + /// Order `a` and `b` lexicographically using `TotalOrd` + pub fn cmp>(mut a: T, mut b: T) -> cmp::Ordering { + loop { + match (a.next(), b.next()) { + (None, None) => return cmp::Equal, + (None, _ ) => return cmp::Less, + (_ , None) => return cmp::Greater, + (Some(x), Some(y)) => match x.cmp(&y) { + cmp::Equal => (), + non_eq => return non_eq, + }, + } + } + } + + /// Compare `a` and `b` for equality (Using partial equality, `Eq`) + pub fn eq>(mut a: T, mut b: T) -> bool { + loop { + match (a.next(), b.next()) { + (None, None) => return true, + (None, _) | (_, None) => return false, + (Some(x), Some(y)) => if !x.eq(&y) { return false }, + } + } + } + + /// Compare `a` and `b` for nonequality (Using partial equality, `Eq`) + pub fn ne>(mut a: T, mut b: T) -> bool { + loop { + match (a.next(), b.next()) { + (None, None) => return false, + (None, _) | (_, None) => return true, + (Some(x), Some(y)) => if x.ne(&y) { return true }, + } + } + } + + /// Return `a` < `b` lexicographically (Using partial order, `Ord`) + pub fn lt>(mut a: T, mut b: T) -> bool { + loop { + match (a.next(), b.next()) { + (None, None) => return false, + (None, _ ) => return true, + (_ , None) => return false, + (Some(x), Some(y)) => if x.ne(&y) { return x.lt(&y) }, + } + } + } + + /// Return `a` <= `b` lexicographically (Using partial order, `Ord`) + pub fn le>(mut a: T, mut b: T) -> bool { + loop { + match (a.next(), b.next()) { + (None, None) => return true, + (None, _ ) => return true, + (_ , None) => return false, + (Some(x), Some(y)) => if x.ne(&y) { return x.le(&y) }, + } + } + } + + /// Return `a` > `b` lexicographically (Using partial order, `Ord`) + pub fn gt>(mut a: T, mut b: T) -> bool { + loop { + match (a.next(), b.next()) { + (None, None) => return false, + (None, _ ) => return false, + (_ , None) => return true, + (Some(x), Some(y)) => if x.ne(&y) { return x.gt(&y) }, + } + } + } + + /// Return `a` >= `b` lexicographically (Using partial order, `Ord`) + pub fn ge>(mut a: T, mut b: T) -> bool { + loop { + match (a.next(), b.next()) { + (None, None) => return true, + (None, _ ) => return false, + (_ , None) => return true, + (Some(x), Some(y)) => if x.ne(&y) { return x.ge(&y) }, + } + } + } +} + #[cfg(test)] mod tests { use super::*; From a2e3cdfc362e27152bb6a3ad6ba0cefc13f061a9 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 22:07:21 +0200 Subject: [PATCH 2/9] extra::dlist: Use iterator::order for sequence ordering --- src/libextra/dlist.rs | 64 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index b0839a55795b7..6e8bd01af226c 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -26,6 +26,7 @@ use std::cast; use std::ptr; use std::util; use std::iterator::{FromIterator, Extendable, Invert}; +use std::iterator; use container::Deque; @@ -589,12 +590,27 @@ impl> Extendable for DList { impl Eq for DList { fn eq(&self, other: &DList) -> bool { self.len() == other.len() && - self.iter().zip(other.iter()).all(|(a, b)| a.eq(b)) + iterator::order::eq(self.iter(), other.iter()) } - #[inline] fn ne(&self, other: &DList) -> bool { - !self.eq(other) + self.len() != other.len() && + iterator::order::ne(self.iter(), other.iter()) + } +} + +impl Ord for DList { + fn lt(&self, other: &DList) -> bool { + iterator::order::lt(self.iter(), other.iter()) + } + fn le(&self, other: &DList) -> bool { + iterator::order::le(self.iter(), other.iter()) + } + fn gt(&self, other: &DList) -> bool { + iterator::order::gt(self.iter(), other.iter()) + } + fn ge(&self, other: &DList) -> bool { + iterator::order::ge(self.iter(), other.iter()) } } @@ -964,6 +980,48 @@ mod tests { assert_eq!(&n, &m); } + #[test] + fn test_ord() { + let n: DList = list_from([]); + let m = list_from([1,2,3]); + assert!(n < m); + assert!(m > n); + assert!(n <= n); + assert!(n >= n); + } + + #[test] + fn test_ord_nan() { + let nan = 0.0/0.0; + let n = list_from([nan]); + let m = list_from([nan]); + assert!(!(n < m)); + assert!(!(n > m)); + assert!(!(n <= m)); + assert!(!(n >= m)); + + let n = list_from([nan]); + let one = list_from([1.0]); + assert!(!(n < one)); + assert!(!(n > one)); + assert!(!(n <= one)); + assert!(!(n >= one)); + + let u = list_from([1.0,2.0,nan]); + let v = list_from([1.0,2.0,3.0]); + assert!(!(u < v)); + assert!(!(u > v)); + assert!(!(u <= v)); + assert!(!(u >= v)); + + let s = list_from([1.0,2.0,4.0,2.0]); + let t = list_from([1.0,2.0,3.0,2.0]); + assert!(!(s < t)); + assert!(s > one); + assert!(!(s <= one)); + assert!(s >= one); + } + #[test] fn test_fuzz() { do 25.times { From e0b08533b4ffa73185fb6f510873ad57a56dac30 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 22:07:21 +0200 Subject: [PATCH 3/9] std: Implement traits for the one-tuple (A,) did not have the trait implementations of 2- to 12- tuples. --- src/libstd/prelude.rs | 1 + src/libstd/tuple.rs | 44 +++++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 65db55297b3b7..bf4c67e10919e 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -69,6 +69,7 @@ pub use from_str::FromStr; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; +pub use tuple::{CloneableTuple1, ImmutableTuple1}; pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5}; pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9}; pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12}; diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 41af29022a66c..3dc7f65b3add1 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -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,59 @@ 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 { + fn ne(&self, other: &($($T,)+)) -> bool { !(*self == *other) } } #[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),+> Ord for ($($T,)+) { #[inline] - fn lt(&self, other: &($($T),+)) -> bool { + fn lt(&self, other: &($($T,)+)) -> bool { lexical_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 { !(*other).lt(&(*self)) } #[inline] - fn ge(&self, other: &($($T),+)) -> bool { !(*self).lt(other) } + fn ge(&self, other: &($($T,)+)) -> bool { !(*self).lt(other) } #[inline] - fn gt(&self, other: &($($T),+)) -> bool { (*other).lt(&(*self)) } + fn gt(&self, other: &($($T,)+)) -> bool { (*other).lt(&(*self)) } } #[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 { @@ -259,6 +259,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 } From 9cac4ccc90c135082911c59fa366a88f234c4ecb Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 22:07:21 +0200 Subject: [PATCH 4/9] std::vec: Use iterator::order functions for Eq, Ord, TotalOrd, TotalEq --- src/libstd/vec.rs | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 36201dc5e8266..87c2a4f9e0a1e 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -564,17 +564,19 @@ pub mod traits { use super::Vector; use clone::Clone; - use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Equal, Equiv}; + use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Equiv}; + use iterator::order; use ops::Add; - use option::{Some, None}; impl<'self,T:Eq> Eq for &'self [T] { fn eq(&self, other: & &'self [T]) -> bool { self.len() == other.len() && - self.iter().zip(other.iter()).all(|(s,o)| *s == *o) + order::eq(self.iter(), other.iter()) + } + fn ne(&self, other: & &'self [T]) -> bool { + self.len() != other.len() != + order::ne(self.iter(), other.iter()) } - #[inline] - fn ne(&self, other: & &'self [T]) -> bool { !self.eq(other) } } impl Eq for ~[T] { @@ -594,7 +596,7 @@ pub mod traits { impl<'self,T:TotalEq> TotalEq for &'self [T] { fn equals(&self, other: & &'self [T]) -> bool { self.len() == other.len() && - self.iter().zip(other.iter()).all(|(s,o)| s.equals(o)) + order::equals(self.iter(), other.iter()) } } @@ -625,13 +627,7 @@ pub mod traits { impl<'self,T:TotalOrd> TotalOrd for &'self [T] { fn cmp(&self, other: & &'self [T]) -> Ordering { - for (s,o) in self.iter().zip(other.iter()) { - match s.cmp(o) { - Equal => {}, - non_eq => { return non_eq; } - } - } - self.len().cmp(&other.len()) + order::cmp(self.iter(), other.iter()) } } @@ -645,23 +641,25 @@ pub mod traits { fn cmp(&self, other: &@[T]) -> Ordering { self.as_slice().cmp(&other.as_slice()) } } - impl<'self,T:Ord> Ord for &'self [T] { + impl<'self, T: Eq + Ord> Ord for &'self [T] { fn lt(&self, other: & &'self [T]) -> bool { - for (s,o) in self.iter().zip(other.iter()) { - if *s < *o { return true; } - if *s > *o { return false; } - } - self.len() < other.len() + order::lt(self.iter(), other.iter()) } #[inline] - fn le(&self, other: & &'self [T]) -> bool { !(*other < *self) } + fn le(&self, other: & &'self [T]) -> bool { + order::le(self.iter(), other.iter()) + } #[inline] - fn ge(&self, other: & &'self [T]) -> bool { !(*self < *other) } + fn ge(&self, other: & &'self [T]) -> bool { + order::ge(self.iter(), other.iter()) + } #[inline] - fn gt(&self, other: & &'self [T]) -> bool { *other < *self } + fn gt(&self, other: & &'self [T]) -> bool { + order::gt(self.iter(), other.iter()) + } } - impl Ord for ~[T] { + impl Ord for ~[T] { #[inline] fn lt(&self, other: &~[T]) -> bool { self.as_slice() < other.as_slice() } #[inline] @@ -672,7 +670,7 @@ pub mod traits { fn gt(&self, other: &~[T]) -> bool { self.as_slice() > other.as_slice() } } - impl Ord for @[T] { + impl Ord for @[T] { #[inline] fn lt(&self, other: &@[T]) -> bool { self.as_slice() < other.as_slice() } #[inline] From 86da55e85b1f1dd520111b52d1f76c61ea43b382 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 22:07:22 +0200 Subject: [PATCH 5/9] std: Fix Ord for Option, using iterator::order --- src/libstd/option.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 66b30d8dd031c..9af3645c7893c 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -47,6 +47,7 @@ use ops::Add; use util; use num::Zero; use iterator::Iterator; +use iterator; use str::{StrSlice, OwnedStr}; use to_str::ToStr; use clone::DeepClone; @@ -58,31 +59,21 @@ pub enum Option { Some(T), } -impl Ord for Option { +impl Ord for Option { fn lt(&self, other: &Option) -> bool { - match (self, other) { - (&None, &None) => false, - (&None, &Some(_)) => true, - (&Some(_), &None) => false, - (&Some(ref a), &Some(ref b)) => *a < *b - } + iterator::order::lt(self.iter(), other.iter()) } fn le(&self, other: &Option) -> bool { - match (self, other) { - (&None, &None) => true, - (&None, &Some(_)) => true, - (&Some(_), &None) => false, - (&Some(ref a), &Some(ref b)) => *a <= *b - } + iterator::order::le(self.iter(), other.iter()) } fn ge(&self, other: &Option) -> bool { - !(self < other) + iterator::order::ge(self.iter(), other.iter()) } fn gt(&self, other: &Option) -> bool { - !(self <= other) + iterator::order::gt(self.iter(), other.iter()) } } @@ -553,6 +544,18 @@ mod tests { assert!(it.next().is_none()); } + #[test] + fn test_ord() { + let small = Some(1.0); + let big = Some(5.0); + let nan = Some(0.0/0.0); + assert!(!(nan < big)); + assert!(!(nan > big)); + assert!(small < big); + assert!(None < big); + assert!(big > None); + } + #[test] fn test_mutate() { let mut x = Some(3i); From 5dde29c947ec1e6b0a52c7f3ccb0771d2a7736f4 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 22:07:22 +0200 Subject: [PATCH 6/9] std: Fix tuple lexicographical order Use the definition, where R is <, <=, >=, or > [x, ..xs] R [y, ..ys] = if x != y { x R y } else { xs R ys } Previously, tuples would only implement < and derive the other comparisons from it; this is incorrect. Included are several testcases involving NaN comparisons that are now correct. Previously, tuples would consider an element equal if both a < b and b < a were false, this was also incorrect. --- src/libstd/tuple.rs | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 3dc7f65b3add1..238b14ed554d5 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -197,17 +197,23 @@ macro_rules! tuple_impls { } #[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()),+) + 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))] @@ -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 { @@ -436,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); @@ -456,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)); From 8ed8a41c62f51fd7b64a9a61e31c595f7b9497d7 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 22:07:22 +0200 Subject: [PATCH 7/9] std::iterator::order test cases --- src/libstd/iterator.rs | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 3d56149fdbaeb..d52175eee0cb3 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -1699,6 +1699,53 @@ pub mod order { } } } + + #[test] + fn test_lt() { + use vec::ImmutableVector; + + let empty: [int, ..0] = []; + let xs = [1,2,3]; + let ys = [1,2,0]; + + assert!(!lt(xs.iter(), ys.iter())); + assert!(!le(xs.iter(), ys.iter())); + assert!( gt(xs.iter(), ys.iter())); + assert!( ge(xs.iter(), ys.iter())); + + assert!( lt(ys.iter(), xs.iter())); + assert!( le(ys.iter(), xs.iter())); + assert!(!gt(ys.iter(), xs.iter())); + assert!(!ge(ys.iter(), xs.iter())); + + assert!( lt(empty.iter(), xs.iter())); + assert!( le(empty.iter(), xs.iter())); + assert!(!gt(empty.iter(), xs.iter())); + assert!(!ge(empty.iter(), xs.iter())); + + // Sequence with NaN + let u = [1.0, 2.0]; + let v = [0.0/0.0, 3.0]; + + assert!(!lt(u.iter(), v.iter())); + assert!(!le(u.iter(), v.iter())); + assert!(!gt(u.iter(), v.iter())); + assert!(!ge(u.iter(), v.iter())); + + let a = [0.0/0.0]; + let b = [1.0]; + let c = [2.0]; + + assert!(lt(a.iter(), b.iter()) == (a[0] < b[0])); + assert!(le(a.iter(), b.iter()) == (a[0] <= b[0])); + assert!(gt(a.iter(), b.iter()) == (a[0] > b[0])); + assert!(ge(a.iter(), b.iter()) == (a[0] >= b[0])); + + assert!(lt(c.iter(), b.iter()) == (c[0] < b[0])); + assert!(le(c.iter(), b.iter()) == (c[0] <= b[0])); + assert!(gt(c.iter(), b.iter()) == (c[0] > b[0])); + assert!(ge(c.iter(), b.iter()) == (c[0] >= b[0])); + } } #[cfg(test)] From 06783ce831b66d48f2003a8e1022cfdba9e6545d Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 8 Aug 2013 23:07:24 +0200 Subject: [PATCH 8/9] std::vec: Fix typo in fn ne --- src/libstd/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 87c2a4f9e0a1e..e088fd9a647dd 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -574,7 +574,7 @@ pub mod traits { order::eq(self.iter(), other.iter()) } fn ne(&self, other: & &'self [T]) -> bool { - self.len() != other.len() != + self.len() != other.len() || order::ne(self.iter(), other.iter()) } } From 854e219d0aff3eff1f0b3762efc2d1a05ebb426b Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 9 Aug 2013 05:54:49 +0200 Subject: [PATCH 9/9] std::tuple: Use != properly in Eq::ne for tuples Just like the Ord methods, Eq::ne needs to be implemented in terms of the same operation on the elements. --- src/libstd/tuple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 238b14ed554d5..cb19470e158be 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -184,7 +184,7 @@ macro_rules! tuple_impls { } #[inline] fn ne(&self, other: &($($T,)+)) -> bool { - !(*self == *other) + $(*self.$get_ref_fn() != *other.$get_ref_fn())||+ } }