Skip to content

Implement .cycle() for clonable iterators and impl Clone for some iterators #7882

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 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/libextra/dlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>,
Expand All @@ -62,6 +63,7 @@ pub struct MutDListIterator<'self, T> {
}

/// DList consuming iterator
#[deriving(Clone)]
pub struct ConsumeIterator<T> {
priv list: DList<T>
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions src/libstd/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>>,
}
Expand All @@ -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, ()>>>,
}
Expand Down
71 changes: 71 additions & 0 deletions src/libstd/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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];
Expand Down
7 changes: 7 additions & 0 deletions src/libstd/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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>
}
Expand All @@ -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>
}
Expand Down
17 changes: 17 additions & 0 deletions src/libstd/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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,
Expand All @@ -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]
}
Expand Down Expand Up @@ -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::*;
Expand Down