auto merge of #7474 : Seldaek/rust/clean-iter, r=thestinger
I think it's WIP - but I wanted to ask for feedback (/cc @thestinger) I had to move the impl of FromIter for vec into extra::iter because I don't think std can depend on extra, but that's a bit messed up. Similarly some FromIter uses are gone now, not sure if this is fixable or if I made a complete mess here..
This commit is contained in:
328
src/libextra/iter.rs
Normal file
328
src/libextra/iter.rs
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
/*! Composable internal iterators
|
||||||
|
|
||||||
|
Internal iterators are functions implementing the protocol used by the `for` loop.
|
||||||
|
|
||||||
|
An internal iterator takes `fn(...) -> bool` as a parameter, with returning `false` used to signal
|
||||||
|
breaking out of iteration. The adaptors in the module work with any such iterator, not just ones
|
||||||
|
tied to specific traits. For example:
|
||||||
|
|
||||||
|
~~~ {.rust}
|
||||||
|
println(iter::to_vec(|f| uint::range(0, 20, f)).to_str());
|
||||||
|
~~~
|
||||||
|
|
||||||
|
An external iterator object implementing the interface in the `iterator` module can be used as an
|
||||||
|
internal iterator by calling the `advance` method. For example:
|
||||||
|
|
||||||
|
~~~ {.rust}
|
||||||
|
let xs = [0u, 1, 2, 3, 4, 5];
|
||||||
|
let ys = [30, 40, 50, 60];
|
||||||
|
let mut it = xs.iter().chain(ys.iter());
|
||||||
|
for it.advance |&x: &uint| {
|
||||||
|
println(x.to_str());
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Internal iterators provide a subset of the functionality of an external iterator. It's not possible
|
||||||
|
to interleave them to implement algorithms like `zip`, `union` and `merge`. However, they're often
|
||||||
|
much easier to implement.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::vec;
|
||||||
|
use std::cmp::Ord;
|
||||||
|
use std::option::{Option, Some, None};
|
||||||
|
use std::num::{One, Zero};
|
||||||
|
use std::ops::{Add, Mul};
|
||||||
|
|
||||||
|
#[allow(missing_doc)]
|
||||||
|
pub trait FromIter<T> {
|
||||||
|
/// Build a container with elements from an internal iterator.
|
||||||
|
///
|
||||||
|
/// # Example:
|
||||||
|
///
|
||||||
|
/// ~~~ {.rust}
|
||||||
|
/// let xs = ~[1, 2, 3];
|
||||||
|
/// let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) };
|
||||||
|
/// assert_eq!(xs, ys);
|
||||||
|
/// ~~~
|
||||||
|
pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if `predicate` is true for any values yielded by an internal iterator.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* let xs = ~[1u, 2, 3, 4, 5];
|
||||||
|
* assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f)));
|
||||||
|
* assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f)));
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn any<T>(predicate: &fn(T) -> bool,
|
||||||
|
iter: &fn(f: &fn(T) -> bool) -> bool) -> bool {
|
||||||
|
for iter |x| {
|
||||||
|
if predicate(x) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if `predicate` is true for all values yielded by an internal iterator.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* assert!(all(|&x: &uint| x < 6, |f| uint::range(1, 6, f)));
|
||||||
|
* assert!(!all(|&x: &uint| x < 5, |f| uint::range(1, 6, f)));
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn all<T>(predicate: &fn(T) -> bool,
|
||||||
|
iter: &fn(f: &fn(T) -> bool) -> bool) -> bool {
|
||||||
|
// If we ever break, iter will return false, so this will only return true
|
||||||
|
// if predicate returns true for everything.
|
||||||
|
iter(|x| predicate(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the first element where `predicate` returns `true`. Return `None` if no element is found.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* let xs = ~[1u, 2, 3, 4, 5, 6];
|
||||||
|
* assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4);
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn find<T>(predicate: &fn(&T) -> bool,
|
||||||
|
iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
|
||||||
|
for iter |x| {
|
||||||
|
if predicate(&x) {
|
||||||
|
return Some(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the largest item yielded by an iterator. Return `None` if the iterator is empty.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
||||||
|
* assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15);
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn max<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
|
||||||
|
let mut result = None;
|
||||||
|
for iter |x| {
|
||||||
|
match result {
|
||||||
|
Some(ref mut y) => {
|
||||||
|
if x > *y {
|
||||||
|
*y = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => result = Some(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the smallest item yielded by an iterator. Return `None` if the iterator is empty.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
||||||
|
* assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &-5);
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
|
||||||
|
let mut result = None;
|
||||||
|
for iter |x| {
|
||||||
|
match result {
|
||||||
|
Some(ref mut y) => {
|
||||||
|
if x < *y {
|
||||||
|
*y = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => result = Some(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduce an iterator to an accumulated value.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn fold<T, U>(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T {
|
||||||
|
let mut result = start;
|
||||||
|
for iter |x| {
|
||||||
|
f(&mut result, x);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduce an iterator to an accumulated value.
|
||||||
|
*
|
||||||
|
* `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it
|
||||||
|
* forces the iterator to yield borrowed pointers.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
|
||||||
|
* fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
|
||||||
|
* }
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T {
|
||||||
|
let mut result = start;
|
||||||
|
for iter |x| {
|
||||||
|
f(&mut result, x);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the sum of the items yielding by an iterator.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* let xs: ~[int] = ~[1, 2, 3, 4];
|
||||||
|
* assert_eq!(do sum |f| { xs.iter().advance(f) }, 10);
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
|
||||||
|
fold_ref(Zero::zero::<T>(), iter, |a, x| *a = a.add(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the product of the items yielded by an iterator.
|
||||||
|
*
|
||||||
|
* # Example:
|
||||||
|
*
|
||||||
|
* ~~~ {.rust}
|
||||||
|
* let xs: ~[int] = ~[1, 2, 3, 4];
|
||||||
|
* assert_eq!(do product |f| { xs.iter().advance(f) }, 24);
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
|
||||||
|
fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromIter<T> for ~[T]{
|
||||||
|
#[inline]
|
||||||
|
pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] {
|
||||||
|
let mut v = ~[];
|
||||||
|
for iter |x| { v.push(x) }
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
|
use int;
|
||||||
|
use uint;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_iter() {
|
||||||
|
let xs = ~[1, 2, 3];
|
||||||
|
let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) };
|
||||||
|
assert_eq!(xs, ys);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_any() {
|
||||||
|
let xs = ~[1u, 2, 3, 4, 5];
|
||||||
|
assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f)));
|
||||||
|
assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_all() {
|
||||||
|
assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f)));
|
||||||
|
assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_find() {
|
||||||
|
let xs = ~[1u, 2, 3, 4, 5, 6];
|
||||||
|
assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_max() {
|
||||||
|
let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
||||||
|
assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_min() {
|
||||||
|
let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
||||||
|
assert_eq!(min(|f| xs.iter().advance(f)).unwrap(), &-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fold() {
|
||||||
|
assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sum() {
|
||||||
|
let xs: ~[int] = ~[1, 2, 3, 4];
|
||||||
|
assert_eq!(do sum |f| { xs.iter().advance(f) }, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_sum() {
|
||||||
|
let xs: ~[int] = ~[];
|
||||||
|
assert_eq!(do sum |f| { xs.iter().advance(f) }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_product() {
|
||||||
|
let xs: ~[int] = ~[1, 2, 3, 4];
|
||||||
|
assert_eq!(do product |f| { xs.iter().advance(f) }, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_product() {
|
||||||
|
let xs: ~[int] = ~[];
|
||||||
|
assert_eq!(do product |f| { xs.iter().advance(f) }, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,6 @@ use util::enum_set::{EnumSet, CLike};
|
|||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::hashmap::{HashMap, HashSet};
|
use std::hashmap::{HashMap, HashSet};
|
||||||
use std::iter;
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::ptr::to_unsafe_ptr;
|
use std::ptr::to_unsafe_ptr;
|
||||||
use std::to_bytes;
|
use std::to_bytes;
|
||||||
@@ -1752,7 +1751,7 @@ pub struct TypeContents {
|
|||||||
|
|
||||||
impl TypeContents {
|
impl TypeContents {
|
||||||
pub fn meets_bounds(&self, cx: ctxt, bbs: BuiltinBounds) -> bool {
|
pub fn meets_bounds(&self, cx: ctxt, bbs: BuiltinBounds) -> bool {
|
||||||
iter::all(|bb| self.meets_bound(cx, bb), |f| bbs.each(f))
|
bbs.iter().all(|bb| self.meets_bound(cx, bb))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn meets_bound(&self, cx: ctxt, bb: BuiltinBound) -> bool {
|
pub fn meets_bound(&self, cx: ctxt, bb: BuiltinBound) -> bool {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::iterator::Iterator;
|
||||||
|
|
||||||
#[deriving(Eq, IterBytes)]
|
#[deriving(Eq, IterBytes)]
|
||||||
pub struct EnumSet<E> {
|
pub struct EnumSet<E> {
|
||||||
@@ -73,6 +74,10 @@ impl<E:CLike> EnumSet<E> {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> EnumSetIterator<E> {
|
||||||
|
EnumSetIterator::new(self.bits)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
||||||
@@ -93,11 +98,43 @@ impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EnumSetIterator<E> {
|
||||||
|
priv index: uint,
|
||||||
|
priv bits: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E:CLike> EnumSetIterator<E> {
|
||||||
|
fn new(bits: uint) -> EnumSetIterator<E> {
|
||||||
|
EnumSetIterator { index: 0, bits: bits }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E:CLike> Iterator<E> for EnumSetIterator<E> {
|
||||||
|
fn next(&mut self) -> Option<E> {
|
||||||
|
if (self.bits == 0) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (self.bits & 1) == 0 {
|
||||||
|
self.index += 1;
|
||||||
|
self.bits >>= 1;
|
||||||
|
}
|
||||||
|
let elem = CLike::from_uint(self.index);
|
||||||
|
self.index += 1;
|
||||||
|
self.bits >>= 1;
|
||||||
|
Some(elem)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (Option<uint>, Option<uint>) {
|
||||||
|
let exact = Some(self.bits.population_count());
|
||||||
|
(exact, exact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use util::enum_set::*;
|
use util::enum_set::*;
|
||||||
|
|
||||||
@@ -199,25 +236,58 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// each
|
// iter / each
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_iterator() {
|
||||||
|
let mut e1: EnumSet<Foo> = EnumSet::empty();
|
||||||
|
|
||||||
|
let elems: ~[Foo] = e1.iter().collect();
|
||||||
|
assert_eq!(~[], elems)
|
||||||
|
|
||||||
|
e1.add(A);
|
||||||
|
let elems: ~[Foo] = e1.iter().collect();
|
||||||
|
assert_eq!(~[A], elems)
|
||||||
|
|
||||||
|
e1.add(C);
|
||||||
|
let elems: ~[Foo] = e1.iter().collect();
|
||||||
|
assert_eq!(~[A,C], elems)
|
||||||
|
|
||||||
|
e1.add(C);
|
||||||
|
let elems: ~[Foo] = e1.iter().collect();
|
||||||
|
assert_eq!(~[A,C], elems)
|
||||||
|
|
||||||
|
e1.add(B);
|
||||||
|
let elems: ~[Foo] = e1.iter().collect();
|
||||||
|
assert_eq!(~[A,B,C], elems)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_each() {
|
fn test_each() {
|
||||||
let mut e1: EnumSet<Foo> = EnumSet::empty();
|
let mut e1: EnumSet<Foo> = EnumSet::empty();
|
||||||
|
|
||||||
assert_eq!(~[], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e1.each(f)))
|
assert_eq!(~[], collect(e1))
|
||||||
|
|
||||||
e1.add(A);
|
e1.add(A);
|
||||||
assert_eq!(~[A], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e1.each(f)))
|
assert_eq!(~[A], collect(e1))
|
||||||
|
|
||||||
e1.add(C);
|
e1.add(C);
|
||||||
assert_eq!(~[A,C], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e1.each(f)))
|
assert_eq!(~[A,C], collect(e1))
|
||||||
|
|
||||||
e1.add(C);
|
e1.add(C);
|
||||||
assert_eq!(~[A,C], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e1.each(f)))
|
assert_eq!(~[A,C], collect(e1))
|
||||||
|
|
||||||
e1.add(B);
|
e1.add(B);
|
||||||
assert_eq!(~[A,B,C], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e1.each(f)))
|
assert_eq!(~[A,B,C], collect(e1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect(e: EnumSet<Foo>) -> ~[Foo] {
|
||||||
|
let mut elems = ~[];
|
||||||
|
e.each(|elem| {
|
||||||
|
elems.push(elem);
|
||||||
|
true
|
||||||
|
});
|
||||||
|
elems
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@@ -234,12 +304,15 @@ mod test {
|
|||||||
e2.add(C);
|
e2.add(C);
|
||||||
|
|
||||||
let e_union = e1 | e2;
|
let e_union = e1 | e2;
|
||||||
assert_eq!(~[A,B,C], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e_union.each(f)))
|
let elems: ~[Foo] = e_union.iter().collect();
|
||||||
|
assert_eq!(~[A,B,C], elems)
|
||||||
|
|
||||||
let e_intersection = e1 & e2;
|
let e_intersection = e1 & e2;
|
||||||
assert_eq!(~[C], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e_intersection.each(f)))
|
let elems: ~[Foo] = e_intersection.iter().collect();
|
||||||
|
assert_eq!(~[C], elems)
|
||||||
|
|
||||||
let e_subtract = e1 - e2;
|
let e_subtract = e1 - e2;
|
||||||
assert_eq!(~[A], iter::FromIter::from_iter::<Foo, ~[Foo]>(|f| e_subtract.each(f)))
|
let elems: ~[Foo] = e_subtract.iter().collect();
|
||||||
|
assert_eq!(~[A], elems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,316 +8,19 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
/*! Composable internal iterators
|
/*! Times trait
|
||||||
|
|
||||||
Internal iterators are functions implementing the protocol used by the `for` loop.
|
|
||||||
|
|
||||||
An internal iterator takes `fn(...) -> bool` as a parameter, with returning `false` used to signal
|
|
||||||
breaking out of iteration. The adaptors in the module work with any such iterator, not just ones
|
|
||||||
tied to specific traits. For example:
|
|
||||||
|
|
||||||
~~~ {.rust}
|
~~~ {.rust}
|
||||||
println(iter::to_vec(|f| uint::range(0, 20, f)).to_str());
|
use iter::Times;
|
||||||
|
let ten = 10 as uint;
|
||||||
|
let mut accum = 0;
|
||||||
|
for ten.times { accum += 1; }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
An external iterator object implementing the interface in the `iterator` module can be used as an
|
|
||||||
internal iterator by calling the `advance` method. For example:
|
|
||||||
|
|
||||||
~~~ {.rust}
|
|
||||||
let xs = [0u, 1, 2, 3, 4, 5];
|
|
||||||
let ys = [30, 40, 50, 60];
|
|
||||||
let mut it = xs.iter().chain(ys.iter());
|
|
||||||
for it.advance |&x: &uint| {
|
|
||||||
println(x.to_str());
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Internal iterators provide a subset of the functionality of an external iterator. It's not possible
|
|
||||||
to interleave them to implement algorithms like `zip`, `union` and `merge`. However, they're often
|
|
||||||
much easier to implement.
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use cmp::Ord;
|
|
||||||
use option::{Option, Some, None};
|
|
||||||
use num::{One, Zero};
|
|
||||||
use ops::{Add, Mul};
|
|
||||||
|
|
||||||
#[allow(missing_doc)]
|
#[allow(missing_doc)]
|
||||||
pub trait Times {
|
pub trait Times {
|
||||||
fn times(&self, it: &fn() -> bool) -> bool;
|
fn times(&self, it: &fn() -> bool) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_doc)]
|
|
||||||
pub trait FromIter<T> {
|
|
||||||
/// Build a container with elements from an internal iterator.
|
|
||||||
///
|
|
||||||
/// # Example:
|
|
||||||
///
|
|
||||||
/// ~~~ {.rust}
|
|
||||||
/// let xs = ~[1, 2, 3];
|
|
||||||
/// let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) };
|
|
||||||
/// assert_eq!(xs, ys);
|
|
||||||
/// ~~~
|
|
||||||
pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if `predicate` is true for any values yielded by an internal iterator.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* let xs = ~[1u, 2, 3, 4, 5];
|
|
||||||
* assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f)));
|
|
||||||
* assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f)));
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn any<T>(predicate: &fn(T) -> bool,
|
|
||||||
iter: &fn(f: &fn(T) -> bool) -> bool) -> bool {
|
|
||||||
for iter |x| {
|
|
||||||
if predicate(x) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if `predicate` is true for all values yielded by an internal iterator.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* assert!(all(|&x: &uint| x < 6, |f| uint::range(1, 6, f)));
|
|
||||||
* assert!(!all(|&x: &uint| x < 5, |f| uint::range(1, 6, f)));
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn all<T>(predicate: &fn(T) -> bool,
|
|
||||||
iter: &fn(f: &fn(T) -> bool) -> bool) -> bool {
|
|
||||||
// If we ever break, iter will return false, so this will only return true
|
|
||||||
// if predicate returns true for everything.
|
|
||||||
iter(|x| predicate(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the first element where `predicate` returns `true`. Return `None` if no element is found.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* let xs = ~[1u, 2, 3, 4, 5, 6];
|
|
||||||
* assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4);
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn find<T>(predicate: &fn(&T) -> bool,
|
|
||||||
iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
|
|
||||||
for iter |x| {
|
|
||||||
if predicate(&x) {
|
|
||||||
return Some(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the largest item yielded by an iterator. Return `None` if the iterator is empty.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
|
||||||
* assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15);
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn max<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
|
|
||||||
let mut result = None;
|
|
||||||
for iter |x| {
|
|
||||||
match result {
|
|
||||||
Some(ref mut y) => {
|
|
||||||
if x > *y {
|
|
||||||
*y = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => result = Some(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the smallest item yielded by an iterator. Return `None` if the iterator is empty.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
|
||||||
* assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &-5);
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
|
|
||||||
let mut result = None;
|
|
||||||
for iter |x| {
|
|
||||||
match result {
|
|
||||||
Some(ref mut y) => {
|
|
||||||
if x < *y {
|
|
||||||
*y = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => result = Some(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reduce an iterator to an accumulated value.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn fold<T, U>(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T {
|
|
||||||
let mut result = start;
|
|
||||||
for iter |x| {
|
|
||||||
f(&mut result, x);
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reduce an iterator to an accumulated value.
|
|
||||||
*
|
|
||||||
* `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it
|
|
||||||
* forces the iterator to yield borrowed pointers.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
|
|
||||||
* fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
|
|
||||||
* }
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T {
|
|
||||||
let mut result = start;
|
|
||||||
for iter |x| {
|
|
||||||
f(&mut result, x);
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the sum of the items yielding by an iterator.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* let xs: ~[int] = ~[1, 2, 3, 4];
|
|
||||||
* assert_eq!(do sum |f| { xs.iter().advance(f) }, 10);
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
|
|
||||||
fold_ref(Zero::zero::<T>(), iter, |a, x| *a = a.add(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the product of the items yielded by an iterator.
|
|
||||||
*
|
|
||||||
* # Example:
|
|
||||||
*
|
|
||||||
* ~~~ {.rust}
|
|
||||||
* let xs: ~[int] = ~[1, 2, 3, 4];
|
|
||||||
* assert_eq!(do product |f| { xs.iter().advance(f) }, 24);
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
|
|
||||||
fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use prelude::*;
|
|
||||||
|
|
||||||
use int;
|
|
||||||
use uint;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_iter() {
|
|
||||||
let xs = ~[1, 2, 3];
|
|
||||||
let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) };
|
|
||||||
assert_eq!(xs, ys);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_any() {
|
|
||||||
let xs = ~[1u, 2, 3, 4, 5];
|
|
||||||
assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f)));
|
|
||||||
assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_all() {
|
|
||||||
assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f)));
|
|
||||||
assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find() {
|
|
||||||
let xs = ~[1u, 2, 3, 4, 5, 6];
|
|
||||||
assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_max() {
|
|
||||||
let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
|
||||||
assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_min() {
|
|
||||||
let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
|
|
||||||
assert_eq!(min(|f| xs.iter().advance(f)).unwrap(), &-5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fold() {
|
|
||||||
assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sum() {
|
|
||||||
let xs: ~[int] = ~[1, 2, 3, 4];
|
|
||||||
assert_eq!(do sum |f| { xs.iter().advance(f) }, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_empty_sum() {
|
|
||||||
let xs: ~[int] = ~[];
|
|
||||||
assert_eq!(do sum |f| { xs.iter().advance(f) }, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_product() {
|
|
||||||
let xs: ~[int] = ~[1, 2, 3, 4];
|
|
||||||
assert_eq!(do product |f| { xs.iter().advance(f) }, 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_empty_product() {
|
|
||||||
let xs: ~[int] = ~[];
|
|
||||||
assert_eq!(do product |f| { xs.iter().advance(f) }, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Great
|
|||||||
pub use char::Char;
|
pub use char::Char;
|
||||||
pub use container::{Container, Mutable, Map, Set};
|
pub use container::{Container, Mutable, Map, Set};
|
||||||
pub use hash::Hash;
|
pub use hash::Hash;
|
||||||
pub use iter::{Times, FromIter};
|
pub use iter::{Times};
|
||||||
pub use iterator::{Iterator, IteratorUtil, OrdIterator};
|
pub use iterator::{Iterator, IteratorUtil, OrdIterator};
|
||||||
pub use num::{Num, NumCast};
|
pub use num::{Num, NumCast};
|
||||||
pub use num::{Orderable, Signed, Unsigned, Round};
|
pub use num::{Orderable, Signed, Unsigned, Round};
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ use cmp;
|
|||||||
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
|
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
|
||||||
use clone::Clone;
|
use clone::Clone;
|
||||||
use iterator::{FromIterator, Iterator, IteratorUtil};
|
use iterator::{FromIterator, Iterator, IteratorUtil};
|
||||||
use iter::FromIter;
|
|
||||||
use kinds::Copy;
|
use kinds::Copy;
|
||||||
use libc;
|
use libc;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
@@ -2168,15 +2167,6 @@ pub struct VecMutRevIterator<'self, T> {
|
|||||||
}
|
}
|
||||||
iterator!{impl VecMutRevIterator -> &'self mut T, -1}
|
iterator!{impl VecMutRevIterator -> &'self mut T, -1}
|
||||||
|
|
||||||
impl<T> FromIter<T> for ~[T]{
|
|
||||||
#[inline]
|
|
||||||
pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] {
|
|
||||||
let mut v = ~[];
|
|
||||||
for iter |x| { v.push(x) }
|
|
||||||
v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
|
impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
|
||||||
pub fn from_iterator(iterator: &mut T) -> ~[A] {
|
pub fn from_iterator(iterator: &mut T) -> ~[A] {
|
||||||
|
|||||||
Reference in New Issue
Block a user