From 435fcda5e99ad5944c780f864a550b3211a6ab47 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 18 Jul 2013 17:09:08 +0200 Subject: [PATCH 1/5] iterator: Add .cycle() to repeat an iterator --- src/libstd/iterator.rs | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index c8cde69197b..13c234d6397 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -729,6 +729,55 @@ impl> OrdIterator for T { } } +/// A trait for iterators that are clonable. +// FIXME #6967: Dummy A parameter to get around type inference bug +pub trait ClonableIterator { + /// 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; +} + +impl> ClonableIterator for T { + #[inline] + fn cycle(self) -> CycleIterator { + CycleIterator{orig: self.clone(), iter: self} + } +} + +/// An iterator that repeats endlessly +pub struct CycleIterator { + priv orig: T, + priv iter: T, +} + +impl> Iterator for CycleIterator { + #[inline] + fn next(&mut self) -> Option { + match self.iter.next() { + None => { self.iter = self.orig.clone(); self.iter.next() } + y => y + } + } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + // 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 pub struct ChainIterator { From 4623e81aa5429cf3b9b0837907b70da5e749facc Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 18 Jul 2013 17:31:33 +0200 Subject: [PATCH 2/5] iterator: Let closure-less iterators derive Clone --- src/libstd/iterator.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 13c234d6397..ce1c1d585d1 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -74,6 +74,7 @@ impl> DoubleEndedIteratorUtil 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 { priv iter: T } @@ -753,6 +754,7 @@ impl> ClonableIterator for T { } /// An iterator that repeats endlessly +#[deriving(Clone)] pub struct CycleIterator { priv orig: T, priv iter: T, @@ -780,6 +782,7 @@ impl> Iterator for CycleIterator { /// An iterator which strings two iterators together // FIXME #6967: Dummy A parameter to get around type inference bug +#[deriving(Clone)] pub struct ChainIterator { priv a: T, priv b: U, @@ -835,6 +838,7 @@ for ChainIterator { /// 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 { priv a: T, priv b: U @@ -988,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 { priv iter: T, priv count: uint @@ -1086,6 +1091,7 @@ impl<'self, A, T: Iterator> Iterator 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 { priv iter: T, priv n: uint @@ -1134,6 +1140,7 @@ impl> Iterator for SkipIterator { /// 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 { priv iter: T, priv n: uint @@ -1285,6 +1292,7 @@ impl<'self, A, St> Iterator for UnfoldrIterator<'self, A, St> { /// An infinite iterator starting at `start` and advancing by `step` with each /// iteration +#[deriving(Clone)] pub struct Counter { /// The current state the counter is at (next value to be yielded) state: A, From ffe2623e47d9c5a5914865a9556cb1298ca00058 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 18 Jul 2013 17:34:28 +0200 Subject: [PATCH 3/5] iterator: Add test for .cycle() --- src/libstd/iterator.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index ce1c1d585d1..198e63f83c6 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -1494,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]; From 24b6901b26f0bde00706a5cbc16ffc29296ea40d Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 18 Jul 2013 17:38:17 +0200 Subject: [PATCH 4/5] std: Implement Clone for VecIterator and iterators using it 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. VecIterator needs a manual impl to handle the lifetime struct member. --- src/libstd/hashmap.rs | 2 ++ src/libstd/str.rs | 7 +++++++ src/libstd/vec.rs | 17 +++++++++++++++++ 3 files changed, 26 insertions(+) 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 Clone for HashMap { } /// HashMap iterator +#[deriving(Clone)] pub struct HashMapIterator<'self, K, V> { priv iter: vec::VecIterator<'self, Option>>, } @@ -563,6 +564,7 @@ pub struct HashMapConsumeIterator { } /// HashSet iterator +#[deriving(Clone)] pub struct HashSetIterator<'self, K> { priv iter: vec::VecIterator<'self, Option>>, } 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 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 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 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 { priv v: ~[T], priv idx: uint, @@ -2270,6 +2275,7 @@ impl Iterator for VecConsumeIterator { } /// An iterator that moves out of a vector in reverse order. +#[deriving(Clone)] pub struct VecConsumeRevIterator { 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::*; From fe134b9509821e5e2fad5545cdd23c5325dfd583 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Thu, 18 Jul 2013 18:46:37 +0200 Subject: [PATCH 5/5] dlist: Implement Clone for immutable iterators --- src/libextra/dlist.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index c42eba1ffa2..fe05b48988e 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -47,6 +47,7 @@ struct Node { } /// Double-ended DList iterator +#[deriving(Clone)] pub struct DListIterator<'self, T> { priv head: &'self Link, priv tail: Rawlink>, @@ -62,6 +63,7 @@ pub struct MutDListIterator<'self, T> { } /// DList consuming iterator +#[deriving(Clone)] pub struct ConsumeIterator { priv list: DList } @@ -93,6 +95,13 @@ impl Rawlink { } } +impl Clone for Rawlink { + #[inline] + fn clone(&self) -> Rawlink { + Rawlink{p: self.p} + } +} + /// Set the .prev field on `next`, then return `Some(next)` fn link_with_prev(mut next: ~Node, prev: Rawlink>) -> Link { 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();