auto merge of #7882 : blake2-ppc/rust/iterator-clone, r=thestinger

Implement method .cycle() that repeats an iterator endlessly

Implement Clone for simple iterators (without closures), including VecIterator.

> The theory is simple, the immutable iterators simply hold state
> variables (indicies or pointers) into frozen containers. We can freely
> clone these iterators, just like we can clone borrowed pointers.
This commit is contained in:
bors 2013-07-20 16:58:30 -07:00
commit 75b4b1b027
5 changed files with 120 additions and 0 deletions

View File

@ -47,6 +47,7 @@ struct Node<T> {
}
/// Double-ended DList iterator
#[deriving(Clone)]
pub struct DListIterator<'self, T> {
priv head: &'self Link<T>,
priv tail: Rawlink<Node<T>>,
@ -62,6 +63,7 @@ pub struct MutDListIterator<'self, T> {
}
/// DList consuming iterator
#[deriving(Clone)]
pub struct ConsumeIterator<T> {
priv list: DList<T>
}
@ -93,6 +95,13 @@ impl<T> Rawlink<T> {
}
}
impl<T> Clone for Rawlink<T> {
#[inline]
fn clone(&self) -> Rawlink<T> {
Rawlink{p: self.p}
}
}
/// Set the .prev field on `next`, then return `Some(next)`
fn link_with_prev<T>(mut next: ~Node<T>, prev: Rawlink<Node<T>>) -> Link<T> {
next.prev = prev;
@ -686,6 +695,20 @@ mod tests {
assert_eq!(it.next(), None);
}
#[test]
fn test_iterator_clone() {
let mut n = DList::new();
n.push_back(2);
n.push_back(3);
n.push_back(4);
let mut it = n.iter();
it.next();
let mut jt = it.clone();
assert_eq!(it.next(), jt.next());
assert_eq!(it.next_back(), jt.next_back());
assert_eq!(it.next(), jt.next());
}
#[test]
fn test_iterator_double_end() {
let mut n = DList::new();

View File

@ -548,6 +548,7 @@ impl<K:Hash + Eq + Clone,V:Clone> Clone for HashMap<K,V> {
}
/// HashMap iterator
#[deriving(Clone)]
pub struct HashMapIterator<'self, K, V> {
priv iter: vec::VecIterator<'self, Option<Bucket<K, V>>>,
}
@ -563,6 +564,7 @@ pub struct HashMapConsumeIterator<K, V> {
}
/// HashSet iterator
#[deriving(Clone)]
pub struct HashSetIterator<'self, K> {
priv iter: vec::VecIterator<'self, Option<Bucket<K, ()>>>,
}

View File

@ -74,6 +74,7 @@ impl<A, T: DoubleEndedIterator<A>> DoubleEndedIteratorUtil<A> for T {
/// An double-ended iterator with the direction inverted
// FIXME #6967: Dummy A parameter to get around type inference bug
#[deriving(Clone)]
pub struct InvertIterator<A, T> {
priv iter: T
}
@ -729,8 +730,59 @@ impl<A: Ord, T: Iterator<A>> OrdIterator<A> for T {
}
}
/// A trait for iterators that are clonable.
// FIXME #6967: Dummy A parameter to get around type inference bug
pub trait ClonableIterator<A> {
/// Repeats an iterator endlessly
///
/// # Example
///
/// ~~~ {.rust}
/// let a = Counter::new(1,1).take_(1);
/// let mut cy = a.cycle();
/// assert_eq!(cy.next(), Some(1));
/// assert_eq!(cy.next(), Some(1));
/// ~~~
fn cycle(self) -> CycleIterator<A, Self>;
}
impl<A, T: Clone + Iterator<A>> ClonableIterator<A> for T {
#[inline]
fn cycle(self) -> CycleIterator<A, T> {
CycleIterator{orig: self.clone(), iter: self}
}
}
/// An iterator that repeats endlessly
#[deriving(Clone)]
pub struct CycleIterator<A, T> {
priv orig: T,
priv iter: T,
}
impl<A, T: Clone + Iterator<A>> Iterator<A> for CycleIterator<A, T> {
#[inline]
fn next(&mut self) -> Option<A> {
match self.iter.next() {
None => { self.iter = self.orig.clone(); self.iter.next() }
y => y
}
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
// the cycle iterator is either empty or infinite
match self.orig.size_hint() {
sz @ (0, Some(0)) => sz,
(0, _) => (0, None),
_ => (uint::max_value, None)
}
}
}
/// An iterator which strings two iterators together
// FIXME #6967: Dummy A parameter to get around type inference bug
#[deriving(Clone)]
pub struct ChainIterator<A, T, U> {
priv a: T,
priv b: U,
@ -786,6 +838,7 @@ for ChainIterator<A, T, U> {
/// An iterator which iterates two other iterators simultaneously
// FIXME #6967: Dummy A & B parameters to get around type inference bug
#[deriving(Clone)]
pub struct ZipIterator<A, T, B, U> {
priv a: T,
priv b: U
@ -939,6 +992,7 @@ for FilterMapIterator<'self, A, B, T> {
/// An iterator which yields the current count and the element during iteration
// FIXME #6967: Dummy A parameter to get around type inference bug
#[deriving(Clone)]
pub struct EnumerateIterator<A, T> {
priv iter: T,
priv count: uint
@ -1037,6 +1091,7 @@ impl<'self, A, T: Iterator<A>> Iterator<A> for TakeWhileIterator<'self, A, T> {
/// An iterator which skips over `n` elements of `iter`.
// FIXME #6967: Dummy A parameter to get around type inference bug
#[deriving(Clone)]
pub struct SkipIterator<A, T> {
priv iter: T,
priv n: uint
@ -1085,6 +1140,7 @@ impl<A, T: Iterator<A>> Iterator<A> for SkipIterator<A, T> {
/// An iterator which only iterates over the first `n` iterations of `iter`.
// FIXME #6967: Dummy A parameter to get around type inference bug
#[deriving(Clone)]
pub struct TakeIterator<A, T> {
priv iter: T,
priv n: uint
@ -1236,6 +1292,7 @@ impl<'self, A, St> Iterator<A> for UnfoldrIterator<'self, A, St> {
/// An infinite iterator starting at `start` and advancing by `step` with each
/// iteration
#[deriving(Clone)]
pub struct Counter<A> {
/// The current state the counter is at (next value to be yielded)
state: A,
@ -1437,6 +1494,20 @@ mod tests {
assert_eq!(i, 10);
}
#[test]
fn test_cycle() {
let cycle_len = 3;
let it = Counter::new(0u,1).take_(cycle_len).cycle();
assert_eq!(it.size_hint(), (uint::max_value, None));
for it.take_(100).enumerate().advance |(i, x)| {
assert_eq!(i % cycle_len, x);
}
let mut it = Counter::new(0u,1).take_(0).cycle();
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next(), None);
}
#[test]
fn test_iterator_nth() {
let v = &[0, 1, 2, 3, 4];

View File

@ -288,6 +288,7 @@ impl<'self, C: CharEq> CharEq for &'self [C] {
/// An iterator over the substrings of a string, separated by `sep`.
#[deriving(Clone)]
pub struct StrCharSplitIterator<'self,Sep> {
priv string: &'self str,
priv position: uint,
@ -355,6 +356,7 @@ impl<'self, Sep: CharEq> Iterator<&'self str> for StrCharSplitIterator<'self, Se
/// An iterator over the start and end indicies of the matches of a
/// substring within a larger string
#[deriving(Clone)]
pub struct StrMatchesIndexIterator<'self> {
priv haystack: &'self str,
priv needle: &'self str,
@ -363,6 +365,7 @@ pub struct StrMatchesIndexIterator<'self> {
/// An iterator over the substrings of a string separated by a given
/// search string
#[deriving(Clone)]
pub struct StrStrSplitIterator<'self> {
priv it: StrMatchesIndexIterator<'self>,
priv last_end: uint,
@ -2269,6 +2272,7 @@ impl Clone for @str {
/// External iterator for a string's characters. Use with the `std::iterator`
/// module.
#[deriving(Clone)]
pub struct StrCharIterator<'self> {
priv index: uint,
priv string: &'self str,
@ -2288,6 +2292,7 @@ impl<'self> Iterator<char> for StrCharIterator<'self> {
}
/// External iterator for a string's characters in reverse order. Use
/// with the `std::iterator` module.
#[deriving(Clone)]
pub struct StrCharRevIterator<'self> {
priv index: uint,
priv string: &'self str,
@ -2308,6 +2313,7 @@ impl<'self> Iterator<char> for StrCharRevIterator<'self> {
/// External iterator for a string's bytes. Use with the `std::iterator`
/// module.
#[deriving(Clone)]
pub struct StrBytesIterator<'self> {
priv it: vec::VecIterator<'self, u8>
}
@ -2321,6 +2327,7 @@ impl<'self> Iterator<u8> for StrBytesIterator<'self> {
/// External iterator for a string's bytes in reverse order. Use with
/// the `std::iterator` module.
#[deriving(Clone)]
pub struct StrBytesRevIterator<'self> {
priv it: vec::VecRevIterator<'self, u8>
}

View File

@ -2232,6 +2232,10 @@ iterator!{impl VecIterator -> &'self T}
double_ended_iterator!{impl VecIterator -> &'self T}
pub type VecRevIterator<'self, T> = InvertIterator<&'self T, VecIterator<'self, T>>;
impl<'self, T> Clone for VecIterator<'self, T> {
fn clone(&self) -> VecIterator<'self, T> { *self }
}
//iterator!{struct VecMutIterator -> *mut T, &'self mut T}
/// An iterator for mutating the elements of a vector.
pub struct VecMutIterator<'self, T> {
@ -2244,6 +2248,7 @@ double_ended_iterator!{impl VecMutIterator -> &'self mut T}
pub type VecMutRevIterator<'self, T> = InvertIterator<&'self mut T, VecMutIterator<'self, T>>;
/// An iterator that moves out of a vector.
#[deriving(Clone)]
pub struct VecConsumeIterator<T> {
priv v: ~[T],
priv idx: uint,
@ -2270,6 +2275,7 @@ impl<T> Iterator<T> for VecConsumeIterator<T> {
}
/// An iterator that moves out of a vector in reverse order.
#[deriving(Clone)]
pub struct VecConsumeRevIterator<T> {
priv v: ~[T]
}
@ -3185,6 +3191,17 @@ mod tests {
assert_eq!(xs.mut_rev_iter().size_hint(), (5, Some(5)));
}
#[test]
fn test_iter_clone() {
let xs = [1, 2, 5];
let mut it = xs.iter();
it.next();
let mut jt = it.clone();
assert_eq!(it.next(), jt.next());
assert_eq!(it.next(), jt.next());
assert_eq!(it.next(), jt.next());
}
#[test]
fn test_mut_iterator() {
use iterator::*;