auto merge of #5587 : thestinger/rust/total, r=pcwalton

This is needed so that hash tables can require strict equality but not require types to be ordered. It's a subset of the functionality of `TotalOrd` so I made that inherit from `TotalEq`.
This commit is contained in:
bors 2013-03-28 02:36:49 -07:00
commit e549b80e3c
5 changed files with 137 additions and 77 deletions

View File

@ -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 // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // 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 * Trait for values that can be compared for equality and inequality.
* and inequality.
* *
* Eventually this may be simplified to only require * This trait allows partial equality, where types can be unordered instead of strictly equal or
* an `eq` method, with the other generated from * unequal. For example, with the built-in floating-point types `a == b` and `a != b` will both
* a default implementation. However it should * evaluate to false if either `a` or `b` is NaN (cf. IEEE 754-2008 section 5.11).
* remain possible to implement `ne` separately, for *
* compatibility with floating-point NaN semantics * Eventually, this will be implemented by default for types that implement `TotalEq`.
* (cf. IEEE 754-2008 section 5.11).
*/ */
#[lang="eq"] #[lang="eq"]
pub trait Eq { pub trait Eq {
@ -37,70 +35,68 @@ pub trait Eq {
fn ne(&self, other: &Self) -> bool; 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)] #[deriving(Eq)]
pub enum Ordering { Less, Equal, Greater } pub enum Ordering { Less, Equal, Greater }
/// Trait for types that form a total order /// Trait for types that form a total order
pub trait TotalOrd { pub trait TotalOrd: TotalEq {
fn cmp(&self, other: &Self) -> Ordering; fn cmp(&self, other: &Self) -> Ordering;
} }
#[inline(always)] macro_rules! totalord_impl(
fn icmp<T: Ord>(a: &T, b: &T) -> Ordering { ($t:ty) => {
if *a < *b { Less } impl TotalOrd for $t {
else if *a > *b { Greater } #[inline(always)]
else { Equal } fn cmp(&self, other: &$t) -> Ordering {
} if *self < *other { Less }
else if *self > *other { Greater }
else { Equal }
}
}
}
)
impl TotalOrd for u8 { totalord_impl!(u8)
#[inline(always)] totalord_impl!(u16)
fn cmp(&self, other: &u8) -> Ordering { icmp(self, other) } totalord_impl!(u32)
} totalord_impl!(u64)
impl TotalOrd for u16 { totalord_impl!(i8)
#[inline(always)] totalord_impl!(i16)
fn cmp(&self, other: &u16) -> Ordering { icmp(self, other) } totalord_impl!(i32)
} totalord_impl!(i64)
impl TotalOrd for u32 { totalord_impl!(int)
#[inline(always)] totalord_impl!(uint)
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) }
}
/** /**
* Trait for values that can be compared for a sort-order. * Trait for values that can be compared for a sort-order.
@ -171,11 +167,17 @@ pub fn max<T:Ord>(v1: T, v2: T) -> T {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
#[test] #[test]
fn test_int() { fn test_int_totalord() {
assert_eq!(5.cmp(&10), Less); assert_eq!(5.cmp(&10), Less);
assert_eq!(10.cmp(&5), Greater); assert_eq!(10.cmp(&5), Greater);
assert_eq!(5.cmp(&5), Equal); assert_eq!(5.cmp(&5), Equal);
assert_eq!((-5).cmp(&12), Less); assert_eq!((-5).cmp(&12), Less);
assert_eq!(12.cmp(-5), Greater); assert_eq!(12.cmp(-5), Greater);
} }
#[test]
fn test_int_totaleq() {
fail_unless!(5.equals(&5));
fail_unless!(!2.equals(&17));
}
} }

View File

@ -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 // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
// //
@ -15,7 +15,7 @@ Functions for the unit type.
*/ */
#[cfg(notest)] #[cfg(notest)]
use cmp::{Eq, Ord, TotalOrd, Ordering, Equal}; use prelude::*;
#[cfg(notest)] #[cfg(notest)]
impl Eq for () { impl Eq for () {
@ -42,3 +42,9 @@ impl TotalOrd for () {
#[inline(always)] #[inline(always)]
fn cmp(&self, _other: &()) -> Ordering { Equal } fn cmp(&self, _other: &()) -> Ordering { Equal }
} }
#[cfg(notest)]
impl TotalEq for () {
#[inline(always)]
fn equals(&self, _other: &()) -> bool { true }
}

View File

@ -24,7 +24,7 @@ pub use result::{Result, Ok, Err};
/* Reexported types and traits */ /* Reexported types and traits */
pub use clone::Clone; 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 container::{Container, Mutable, Map, Set};
pub use hash::Hash; pub use hash::Hash;
pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};

View File

@ -21,7 +21,7 @@ use at_vec;
use cast; use cast;
use char; use char;
use clone::Clone; use clone::Clone;
use cmp::{Equiv, TotalOrd, Ordering, Less, Equal, Greater}; use cmp::{Equiv, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
use libc; use libc;
use option::{None, Option, Some}; use option::{None, Option, Some};
use ptr; use ptr;
@ -930,6 +930,30 @@ impl Eq for @str {
fn ne(&self, other: &@str) -> bool { !(*self).eq(other) } 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)] #[cfg(notest)]
impl Ord for ~str { impl Ord for ~str {
#[inline(always)] #[inline(always)]

View File

@ -14,7 +14,7 @@
use container::{Container, Mutable}; use container::{Container, Mutable};
use cast; 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 clone::Clone;
use iter::BaseIter; use iter::BaseIter;
use iter; use iter;
@ -1547,7 +1547,7 @@ pub fn as_mut_buf<T,U>(s: &mut [T], f: &fn(*mut T, uint) -> U) -> U {
// Equality // Equality
fn eq<T:Eq>(a: &[T], b: &[T]) -> bool { fn eq<T: Eq>(a: &[T], b: &[T]) -> bool {
let (a_len, b_len) = (a.len(), b.len()); let (a_len, b_len) = (a.len(), b.len());
if a_len != b_len { return false; } if a_len != b_len { return false; }
@ -1556,33 +1556,61 @@ fn eq<T:Eq>(a: &[T], b: &[T]) -> bool {
if a[i] != b[i] { return false; } if a[i] != b[i] { return false; }
i += 1; i += 1;
} }
true
}
fn equals<T: TotalEq>(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 true
} }
#[cfg(notest)] #[cfg(notest)]
impl<'self,T:Eq> Eq for &'self [T] { impl<'self,T:Eq> Eq for &'self [T] {
#[inline(always)] #[inline(always)]
fn eq(&self, other: & &'self [T]) -> bool { eq((*self), (*other)) } fn eq(&self, other: & &'self [T]) -> bool { eq(*self, *other) }
#[inline(always)] #[inline(always)]
fn ne(&self, other: & &'self [T]) -> bool { !(*self).eq(other) } fn ne(&self, other: & &'self [T]) -> bool { !self.eq(other) }
} }
#[cfg(notest)] #[cfg(notest)]
impl<T:Eq> Eq for ~[T] { impl<T:Eq> Eq for ~[T] {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &~[T]) -> bool { eq((*self), (*other)) } fn eq(&self, other: &~[T]) -> bool { eq(*self, *other) }
#[inline(always)] #[inline(always)]
fn ne(&self, other: &~[T]) -> bool { !(*self).eq(other) } fn ne(&self, other: &~[T]) -> bool { !self.eq(other) }
} }
#[cfg(notest)] #[cfg(notest)]
impl<T:Eq> Eq for @[T] { impl<T:Eq> Eq for @[T] {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &@[T]) -> bool { eq((*self), (*other)) } fn eq(&self, other: &@[T]) -> bool { eq(*self, *other) }
#[inline(always)] #[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<T:TotalEq> TotalEq for ~[T] {
#[inline(always)]
fn equals(&self, other: &~[T]) -> bool { equals(*self, *other) }
}
#[cfg(notest)]
impl<T:TotalEq> TotalEq for @[T] {
#[inline(always)]
fn equals(&self, other: &@[T]) -> bool { equals(*self, *other) }
} }
#[cfg(notest)] #[cfg(notest)]