diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index e58ef49c17fa6..ad0dfbe31b5be 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -309,7 +309,7 @@ pub trait Iterator { /// Creates a new iterator which behaves in a similar fashion to fold. /// There is a state which is passed between each iteration and can be /// mutated as necessary. The yielded values from the closure are yielded - /// from the Scan instance when not None. + /// from the Scan instance. /// /// # Example /// @@ -332,6 +332,35 @@ pub trait Iterator { Scan{iter: self, f: f, state: initial_state} } + /// Creates a new iterator which behaves like `scan`, but skips None + /// results. + /// + /// # Example + /// + /// ```rust + /// let s = "this is a sentence"; + /// let mut it = s.char_indices().filter_scan(None, |s_idx, (idx, c)| { + /// if c.is_whitespace() { + /// s_idx.take().map(|i| s.slice(i, idx)) + /// } else { + /// if s_idx.is_none() { + /// *s_idx = Some(idx); + /// } + /// None + /// } + /// }).chain_state(|idx| idx.map(|i| s.slice_from(i))); + /// assert_eq!(it.next(), Some("this")); + /// assert_eq!(it.next(), Some("is")); + /// assert_eq!(it.next(), Some("a")); + /// assert_eq!(it.next(), Some("sentence")); + /// assert_eq!(it.next(), None); + /// ``` + #[inline] + fn filter_scan<'r, St, B>(self, initial_state: St, f: |&mut St, A|: 'r -> Option) + -> FilterScan<'r, A, B, Self, St> { + FilterScan { iter: self, f: f, state: initial_state, state_f: None } + } + /// Creates an iterator that maps each element to an iterator, /// and yields the elements of the produced iterators /// @@ -1685,6 +1714,45 @@ impl<'a, A, B, T: Iterator, St> Iterator for Scan<'a, A, B, T, St> { } } +/// An iterator to maintain state while iterating another iterator, with filtering. +pub struct FilterScan<'a, A, B, T, St> { + iter: T, + f: |&mut St, A|: 'a -> Option, + state_f: Option<|&mut St|: 'a -> Option>, + + /// The current internal state to be passed to the closure next. + pub state: St +} + +impl<'a, A, B, T, St> FilterScan<'a, A, B, T, St> { + /// Yields one more iteration value by mapping the state after the iterator is done. + /// + /// Calling this a second time will replace the previous state mapping function. + #[inline] + pub fn chain_state(self, state_f: |&mut St|: 'a -> Option) -> FilterScan<'a, A, B, T, St> { + FilterScan { state_f: Some(state_f), ..self } + } +} + +impl<'a, A, B, T: Iterator, St> Iterator for FilterScan<'a, A, B, T, St> { + #[inline] + fn next(&mut self) -> Option { + for x in self.iter { + match (self.f)(&mut self.state, x) { + a@Some(_) => return a, + None => () + } + } + self.state_f.take().and_then(|f| f(&mut self.state)) + } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper.map(|u| u + self.state_f.as_ref().map_or(0, |_| 1))) + } +} + /// An iterator that maps each element to an iterator, /// and yields the elements of the produced iterators ///