rust/src/libcore/iter.rs

309 lines
8.0 KiB
Rust
Raw Normal View History

/*!
The iteration traits and common implementation
*/
2012-08-27 18:26:35 -05:00
use cmp::{Eq, Ord};
/// A function used to initialize the elements of a sequence
type InitOp<T> = fn(uint) -> T;
2012-08-14 18:54:13 -05:00
trait BaseIter<A> {
pure fn each(blk: fn(v: &A) -> bool);
2012-08-20 14:23:37 -05:00
pure fn size_hint() -> Option<uint>;
}
2012-08-14 18:54:13 -05:00
trait ExtendedIter<A> {
pure fn eachi(blk: fn(uint, A) -> bool);
pure fn all(blk: fn(A) -> bool) -> bool;
pure fn any(blk: fn(A) -> bool) -> bool;
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> {
pure fn contains(x: A) -> bool;
pure fn count(x: A) -> uint;
}
2012-08-14 18:54:13 -05:00
trait Times {
pure fn times(it: fn() -> bool);
}
2012-08-14 18:54:13 -05:00
trait TimesIx{
pure fn timesi(it: fn(uint) -> bool);
2012-07-20 17:33:18 -05:00
}
trait CopyableIter<A:Copy> {
pure fn filter_to_vec(pred: fn(A) -> bool) -> ~[A];
pure fn map_to_vec<B>(op: fn(A) -> B) -> ~[B];
pure fn to_vec() -> ~[A];
2012-08-27 18:26:35 -05:00
pure fn find(p: fn(A) -> bool) -> Option<A>;
}
trait CopyableOrderedIter<A:Copy Ord> {
pure fn min() -> A;
pure fn max() -> A;
}
// 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,
builder: fn(push: pure fn(+A))) -> self;
}
pure fn eachi<A,IA:BaseIter<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| {
if !blk(i, *a) { break; }
i += 1u;
}
}
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| {
if !blk(*a) { return false; }
}
2012-08-01 19:30:05 -05:00
return true;
}
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| {
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
}
pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(self: IA,
prd: fn(A) -> bool) -> ~[A] {
do vec::build_sized_opt(self.size_hint()) |push| {
for self.each |a| {
if prd(*a) { push(*a); }
}
}
}
pure fn map_to_vec<A:Copy,B,IA:BaseIter<A>>(self: IA, op: fn(A) -> B)
-> ~[B] {
do vec::build_sized_opt(self.size_hint()) |push| {
for self.each |a| {
push(op(*a));
}
}
}
pure fn flat_map_to_vec<A:Copy,B:Copy,IA:BaseIter<A>,IB:BaseIter<B>>(
self: IA, op: fn(A) -> IB) -> ~[B] {
do vec::build |push| {
for self.each |a| {
for op(*a).each |b| {
push(*b);
}
}
}
}
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| {
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
}
pure fn to_vec<A:Copy,IA:BaseIter<A>>(self: IA) -> ~[A] {
2012-09-02 17:37:15 -05:00
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy r, ~[a]))
}
2012-08-27 18:26:35 -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| {
if *a == x { return true; }
}
2012-08-01 19:30:05 -05:00
return false;
2012-02-12 04:44:40 -06:00
}
2012-08-27 18:26:35 -05:00
pure fn count<A:Eq,IA:BaseIter<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
}
}
}
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| {
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.
pure fn repeat(times: uint, blk: fn() -> bool) {
2012-03-06 22:48:40 -06:00
let mut i = 0u;
while i < times {
if !blk() { break }
i += 1u;
}
}
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-08-20 14:23:37 -05:00
Some(a_) if a_ < b => {
// FIXME (#2005): Not sure if this is successfully optimized to
// a move
a
}
2012-08-20 14:23:37 -05:00
_ => Some(b)
2012-02-12 04:36:40 -06:00
}
} {
2012-08-20 14:23:37 -05:00
Some(val) => val,
None => fail ~"min called on empty iterator"
2012-02-12 04:36:40 -06: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-08-20 14:23:37 -05:00
Some(a_) if a_ > b => {
// FIXME (#2005): Not sure if this is successfully optimized to
// a move.
a
}
2012-08-20 14:23:37 -05:00
_ => Some(b)
2012-02-12 04:36:40 -06:00
}
} {
2012-08-20 14:23:37 -05:00
Some(val) => val,
None => fail ~"max called on empty iterator"
2012-02-12 04:36:40 -06: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> {
for self.each |i| {
if p(*i) { return Some(*i) }
}
2012-08-20 14:23:37 -05:00
return None;
}
// 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)]
pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(+A))) -> B {
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>,
builder: fn(push: pure fn(+A))) -> B {
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| {
push(f(*elem));
}
}
}
/**
* 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`.
*/
pure fn from_elem<T: Copy,BT: Buildable<T>>(n_elts: uint, t: T) -> BT {
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)]
pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
lhs: IT, rhs: IT) -> BT {
let size_opt = lhs.size_hint().chain(
|sz1| rhs.size_hint().map(|sz2| sz1+sz2));
do build_sized_opt(size_opt) |push| {
for lhs.each |x| { push(*x); }
for rhs.each |x| { push(*x); }
}
}
/// Copies a generic sequence, possibly converting it to a different
/// type of sequence.
#[inline(always)]
pure fn copy_seq<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
v: IT) -> BT {
do build_sized_opt(v.size_hint()) |push| {
for v.each |x| { push(*x); }
}
}