about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-20 16:58:30 -0700
committerbors <bors@rust-lang.org>2013-07-20 16:58:30 -0700
commit75b4b1b027ec5c5b72d496b7a10da418d5308c01 (patch)
treeddfc2e765cb0ca29eea8fb60196e7bff10fbb7c9 /src/libstd
parentbb8ca1f52cfa59e0040c2c749a1c46048fc6d48d (diff)
parentfe134b9509821e5e2fad5545cdd23c5325dfd583 (diff)
downloadrust-75b4b1b027ec5c5b72d496b7a10da418d5308c01.tar.gz
rust-75b4b1b027ec5c5b72d496b7a10da418d5308c01.zip
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.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/hashmap.rs2
-rw-r--r--src/libstd/iterator.rs71
-rw-r--r--src/libstd/str.rs7
-rw-r--r--src/libstd/vec.rs17
4 files changed, 97 insertions, 0 deletions
diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs
index 182ee37202a..56774560d1d 100644
--- a/src/libstd/hashmap.rs
+++ b/src/libstd/hashmap.rs
@@ -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, ()>>>,
 }
diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs
index c8cde69197b..198e63f83c6 100644
--- a/src/libstd/iterator.rs
+++ b/src/libstd/iterator.rs
@@ -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,
@@ -1438,6 +1495,20 @@ mod tests {
     }
 
     #[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];
         for uint::range(0, v.len()) |i| {
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index 0811dab407e..c74c1e18e6d 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -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>
 }
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index 03e94a902c1..877ee65b4d6 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -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]
 }
@@ -3186,6 +3192,17 @@ mod tests {
     }
 
     #[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::*;
         let mut xs = [1, 2, 3, 4, 5];