diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index bf618d7bd3a6f..6dedd9ee4dd26 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -13,7 +13,7 @@ use std::cmp; use std::iterator::RandomAccessIterator; -use std::iterator::{Invert, Enumerate}; +use std::iterator::{Invert, Enumerate, Repeat, Map, Zip}; use std::num; use std::ops; use std::uint; @@ -206,14 +206,13 @@ impl BigBitv { #[inline] pub fn equals(&self, b: &BigBitv, nbits: uint) -> bool { let len = b.storage.len(); - do uint::iterate(0, len) |i| { + for i in range(0, len) { let mask = big_mask(nbits, i); if mask & self.storage[i] != mask & b.storage[i] { - false - } else { - true + return false; } } + true } } @@ -864,13 +863,12 @@ impl BitvSet { /// w1, w2) where the bit location is the number of bits offset so far, /// and w1/w2 are the words coming from the two vectors self, other. fn common_iter<'a>(&'a self, other: &'a BitvSet) - -> MapE<(uint,&uint),(uint,uint,uint), &'a ~[uint],Enumerate>> { - let min = num::min(self.bitv.storage.len(), - other.bitv.storage.len()); - MapE{iter: self.bitv.storage.slice(0, min).iter().enumerate(), - env: &other.bitv.storage, - f: |(i, &w): (uint, &uint), o_store| (i * uint::bits, w, o_store[i]) - } + -> Map<'static, ((uint, &'a uint), &'a ~[uint]), (uint, uint, uint), + Zip>, Repeat<&'a ~[uint]>>> { + let min = num::min(self.bitv.storage.len(), other.bitv.storage.len()); + self.bitv.storage.slice(0, min).iter().enumerate() + .zip(Repeat::new(&other.bitv.storage)) + .transform(|((i, &w), o_store)| (i * uint::bits, w, o_store[i])) } /// Visits each word in self or other that extends beyond the other. This @@ -881,45 +879,21 @@ impl BitvSet { /// is true if the word comes from 'self', and false if it comes from /// 'other'. fn outlier_iter<'a>(&'a self, other: &'a BitvSet) - -> MapE<(uint, &uint),(bool, uint, uint), uint, Enumerate>> { - let len1 = self.bitv.storage.len(); - let len2 = other.bitv.storage.len(); - let min = num::min(len1, len2); - - if min < len1 { - MapE{iter: self.bitv.storage.slice(min, len1).iter().enumerate(), - env: min, - f: |(i, &w): (uint, &uint), min| (true, (i + min) * uint::bits, w) - } + -> Map<'static, ((uint, &'a uint), uint), (bool, uint, uint), + Zip>, Repeat>> { + let slen = self.bitv.storage.len(); + let olen = other.bitv.storage.len(); + + if olen < slen { + self.bitv.storage.slice_from(olen).iter().enumerate() + .zip(Repeat::new(olen)) + .transform(|((i, &w), min)| (true, (i + min) * uint::bits, w)) } else { - MapE{iter: other.bitv.storage.slice(min, len2).iter().enumerate(), - env: min, - f: |(i, &w): (uint, &uint), min| (false, (i + min) * uint::bits, w) - } - } - } -} - -/// Like iterator::Map with explicit env capture -struct MapE { - priv env: Env, - priv f: &'static fn(A, Env) -> B, - priv iter: I, -} - -impl<'self, A, B, Env: Clone, I: Iterator> Iterator for MapE { - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - Some(elt) => Some((self.f)(elt, self.env.clone())), - None => None + other.bitv.storage.slice_from(slen).iter().enumerate() + .zip(Repeat::new(slen)) + .transform(|((i, &w), min)| (false, (i + min) * uint::bits, w)) } } - - #[inline] - fn size_hint(&self) -> (uint, Option) { - self.iter.size_hint() - } } pub struct BitvSetIterator<'self> { diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 658f854c50d81..fbc471c0ae05d 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -19,7 +19,8 @@ use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; use clone::Clone; use cmp::{Eq, Equiv}; use hash::Hash; -use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, Chain, range}; +use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, range}; +use iterator::{FilterMap, Chain, Repeat, Zip}; use num; use option::{None, Option, Some}; use rand::RngUtil; @@ -712,10 +713,12 @@ impl HashSet { } /// Visit the values representing the difference - pub fn difference_iter<'a>(&'a self, other: &'a HashSet) - -> SetAlgebraIter<'a, T> { - EnvFilterIterator{iter: self.iter(), env: other, - filter: |elt, other| !other.contains(elt) } + pub fn difference_iter<'a>(&'a self, other: &'a HashSet) -> SetAlgebraIter<'a, T> { + Repeat::new(other) + .zip(self.iter()) + .filter_map(|(other, elt)| { + if !other.contains(elt) { Some(elt) } else { None } + }) } /// Visit the values representing the symmetric difference @@ -727,8 +730,11 @@ impl HashSet { /// Visit the values representing the intersection pub fn intersection_iter<'a>(&'a self, other: &'a HashSet) -> SetAlgebraIter<'a, T> { - EnvFilterIterator{iter: self.iter(), env: other, - filter: |elt, other| other.contains(elt) } + Repeat::new(other) + .zip(self.iter()) + .filter_map(|(other, elt)| { + if other.contains(elt) { Some(elt) } else { None } + }) } /// Visit the values representing the union @@ -756,38 +762,12 @@ impl> Extendable for HashSet { } } -// FIXME #7814: use std::iterator::FilterIterator -/// Building block for Set operation iterators -pub struct EnvFilterIterator { - priv env: Env, - priv filter: &'static fn(&A, Env) -> bool, - priv iter: I, -} - -impl<'self, A, Env: Clone, I: Iterator<&'self A>> Iterator<&'self A> - for EnvFilterIterator { - #[inline] - fn next(&mut self) -> Option<&'self A> { - loop { - match self.iter.next() { - Some(elt) => if (self.filter)(elt, self.env.clone()) { - return Some(elt) - }, - None => return None, - } - } - } - - #[inline] - fn size_hint(&self) -> (uint, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } -} - +// `Repeat` is used to feed the filter closure an explicit capture +// of a reference to the other set /// Set operations iterator pub type SetAlgebraIter<'self, T> = - EnvFilterIterator, HashSetIterator<'self, T>>; + FilterMap<'static,(&'self HashSet, &'self T), &'self T, + Zip>,HashSetIterator<'self,T>>>; #[cfg(test)] diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 0769aa6a76464..56a0dca56679c 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -82,6 +82,17 @@ pub trait DoubleEndedIteratorUtil { /// In the future these will be default methods instead of a utility trait. impl> DoubleEndedIteratorUtil for T { /// Flip the direction of the iterator + /// + /// The inverted iterator flips the ends on an iterator that can already + /// be iterated from the front and from the back. + /// + /// + /// If the iterator also implements RandomAccessIterator, the inverted + /// iterator is also random access, with the indices starting at the back + /// of the original iterator. + /// + /// Note: Random access with inverted indices still only applies to the first + /// `uint::max_value` elements of the original iterator. #[inline] fn invert(self) -> Invert { Invert{iter: self} @@ -106,6 +117,16 @@ impl> DoubleEndedIterator for Invert { fn next_back(&mut self) -> Option { self.iter.next() } } +impl + RandomAccessIterator> RandomAccessIterator + for Invert { + #[inline] + fn indexable(&self) -> uint { self.iter.indexable() } + #[inline] + fn idx(&self, index: uint) -> Option { + self.iter.idx(self.indexable() - index - 1) + } +} + /// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also /// implementations of the `Iterator` trait. /// @@ -1555,6 +1576,39 @@ impl + Clone> Iterator for Counter { } } +/// An iterator that repeats an element endlessly +#[deriving(Clone, DeepClone)] +pub struct Repeat { + priv element: A +} + +impl Repeat { + /// Create a new `Repeat` that enlessly repeats the element `elt`. + #[inline] + pub fn new(elt: A) -> Repeat { + Repeat{element: elt} + } +} + +impl Iterator for Repeat { + #[inline] + fn next(&mut self) -> Option { self.idx(0) } + #[inline] + fn size_hint(&self) -> (uint, Option) { (uint::max_value, None) } +} + +impl DoubleEndedIterator for Repeat { + #[inline] + fn next_back(&mut self) -> Option { self.idx(0) } +} + +impl RandomAccessIterator for Repeat { + #[inline] + fn indexable(&self) -> uint { uint::max_value } + #[inline] + fn idx(&self, _: uint) -> Option { Some(self.element.clone()) } +} + #[cfg(test)] mod tests { use super::*; @@ -2017,6 +2071,17 @@ mod tests { check_randacc_iter(xs.iter().enumerate(), xs.len()); } + #[test] + fn test_random_access_invert() { + let xs = [1, 2, 3, 4, 5]; + check_randacc_iter(xs.iter().invert(), xs.len()); + let mut it = xs.iter().invert(); + it.next(); + it.next_back(); + it.next(); + check_randacc_iter(it, xs.len() - 3); + } + #[test] fn test_random_access_zip() { let xs = [1, 2, 3, 4, 5]; diff --git a/src/libstd/num/uint.rs b/src/libstd/num/uint.rs index 275a72d6ecc05..86bc98e53fcb6 100644 --- a/src/libstd/num/uint.rs +++ b/src/libstd/num/uint.rs @@ -70,30 +70,6 @@ pub fn div_round(x: uint, y: uint) -> uint { /// pub fn div_floor(x: uint, y: uint) -> uint { return x / y; } -/// -/// Iterate over the range [`lo`..`hi`), or stop when requested -/// -/// # Arguments -/// -/// * lo - The integer at which to start the loop (included) -/// * hi - The integer at which to stop the loop (excluded) -/// * it - A block to execute with each consecutive integer of the range. -/// Return `true` to continue, `false` to stop. -/// -/// # Return value -/// -/// `true` If execution proceeded correctly, `false` if it was interrupted, -/// that is if `it` returned `false` at any point. -/// -pub fn iterate(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool { - let mut i = lo; - while i < hi { - if (!it(i)) { return false; } - i += 1u; - } - return true; -} - impl iter::Times for uint { #[inline] /// diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 3a4a9220ee16c..ea1bddcdb4b9d 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -116,7 +116,7 @@ impl ToStr for Option { impl Option { /// Return an iterator over the possibly contained value #[inline] - pub fn iter<'r>(&'r self) -> OptionIterator<'r, T> { + pub fn iter<'r>(&'r self) -> OptionIterator<&'r T> { match *self { Some(ref x) => OptionIterator{opt: Some(x)}, None => OptionIterator{opt: None} @@ -125,13 +125,19 @@ impl Option { /// Return a mutable iterator over the possibly contained value #[inline] - pub fn mut_iter<'r>(&'r mut self) -> OptionMutIterator<'r, T> { + pub fn mut_iter<'r>(&'r mut self) -> OptionIterator<&'r mut T> { match *self { - Some(ref mut x) => OptionMutIterator{opt: Some(x)}, - None => OptionMutIterator{opt: None} + Some(ref mut x) => OptionIterator{opt: Some(x)}, + None => OptionIterator{opt: None} } } + /// Return a consuming iterator over the possibly contained value + #[inline] + pub fn consume(self) -> OptionIterator { + OptionIterator{opt: self} + } + /// Returns true if the option equals `None` #[inline] pub fn is_none(&self) -> bool { @@ -404,34 +410,18 @@ impl Zero for Option { fn is_zero(&self) -> bool { self.is_none() } } -/// Immutable iterator over an `Option` -pub struct OptionIterator<'self, A> { - priv opt: Option<&'self A> -} - -impl<'self, A> Iterator<&'self A> for OptionIterator<'self, A> { - fn next(&mut self) -> Option<&'self A> { - util::replace(&mut self.opt, None) - } - - fn size_hint(&self) -> (uint, Option) { - match self.opt { - Some(_) => (1, Some(1)), - None => (0, Some(0)), - } - } -} - -/// Mutable iterator over an `Option` -pub struct OptionMutIterator<'self, A> { - priv opt: Option<&'self mut A> +/// An iterator that yields either one or zero elements +pub struct OptionIterator { + priv opt: Option } -impl<'self, A> Iterator<&'self mut A> for OptionMutIterator<'self, A> { - fn next(&mut self) -> Option<&'self mut A> { - util::replace(&mut self.opt, None) +impl Iterator for OptionIterator { + #[inline] + fn next(&mut self) -> Option { + self.opt.take() } + #[inline] fn size_hint(&self) -> (uint, Option) { match self.opt { Some(_) => (1, Some(1)), diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 55c18faf83dee..dfd11f9227d41 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -12,6 +12,7 @@ use cast; use clone::Clone; +use iterator::{range, Iterator}; use option::{Option, Some, None}; use unstable::intrinsics; use util::swap; @@ -20,7 +21,6 @@ use util::swap; #[cfg(not(test))] use num::Int; #[cfg(not(test))] use cmp::{Eq, Ord}; -use uint; /// Calculate the offset from a pointer #[inline] @@ -240,11 +240,10 @@ pub unsafe fn array_each_with_len(arr: **T, len: uint, cb: &fn(*T)) { fail!("ptr::array_each_with_len failure: arr input is null pointer"); } //let start_ptr = *arr; - uint::iterate(0, len, |e| { + for e in range(0, len) { let n = offset(arr, e as int); cb(*n); - true - }); + } debug!("array_each_with_len: after iterate"); } diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 181590e3929c5..91f42edf0aecd 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -16,7 +16,7 @@ use clone::Clone; use cmp::Eq; use either; use iterator::Iterator; -use option::{None, Option, Some}; +use option::{None, Option, Some, OptionIterator}; use vec; use vec::{OwnedVector, ImmutableVector}; use container::Container; @@ -86,15 +86,15 @@ impl Result { /// /// Example: /// - /// do read_file(file).iter |buf| { + /// for buf in read_file(file) { /// print_buf(buf) /// } #[inline] - pub fn iter(&self, f: &fn(&T)) { + pub fn iter<'r>(&'r self) -> OptionIterator<&'r T> { match *self { - Ok(ref t) => f(t), - Err(_) => (), - } + Ok(ref t) => Some(t), + Err(*) => None, + }.consume() } /// Call a method based on a previous result @@ -104,11 +104,11 @@ impl Result { /// immediately returned. This function can be used to pass through a /// successful result while handling an error. #[inline] - pub fn iter_err(&self, f: &fn(&E)) { + pub fn iter_err<'r>(&'r self) -> OptionIterator<&'r E> { match *self { - Ok(_) => (), - Err(ref e) => f(e), - } + Ok(*) => None, + Err(ref t) => Some(t), + }.consume() } /// Unwraps a result, yielding the content of an `Ok`. @@ -214,7 +214,7 @@ impl Result { /// parse_bytes(buf) /// }; #[inline] - pub fn map(&self, op: &fn(&T) -> U) -> Result { + pub fn map(&self, op: &fn(&T) -> U) -> Result { match *self { Ok(ref t) => Ok(op(t)), Err(ref e) => Err(e.clone()) @@ -335,21 +335,25 @@ mod tests { #[test] pub fn test_impl_iter() { let mut valid = false; - Ok::<~str, ~str>(~"a").iter(|_x| valid = true); + let okval = Ok::<~str, ~str>(~"a"); + do okval.iter().next().map |_| { valid = true; }; assert!(valid); - Err::<~str, ~str>(~"b").iter(|_x| valid = false); + let errval = Err::<~str, ~str>(~"b"); + do errval.iter().next().map |_| { valid = false; }; assert!(valid); } #[test] pub fn test_impl_iter_err() { let mut valid = true; - Ok::<~str, ~str>(~"a").iter_err(|_x| valid = false); + let okval = Ok::<~str, ~str>(~"a"); + do okval.iter_err().next().map |_| { valid = false }; assert!(valid); valid = false; - Err::<~str, ~str>(~"b").iter_err(|_x| valid = true); + let errval = Err::<~str, ~str>(~"b"); + do errval.iter_err().next().map |_| { valid = true }; assert!(valid); } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 4d4437cc963ea..0259b547ab3f0 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -479,6 +479,7 @@ pub fn each_permutation(values: &[T], fun: &fn(perm : &[T]) -> bool) -> /// An iterator over the (overlapping) slices of length `size` within /// a vector. +#[deriving(Clone)] pub struct WindowIter<'self, T> { priv v: &'self [T], priv size: uint @@ -498,6 +499,10 @@ impl<'self, T> Iterator<&'self [T]> for WindowIter<'self, T> { /// An iterator over a vector in (non-overlapping) chunks (`size` /// elements at a time). +/// +/// When the vector len is not evenly divided by the chunk size, +/// the last slice of the iteration will be the remainer. +#[deriving(Clone)] pub struct ChunkIter<'self, T> { priv v: &'self [T], priv size: uint @@ -505,16 +510,49 @@ pub struct ChunkIter<'self, T> { impl<'self, T> Iterator<&'self [T]> for ChunkIter<'self, T> { fn next(&mut self) -> Option<&'self [T]> { - if self.size == 0 { + if self.v.len() == 0 { None - } else if self.size >= self.v.len() { - // finished - self.size = 0; - Some(self.v) } else { - let ret = Some(self.v.slice(0, self.size)); - self.v = self.v.slice(self.size, self.v.len()); - ret + let chunksz = cmp::min(self.v.len(), self.size); + let (fst, snd) = (self.v.slice_to(chunksz), + self.v.slice_from(chunksz)); + self.v = snd; + Some(fst) + } + } +} + +impl<'self, T> DoubleEndedIterator<&'self [T]> for ChunkIter<'self, T> { + fn next_back(&mut self) -> Option<&'self [T]> { + if self.v.len() == 0 { + None + } else { + let remainder = self.v.len() % self.size; + let chunksz = if remainder != 0 { remainder } else { self.size }; + let (fst, snd) = (self.v.slice_to(self.v.len() - chunksz), + self.v.slice_from(self.v.len() - chunksz)); + self.v = fst; + Some(snd) + } + } +} + +impl<'self, T> RandomAccessIterator<&'self [T]> for ChunkIter<'self, T> { + #[inline] + fn indexable(&self) -> uint { + self.v.len()/self.size + if self.v.len() % self.size != 0 { 1 } else { 0 } + } + + #[inline] + fn idx(&self, index: uint) -> Option<&'self [T]> { + if index < self.indexable() { + let lo = index * self.size; + let mut hi = lo + self.size; + if hi < lo || hi > self.v.len() { hi = self.v.len(); } + + Some(self.v.slice(lo, hi)) + } else { + None } } } @@ -3378,6 +3416,14 @@ mod tests { assert_eq!(v.chunk_iter(2).collect::<~[&[int]]>(), ~[&[1i,2], &[3,4], &[5]]); assert_eq!(v.chunk_iter(3).collect::<~[&[int]]>(), ~[&[1i,2,3], &[4,5]]); assert_eq!(v.chunk_iter(6).collect::<~[&[int]]>(), ~[&[1i,2,3,4,5]]); + + assert_eq!(v.chunk_iter(2).invert().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]); + let it = v.chunk_iter(2); + assert_eq!(it.indexable(), 3); + assert_eq!(it.idx(0).unwrap(), &[1,2]); + assert_eq!(it.idx(1).unwrap(), &[3,4]); + assert_eq!(it.idx(2).unwrap(), &[5]); + assert_eq!(it.idx(3), None); } #[test]