2012-09-19 18:52:32 -05:00
|
|
|
/*!
|
|
|
|
|
|
|
|
The iteration traits and common implementation
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2012-10-03 16:52:09 -05:00
|
|
|
#[forbid(deprecated_mode)];
|
|
|
|
#[forbid(deprecated_pattern)];
|
|
|
|
|
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-10-01 18:36:15 -05:00
|
|
|
pub type InitOp<T> = &fn(uint) -> T;
|
2012-08-24 16:45:02 -05:00
|
|
|
|
2012-10-01 18:36:15 -05:00
|
|
|
pub 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-10-01 18:36:15 -05:00
|
|
|
pub 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-10-02 13:37:37 -05:00
|
|
|
pure fn foldl<B>(b0: B, blk: fn(&B, &A) -> B) -> B;
|
2012-09-28 23:51:14 -05:00
|
|
|
pure fn position(f: fn(&A) -> bool) -> Option<uint>;
|
2012-08-27 18:26:35 -05:00
|
|
|
}
|
|
|
|
|
2012-10-01 18:36:15 -05:00
|
|
|
pub 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-10-01 18:36:15 -05:00
|
|
|
pub 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-10-01 18:36:15 -05:00
|
|
|
|
|
|
|
pub trait CopyableIter<A:Copy> {
|
2012-10-02 13:37:37 -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-10-02 13:37:37 -05:00
|
|
|
pure fn find(p: fn(a: A) -> bool) -> Option<A>;
|
2012-08-27 18:26:35 -05:00
|
|
|
}
|
|
|
|
|
2012-10-01 18:36:15 -05:00
|
|
|
pub 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-10-31 18:02:16 -05:00
|
|
|
pub trait CopyableNonstrictIter<A:Copy> {
|
|
|
|
// Like "each", but copies out the value. If the receiver is mutated while
|
|
|
|
// iterating over it, the semantics must not be memory-unsafe but are
|
|
|
|
// otherwise undefined.
|
|
|
|
pure fn each_val(&const self, f: &fn(A) -> bool);
|
|
|
|
}
|
|
|
|
|
2012-08-24 16:45:02 -05:00
|
|
|
// A trait for sequences that can be by imperatively pushing elements
|
|
|
|
// onto them.
|
2012-10-01 18:36:15 -05:00
|
|
|
pub trait Buildable<A> {
|
2012-08-24 16:45:02 -05:00
|
|
|
/**
|
|
|
|
* 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-10-02 13:37:37 -05:00
|
|
|
builder: fn(push: pure fn(v: A))) -> self;
|
2012-08-24 16:45:02 -05:00
|
|
|
}
|
|
|
|
|
2012-10-01 18:36:15 -05:00
|
|
|
pub pure fn eachi<A,IA:BaseIter<A>>(self: &IA,
|
|
|
|
blk: fn(uint, v: &A) -> bool) {
|
2012-09-25 19:39:22 -05:00
|
|
|
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-10-01 18:36:15 -05:00
|
|
|
pub 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-10-01 18:36:15 -05:00
|
|
|
pub 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-10-01 18:36:15 -05:00
|
|
|
pub pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(
|
2012-10-02 13:37:37 -05:00
|
|
|
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-10-01 18:36:15 -05:00
|
|
|
pub pure fn map_to_vec<A:Copy,B,IA:BaseIter<A>>(self: &IA,
|
2012-10-02 13:37:37 -05:00
|
|
|
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-10-01 18:36:15 -05:00
|
|
|
pub pure fn flat_map_to_vec<A:Copy,B:Copy,IA:BaseIter<A>,IB:BaseIter<B>>(
|
2012-10-02 13:37:37 -05:00
|
|
|
self: &IA, op: fn(a: A) -> IB) -> ~[B] {
|
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-10-02 13:37:37 -05:00
|
|
|
pub pure fn foldl<A,B,IA:BaseIter<A>>(self: &IA, b0: B,
|
2012-10-01 18:36:15 -05:00
|
|
|
blk: fn(&B, &A) -> B)
|
2012-09-28 18:37:14 -05:00
|
|
|
-> B {
|
2012-10-23 13:11:23 -05:00
|
|
|
let mut b = move 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-10-01 18:36:15 -05:00
|
|
|
pub pure fn to_vec<A:Copy,IA:BaseIter<A>>(self: &IA) -> ~[A] {
|
2012-09-28 19:59:01 -05:00
|
|
|
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy (*r), ~[*a]))
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
|
2012-10-01 18:36:15 -05:00
|
|
|
pub 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-10-01 18:36:15 -05:00
|
|
|
pub 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-10-01 18:36:15 -05:00
|
|
|
pub 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-28 23:51:14 -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-10-01 18:36:15 -05:00
|
|
|
pub pure fn repeat(times: uint, blk: fn() -> bool) {
|
2012-09-28 23:51:14 -05:00
|
|
|
let mut i = 0;
|
2012-01-31 20:52:20 -06:00
|
|
|
while i < times {
|
2012-07-03 18:46:57 -05:00
|
|
|
if !blk() { break }
|
2012-09-28 23:51:14 -05:00
|
|
|
i += 1;
|
2012-01-31 20:52:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-01 18:36:15 -05:00
|
|
|
pub 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 19:59:01 -05:00
|
|
|
&Some(ref a_) if *a_ < *b => {
|
2012-09-28 18:37:14 -05:00
|
|
|
*(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-10-01 18:36:15 -05:00
|
|
|
pub 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 19:59:01 -05:00
|
|
|
&Some(ref a_) if *a_ > *b => {
|
2012-09-28 18:37:14 -05:00
|
|
|
*(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-10-01 18:36:15 -05:00
|
|
|
pub pure fn find<A: Copy,IA:BaseIter<A>>(self: &IA,
|
2012-10-02 13:37:37 -05:00
|
|
|
p: fn(a: 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-10-02 13:37:37 -05:00
|
|
|
pub pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(v: A)))
|
2012-10-01 18:36:15 -05:00
|
|
|
-> 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)]
|
2012-10-01 18:36:15 -05:00
|
|
|
pub pure fn build_sized_opt<A,B: Buildable<A>>(
|
2012-08-20 14:23:37 -05:00
|
|
|
size: Option<uint>,
|
2012-10-02 13:37:37 -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
|
2012-10-01 18:36:15 -05:00
|
|
|
pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: fn(&T) -> U)
|
|
|
|
-> BU {
|
2012-08-24 16:45:02 -05:00
|
|
|
do build_sized_opt(v.size_hint()) |push| {
|
|
|
|
for v.each() |elem| {
|
2012-09-28 20:11:22 -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`.
|
|
|
|
*/
|
2012-10-01 18:36:15 -05:00
|
|
|
pub pure fn from_fn<T,BT: Buildable<T>>(n_elts: uint,
|
|
|
|
op: InitOp<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(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-10-01 18:36:15 -05:00
|
|
|
pub pure fn from_elem<T: Copy,BT: Buildable<T>>(n_elts: uint,
|
2012-10-02 13:37:37 -05:00
|
|
|
t: T) -> BT {
|
2012-08-24 16:45:02 -05:00
|
|
|
do build_sized(n_elts) |push| {
|
2012-09-28 20:11:22 -05:00
|
|
|
let mut i: uint = 0;
|
|
|
|
while i < n_elts { push(t); i += 1; }
|
2012-08-24 16:45:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Appending two generic sequences
|
|
|
|
#[inline(always)]
|
2012-10-01 18:36:15 -05:00
|
|
|
pub pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
|
2012-09-28 20:11:22 -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-10-01 18:36:15 -05:00
|
|
|
pub pure fn copy_seq<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
|
2012-09-28 20:11:22 -05:00
|
|
|
v: &IT) -> BT {
|
2012-08-24 16:45:02 -05:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|