diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 7c45ecae632..95f6f9bc1b5 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -21,15 +21,13 @@ and `Eq` to overload the `==` and `!=` operators. */ /** -* Trait for values that can be compared for equality -* and inequality. +* Trait for values that can be compared for equality and inequality. * -* Eventually this may be simplified to only require -* an `eq` method, with the other generated from -* a default implementation. However it should -* remain possible to implement `ne` separately, for -* compatibility with floating-point NaN semantics -* (cf. IEEE 754-2008 section 5.11). +* This trait allows partial equality, where types can be unordered instead of strictly equal or +* unequal. For example, with the built-in floating-point types `a == b` and `a != b` will both +* evaluate to false if either `a` or `b` is NaN (cf. IEEE 754-2008 section 5.11). +* +* Eventually, this will be implemented by default for types that implement `TotalEq`. */ #[lang="eq"] pub trait Eq { @@ -37,70 +35,68 @@ pub trait Eq { fn ne(&self, other: &Self) -> bool; } +/// Trait for equality comparisons where `a == b` and `a != b` are strict inverses. +pub trait TotalEq { + fn equals(&self, other: &Self) -> bool; +} + +macro_rules! totaleq_impl( + ($t:ty) => { + impl TotalEq for $t { + #[inline(always)] + fn equals(&self, other: &$t) -> bool { *self == *other } + } + } +) + +totaleq_impl!(bool) + +totaleq_impl!(u8) +totaleq_impl!(u16) +totaleq_impl!(u32) +totaleq_impl!(u64) + +totaleq_impl!(i8) +totaleq_impl!(i16) +totaleq_impl!(i32) +totaleq_impl!(i64) + +totaleq_impl!(int) +totaleq_impl!(uint) + #[deriving(Eq)] pub enum Ordering { Less, Equal, Greater } /// Trait for types that form a total order -pub trait TotalOrd { +pub trait TotalOrd: TotalEq { fn cmp(&self, other: &Self) -> Ordering; } -#[inline(always)] -fn icmp(a: &T, b: &T) -> Ordering { - if *a < *b { Less } - else if *a > *b { Greater } - else { Equal } -} +macro_rules! totalord_impl( + ($t:ty) => { + impl TotalOrd for $t { + #[inline(always)] + fn cmp(&self, other: &$t) -> Ordering { + if *self < *other { Less } + else if *self > *other { Greater } + else { Equal } + } + } + } +) -impl TotalOrd for u8 { - #[inline(always)] - fn cmp(&self, other: &u8) -> Ordering { icmp(self, other) } -} +totalord_impl!(u8) +totalord_impl!(u16) +totalord_impl!(u32) +totalord_impl!(u64) -impl TotalOrd for u16 { - #[inline(always)] - fn cmp(&self, other: &u16) -> Ordering { icmp(self, other) } -} +totalord_impl!(i8) +totalord_impl!(i16) +totalord_impl!(i32) +totalord_impl!(i64) -impl TotalOrd for u32 { - #[inline(always)] - fn cmp(&self, other: &u32) -> Ordering { icmp(self, other) } -} - -impl TotalOrd for u64 { - #[inline(always)] - fn cmp(&self, other: &u64) -> Ordering { icmp(self, other) } -} - -impl TotalOrd for i8 { - #[inline(always)] - fn cmp(&self, other: &i8) -> Ordering { icmp(self, other) } -} - -impl TotalOrd for i16 { - #[inline(always)] - fn cmp(&self, other: &i16) -> Ordering { icmp(self, other) } -} - -impl TotalOrd for i32 { - #[inline(always)] - fn cmp(&self, other: &i32) -> Ordering { icmp(self, other) } -} - -impl TotalOrd for i64 { - #[inline(always)] - fn cmp(&self, other: &i64) -> Ordering { icmp(self, other) } -} - -impl TotalOrd for int { - #[inline(always)] - fn cmp(&self, other: &int) -> Ordering { icmp(self, other) } -} - -impl TotalOrd for uint { - #[inline(always)] - fn cmp(&self, other: &uint) -> Ordering { icmp(self, other) } -} +totalord_impl!(int) +totalord_impl!(uint) /** * Trait for values that can be compared for a sort-order. @@ -171,11 +167,17 @@ pub fn max(v1: T, v2: T) -> T { #[cfg(test)] mod test { #[test] - fn test_int() { + fn test_int_totalord() { assert_eq!(5.cmp(&10), Less); assert_eq!(10.cmp(&5), Greater); assert_eq!(5.cmp(&5), Equal); assert_eq!((-5).cmp(&12), Less); assert_eq!(12.cmp(-5), Greater); } + + #[test] + fn test_int_totaleq() { + fail_unless!(5.equals(&5)); + fail_unless!(!2.equals(&17)); + } } diff --git a/src/libcore/nil.rs b/src/libcore/nil.rs index 8c52ac9593a..6b8c390fc25 100644 --- a/src/libcore/nil.rs +++ b/src/libcore/nil.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,7 +15,7 @@ Functions for the unit type. */ #[cfg(notest)] -use cmp::{Eq, Ord, TotalOrd, Ordering, Equal}; +use prelude::*; #[cfg(notest)] impl Eq for () { @@ -42,3 +42,9 @@ impl TotalOrd for () { #[inline(always)] fn cmp(&self, _other: &()) -> Ordering { Equal } } + +#[cfg(notest)] +impl TotalEq for () { + #[inline(always)] + fn equals(&self, _other: &()) -> bool { true } +} diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 7166ffbd3d3..0194e8f009c 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -24,7 +24,7 @@ pub use result::{Result, Ok, Err}; /* Reexported types and traits */ pub use clone::Clone; -pub use cmp::{Eq, Ord, TotalOrd, Ordering, Less, Equal, Greater}; +pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 8ca65606fe2..a6f9ae84f44 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -21,7 +21,7 @@ use at_vec; use cast; use char; use clone::Clone; -use cmp::{Equiv, TotalOrd, Ordering, Less, Equal, Greater}; +use cmp::{Equiv, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use libc; use option::{None, Option, Some}; use ptr; @@ -930,6 +930,30 @@ impl Eq for @str { fn ne(&self, other: &@str) -> bool { !(*self).eq(other) } } +#[cfg(notest)] +impl<'self> TotalEq for &'self str { + #[inline(always)] + fn equals(&self, other: & &'self str) -> bool { + eq_slice((*self), (*other)) + } +} + +#[cfg(notest)] +impl TotalEq for ~str { + #[inline(always)] + fn equals(&self, other: &~str) -> bool { + eq_slice((*self), (*other)) + } +} + +#[cfg(notest)] +impl TotalEq for @str { + #[inline(always)] + fn equals(&self, other: &@str) -> bool { + eq_slice((*self), (*other)) + } +} + #[cfg(notest)] impl Ord for ~str { #[inline(always)] diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 702ae73852e..174960560df 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -14,7 +14,7 @@ use container::{Container, Mutable}; use cast; -use cmp::{Eq, Equiv, Ord, TotalOrd, Ordering, Less, Equal, Greater}; +use cmp::{Eq, Equiv, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use clone::Clone; use iter::BaseIter; use iter; @@ -1547,7 +1547,7 @@ pub fn as_mut_buf(s: &mut [T], f: &fn(*mut T, uint) -> U) -> U { // Equality -fn eq(a: &[T], b: &[T]) -> bool { +fn eq(a: &[T], b: &[T]) -> bool { let (a_len, b_len) = (a.len(), b.len()); if a_len != b_len { return false; } @@ -1556,33 +1556,61 @@ fn eq(a: &[T], b: &[T]) -> bool { if a[i] != b[i] { return false; } i += 1; } + true +} +fn equals(a: &[T], b: &[T]) -> bool { + let (a_len, b_len) = (a.len(), b.len()); + if a_len != b_len { return false; } + + let mut i = 0; + while i < a_len { + if !a[i].equals(&b[i]) { return false; } + i += 1; + } true } #[cfg(notest)] impl<'self,T:Eq> Eq for &'self [T] { #[inline(always)] - fn eq(&self, other: & &'self [T]) -> bool { eq((*self), (*other)) } + fn eq(&self, other: & &'self [T]) -> bool { eq(*self, *other) } #[inline(always)] - fn ne(&self, other: & &'self [T]) -> bool { !(*self).eq(other) } + fn ne(&self, other: & &'self [T]) -> bool { !self.eq(other) } } - #[cfg(notest)] impl Eq for ~[T] { #[inline(always)] - fn eq(&self, other: &~[T]) -> bool { eq((*self), (*other)) } + fn eq(&self, other: &~[T]) -> bool { eq(*self, *other) } #[inline(always)] - fn ne(&self, other: &~[T]) -> bool { !(*self).eq(other) } + fn ne(&self, other: &~[T]) -> bool { !self.eq(other) } } #[cfg(notest)] impl Eq for @[T] { #[inline(always)] - fn eq(&self, other: &@[T]) -> bool { eq((*self), (*other)) } + fn eq(&self, other: &@[T]) -> bool { eq(*self, *other) } #[inline(always)] - fn ne(&self, other: &@[T]) -> bool { !(*self).eq(other) } + fn ne(&self, other: &@[T]) -> bool { !self.eq(other) } +} + +#[cfg(notest)] +impl<'self,T:TotalEq> TotalEq for &'self [T] { + #[inline(always)] + fn equals(&self, other: & &'self [T]) -> bool { equals(*self, *other) } +} + +#[cfg(notest)] +impl TotalEq for ~[T] { + #[inline(always)] + fn equals(&self, other: &~[T]) -> bool { equals(*self, *other) } +} + +#[cfg(notest)] +impl TotalEq for @[T] { + #[inline(always)] + fn equals(&self, other: &@[T]) -> bool { equals(*self, *other) } } #[cfg(notest)]