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
|
@ -26,6 +26,7 @@ use std::cast;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::util;
|
use std::util;
|
||||||
use std::iterator::{FromIterator, Extendable, Invert};
|
use std::iterator::{FromIterator, Extendable, Invert};
|
||||||
|
use std::iterator;
|
||||||
|
|
||||||
use container::Deque;
|
use container::Deque;
|
||||||
|
|
||||||
|
@ -589,12 +590,27 @@ impl<A, T: Iterator<A>> Extendable<A, T> for DList<A> {
|
||||||
impl<A: Eq> Eq for DList<A> {
|
impl<A: Eq> Eq for DList<A> {
|
||||||
fn eq(&self, other: &DList<A>) -> bool {
|
fn eq(&self, other: &DList<A>) -> bool {
|
||||||
self.len() == other.len() &&
|
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<A>) -> bool {
|
fn ne(&self, other: &DList<A>) -> bool {
|
||||||
!self.eq(other)
|
self.len() != other.len() &&
|
||||||
|
iterator::order::ne(self.iter(), other.iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Eq + Ord> Ord for DList<A> {
|
||||||
|
fn lt(&self, other: &DList<A>) -> bool {
|
||||||
|
iterator::order::lt(self.iter(), other.iter())
|
||||||
|
}
|
||||||
|
fn le(&self, other: &DList<A>) -> bool {
|
||||||
|
iterator::order::le(self.iter(), other.iter())
|
||||||
|
}
|
||||||
|
fn gt(&self, other: &DList<A>) -> bool {
|
||||||
|
iterator::order::gt(self.iter(), other.iter())
|
||||||
|
}
|
||||||
|
fn ge(&self, other: &DList<A>) -> bool {
|
||||||
|
iterator::order::ge(self.iter(), other.iter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,6 +980,48 @@ mod tests {
|
||||||
assert_eq!(&n, &m);
|
assert_eq!(&n, &m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ord() {
|
||||||
|
let n: DList<int> = 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]
|
#[test]
|
||||||
fn test_fuzz() {
|
fn test_fuzz() {
|
||||||
do 25.times {
|
do 25.times {
|
||||||
|
|
|
@ -1568,6 +1568,163 @@ impl<A: Clone> RandomAccessIterator<A> for Repeat<A> {
|
||||||
fn idx(&self, _: uint) -> Option<A> { Some(self.element.clone()) }
|
fn idx(&self, _: uint) -> Option<A> { 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<A: TotalEq, T: Iterator<A>>(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<A: TotalOrd, T: Iterator<A>>(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<A: Eq, T: Iterator<A>>(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<A: Eq, T: Iterator<A>>(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<A: Eq + Ord, T: Iterator<A>>(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<A: Eq + Ord, T: Iterator<A>>(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<A: Eq + Ord, T: Iterator<A>>(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<A: Eq + Ord, T: Iterator<A>>(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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -47,6 +47,7 @@ use ops::Add;
|
||||||
use util;
|
use util;
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
use iterator::Iterator;
|
use iterator::Iterator;
|
||||||
|
use iterator;
|
||||||
use str::{StrSlice, OwnedStr};
|
use str::{StrSlice, OwnedStr};
|
||||||
use to_str::ToStr;
|
use to_str::ToStr;
|
||||||
use clone::DeepClone;
|
use clone::DeepClone;
|
||||||
|
@ -58,31 +59,21 @@ pub enum Option<T> {
|
||||||
Some(T),
|
Some(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Ord> Ord for Option<T> {
|
impl<T: Eq + Ord> Ord for Option<T> {
|
||||||
fn lt(&self, other: &Option<T>) -> bool {
|
fn lt(&self, other: &Option<T>) -> bool {
|
||||||
match (self, other) {
|
iterator::order::lt(self.iter(), other.iter())
|
||||||
(&None, &None) => false,
|
|
||||||
(&None, &Some(_)) => true,
|
|
||||||
(&Some(_), &None) => false,
|
|
||||||
(&Some(ref a), &Some(ref b)) => *a < *b
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn le(&self, other: &Option<T>) -> bool {
|
fn le(&self, other: &Option<T>) -> bool {
|
||||||
match (self, other) {
|
iterator::order::le(self.iter(), other.iter())
|
||||||
(&None, &None) => true,
|
|
||||||
(&None, &Some(_)) => true,
|
|
||||||
(&Some(_), &None) => false,
|
|
||||||
(&Some(ref a), &Some(ref b)) => *a <= *b
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ge(&self, other: &Option<T>) -> bool {
|
fn ge(&self, other: &Option<T>) -> bool {
|
||||||
!(self < other)
|
iterator::order::ge(self.iter(), other.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gt(&self, other: &Option<T>) -> bool {
|
fn gt(&self, other: &Option<T>) -> bool {
|
||||||
!(self <= other)
|
iterator::order::gt(self.iter(), other.iter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -553,6 +544,18 @@ mod tests {
|
||||||
assert!(it.next().is_none());
|
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]
|
#[test]
|
||||||
fn test_mutate() {
|
fn test_mutate() {
|
||||||
let mut x = Some(3i);
|
let mut x = Some(3i);
|
||||||
|
|
|
@ -70,6 +70,7 @@ pub use from_str::FromStr;
|
||||||
pub use to_bytes::IterBytes;
|
pub use to_bytes::IterBytes;
|
||||||
pub use to_str::{ToStr, ToStrConsume};
|
pub use to_str::{ToStr, ToStrConsume};
|
||||||
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
|
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
|
||||||
|
pub use tuple::{CloneableTuple1, ImmutableTuple1};
|
||||||
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
|
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
|
||||||
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
|
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
|
||||||
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
|
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
|
||||||
|
|
|
@ -148,7 +148,7 @@ macro_rules! tuple_impls {
|
||||||
$(fn $get_fn(&self) -> $T;)+
|
$(fn $get_fn(&self) -> $T;)+
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<$($T:Clone),+> $cloneable_trait<$($T),+> for ($($T),+) {
|
impl<$($T:Clone),+> $cloneable_trait<$($T),+> for ($($T,)+) {
|
||||||
$(
|
$(
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $get_fn(&self) -> $T {
|
fn $get_fn(&self) -> $T {
|
||||||
|
@ -161,7 +161,7 @@ macro_rules! tuple_impls {
|
||||||
$(fn $get_ref_fn<'a>(&'a self) -> &'a $T;)+
|
$(fn $get_ref_fn<'a>(&'a self) -> &'a $T;)+
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<$($T),+> $immutable_trait<$($T),+> for ($($T),+) {
|
impl<$($T),+> $immutable_trait<$($T),+> for ($($T,)+) {
|
||||||
$(
|
$(
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $get_ref_fn<'a>(&'a self) -> &'a $T {
|
fn $get_ref_fn<'a>(&'a self) -> &'a $T {
|
||||||
|
@ -170,59 +170,65 @@ macro_rules! tuple_impls {
|
||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<$($T:Clone),+> Clone for ($($T),+) {
|
impl<$($T:Clone),+> Clone for ($($T,)+) {
|
||||||
fn clone(&self) -> ($($T),+) {
|
fn clone(&self) -> ($($T,)+) {
|
||||||
($(self.$get_ref_fn().clone()),+)
|
($(self.$get_ref_fn().clone(),)+)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
impl<$($T:Eq),+> Eq for ($($T),+) {
|
impl<$($T:Eq),+> Eq for ($($T,)+) {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &($($T),+)) -> bool {
|
fn eq(&self, other: &($($T,)+)) -> bool {
|
||||||
$(*self.$get_ref_fn() == *other.$get_ref_fn())&&+
|
$(*self.$get_ref_fn() == *other.$get_ref_fn())&&+
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ne(&self, other: &($($T),+)) -> bool {
|
fn ne(&self, other: &($($T,)+)) -> bool {
|
||||||
!(*self == *other)
|
$(*self.$get_ref_fn() != *other.$get_ref_fn())||+
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
impl<$($T:TotalEq),+> TotalEq for ($($T),+) {
|
impl<$($T:TotalEq),+> TotalEq for ($($T,)+) {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn equals(&self, other: &($($T),+)) -> bool {
|
fn equals(&self, other: &($($T,)+)) -> bool {
|
||||||
$(self.$get_ref_fn().equals(other.$get_ref_fn()))&&+
|
$(self.$get_ref_fn().equals(other.$get_ref_fn()))&&+
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
impl<$($T:Ord),+> Ord for ($($T),+) {
|
impl<$($T:Ord + Eq),+> Ord for ($($T,)+) {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lt(&self, other: &($($T),+)) -> bool {
|
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]
|
#[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]
|
#[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]
|
#[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))]
|
#[cfg(not(test))]
|
||||||
impl<$($T:TotalOrd),+> TotalOrd for ($($T),+) {
|
impl<$($T:TotalOrd),+> TotalOrd for ($($T,)+) {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cmp(&self, other: &($($T),+)) -> Ordering {
|
fn cmp(&self, other: &($($T,)+)) -> Ordering {
|
||||||
lexical_cmp!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
lexical_cmp!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
impl<$($T:Zero),+> Zero for ($($T),+) {
|
impl<$($T:Zero),+> Zero for ($($T,)+) {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn zero() -> ($($T),+) {
|
fn zero() -> ($($T,)+) {
|
||||||
($(Zero::zero::<$T>()),+)
|
($(Zero::zero::<$T>(),)+)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_zero(&self) -> bool {
|
fn is_zero(&self) -> bool {
|
||||||
|
@ -234,17 +240,16 @@ macro_rules! tuple_impls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructs an expression that performs a lexical less-than
|
// Constructs an expression that performs a lexical ordering using method $rel.
|
||||||
// ordering. The values are interleaved, so the macro invocation for
|
// The values are interleaved, so the macro invocation for
|
||||||
// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_lt!(a1, b1, a2, b2,
|
// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
|
||||||
// a3, b3)` (and similarly for `lexical_cmp`)
|
// a3, b3)` (and similarly for `lexical_cmp`)
|
||||||
macro_rules! lexical_lt {
|
macro_rules! lexical_ord {
|
||||||
($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
|
($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
|
||||||
if *$a < *$b { true }
|
if *$a != *$b { lexical_ord!($rel, $a, $b) }
|
||||||
else if !(*$b < *$a) { lexical_lt!($($rest_a, $rest_b),+) }
|
else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
|
||||||
else { false }
|
|
||||||
};
|
};
|
||||||
($a:expr, $b:expr) => { *$a < *$b };
|
($rel: ident, $a:expr, $b:expr) => { (*$a) . $rel ($b) };
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! lexical_cmp {
|
macro_rules! lexical_cmp {
|
||||||
|
@ -259,6 +264,10 @@ macro_rules! lexical_cmp {
|
||||||
|
|
||||||
|
|
||||||
tuple_impls! {
|
tuple_impls! {
|
||||||
|
(CloneableTuple1, ImmutableTuple1) {
|
||||||
|
(n0, n0_ref) -> A { (ref a,) => a }
|
||||||
|
}
|
||||||
|
|
||||||
(CloneableTuple2, ImmutableTuple2) {
|
(CloneableTuple2, ImmutableTuple2) {
|
||||||
(n0, n0_ref) -> A { (ref a,_) => a }
|
(n0, n0_ref) -> A { (ref a,_) => a }
|
||||||
(n1, n1_ref) -> B { (_,ref b) => b }
|
(n1, n1_ref) -> B { (_,ref b) => b }
|
||||||
|
@ -432,6 +441,8 @@ mod tests {
|
||||||
fn test_tuple_cmp() {
|
fn test_tuple_cmp() {
|
||||||
let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u));
|
let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u));
|
||||||
|
|
||||||
|
let nan = 0.0/0.0;
|
||||||
|
|
||||||
// Eq
|
// Eq
|
||||||
assert_eq!(small, small);
|
assert_eq!(small, small);
|
||||||
assert_eq!(big, big);
|
assert_eq!(big, big);
|
||||||
|
@ -452,6 +463,13 @@ mod tests {
|
||||||
assert!(big >= small);
|
assert!(big >= small);
|
||||||
assert!(big >= big);
|
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
|
// TotalEq
|
||||||
assert!(small.equals(&small));
|
assert!(small.equals(&small));
|
||||||
assert!(big.equals(&big));
|
assert!(big.equals(&big));
|
||||||
|
|
|
@ -564,17 +564,19 @@ pub mod traits {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use clone::Clone;
|
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 ops::Add;
|
||||||
use option::{Some, None};
|
|
||||||
|
|
||||||
impl<'self,T:Eq> Eq for &'self [T] {
|
impl<'self,T:Eq> Eq for &'self [T] {
|
||||||
fn eq(&self, other: & &'self [T]) -> bool {
|
fn eq(&self, other: & &'self [T]) -> bool {
|
||||||
self.len() == other.len() &&
|
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<T:Eq> Eq for ~[T] {
|
impl<T:Eq> Eq for ~[T] {
|
||||||
|
@ -594,7 +596,7 @@ pub mod traits {
|
||||||
impl<'self,T:TotalEq> TotalEq for &'self [T] {
|
impl<'self,T:TotalEq> TotalEq for &'self [T] {
|
||||||
fn equals(&self, other: & &'self [T]) -> bool {
|
fn equals(&self, other: & &'self [T]) -> bool {
|
||||||
self.len() == other.len() &&
|
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] {
|
impl<'self,T:TotalOrd> TotalOrd for &'self [T] {
|
||||||
fn cmp(&self, other: & &'self [T]) -> Ordering {
|
fn cmp(&self, other: & &'self [T]) -> Ordering {
|
||||||
for (s,o) in self.iter().zip(other.iter()) {
|
order::cmp(self.iter(), other.iter())
|
||||||
match s.cmp(o) {
|
|
||||||
Equal => {},
|
|
||||||
non_eq => { return non_eq; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.len().cmp(&other.len())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,23 +641,25 @@ pub mod traits {
|
||||||
fn cmp(&self, other: &@[T]) -> Ordering { self.as_slice().cmp(&other.as_slice()) }
|
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 {
|
fn lt(&self, other: & &'self [T]) -> bool {
|
||||||
for (s,o) in self.iter().zip(other.iter()) {
|
order::lt(self.iter(), other.iter())
|
||||||
if *s < *o { return true; }
|
|
||||||
if *s > *o { return false; }
|
|
||||||
}
|
|
||||||
self.len() < other.len()
|
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn le(&self, other: & &'self [T]) -> bool { !(*other < *self) }
|
fn le(&self, other: & &'self [T]) -> bool {
|
||||||
|
order::le(self.iter(), other.iter())
|
||||||
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ge(&self, other: & &'self [T]) -> bool { !(*self < *other) }
|
fn ge(&self, other: & &'self [T]) -> bool {
|
||||||
|
order::ge(self.iter(), other.iter())
|
||||||
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn gt(&self, other: & &'self [T]) -> bool { *other < *self }
|
fn gt(&self, other: & &'self [T]) -> bool {
|
||||||
|
order::gt(self.iter(), other.iter())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Ord> Ord for ~[T] {
|
impl<T: Eq + Ord> Ord for ~[T] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lt(&self, other: &~[T]) -> bool { self.as_slice() < other.as_slice() }
|
fn lt(&self, other: &~[T]) -> bool { self.as_slice() < other.as_slice() }
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -672,7 +670,7 @@ pub mod traits {
|
||||||
fn gt(&self, other: &~[T]) -> bool { self.as_slice() > other.as_slice() }
|
fn gt(&self, other: &~[T]) -> bool { self.as_slice() > other.as_slice() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Ord> Ord for @[T] {
|
impl<T: Eq + Ord> Ord for @[T] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lt(&self, other: &@[T]) -> bool { self.as_slice() < other.as_slice() }
|
fn lt(&self, other: &@[T]) -> bool { self.as_slice() < other.as_slice() }
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Reference in a new issue