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 {
diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs
index 29f54bd10fba1..d52175eee0cb3 100644
--- a/src/libstd/iterator.rs
+++ b/src/libstd/iterator.rs
@@ -1591,6 +1591,163 @@ 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) },
+ }
+ }
+ }
+
+ #[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)]
mod tests {
use super::*;
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);
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..cb19470e158be 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,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));
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index 36201dc5e8266..e088fd9a647dd 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]