about summary refs log tree commit diff
path: root/src/libstd/iterator.rs
diff options
context:
space:
mode:
authorblake2-ppc <blake2-ppc>2013-06-24 02:34:38 +0200
committerblake2-ppc <blake2-ppc>2013-06-24 12:50:41 +0200
commit6291702cf334f4b1fe41662bc3b0d996ca7ced19 (patch)
tree76081ca5cd2e78c7bfd13d57a3f7185f06bf5783 /src/libstd/iterator.rs
parentdfb7de8e0e6d305b0dc42c0f30a0c388b49b2493 (diff)
downloadrust-6291702cf334f4b1fe41662bc3b0d996ca7ced19.tar.gz
rust-6291702cf334f4b1fe41662bc3b0d996ca7ced19.zip
iterator: Add `IteratorUtil::flat_map_` method
flat_map_ produces an iterator that maps each element to an iterator,
and yields the elements of the produced iterators.

This is the monadic bind :: M a -> (a -> M b) -> M b  for iterators.

Named just like the vec method, but with a trailing underline until the
method resolution bug is resolved.
Diffstat (limited to 'src/libstd/iterator.rs')
-rw-r--r--src/libstd/iterator.rs67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs
index d96191f296d..5e866f25b6a 100644
--- a/src/libstd/iterator.rs
+++ b/src/libstd/iterator.rs
@@ -226,6 +226,26 @@ pub trait IteratorUtil<A> {
     fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>)
         -> ScanIterator<'r, A, B, Self, St>;
 
+    /// Creates an iterator that maps each element to an iterator,
+    /// and yields the elements of the produced iterators
+    ///
+    /// # Example
+    ///
+    /// ~~~ {.rust}
+    /// let xs = [2u, 3];
+    /// let ys = [0u, 1, 0, 1, 2];
+    /// let mut it = xs.iter().flat_map_(|&x| Counter::new(0u, 1).take_(x));
+    /// // Check that `it` has the same elements as `ys`
+    /// let mut i = 0;
+    /// for it.advance |x: uint| {
+    ///     assert_eq!(x, ys[i]);
+    ///     i += 1;
+    /// }
+    /// ~~~
+    // FIXME: #5898: should be called `flat_map`
+    fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U)
+        -> FlatMapIterator<'r, A, B, Self, U>;
+
     /// An adaptation of an external iterator to the for-loop protocol of rust.
     ///
     /// # Example
@@ -397,6 +417,12 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T {
         ScanIterator{iter: self, f: f, state: initial_state}
     }
 
+    #[inline]
+    fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U)
+        -> FlatMapIterator<'r, A, B, T, U> {
+        FlatMapIterator{iter: self, f: f, subiter: None }
+    }
+
     /// A shim implementing the `for` loop iteration protocol for iterator objects
     #[inline]
     fn advance(&mut self, f: &fn(A) -> bool) -> bool {
@@ -873,6 +899,34 @@ impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for ScanIterator<'self, A, B,
     }
 }
 
+/// An iterator that maps each element to an iterator,
+/// and yields the elements of the produced iterators
+///
+// FIXME #6967: Dummy B parameter to get around type inference bug
+pub struct FlatMapIterator<'self, A, B, T, U> {
+    priv iter: T,
+    priv f: &'self fn(A) -> U,
+    priv subiter: Option<U>,
+}
+
+impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for
+    FlatMapIterator<'self, A, B, T, U> {
+    #[inline]
+    fn next(&mut self) -> Option<B> {
+        loop {
+            for self.subiter.mut_iter().advance |inner| {
+                for inner.advance |x| {
+                    return Some(x)
+                }
+            }
+            match self.iter.next().map_consume(self.f) {
+                None => return None,
+                next => self.subiter = next,
+            }
+        }
+    }
+}
+
 /// An iterator which just modifies the contained state throughout iteration.
 pub struct UnfoldrIterator<'self, A, St> {
     priv f: &'self fn(&mut St) -> Option<A>,
@@ -1052,6 +1106,19 @@ mod tests {
     }
 
     #[test]
+    fn test_iterator_flat_map() {
+        let xs = [0u, 3, 6];
+        let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8];
+        let mut it = xs.iter().flat_map_(|&x| Counter::new(x, 1).take_(3));
+        let mut i = 0;
+        for it.advance |x: uint| {
+            assert_eq!(x, ys[i]);
+            i += 1;
+        }
+        assert_eq!(i, ys.len());
+    }
+
+    #[test]
     fn test_unfoldr() {
         fn count(st: &mut uint) -> Option<uint> {
             if *st < 10 {