]> git.lizzy.rs Git - rust.git/commitdiff
add Iterator::flatten and redefine flat_map(f) in terms of map(f).flatten()
authorMazdak Farrokhzad <twingoow@gmail.com>
Tue, 20 Feb 2018 07:26:30 +0000 (08:26 +0100)
committerMazdak Farrokhzad <twingoow@gmail.com>
Tue, 20 Feb 2018 07:27:32 +0000 (08:27 +0100)
src/libcore/iter/iterator.rs
src/libcore/iter/mod.rs
src/libcore/lib.rs
src/libcore/tests/iter.rs

index 33adb3f49dd0d6de94a7acd26096c659386ab52a..8ed3450dc3ac4ee2456faffc4850036cd397cc9b 100644 (file)
@@ -12,7 +12,7 @@
 use ops::Try;
 
 use super::{AlwaysOk, LoopState};
-use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
+use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Flatten, FlatMap, Fuse};
 use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
 use super::{Zip, Sum, Product};
 use super::{ChainState, FromIterator, ZipImpl};
@@ -997,11 +997,15 @@ fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
     /// an extra layer of indirection. `flat_map()` will remove this extra layer
     /// on its own.
     ///
+    /// You can think of [`flat_map(f)`][flat_map] as the equivalent of
+    /// [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
+    ///
     /// Another way of thinking about `flat_map()`: [`map`]'s closure returns
     /// one item for each element, and `flat_map()`'s closure returns an
     /// iterator for each element.
     ///
     /// [`map`]: #method.map
+    /// [`flatten`]: #method.flatten
     ///
     /// # Examples
     ///
@@ -1021,7 +1025,46 @@ fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
     fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
         where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U,
     {
-        FlatMap{iter: self, f: f, frontiter: None, backiter: None }
+        self.map(f).flatten()
+    }
+
+    /// Creates an iterator that flattens nested structure.
+    ///
+    /// This is useful when you have an iterator of iterators or an iterator of
+    /// things that can be turned into iterators and you want to remove one
+    /// level of indirection.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iterator_flatten)]
+    ///
+    /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
+    /// let flattened = data.into_iter().flatten().collect::<Vec<u8>>();
+    /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]);
+    /// ```
+    ///
+    /// Mapping and then flattening:
+    ///
+    /// ```
+    /// #![feature(iterator_flatten)]
+    ///
+    /// let words = ["alpha", "beta", "gamma"];
+    ///
+    /// // chars() returns an iterator
+    /// let merged: String = words.iter()
+    ///                           .map(|s| s.chars())
+    ///                           .flatten()
+    ///                           .collect();
+    /// assert_eq!(merged, "alphabetagamma");
+    /// ```
+    #[inline]
+    #[unstable(feature = "iterator_flatten", issue = "0")]
+    fn flatten(self) -> Flatten<Self, <Self::Item as IntoIterator>::IntoIter>
+    where Self: Sized, Self::Item: IntoIterator {
+        Flatten { iter: self, frontiter: None, backiter: None }
     }
 
     /// Creates an iterator which ends after the first [`None`].
index 1a2da83429af9ef160021d984ef5787cade8ae9f..bd801d2ae69c8caf9879c67c43b9b5c41c102c1a 100644 (file)
@@ -2403,37 +2403,35 @@ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
 /// An iterator that maps each element to an iterator, and yields the elements
 /// of the produced iterators.
 ///
-/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
+/// This `type` is created by the [`flat_map`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
 /// [`flat_map`]: trait.Iterator.html#method.flat_map
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct FlatMap<I, U: IntoIterator, F> {
-    iter: I,
-    f: F,
-    frontiter: Option<U::IntoIter>,
-    backiter: Option<U::IntoIter>,
-}
+type FlatMap<I, U, F> = Flatten<Map<I, F>, <U as IntoIterator>::IntoIter>;
 
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, U: IntoIterator, F> fmt::Debug for FlatMap<I, U, F>
-    where U::IntoIter: fmt::Debug
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("FlatMap")
-            .field("iter", &self.iter)
-            .field("frontiter", &self.frontiter)
-            .field("backiter", &self.backiter)
-            .finish()
-    }
+/// An iterator that flattens one level of nesting in an iterator of things
+/// that can be turned into iterators.
+///
+/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`flatten`]: trait.Iterator.html#method.flatten
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[unstable(feature = "iterator_flatten", issue = "0")]
+#[derive(Clone, Debug)]
+pub struct Flatten<I, U> {
+    iter: I,
+    frontiter: Option<U>,
+    backiter: Option<U>,
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
-    where F: FnMut(I::Item) -> U,
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I: Iterator, U: Iterator> Iterator for Flatten<I, U>
+    where I::Item: IntoIterator<IntoIter = U, Item = U::Item>
 {
     type Item = U::Item;
 
@@ -2441,13 +2439,11 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
     fn next(&mut self) -> Option<U::Item> {
         loop {
             if let Some(ref mut inner) = self.frontiter {
-                if let Some(x) = inner.by_ref().next() {
-                    return Some(x)
-                }
+                if let elt@Some(_) = inner.next() { return elt }
             }
-            match self.iter.next().map(&mut self.f) {
+            match self.iter.next() {
                 None => return self.backiter.as_mut().and_then(|it| it.next()),
-                next => self.frontiter = next.map(IntoIterator::into_iter),
+                Some(inner) => self.frontiter = Some(inner.into_iter()),
             }
         }
     }
@@ -2473,10 +2469,9 @@ fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
         self.frontiter = None;
 
         {
-            let f = &mut self.f;
             let frontiter = &mut self.frontiter;
             init = self.iter.try_fold(init, |acc, x| {
-                let mut mid = f(x).into_iter();
+                let mut mid = x.into_iter();
                 let r = mid.try_fold(acc, &mut fold);
                 *frontiter = Some(mid);
                 r
@@ -2497,27 +2492,24 @@ fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
         where Fold: FnMut(Acc, Self::Item) -> Acc,
     {
         self.frontiter.into_iter()
-            .chain(self.iter.map(self.f).map(U::into_iter))
+            .chain(self.iter.map(IntoIterator::into_iter))
             .chain(self.backiter)
             .fold(init, |acc, iter| iter.fold(acc, &mut fold))
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> where
-    F: FnMut(I::Item) -> U,
-    U: IntoIterator,
-    U::IntoIter: DoubleEndedIterator
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I, U> DoubleEndedIterator for Flatten<I, U>
+    where I: DoubleEndedIterator, U: DoubleEndedIterator,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item>
 {
     #[inline]
     fn next_back(&mut self) -> Option<U::Item> {
         loop {
             if let Some(ref mut inner) = self.backiter {
-                if let Some(y) = inner.next_back() {
-                    return Some(y)
-                }
+                if let elt@Some(_) = inner.next_back() { return elt }
             }
-            match self.iter.next_back().map(&mut self.f) {
+            match self.iter.next_back() {
                 None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
                 next => self.backiter = next.map(IntoIterator::into_iter),
             }
@@ -2534,10 +2526,9 @@ fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
         self.backiter = None;
 
         {
-            let f = &mut self.f;
             let backiter = &mut self.backiter;
             init = self.iter.try_rfold(init, |acc, x| {
-                let mut mid = f(x).into_iter();
+                let mut mid = x.into_iter();
                 let r = mid.try_rfold(acc, &mut fold);
                 *backiter = Some(mid);
                 r
@@ -2558,15 +2549,15 @@ fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
         where Fold: FnMut(Acc, Self::Item) -> Acc,
     {
         self.frontiter.into_iter()
-            .chain(self.iter.map(self.f).map(U::into_iter))
+            .chain(self.iter.map(IntoIterator::into_iter))
             .chain(self.backiter)
             .rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
-impl<I, U, F> FusedIterator for FlatMap<I, U, F>
-    where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
+#[unstable(feature = "fused", issue = "0")]
+impl<I: FusedIterator, U: Iterator> FusedIterator for Flatten<I, U>
+    where I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
 
 /// An iterator that yields `None` forever after the underlying iterator
 /// yields `None` once.
index d2162d307e038e260500d217cc54a9ef541399ff..3dd30ee1c69e235a5ba2ac9685cf4751d0825fa3 100644 (file)
@@ -93,6 +93,7 @@
 #![feature(doc_spotlight)]
 #![feature(rustc_const_unstable)]
 #![feature(iterator_repeat_with)]
+#![feature(iterator_flatten)]
 
 #[prelude_import]
 #[allow(unused)]
index f91c919d7447d6111d258a79532d6ef8fd8c29e1..f28f5ef181ce9c987551c541509d884880bb366c 100644 (file)
@@ -836,6 +836,8 @@ fn add(old: &mut isize, new: &usize) -> Option<f64> {
     assert_eq!(i, ys.len());
 }
 
+// Note: We test flatten() by testing flat_map().
+
 #[test]
 fn test_iterator_flat_map() {
     let xs = [0, 3, 6];