Correct tuple Ord impl, add Total{Eq,Ord} impls and add some tests.

This commit is contained in:
Huon Wilson 2013-05-19 18:51:14 +10:00
parent 7103c39dbb
commit 3a11ddb1b2

View File

@ -114,17 +114,17 @@ impl<A:Copy,B:Copy> ExtendedTupleOps<A,B> for (~[A], ~[B]) {
// macro for implementing n-ary tuple functions and operations
macro_rules! tuple_impls(
macro_rules! tuple_impls {
($(
($cloneable_trait:ident, $immutable_trait:ident) {
$(($get_fn:ident, $get_ref_fn:ident) -> $T:ident {
$get_pattern:pat => $ret:expr
})+
}
)+) => (
)+) => {
pub mod inner {
use clone::Clone;
#[cfg(not(test))] use cmp::{Eq, Ord};
#[cfg(not(test))] use cmp::*;
$(
pub trait $cloneable_trait<$($T),+> {
@ -171,11 +171,19 @@ macro_rules! tuple_impls(
}
}
#[cfg(not(test))]
impl<$($T:TotalEq),+> TotalEq for ($($T),+) {
#[inline(always)]
fn equals(&self, other: &($($T),+)) -> bool {
$(self.$get_ref_fn().equals(other.$get_ref_fn()))&&+
}
}
#[cfg(not(test))]
impl<$($T:Ord),+> Ord for ($($T),+) {
#[inline(always)]
fn lt(&self, other: &($($T),+)) -> bool {
lexical_lt!($(*self.$get_ref_fn(), *other.$get_ref_fn()),+)
lexical_lt!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
}
#[inline(always)]
fn le(&self, other: &($($T),+)) -> bool { !(*other).lt(&(*self)) }
@ -184,22 +192,44 @@ macro_rules! tuple_impls(
#[inline(always)]
fn gt(&self, other: &($($T),+)) -> bool { (*other).lt(&(*self)) }
}
#[cfg(not(test))]
impl<$($T:TotalOrd),+> TotalOrd for ($($T),+) {
#[inline]
fn cmp(&self, other: &($($T),+)) -> Ordering {
lexical_cmp!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
}
}
)+
}
)
)
}
}
// 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, a3, b3)`
macro_rules! lexical_lt(
($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => (
if $a < $b { true } else { lexical_lt!($($rest_a, $rest_b),+) }
);
($a:expr, $b:expr) => ($a < $b);
)
// 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,
// 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 }
};
($a:expr, $b:expr) => { *$a < *$b };
}
tuple_impls!(
macro_rules! lexical_cmp {
($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
match ($a).cmp($b) {
Equal => lexical_cmp!($($rest_a, $rest_b),+),
ordering => ordering
}
};
($a:expr, $b:expr) => { ($a).cmp($b) };
}
tuple_impls! {
(CloneableTuple2, ImmutableTuple2) {
(n0, n0_ref) -> A { (ref a,_) => a }
(n1, n1_ref) -> B { (_,ref b) => b }
@ -309,12 +339,13 @@ tuple_impls!(
(n10, n10_ref) -> K { (_,_,_,_,_,_,_,_,_,_,ref k,_) => k }
(n11, n11_ref) -> L { (_,_,_,_,_,_,_,_,_,_,_,ref l) => l }
}
)
}
#[cfg(test)]
mod tests {
use super::*;
use clone::Clone;
use cmp::*;
#[test]
fn test_tuple_ref() {
@ -368,4 +399,41 @@ mod tests {
assert_eq!(t.n10_ref(), &10f32);
assert_eq!(t.n11_ref(), &11f64);
}
#[test]
fn test_tuple_cmp() {
let small = (1u, 2u, 3u), big = (3u, 2u, 1u);
// Eq
assert_eq!(small, small);
assert_eq!(big, big);
assert!(small != big);
assert!(big != small);
// Ord
assert!(small < big);
assert!(!(small < small));
assert!(!(big < small));
assert!(!(big < big));
assert!(small <= small);
assert!(big <= big);
assert!(big > small);
assert!(small >= small);
assert!(big >= small);
assert!(big >= big);
// TotalEq
assert!(small.equals(&small));
assert!(big.equals(&big));
assert!(!small.equals(&big));
assert!(!big.equals(&small));
// TotalOrd
assert_eq!(small.cmp(&small), Equal);
assert_eq!(big.cmp(&big), Equal);
assert_eq!(small.cmp(&big), Less);
assert_eq!(big.cmp(&small), Greater);
}
}