2012-09-19 18:52:32 -05:00
|
|
|
/*!
|
|
|
|
|
|
|
|
The iteration traits and common implementation
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2012-08-27 18:26:35 -05:00
|
|
|
use cmp::{Eq, Ord};
|
|
|
|
|
2012-08-24 16:45:02 -05:00
|
|
|
/// A function used to initialize the elements of a sequence
|
2012-09-26 12:33:55 -05:00
|
|
|
type InitOp<T> = &fn(uint) -> T;
|
2012-08-24 16:45:02 -05:00
|
|
|
|
2012-08-14 18:54:13 -05:00
|
|
|
trait BaseIter<A> {
|
2012-09-19 18:55:01 -05:00
|
|
|
pure fn each(blk: fn(v: &A) -> bool);
|
2012-08-20 14:23:37 -05:00
|
|
|
pure fn size_hint() -> Option<uint>;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-08-14 18:54:13 -05:00
|
|
|
trait ExtendedIter<A> {
|
2012-09-21 20:43:30 -05:00
|
|
|
pure fn eachi(blk: fn(uint, v: &A) -> bool);
|
2012-09-28 19:04:39 -05:00
|
|
|
pure fn all(blk: fn(&A) -> bool) -> bool;
|
|
|
|
pure fn any(blk: fn(&A) -> bool) -> bool;
|
2012-09-28 18:37:14 -05:00
|
|
|
pure fn foldl<B>(+b0: B, blk: fn(&B, &A) -> B) -> B;
|
2012-09-13 11:13:03 -05:00
|
|
|
pure fn position(f: fn(A) -> bool) -> Option<uint>;
|
2012-08-27 18:26:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
trait EqIter<A:Eq> {
|
2012-09-25 19:39:22 -05:00
|
|
|
pure fn contains(x: &A) -> bool;
|
|
|
|
pure fn count(x: &A) -> uint;
|
2012-07-11 17:00:40 -05:00
|
|
|
}
|
|
|
|
|
2012-08-14 18:54:13 -05:00
|
|
|
trait Times {
|
2012-08-23 12:22:14 -05:00
|
|
|
pure fn times(it: fn() -> 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-08-14 18:54:13 -05:00
|
|
|
trait TimesIx{
|
2012-08-23 12:22:14 -05:00
|
|
|
pure fn timesi(it: fn(uint) -> bool);
|
2012-07-20 17:33:18 -05:00
|
|
|
}
|
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-09-07 16:52:28 -05:00
|
|
|
trait CopyableIter<A:Copy> {
|
2012-09-28 19:04:39 -05:00
|
|
|
pure fn filter_to_vec(pred: fn(+a: A) -> bool) -> ~[A];
|
|
|
|
pure fn map_to_vec<B>(op: fn(+v: A) -> B) -> ~[B];
|
2012-08-23 12:22:14 -05:00
|
|
|
pure fn to_vec() -> ~[A];
|
2012-08-27 18:26:35 -05:00
|
|
|
pure fn find(p: fn(A) -> bool) -> Option<A>;
|
|
|
|
}
|
|
|
|
|
2012-09-07 16:52:28 -05:00
|
|
|
trait CopyableOrderedIter<A:Copy Ord> {
|
2012-08-23 12:22:14 -05:00
|
|
|
pure fn min() -> A;
|
|
|
|
pure fn max() -> A;
|
2012-07-11 14:45:54 -05:00
|
|
|
}
|
|
|
|
|
2012-08-24 16:45:02 -05:00
|
|
|
// A trait for sequences that can be by imperatively pushing elements
|
|
|
|
// onto them.
|
|
|
|
trait Buildable<A> {
|
|
|
|
/**
|
|
|
|
* Builds a buildable sequence by calling a provided function with
|
|
|
|
* an argument function that pushes an element onto the back of
|
|
|
|
* the sequence.
|
|
|
|
* This version takes an initial size for the sequence.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * size - A hint for an initial size of the sequence
|
|
|
|
* * builder - A function that will construct the sequence. It recieves
|
|
|
|
* as an argument a function that will push an element
|
|
|
|
* onto the sequence being constructed.
|
|
|
|
*/
|
|
|
|
static pure fn build_sized(size: uint,
|
2012-09-23 06:39:27 -05:00
|
|
|
builder: fn(push: pure fn(+v: A))) -> self;
|
2012-08-24 16:45:02 -05:00
|
|
|
}
|
|
|
|
|
2012-09-25 19:39:22 -05:00
|
|
|
pure fn eachi<A,IA:BaseIter<A>>(self: &IA, blk: fn(uint, v: &A) -> bool) {
|
|
|
|
let mut i = 0;
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-09-21 20:43:30 -05:00
|
|
|
if !blk(i, a) { break; }
|
2012-09-25 19:39:22 -05:00
|
|
|
i += 1;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-28 19:04:39 -05:00
|
|
|
pure fn all<A,IA:BaseIter<A>>(self: &IA, blk: fn(&A) -> bool) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-09-28 19:04:39 -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-09-28 19:04:39 -05:00
|
|
|
pure fn any<A,IA:BaseIter<A>>(self: &IA, blk: fn(&A) -> bool) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-09-28 19:04:39 -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-09-28 19:04:39 -05:00
|
|
|
pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(self: &IA,
|
|
|
|
prd: fn(+a: A) -> bool) -> ~[A] {
|
2012-08-23 12:22:14 -05:00
|
|
|
do vec::build_sized_opt(self.size_hint()) |push| {
|
|
|
|
for self.each |a| {
|
2012-09-19 18:55:01 -05:00
|
|
|
if prd(*a) { push(*a); }
|
2012-08-23 12:22:14 -05:00
|
|
|
}
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-28 19:04:39 -05:00
|
|
|
pure fn map_to_vec<A:Copy,B,IA:BaseIter<A>>(self: &IA, op: fn(+v: A) -> B)
|
2012-08-23 12:22:14 -05:00
|
|
|
-> ~[B] {
|
|
|
|
do vec::build_sized_opt(self.size_hint()) |push| {
|
|
|
|
for self.each |a| {
|
2012-09-28 19:04:39 -05:00
|
|
|
push(op(*a));
|
2012-08-23 12:22:14 -05:00
|
|
|
}
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-07 16:52:28 -05:00
|
|
|
pure fn flat_map_to_vec<A:Copy,B:Copy,IA:BaseIter<A>,IB:BaseIter<B>>(
|
2012-09-28 19:04:39 -05:00
|
|
|
self: &IA, op: fn(+a: A) -> IB) -> ~[B] {
|
2012-04-11 23:45:18 -05:00
|
|
|
|
2012-08-23 12:22:14 -05:00
|
|
|
do vec::build |push| {
|
|
|
|
for self.each |a| {
|
2012-09-19 18:55:01 -05:00
|
|
|
for op(*a).each |b| {
|
|
|
|
push(*b);
|
2012-08-23 12:22:14 -05:00
|
|
|
}
|
2012-04-11 23:45:18 -05:00
|
|
|
}
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-28 18:37:14 -05:00
|
|
|
pure fn foldl<A,B,IA:BaseIter<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-09-28 18:37:14 -05:00
|
|
|
b = blk(&b, a);
|
2012-02-12 04:57:50 -06:00
|
|
|
}
|
2012-09-10 14:14:14 -05:00
|
|
|
move b
|
2012-02-12 04:57:50 -06:00
|
|
|
}
|
|
|
|
|
2012-09-28 18:37:14 -05:00
|
|
|
pure fn to_vec<A:Copy,IA:BaseIter<A>>(self: &IA) -> ~[A] {
|
|
|
|
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(*r, ~[*a]))
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-09-25 19:39:22 -05:00
|
|
|
pure fn contains<A:Eq,IA:BaseIter<A>>(self: IA, x: &A) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-09-25 19:39:22 -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-09-28 18:37:14 -05:00
|
|
|
pure fn count<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> uint {
|
2012-09-25 19:39:22 -05:00
|
|
|
do foldl(self, 0) |count, value| {
|
2012-09-28 18:37:14 -05:00
|
|
|
if *value == *x {
|
|
|
|
*count + 1
|
2012-02-12 04:50:37 -06:00
|
|
|
} else {
|
2012-09-28 18:37:14 -05:00
|
|
|
*count
|
2012-02-12 04:50:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-23 12:22:14 -05:00
|
|
|
pure fn position<A,IA:BaseIter<A>>(self: IA, f: fn(A) -> bool)
|
2012-09-13 11:13:03 -05:00
|
|
|
-> Option<uint>
|
|
|
|
{
|
2012-06-25 17:04:00 -05:00
|
|
|
let mut i = 0;
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each |a| {
|
2012-09-19 18:55:01 -05:00
|
|
|
if f(*a) { return Some(i); }
|
2012-06-25 17:04:00 -05:00
|
|
|
i += 1;
|
|
|
|
}
|
2012-08-20 14:23:37 -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-08-23 12:22:14 -05:00
|
|
|
pure 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-09-28 18:37:14 -05:00
|
|
|
pure fn min<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
|
2012-08-20 14:23:37 -05:00
|
|
|
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
|
2012-08-06 14:34:08 -05:00
|
|
|
match a {
|
2012-09-28 18:37:14 -05:00
|
|
|
&Some(a_) if a_ < *b => {
|
|
|
|
*(move a)
|
2012-02-12 05:04:33 -06:00
|
|
|
}
|
2012-09-28 18:37:14 -05:00
|
|
|
_ => Some(*b)
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
} {
|
2012-09-28 15:00:07 -05:00
|
|
|
Some(move val) => val,
|
2012-08-20 14:23:37 -05:00
|
|
|
None => fail ~"min called on empty iterator"
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-28 18:37:14 -05:00
|
|
|
pure fn max<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
|
2012-08-20 14:23:37 -05:00
|
|
|
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
|
2012-08-06 14:34:08 -05:00
|
|
|
match a {
|
2012-09-28 18:37:14 -05:00
|
|
|
&Some(a_) if a_ > *b => {
|
|
|
|
*(move a)
|
2012-02-12 05:04:33 -06:00
|
|
|
}
|
2012-09-28 18:37:14 -05:00
|
|
|
_ => Some(*b)
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
} {
|
2012-09-28 15:00:07 -05:00
|
|
|
Some(move val) => val,
|
2012-08-20 14:23:37 -05:00
|
|
|
None => fail ~"max called on empty iterator"
|
2012-02-12 04:36:40 -06:00
|
|
|
}
|
|
|
|
}
|
2012-01-31 20:52:20 -06:00
|
|
|
|
2012-09-07 16:52:28 -05:00
|
|
|
pure fn find<A: Copy,IA:BaseIter<A>>(self: IA,
|
2012-08-20 14:23:37 -05:00
|
|
|
p: fn(A) -> bool) -> Option<A> {
|
2012-08-23 12:22:14 -05:00
|
|
|
for self.each |i| {
|
2012-09-19 18:55:01 -05:00
|
|
|
if p(*i) { return Some(*i) }
|
2012-08-23 12:22:14 -05:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
return None;
|
2012-08-23 12:22:14 -05:00
|
|
|
}
|
|
|
|
|
2012-08-24 16:45:02 -05:00
|
|
|
// Some functions for just building
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a sequence by calling a provided function with an argument
|
|
|
|
* function that pushes an element to the back of a sequence.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * builder - A function that will construct the sequence. It recieves
|
|
|
|
* as an argument a function that will push an element
|
|
|
|
* onto the sequence being constructed.
|
|
|
|
*/
|
|
|
|
#[inline(always)]
|
2012-09-23 06:39:27 -05:00
|
|
|
pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(+v: A))) -> B {
|
2012-08-24 16:45:02 -05:00
|
|
|
build_sized(4, builder)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a sequence by calling a provided function with an argument
|
|
|
|
* function that pushes an element to the back of a sequence.
|
|
|
|
* This version takes an initial size for the sequence.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * size - An option, maybe containing initial size of the sequence
|
|
|
|
* to reserve
|
|
|
|
* * builder - A function that will construct the sequence. It recieves
|
|
|
|
* as an argument a function that will push an element
|
|
|
|
* onto the sequence being constructed.
|
|
|
|
*/
|
|
|
|
#[inline(always)]
|
|
|
|
pure fn build_sized_opt<A,B: Buildable<A>>(
|
2012-08-20 14:23:37 -05:00
|
|
|
size: Option<uint>,
|
2012-09-23 06:39:27 -05:00
|
|
|
builder: fn(push: pure fn(+v: A))) -> B {
|
2012-08-24 16:45:02 -05:00
|
|
|
|
|
|
|
build_sized(size.get_default(4), builder)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Functions that combine iteration and building
|
|
|
|
|
|
|
|
/// Apply a function to each element of an iterable and return the results
|
|
|
|
fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: IT, f: fn(T) -> U) -> BU {
|
|
|
|
do build_sized_opt(v.size_hint()) |push| {
|
|
|
|
for v.each() |elem| {
|
2012-09-19 18:55:01 -05:00
|
|
|
push(f(*elem));
|
2012-08-24 16:45:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates and initializes a generic sequence from a function
|
|
|
|
*
|
|
|
|
* Creates a generic sequence of size `n_elts` and initializes the elements
|
|
|
|
* to the value returned by the function `op`.
|
|
|
|
*/
|
|
|
|
pure fn from_fn<T,BT: Buildable<T>>(n_elts: uint, op: InitOp<T>) -> BT {
|
|
|
|
do build_sized(n_elts) |push| {
|
|
|
|
let mut i: uint = 0u;
|
|
|
|
while i < n_elts { push(op(i)); i += 1u; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates and initializes a generic sequence with some element
|
|
|
|
*
|
|
|
|
* Creates an immutable vector of size `n_elts` and initializes the elements
|
|
|
|
* to the value `t`.
|
|
|
|
*/
|
2012-09-07 16:52:28 -05:00
|
|
|
pure fn from_elem<T: Copy,BT: Buildable<T>>(n_elts: uint, t: T) -> BT {
|
2012-08-24 16:45:02 -05:00
|
|
|
do build_sized(n_elts) |push| {
|
|
|
|
let mut i: uint = 0u;
|
|
|
|
while i < n_elts { push(t); i += 1u; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Appending two generic sequences
|
|
|
|
#[inline(always)]
|
2012-09-07 16:52:28 -05:00
|
|
|
pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
|
2012-08-24 16:45:02 -05:00
|
|
|
lhs: IT, rhs: IT) -> BT {
|
2012-09-27 19:01:28 -05:00
|
|
|
let size_opt = lhs.size_hint().chain_ref(
|
|
|
|
|sz1| rhs.size_hint().map(|sz2| *sz1+*sz2));
|
2012-08-24 16:45:02 -05:00
|
|
|
do build_sized_opt(size_opt) |push| {
|
2012-09-19 18:55:01 -05:00
|
|
|
for lhs.each |x| { push(*x); }
|
|
|
|
for rhs.each |x| { push(*x); }
|
2012-08-24 16:45:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Copies a generic sequence, possibly converting it to a different
|
|
|
|
/// type of sequence.
|
|
|
|
#[inline(always)]
|
2012-09-07 16:52:28 -05:00
|
|
|
pure fn copy_seq<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
|
2012-08-24 16:45:02 -05:00
|
|
|
v: IT) -> BT {
|
|
|
|
do build_sized_opt(v.size_hint()) |push| {
|
2012-09-19 18:55:01 -05:00
|
|
|
for v.each |x| { push(*x); }
|
2012-08-24 16:45:02 -05:00
|
|
|
}
|
|
|
|
}
|