2012-07-31 12:27:51 -05:00
|
|
|
trait base_iter<A> {
|
2012-04-11 23:45:18 -05:00
|
|
|
fn each(blk: fn(A) -> bool);
|
|
|
|
fn size_hint() -> option<uint>;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-07-11 17:00:40 -05:00
|
|
|
trait extended_iter<A> {
|
|
|
|
fn eachi(blk: fn(uint, A) -> bool);
|
|
|
|
fn all(blk: fn(A) -> bool) -> bool;
|
|
|
|
fn any(blk: fn(A) -> bool) -> bool;
|
|
|
|
fn foldl<B>(+b0: B, blk: fn(B, A) -> B) -> B;
|
|
|
|
fn contains(x: A) -> bool;
|
|
|
|
fn count(x: A) -> uint;
|
|
|
|
fn position(f: fn(A) -> bool) -> option<uint>;
|
|
|
|
}
|
|
|
|
|
2012-07-31 12:27:51 -05:00
|
|
|
trait times {
|
A new `times` method on numeric types
This method is intended to elegantly subsume two common iteration functions.
The first is `iter::range`, which is used identically to the method introduced
in this commit, but currently works only on uints. The second is a common case
of `{int, i8, uint, etc.}::range`, in the case where the inductive variable is
ignored. Compare the usage of the three:
```
for iter::range(100u) {
// do whatever
}
for int::range(0, 100) |_i| {
// do whatever
}
for 100.times {
// do whatever
}
```
I feel that the latter reads much more nicely than the first two approaches,
and unlike the first two the new method allows the user to ignore the specific
type of the number (ineed, if we're throwing away the inductive variable, who
cares what type it is?). A minor benefit is that this new method will be
somewhat familiar to users of Ruby, from which we borrow the name "times".
2012-07-05 21:12:26 -05:00
|
|
|
fn times(it: fn() -> bool);
|
|
|
|
}
|
2012-07-31 12:27:51 -05:00
|
|
|
trait timesi{
|
2012-07-20 17:33:18 -05:00
|
|
|
fn timesi(it: fn(uint) -> bool);
|
|
|
|
}
|
A new `times` method on numeric types
This method is intended to elegantly subsume two common iteration functions.
The first is `iter::range`, which is used identically to the method introduced
in this commit, but currently works only on uints. The second is a common case
of `{int, i8, uint, etc.}::range`, in the case where the inductive variable is
ignored. Compare the usage of the three:
```
for iter::range(100u) {
// do whatever
}
for int::range(0, 100) |_i| {
// do whatever
}
for 100.times {
// do whatever
}
```
I feel that the latter reads much more nicely than the first two approaches,
and unlike the first two the new method allows the user to ignore the specific
type of the number (ineed, if we're throwing away the inductive variable, who
cares what type it is?). A minor benefit is that this new method will be
somewhat familiar to users of Ruby, from which we borrow the name "times".
2012-07-05 21:12:26 -05:00
|
|
|
|
2012-07-11 14:45:54 -05:00
|
|
|
trait copyable_iter<A:copy> {
|
|
|
|
fn filter_to_vec(pred: fn(A) -> bool) -> ~[A];
|
|
|
|
fn map_to_vec<B>(op: fn(A) -> B) -> ~[B];
|
|
|
|
fn to_vec() -> ~[A];
|
|
|
|
fn min() -> A;
|
|
|
|
fn max() -> A;
|
|
|
|
fn find(p: fn(A) -> bool) -> option<A>;
|
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn eachi<A,IA:base_iter<A>>(self: IA, blk: fn(uint, A) -> bool) {
|
2012-03-06 22:48:40 -06:00
|
|
|
let mut i = 0u;
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-04-11 23:45:18 -05:00
|
|
|
if !blk(i, a) { break; }
|
2012-01-31 20:52:20 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn all<A,IA:base_iter<A>>(self: IA, blk: fn(A) -> bool) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-08-01 19:30:05 -05:00
|
|
|
if !blk(a) { return false; }
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return true;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn any<A,IA:base_iter<A>>(self: IA, blk: fn(A) -> bool) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-08-01 19:30:05 -05:00
|
|
|
if blk(a) { return true; }
|
2012-02-13 00:30:58 -06:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-02-13 00:30:58 -06:00
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn filter_to_vec<A:copy,IA:base_iter<A>>(self: IA,
|
2012-06-29 18:26:56 -05:00
|
|
|
prd: fn(A) -> bool) -> ~[A] {
|
|
|
|
let mut result = ~[];
|
2012-06-30 18:19:07 -05:00
|
|
|
self.size_hint().iter(|hint| vec::reserve(result, hint));
|
|
|
|
for self.each |a| {
|
2012-04-11 23:45:18 -05:00
|
|
|
if prd(a) { vec::push(result, a); }
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return result;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn map_to_vec<A:copy,B,IA:base_iter<A>>(self: IA, op: fn(A) -> B) -> ~[B] {
|
|
|
|
let mut result = ~[];
|
2012-06-30 18:19:07 -05:00
|
|
|
self.size_hint().iter(|hint| vec::reserve(result, hint));
|
|
|
|
for self.each |a| {
|
2012-04-11 23:45:18 -05:00
|
|
|
vec::push(result, op(a));
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return result;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn flat_map_to_vec<A:copy,B:copy,IA:base_iter<A>,IB:base_iter<B>>(
|
2012-06-29 18:26:56 -05:00
|
|
|
self: IA, op: fn(A) -> IB) -> ~[B] {
|
2012-04-11 23:45:18 -05:00
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut result = ~[];
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
|
|
|
for op(a).each |b| {
|
2012-04-11 23:45:18 -05:00
|
|
|
vec::push(result, b);
|
|
|
|
}
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return result;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn foldl<A,B,IA:base_iter<A>>(self: IA, +b0: B, blk: fn(B, A) -> B) -> B {
|
2012-03-06 22:48:40 -06:00
|
|
|
let mut b <- b0;
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-04-11 23:45:18 -05:00
|
|
|
b = blk(b, a);
|
2012-02-12 04:57:50 -06:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return b;
|
2012-02-12 04:57:50 -06:00
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn to_vec<A:copy,IA:base_iter<A>>(self: IA) -> ~[A] {
|
2012-06-30 18:19:07 -05:00
|
|
|
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(r, ~[a]))
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn contains<A,IA:base_iter<A>>(self: IA, x: A) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-08-01 19:30:05 -05:00
|
|
|
if a == x { return true; }
|
2012-04-11 23:45:18 -05:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-02-12 04:44:40 -06:00
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn count<A,IA:base_iter<A>>(self: IA, x: A) -> uint {
|
2012-06-30 18:19:07 -05:00
|
|
|
do foldl(self, 0u) |count, value| {
|
2012-02-12 04:50:37 -06:00
|
|
|
if value == x {
|
|
|
|
count + 1u
|
|
|
|
} else {
|
|
|
|
count
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-25 17:04:00 -05:00
|
|
|
fn position<A,IA:base_iter<A>>(self: IA, f: fn(A) -> bool)
|
|
|
|
-> option<uint> {
|
|
|
|
let mut i = 0;
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-08-01 19:30:05 -05:00
|
|
|
if f(a) { return some(i); }
|
2012-06-25 17:04:00 -05:00
|
|
|
i += 1;
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return none;
|
2012-06-25 17:04:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// note: 'rposition' would only make sense to provide with a bidirectional
|
|
|
|
// iter interface, such as would provide "reach" in addition to "each". as is,
|
|
|
|
// it would have to be implemented with foldr, which is too inefficient.
|
|
|
|
|
2012-07-03 18:46:57 -05:00
|
|
|
fn repeat(times: uint, blk: fn() -> bool) {
|
2012-03-06 22:48:40 -06:00
|
|
|
let mut i = 0u;
|
2012-01-31 20:52:20 -06:00
|
|
|
while i < times {
|
2012-07-03 18:46:57 -05:00
|
|
|
if !blk() { break }
|
2012-01-31 20:52:20 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn min<A:copy,IA:base_iter<A>>(self: IA) -> A {
|
2012-06-30 18:19:07 -05:00
|
|
|
alt do foldl::<A,option<A>,IA>(self, none) |a, b| {
|
2012-02-12 04:36:40 -06:00
|
|
|
alt a {
|
2012-08-03 21:59:04 -05:00
|
|
|
some(a_) if a_ < b => {
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2005): Not sure if this is successfully optimized to
|
|
|
|
// a move
|
2012-02-12 05:04:33 -06:00
|
|
|
a
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => some(b)
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
} {
|
2012-08-03 21:59:04 -05:00
|
|
|
some(val) => val,
|
|
|
|
none => fail ~"min called on empty iterator"
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
fn max<A:copy,IA:base_iter<A>>(self: IA) -> A {
|
2012-06-30 18:19:07 -05:00
|
|
|
alt do foldl::<A,option<A>,IA>(self, none) |a, b| {
|
2012-02-12 04:36:40 -06:00
|
|
|
alt a {
|
2012-08-03 21:59:04 -05:00
|
|
|
some(a_) if a_ > b => {
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2005): Not sure if this is successfully optimized to
|
|
|
|
// a move.
|
2012-02-12 05:04:33 -06:00
|
|
|
a
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => some(b)
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
} {
|
2012-08-03 21:59:04 -05:00
|
|
|
some(val) => val,
|
|
|
|
none => fail ~"max called on empty iterator"
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
}
|
2012-01-31 20:52:20 -06:00
|
|
|
|
2012-04-11 23:45:18 -05:00
|
|
|
/*
|
2012-01-31 20:52:20 -06:00
|
|
|
#[test]
|
|
|
|
fn test_enumerate() {
|
|
|
|
enumerate(["0", "1", "2"]) {|i,j|
|
2012-07-30 18:01:07 -05:00
|
|
|
assert fmt!{"%u",i} == j;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-03-27 16:50:23 -05:00
|
|
|
fn test_map_and_to_vec() {
|
2012-06-29 18:26:56 -05:00
|
|
|
let a = bind vec::iter(~[0, 1, 2], _);
|
2012-03-22 22:06:01 -05:00
|
|
|
let b = bind map(a, {|i| 2*i}, _);
|
2012-03-27 16:50:23 -05:00
|
|
|
let c = to_vec(b);
|
2012-06-29 18:26:56 -05:00
|
|
|
assert c == ~[0, 2, 4];
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_map_directly_on_vec() {
|
2012-06-29 18:26:56 -05:00
|
|
|
let b = bind map(~[0, 1, 2], {|i| 2*i}, _);
|
2012-03-27 16:50:23 -05:00
|
|
|
let c = to_vec(b);
|
2012-06-29 18:26:56 -05:00
|
|
|
assert c == ~[0, 2, 4];
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_filter_on_int_range() {
|
|
|
|
fn is_even(&&i: int) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return (i % 2) == 0;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-03-27 16:50:23 -05:00
|
|
|
let l = to_vec(bind filter(bind int::range(0, 10, _), is_even, _));
|
2012-06-29 18:26:56 -05:00
|
|
|
assert l == ~[0, 2, 4, 6, 8];
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_filter_on_uint_range() {
|
|
|
|
fn is_even(&&i: uint) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return (i % 2u) == 0u;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-03-27 16:50:23 -05:00
|
|
|
let l = to_vec(bind filter(bind uint::range(0u, 10u, _), is_even, _));
|
2012-06-29 18:26:56 -05:00
|
|
|
assert l == ~[0u, 2u, 4u, 6u, 8u];
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-02-13 00:30:58 -06:00
|
|
|
#[test]
|
|
|
|
fn test_filter_map() {
|
|
|
|
fn negativate_the_evens(&&i: int) -> option<int> {
|
|
|
|
if i % 2 == 0 {
|
|
|
|
some(-i)
|
|
|
|
} else {
|
|
|
|
none
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-27 16:50:23 -05:00
|
|
|
let l = to_vec(bind filter_map(
|
2012-02-13 00:30:58 -06:00
|
|
|
bind int::range(0, 5, _), negativate_the_evens, _));
|
2012-06-29 18:26:56 -05:00
|
|
|
assert l == ~[0, -2, -4];
|
2012-02-13 00:30:58 -06:00
|
|
|
}
|
|
|
|
|
2012-01-31 20:52:20 -06:00
|
|
|
#[test]
|
|
|
|
fn test_flat_map_with_option() {
|
|
|
|
fn if_even(&&i: int) -> option<int> {
|
|
|
|
if (i % 2) == 0 { some(i) }
|
|
|
|
else { none }
|
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let a = bind vec::iter(~[0, 1, 2], _);
|
2012-01-31 20:52:20 -06:00
|
|
|
let b = bind flat_map(a, if_even, _);
|
2012-03-27 16:50:23 -05:00
|
|
|
let c = to_vec(b);
|
2012-06-29 18:26:56 -05:00
|
|
|
assert c == ~[0, 2];
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_flat_map_with_list() {
|
2012-06-29 18:26:56 -05:00
|
|
|
fn repeat(&&i: int) -> ~[int] {
|
|
|
|
let mut r = ~[];
|
|
|
|
int::range(0, i) {|_j| r += ~[i]; }
|
2012-01-31 20:52:20 -06:00
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let a = bind vec::iter(~[0, 1, 2, 3], _);
|
2012-01-31 20:52:20 -06:00
|
|
|
let b = bind flat_map(a, repeat, _);
|
2012-03-27 16:50:23 -05:00
|
|
|
let c = to_vec(b);
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"c = %?", c};
|
2012-06-29 18:26:56 -05:00
|
|
|
assert c == ~[1, 2, 2, 3, 3, 3];
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_repeat() {
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut c = ~[], i = 0u;
|
2012-01-31 20:52:20 -06:00
|
|
|
repeat(5u) {||
|
2012-06-29 18:26:56 -05:00
|
|
|
c += ~[(i * i)];
|
2012-01-31 20:52:20 -06:00
|
|
|
i += 1u;
|
|
|
|
};
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"c = %?", c};
|
2012-06-29 18:26:56 -05:00
|
|
|
assert c == ~[0u, 1u, 4u, 9u, 16u];
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-02-12 04:36:40 -06:00
|
|
|
#[test]
|
|
|
|
fn test_min() {
|
2012-06-29 18:26:56 -05:00
|
|
|
assert min(~[5, 4, 1, 2, 3]) == 1;
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
2012-01-31 20:52:20 -06:00
|
|
|
|
2012-02-12 04:36:40 -06:00
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[ignore(cfg(windows))]
|
2012-02-12 04:36:40 -06:00
|
|
|
fn test_min_empty() {
|
2012-06-29 18:26:56 -05:00
|
|
|
min::<int, ~[int]>(~[]);
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_max() {
|
2012-06-29 18:26:56 -05:00
|
|
|
assert max(~[1, 2, 4, 2, 3]) == 4;
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[ignore(cfg(windows))]
|
2012-02-12 04:36:40 -06:00
|
|
|
fn test_max_empty() {
|
2012-06-29 18:26:56 -05:00
|
|
|
max::<int, ~[int]>(~[]);
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
2012-02-12 04:44:40 -06:00
|
|
|
|
|
|
|
#[test]
|
2012-02-13 00:11:42 -06:00
|
|
|
fn test_reversed() {
|
2012-06-29 18:26:56 -05:00
|
|
|
assert to_vec(bind reversed(~[1, 2, 3], _)) == ~[3, 2, 1];
|
2012-02-12 04:50:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_count() {
|
2012-06-29 18:26:56 -05:00
|
|
|
assert count(~[1, 2, 1, 2, 1], 1) == 3u;
|
2012-02-12 04:57:50 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_foldr() {
|
2012-04-12 23:58:32 -05:00
|
|
|
fn sub(&&a: int, &&b: int) -> int {
|
2012-02-12 04:57:50 -06:00
|
|
|
a - b
|
|
|
|
}
|
2012-06-29 18:26:56 -05:00
|
|
|
let sum = foldr(~[1, 2, 3, 4], 0, sub);
|
2012-02-12 04:57:50 -06:00
|
|
|
assert sum == -2;
|
2012-04-11 23:45:18 -05:00
|
|
|
}
|
|
|
|
*/
|