Skip to content

Assorted iterator fixes in libstd #8265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
70 changes: 22 additions & 48 deletions src/libextra/bitv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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<vec::VecIterator<'a,uint>>> {
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<Enumerate<vec::VecIterator<'a, uint>>, 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
Expand All @@ -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<vec::VecIterator<'a, uint>>> {
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<Enumerate<vec::VecIterator<'a, uint>>, Repeat<uint>>> {
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<A, B, Env, I> {
priv env: Env,
priv f: &'static fn(A, Env) -> B,
priv iter: I,
}

impl<'self, A, B, Env: Clone, I: Iterator<A>> Iterator<B> for MapE<A, B, Env, I> {
#[inline]
fn next(&mut self) -> Option<B> {
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<uint>) {
self.iter.size_hint()
}
}

pub struct BitvSetIterator<'self> {
Expand Down
54 changes: 17 additions & 37 deletions src/libstd/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -712,10 +713,12 @@ impl<T:Hash + Eq> HashSet<T> {
}

/// Visit the values representing the difference
pub fn difference_iter<'a>(&'a self, other: &'a HashSet<T>)
-> 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<T>) -> 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
Expand All @@ -727,8 +730,11 @@ impl<T:Hash + Eq> HashSet<T> {
/// Visit the values representing the intersection
pub fn intersection_iter<'a>(&'a self, other: &'a HashSet<T>)
-> 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
Expand Down Expand Up @@ -756,38 +762,12 @@ impl<K: Eq + Hash, T: Iterator<K>> Extendable<K, T> for HashSet<K> {
}
}

// FIXME #7814: use std::iterator::FilterIterator
/// Building block for Set operation iterators
pub struct EnvFilterIterator<A, Env, I> {
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<A, Env, I> {
#[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<uint>) {
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<T, &'self HashSet<T>, HashSetIterator<'self, T>>;
FilterMap<'static,(&'self HashSet<T>, &'self T), &'self T,
Zip<Repeat<&'self HashSet<T>>,HashSetIterator<'self,T>>>;


#[cfg(test)]
Expand Down
65 changes: 65 additions & 0 deletions src/libstd/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ pub trait DoubleEndedIteratorUtil {
/// In the future these will be default methods instead of a utility trait.
impl<A, T: DoubleEndedIterator<A>> 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<T> {
Invert{iter: self}
Expand All @@ -106,6 +117,16 @@ impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Invert<T> {
fn next_back(&mut self) -> Option<A> { self.iter.next() }
}

impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterator<A>
for Invert<T> {
#[inline]
fn indexable(&self) -> uint { self.iter.indexable() }
#[inline]
fn idx(&self, index: uint) -> Option<A> {
self.iter.idx(self.indexable() - index - 1)
}
}

/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also
/// implementations of the `Iterator` trait.
///
Expand Down Expand Up @@ -1555,6 +1576,39 @@ impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
}
}

/// An iterator that repeats an element endlessly
#[deriving(Clone, DeepClone)]
pub struct Repeat<A> {
priv element: A
}

impl<A: Clone> Repeat<A> {
/// Create a new `Repeat` that enlessly repeats the element `elt`.
#[inline]
pub fn new(elt: A) -> Repeat<A> {
Repeat{element: elt}
}
}

impl<A: Clone> Iterator<A> for Repeat<A> {
#[inline]
fn next(&mut self) -> Option<A> { self.idx(0) }
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) { (uint::max_value, None) }
}

impl<A: Clone> DoubleEndedIterator<A> for Repeat<A> {
#[inline]
fn next_back(&mut self) -> Option<A> { self.idx(0) }
}

impl<A: Clone> RandomAccessIterator<A> for Repeat<A> {
#[inline]
fn indexable(&self) -> uint { uint::max_value }
#[inline]
fn idx(&self, _: uint) -> Option<A> { Some(self.element.clone()) }
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -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];
Expand Down
24 changes: 0 additions & 24 deletions src/libstd/num/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
///
Expand Down
46 changes: 18 additions & 28 deletions src/libstd/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<T: ToStr> ToStr for Option<T> {
impl<T> Option<T> {
/// 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}
Expand All @@ -125,13 +125,19 @@ impl<T> Option<T> {

/// 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<T> {
OptionIterator{opt: self}
}

/// Returns true if the option equals `None`
#[inline]
pub fn is_none(&self) -> bool {
Expand Down Expand Up @@ -404,34 +410,18 @@ impl<T> Zero for Option<T> {
fn is_zero(&self) -> bool { self.is_none() }
}

/// Immutable iterator over an `Option<A>`
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<uint>) {
match self.opt {
Some(_) => (1, Some(1)),
None => (0, Some(0)),
}
}
}

/// Mutable iterator over an `Option<A>`
pub struct OptionMutIterator<'self, A> {
priv opt: Option<&'self mut A>
/// An iterator that yields either one or zero elements
pub struct OptionIterator<A> {
priv opt: Option<A>
}

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<A> Iterator<A> for OptionIterator<A> {
#[inline]
fn next(&mut self) -> Option<A> {
self.opt.take()
}

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
match self.opt {
Some(_) => (1, Some(1)),
Expand Down
Loading