From d2b267bcb5ac1adbc20bca0c170106ae3b3538ab Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 27 Mar 2013 15:20:44 -0400 Subject: [PATCH] add a TotalEq trait --- src/libcore/cmp.rs | 55 +++++++++++++++++++++++++++++++++--------- src/libcore/nil.rs | 10 ++++++-- src/libcore/prelude.rs | 2 +- src/libcore/str.rs | 26 +++++++++++++++++++- src/libcore/vec.rs | 46 ++++++++++++++++++++++++++++------- 5 files changed, 115 insertions(+), 24 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index bc5b4b7f148..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 @@ */ /** -* 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,11 +35,40 @@ 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; } @@ -140,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 @@ */ #[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 @@ /* 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 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 @@ fn eq(&self, other: &@str) -> bool { 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)]