about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-06-26 09:47:16 -0700
committerbors <bors@rust-lang.org>2013-06-26 09:47:16 -0700
commit3433851a37f04621e0c091ec2180aeddbdd5ada5 (patch)
tree521ab48bddd3bc26043cfcaa23db5b85cf8ab8c5 /src/libstd
parent4e5b4807a5b620627cf6e782524fbe6fc1463c2d (diff)
parent6291702cf334f4b1fe41662bc3b0d996ca7ced19 (diff)
downloadrust-3433851a37f04621e0c091ec2180aeddbdd5ada5.tar.gz
rust-3433851a37f04621e0c091ec2180aeddbdd5ada5.zip
auto merge of #7345 : blake2-ppc/rust/iterator-flat-map, r=thestinger
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.

We discussed the name chain_map, but I decided to go with flat_map_ for consistency with vec.

Since it.map(f).flatten()  would be the same as it.flat_map(f), we could choose
to just implement a flatten method instead. Either way the possibilities are the same but flat_map is more convenient.
Diffstat (limited to 'src/libstd')
-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 9177ecabed6..ab433a9a79d 100644
--- a/src/libstd/iterator.rs
+++ b/src/libstd/iterator.rs
@@ -225,6 +225,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
@@ -396,6 +416,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 {
@@ -868,6 +894,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>,
@@ -1047,6 +1101,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 {