libsyntax: short-circuit on non-matching variants in deriving code.
Allow a deriving instance using the generic code to short-circuit for any non-matching enum variants (grouping them all into a _ match), reducing the number of arms required. Use this to speed up the Eq & TotalEq implementations.
This commit is contained in:
parent
99492796dc
commit
bff3748731
@ -29,6 +29,7 @@ pub fn expand_deriving_clone(cx: @ext_ctxt,
|
||||
name: ~"clone",
|
||||
nargs: 0,
|
||||
output_type: None, // return Self
|
||||
const_nonmatching: false,
|
||||
combine_substructure: cs_clone
|
||||
}
|
||||
]
|
||||
|
@ -31,24 +31,24 @@ pub fn expand_deriving_eq(cx: @ext_ctxt,
|
||||
cs_or(|cx, span, _| build::mk_bool(cx, span, true),
|
||||
cx, span, substr)
|
||||
}
|
||||
|
||||
macro_rules! md (
|
||||
($name:expr, $f:ident) => {
|
||||
MethodDef {
|
||||
name: $name,
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
const_nonmatching: true,
|
||||
combine_substructure: $f
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
let trait_def = TraitDef {
|
||||
path: ~[~"core", ~"cmp", ~"Eq"],
|
||||
additional_bounds: ~[],
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"ne",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
combine_substructure: cs_ne
|
||||
},
|
||||
MethodDef {
|
||||
name: ~"eq",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
combine_substructure: cs_eq
|
||||
}
|
||||
md!(~"eq", cs_eq),
|
||||
md!(~"ne", cs_ne)
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -16,10 +16,16 @@ use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
use core::option::Some;
|
||||
|
||||
macro_rules! mk_cso {
|
||||
($less:expr, $equal:expr) => {
|
||||
|cx, span, substr|
|
||||
cs_ord($less, $equal, cx, span, substr)
|
||||
macro_rules! md {
|
||||
($name:expr, $less:expr, $equal:expr) => {
|
||||
MethodDef {
|
||||
name: $name,
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
const_nonmatching: false,
|
||||
combine_substructure: |cx, span, substr|
|
||||
cs_ord($less, $equal, cx, span, substr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,30 +38,10 @@ pub fn expand_deriving_ord(cx: @ext_ctxt,
|
||||
// XXX: Ord doesn't imply Eq yet
|
||||
additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]],
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"lt",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
combine_substructure: mk_cso!(true, false)
|
||||
},
|
||||
MethodDef {
|
||||
name: ~"le",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
combine_substructure: mk_cso!(true, true)
|
||||
},
|
||||
MethodDef {
|
||||
name: ~"gt",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
combine_substructure: mk_cso!(false, false)
|
||||
},
|
||||
MethodDef {
|
||||
name: ~"ge",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
combine_substructure: mk_cso!(false, true)
|
||||
},
|
||||
md!(~"lt", true, false),
|
||||
md!(~"le", true, true),
|
||||
md!(~"gt", false, false),
|
||||
md!(~"ge", false, true)
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,7 @@ pub fn expand_deriving_totaleq(cx: @ext_ctxt,
|
||||
name: ~"equals",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
const_nonmatching: true,
|
||||
combine_substructure: cs_equals
|
||||
}
|
||||
]
|
||||
|
@ -28,6 +28,7 @@ pub fn expand_deriving_totalord(cx: @ext_ctxt,
|
||||
name: ~"cmp",
|
||||
output_type: Some(~[~"core", ~"cmp", ~"Ordering"]),
|
||||
nargs: 1,
|
||||
const_nonmatching: false,
|
||||
combine_substructure: cs_cmp
|
||||
}
|
||||
]
|
||||
|
@ -40,7 +40,8 @@ arguments:
|
||||
- `EnumMatching`, when `Self` is an enum and all the arguments are the
|
||||
same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
|
||||
- `EnumNonMatching` when `Self` is an enum and the arguments are not
|
||||
the same variant (e.g. `None`, `Some(1)` and `None`)
|
||||
the same variant (e.g. `None`, `Some(1)` and `None`). If
|
||||
`const_nonmatching` is true, this will contain an empty list.
|
||||
|
||||
In the first two cases, the values from the corresponding fields in
|
||||
all the arguments are grouped together. In the `EnumNonMatching` case
|
||||
@ -129,9 +130,11 @@ use core::prelude::*;
|
||||
use ast;
|
||||
|
||||
use ast::{
|
||||
|
||||
and, binop, deref, enum_def, expr, expr_match, ident, impure_fn,
|
||||
item, Generics, m_imm, meta_item, method, named_field, or, public,
|
||||
struct_def, sty_region, ty_rptr, ty_path, variant};
|
||||
item, Generics, m_imm, meta_item, method, named_field, or,
|
||||
pat_wild, public, struct_def, sty_region, ty_rptr, ty_path,
|
||||
variant};
|
||||
|
||||
use ast_util;
|
||||
use ext::base::ext_ctxt;
|
||||
@ -177,6 +180,10 @@ pub struct MethodDef<'self> {
|
||||
/// Number of arguments other than `self` (all of type `&Self`)
|
||||
nargs: uint,
|
||||
|
||||
/// if the value of the nonmatching enums is independent of the
|
||||
/// actual enums, i.e. can use _ => .. match.
|
||||
const_nonmatching: bool,
|
||||
|
||||
combine_substructure: CombineSubstructureFunc<'self>
|
||||
}
|
||||
|
||||
@ -555,12 +562,13 @@ impl<'self> MethodDef<'self> {
|
||||
enum_def: &enum_def,
|
||||
type_ident: ident)
|
||||
-> @expr {
|
||||
self.build_enum_match(cx, span, enum_def, type_ident, ~[])
|
||||
self.build_enum_match(cx, span, enum_def, type_ident,
|
||||
None, ~[], 0)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Creates the nested matches for an enum definition, i.e.
|
||||
Creates the nested matches for an enum definition recursively, i.e.
|
||||
|
||||
```
|
||||
match self {
|
||||
@ -575,14 +583,20 @@ impl<'self> MethodDef<'self> {
|
||||
the tree are the same. Hopefully the optimisers get rid of any
|
||||
repetition, otherwise derived methods with many Self arguments will be
|
||||
exponentially large.
|
||||
|
||||
`matching` is Some(n) if all branches in the tree above the
|
||||
current position are variant `n`, `None` otherwise (including on
|
||||
the first call).
|
||||
*/
|
||||
fn build_enum_match(&self,
|
||||
cx: @ext_ctxt, span: span,
|
||||
enum_def: &enum_def,
|
||||
type_ident: ident,
|
||||
matching: Option<uint>,
|
||||
matches_so_far: ~[(uint, variant,
|
||||
~[(Option<ident>, @expr)])]) -> @expr {
|
||||
if matches_so_far.len() == self.nargs + 1 {
|
||||
~[(Option<ident>, @expr)])],
|
||||
match_count: uint) -> @expr {
|
||||
if match_count == self.nargs + 1 {
|
||||
// we've matched against all arguments, so make the final
|
||||
// expression at the bottom of the match tree
|
||||
match matches_so_far {
|
||||
@ -594,41 +608,44 @@ impl<'self> MethodDef<'self> {
|
||||
// vec of tuples, where each tuple represents a
|
||||
// field.
|
||||
|
||||
// `ref` inside let matches is buggy. Causes havoc wih rusc.
|
||||
// let (variant_index, ref self_vec) = matches_so_far[0];
|
||||
let (variant_index, variant, self_vec) = match matches_so_far[0] {
|
||||
(i, v, ref s) => (i, v, s)
|
||||
};
|
||||
|
||||
let substructure;
|
||||
|
||||
// most arms don't have matching variants, so do a
|
||||
// quick check to see if they match (even though
|
||||
// this means iterating twice) instead of being
|
||||
// optimistic and doing a pile of allocations etc.
|
||||
if matches_so_far.all(|&(v_i, _, _)| v_i == variant_index) {
|
||||
let mut enum_matching_fields = vec::from_elem(self_vec.len(), ~[]);
|
||||
match matching {
|
||||
Some(variant_index) => {
|
||||
// `ref` inside let matches is buggy. Causes havoc wih rusc.
|
||||
// let (variant_index, ref self_vec) = matches_so_far[0];
|
||||
let (variant, self_vec) = match matches_so_far[0] {
|
||||
(_, v, ref s) => (v, s)
|
||||
};
|
||||
|
||||
for matches_so_far.tail().each |&(_, _, other_fields)| {
|
||||
for other_fields.eachi |i, &(_, other_field)| {
|
||||
enum_matching_fields[i].push(other_field);
|
||||
let mut enum_matching_fields = vec::from_elem(self_vec.len(), ~[]);
|
||||
|
||||
for matches_so_far.tail().each |&(_, _, other_fields)| {
|
||||
for other_fields.eachi |i, &(_, other_field)| {
|
||||
enum_matching_fields[i].push(other_field);
|
||||
}
|
||||
}
|
||||
let field_tuples =
|
||||
do vec::map2(*self_vec,
|
||||
enum_matching_fields) |&(id, self_f), &other| {
|
||||
(id, self_f, other)
|
||||
};
|
||||
substructure = EnumMatching(variant_index, variant, field_tuples);
|
||||
}
|
||||
None => {
|
||||
substructure = EnumNonMatching(matches_so_far);
|
||||
}
|
||||
let field_tuples =
|
||||
do vec::map2(*self_vec,
|
||||
enum_matching_fields) |&(id, self_f), &other| {
|
||||
(id, self_f, other)
|
||||
};
|
||||
substructure = EnumMatching(variant_index, variant, field_tuples);
|
||||
} else {
|
||||
substructure = EnumNonMatching(matches_so_far);
|
||||
}
|
||||
self.call_substructure_method(cx, span, type_ident, &substructure)
|
||||
}
|
||||
}
|
||||
|
||||
} else { // there are still matches to create
|
||||
let (current_match_ident, current_match_str) = if matches_so_far.is_empty() {
|
||||
let (current_match_ident, current_match_str) = if match_count == 0 {
|
||||
(cx.ident_of(~"self"), ~"__self")
|
||||
} else {
|
||||
let s = fmt!("__other_%u", matches_so_far.len() - 1);
|
||||
@ -640,8 +657,32 @@ impl<'self> MethodDef<'self> {
|
||||
// this is used as a stack
|
||||
let mut matches_so_far = matches_so_far;
|
||||
|
||||
// create an arm matching on each variant
|
||||
for enum_def.variants.eachi |index, variant| {
|
||||
macro_rules! mk_arm(
|
||||
($pat:expr, $expr:expr) => {
|
||||
{
|
||||
let blk = build::mk_simple_block(cx, span, $expr);
|
||||
let arm = ast::arm {
|
||||
pats: ~[$ pat ],
|
||||
guard: None,
|
||||
body: blk
|
||||
};
|
||||
arm
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// the code for nonmatching variants only matters when
|
||||
// we've seen at least one other variant already
|
||||
if self.const_nonmatching && match_count > 0 {
|
||||
// make a matching-variant match, and a _ match.
|
||||
let index = match matching {
|
||||
Some(i) => i,
|
||||
None => cx.span_bug(span, ~"Non-matching variants when required to\
|
||||
be matching in `deriving_generic`")
|
||||
};
|
||||
|
||||
// matching-variant match
|
||||
let variant = &enum_def.variants[index];
|
||||
let pattern = create_enum_variant_pattern(cx, span,
|
||||
variant,
|
||||
current_match_str);
|
||||
@ -653,23 +694,63 @@ impl<'self> MethodDef<'self> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
matches_so_far.push((index, *variant, idents));
|
||||
let arm_expr = self.build_enum_match(cx, span,
|
||||
enum_def,
|
||||
type_ident,
|
||||
matches_so_far);
|
||||
matching,
|
||||
matches_so_far,
|
||||
match_count + 1);
|
||||
matches_so_far.pop();
|
||||
|
||||
let arm_block = build::mk_simple_block(cx, span, arm_expr);
|
||||
let arm = ast::arm {
|
||||
pats: ~[ pattern ],
|
||||
guard: None,
|
||||
body: arm_block
|
||||
};
|
||||
let arm = mk_arm!(pattern, arm_expr);
|
||||
arms.push(arm);
|
||||
}
|
||||
|
||||
if enum_def.variants.len() > 1 {
|
||||
// _ match, if necessary
|
||||
let wild_pat = @ast::pat {
|
||||
id: cx.next_id(),
|
||||
node: pat_wild,
|
||||
span: span
|
||||
};
|
||||
|
||||
let wild_expr = self.call_substructure_method(cx, span, type_ident,
|
||||
&EnumNonMatching(~[]));
|
||||
let wild_arm = mk_arm!(wild_pat, wild_expr);
|
||||
arms.push(wild_arm);
|
||||
}
|
||||
} else {
|
||||
// create an arm matching on each variant
|
||||
for enum_def.variants.eachi |index, variant| {
|
||||
let pattern = create_enum_variant_pattern(cx, span,
|
||||
variant,
|
||||
current_match_str);
|
||||
|
||||
let idents = do vec::build |push| {
|
||||
for each_variant_arg_ident(cx, span, variant) |i, field_id| {
|
||||
let id = cx.ident_of(fmt!("%s_%u", current_match_str, i));
|
||||
push((field_id, build::mk_path(cx, span, ~[ id ])));
|
||||
}
|
||||
};
|
||||
|
||||
matches_so_far.push((index, *variant, idents));
|
||||
let new_matching =
|
||||
match matching {
|
||||
_ if match_count == 0 => Some(index),
|
||||
Some(i) if index == i => Some(i),
|
||||
_ => None
|
||||
};
|
||||
let arm_expr = self.build_enum_match(cx, span,
|
||||
enum_def,
|
||||
type_ident,
|
||||
new_matching,
|
||||
matches_so_far,
|
||||
match_count + 1);
|
||||
matches_so_far.pop();
|
||||
|
||||
let arm = mk_arm!(pattern, arm_expr);
|
||||
arms.push(arm);
|
||||
}
|
||||
}
|
||||
let deref_expr = build::mk_unary(cx, span, deref,
|
||||
build::mk_path(cx, span,
|
||||
~[ current_match_ident ]));
|
||||
|
50
src/test/run-pass/deriving-cmp-generic-enum.rs
Normal file
50
src/test/run-pass/deriving-cmp-generic-enum.rs
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
enum E<T> {
|
||||
E0,
|
||||
E1(T),
|
||||
E2(T,T)
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let e0 = E0, e11 = E1(1), e12 = E1(2), e21 = E2(1,1), e22 = E2(1, 2);
|
||||
|
||||
// in order for both Ord and TotalOrd
|
||||
let es = [e0, e11, e12, e21, e22];
|
||||
|
||||
for es.eachi |i, e1| {
|
||||
for es.eachi |j, e2| {
|
||||
let ord = i.cmp(&j);
|
||||
|
||||
let eq = i == j;
|
||||
let lt = i < j, le = i <= j;
|
||||
let gt = i > j, ge = i >= j;
|
||||
|
||||
// Eq
|
||||
assert_eq!(*e1 == *e2, eq);
|
||||
assert_eq!(*e1 != *e2, !eq);
|
||||
|
||||
// TotalEq
|
||||
assert_eq!(e1.equals(e2), eq);
|
||||
|
||||
// Ord
|
||||
assert_eq!(*e1 < *e2, lt);
|
||||
assert_eq!(*e1 > *e2, gt);
|
||||
|
||||
assert_eq!(*e1 <= *e2, le);
|
||||
assert_eq!(*e1 >= *e2, ge);
|
||||
|
||||
// TotalOrd
|
||||
assert_eq!(e1.cmp(e2), ord);
|
||||
}
|
||||
}
|
||||
}
|
52
src/test/run-pass/deriving-cmp-generic-struct-enum.rs
Normal file
52
src/test/run-pass/deriving-cmp-generic-struct-enum.rs
Normal file
@ -0,0 +1,52 @@
|
||||
// xfail-test #5530
|
||||
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
enum ES<T> {
|
||||
ES1 { x: T },
|
||||
ES2 { x: T, y: T }
|
||||
}
|
||||
|
||||
|
||||
pub fn main() {
|
||||
let es11 = ES1 {x: 1}, es12 = ES1 {x: 2}, es21 = ES2 {x: 1, y: 1}, es22 = ES2 {x: 1, y: 2};
|
||||
|
||||
// in order for both Ord and TotalOrd
|
||||
let ess = [es11, es12, es21, es22];
|
||||
|
||||
for ess.eachi |i, es1| {
|
||||
for ess.eachi |j, es2| {
|
||||
let ord = i.cmp(&j);
|
||||
|
||||
let eq = i == j;
|
||||
let lt = i < j, le = i <= j;
|
||||
let gt = i > j, ge = i >= j;
|
||||
|
||||
// Eq
|
||||
assert_eq!(*es1 == *es2, eq);
|
||||
assert_eq!(*es1 != *es2, !eq);
|
||||
|
||||
// TotalEq
|
||||
assert_eq!(es1.equals(es2), eq);
|
||||
|
||||
// Ord
|
||||
assert_eq!(*es1 < *es2, lt);
|
||||
assert_eq!(*es1 > *es2, gt);
|
||||
|
||||
assert_eq!(*es1 <= *es2, le);
|
||||
assert_eq!(*es1 >= *es2, ge);
|
||||
|
||||
// TotalOrd
|
||||
assert_eq!(es1.cmp(es2), ord);
|
||||
}
|
||||
}
|
||||
}
|
49
src/test/run-pass/deriving-cmp-generic-struct.rs
Normal file
49
src/test/run-pass/deriving-cmp-generic-struct.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
struct S<T> {
|
||||
x: T,
|
||||
y: T
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let s1 = S {x: 1, y: 1}, s2 = S {x: 1, y: 2};
|
||||
|
||||
// in order for both Ord and TotalOrd
|
||||
let ss = [s1, s2];
|
||||
|
||||
for ss.eachi |i, s1| {
|
||||
for ss.eachi |j, s2| {
|
||||
let ord = i.cmp(&j);
|
||||
|
||||
let eq = i == j;
|
||||
let lt = i < j, le = i <= j;
|
||||
let gt = i > j, ge = i >= j;
|
||||
|
||||
// Eq
|
||||
assert_eq!(*s1 == *s2, eq);
|
||||
assert_eq!(*s1 != *s2, !eq);
|
||||
|
||||
// TotalEq
|
||||
assert_eq!(s1.equals(s2), eq);
|
||||
|
||||
// Ord
|
||||
assert_eq!(*s1 < *s2, lt);
|
||||
assert_eq!(*s1 > *s2, gt);
|
||||
|
||||
assert_eq!(*s1 <= *s2, le);
|
||||
assert_eq!(*s1 >= *s2, ge);
|
||||
|
||||
// TotalOrd
|
||||
assert_eq!(s1.cmp(s2), ord);
|
||||
}
|
||||
}
|
||||
}
|
47
src/test/run-pass/deriving-cmp-generic-tuple-struct.rs
Normal file
47
src/test/run-pass/deriving-cmp-generic-tuple-struct.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
struct TS<T>(T,T);
|
||||
|
||||
|
||||
pub fn main() {
|
||||
let ts1 = TS(1, 1), ts2 = TS(1,2);
|
||||
|
||||
// in order for both Ord and TotalOrd
|
||||
let tss = [ts1, ts2];
|
||||
|
||||
for tss.eachi |i, ts1| {
|
||||
for tss.eachi |j, ts2| {
|
||||
let ord = i.cmp(&j);
|
||||
|
||||
let eq = i == j;
|
||||
let lt = i < j, le = i <= j;
|
||||
let gt = i > j, ge = i >= j;
|
||||
|
||||
// Eq
|
||||
assert_eq!(*ts1 == *ts2, eq);
|
||||
assert_eq!(*ts1 != *ts2, !eq);
|
||||
|
||||
// TotalEq
|
||||
assert_eq!(ts1.equals(ts2), eq);
|
||||
|
||||
// Ord
|
||||
assert_eq!(*ts1 < *ts2, lt);
|
||||
assert_eq!(*ts1 > *ts2, gt);
|
||||
|
||||
assert_eq!(*ts1 <= *ts2, le);
|
||||
assert_eq!(*ts1 >= *ts2, ge);
|
||||
|
||||
// TotalOrd
|
||||
assert_eq!(ts1.cmp(ts2), ord);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
struct S<T> {
|
||||
x: T,
|
||||
y: T
|
||||
}
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
struct TS<T>(T,T);
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
enum E<T> {
|
||||
E0,
|
||||
E1(T),
|
||||
E2(T,T)
|
||||
}
|
||||
|
||||
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
|
||||
enum ES<T> {
|
||||
ES1 { x: T },
|
||||
ES2 { x: T, y: T }
|
||||
}
|
||||
|
||||
|
||||
pub fn main() {
|
||||
let s1 = S {x: 1, y: 1}, s2 = S {x: 1, y: 2};
|
||||
let ts1 = TS(1, 1), ts2 = TS(1,2);
|
||||
let e0 = E0, e11 = E1(1), e12 = E1(2), e21 = E2(1,1), e22 = E2(1, 2);
|
||||
let es11 = ES1 {x: 1}, es12 = ES1 {x: 2}, es21 = ES2 {x: 1, y: 1}, es22 = ES2 {x: 1, y: 2};
|
||||
|
||||
test([s1, s2]);
|
||||
test([ts1, ts2]);
|
||||
test([e0, e11, e12, e21, e22]);
|
||||
test([es11, es12, es21, es22]);
|
||||
}
|
||||
|
||||
fn test<T: Eq+TotalEq+Ord+TotalOrd>(ts: &[T]) {
|
||||
// compare each element against all other elements. The list
|
||||
// should be in sorted order, so that if i < j, then ts[i] <
|
||||
// ts[j], etc.
|
||||
for ts.eachi |i, t1| {
|
||||
for ts.eachi |j, t2| {
|
||||
let ord = i.cmp(&j);
|
||||
|
||||
let eq = i == j;
|
||||
let lt = i < j, le = i <= j;
|
||||
let gt = i > j, ge = i >= j;
|
||||
|
||||
// Eq
|
||||
assert_eq!(*t1 == *t2, eq);
|
||||
|
||||
// TotalEq
|
||||
assert_eq!(t1.equals(t2), eq);
|
||||
|
||||
// Ord
|
||||
assert_eq!(*t1 < *t2, lt);
|
||||
assert_eq!(*t1 > *t2, gt);
|
||||
|
||||
assert_eq!(*t1 <= *t2, le);
|
||||
assert_eq!(*t1 >= *t2, ge);
|
||||
|
||||
// TotalOrd
|
||||
assert_eq!(t1.cmp(t2), ord);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user