]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #8276 : kballard/rust/iterator-protocol, r=cmr
authorbors <bors@rust-lang.org>
Sun, 1 Sep 2013 14:00:44 +0000 (07:00 -0700)
committerbors <bors@rust-lang.org>
Sun, 1 Sep 2013 14:00:44 +0000 (07:00 -0700)
r? @thestinger

doc/tutorial-container.md
src/libstd/iterator.rs

index f2c3d8d4450f2ce045417810e0e219a78791d006..7851e9852c115893a6f4cdba9c33f9c1501ab9b3 100644 (file)
@@ -105,6 +105,10 @@ impl Iterator<int> for ZeroStream {
 }
 ~~~
 
+In general, you cannot rely on the behavior of the `next()` method after it has
+returned `None`. Some iterators may return `None` forever. Others may behave
+differently.
+
 ## Container iterators
 
 Containers implement iteration over the contained elements by returning an
@@ -112,7 +116,7 @@ iterator object. For example, vector slices several iterators available:
 
 * `iter()` and `rev_iter()`, for immutable references to the elements
 * `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements
-* `move_iter()` and `move_rev_iter`, to move the elements out by-value
+* `move_iter()` and `move_rev_iter()`, to move the elements out by-value
 
 A typical mutable container will implement at least `iter()`, `mut_iter()` and
 `move_iter()` along with the reverse variants if it maintains an order.
@@ -149,7 +153,7 @@ let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
 assert_eq!(result, -41);
 ~~~
 
-Some adaptors return an adaptor object implementing the `Iterator` trait itself:
+Most adaptors return an adaptor object implementing the `Iterator` trait itself:
 
 ~~~
 let xs = [1, 9, 2, 3, 14, 12];
@@ -158,6 +162,35 @@ let sum = xs.iter().chain(ys.iter()).fold(0, |a, b| a + *b);
 assert_eq!(sum, 57);
 ~~~
 
+Some iterator adaptors may return `None` before exhausting the underlying
+iterator. Additionally, if these iterator adaptors are called again after
+returning `None`, they may call their underlying iterator again even if the
+adaptor will continue to return `None` forever. This may not be desired if the
+underlying iterator has side-effects.
+
+In order to provide a guarantee about behavior once `None` has been returned, an
+iterator adaptor named `fuse()` is provided. This returns an iterator that will
+never call its underlying iterator again once `None` has been returned:
+
+~~~
+let xs = [1,2,3,4,5];
+let mut calls = 0;
+let it = xs.iter().scan((), |_, x| {
+    calls += 1;
+    if *x < 3 { Some(x) } else { None }});
+// the iterator will only yield 1 and 2 before returning None
+// If we were to call it 5 times, calls would end up as 5, despite only 2 values
+// being yielded (and therefore 3 unique calls being made). The fuse() adaptor
+// can fix this.
+let mut it = it.fuse();
+it.next();
+it.next();
+it.next();
+it.next();
+it.next();
+assert_eq!(calls, 3);
+~~~
+
 ## For loops
 
 The function `range` (or `range_inclusive`) allows to simply iterate through a given range:
index 4af7b3e242596476ec131209c13d1cdc6540a5f4..3b4c31349c9c27881b83dff4e85dd861102ef175 100644 (file)
@@ -41,6 +41,13 @@ pub trait Extendable<A>: FromIterator<A> {
 /// An interface for dealing with "external iterators". These types of iterators
 /// can be resumed at any time as all state is stored internally as opposed to
 /// being located on the call stack.
+///
+/// The Iterator protocol states that an iterator yields a (potentially-empty,
+/// potentially-infinite) sequence of values, and returns `None` to signal that
+/// it's finished. The Iterator protocol does not define behavior after `None`
+/// is returned. A concrete Iterator implementation may choose to behave however
+/// it wishes, either by returning `None` infinitely, or by doing something
+/// else.
 pub trait Iterator<A> {
     /// Advance the iterator and return the next value. Return `None` when the end is reached.
     fn next(&mut self) -> Option<A>;
@@ -300,6 +307,36 @@ fn flat_map<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U)
         FlatMap{iter: self, f: f, frontiter: None, backiter: None }
     }
 
+    /// Creates an iterator that yields `None` forever after the underlying
+    /// iterator yields `None`. Random-access iterator behavior is not
+    /// affected, only single and double-ended iterator behavior.
+    ///
+    /// # Example
+    ///
+    /// ~~~ {.rust}
+    /// fn process<U: Iterator<int>>(it: U) -> int {
+    ///     let mut it = it.fuse();
+    ///     let mut sum = 0;
+    ///     for x in it {
+    ///         if x > 5 {
+    ///             break;
+    ///         }
+    ///         sum += x;
+    ///     }
+    ///     // did we exhaust the iterator?
+    ///     if it.next().is_none() {
+    ///         sum += 1000;
+    ///     }
+    ///     sum
+    /// }
+    /// let x = ~[1,2,3,7,8,9];
+    /// assert_eq!(process(x.move_iter()), 1006);
+    /// ~~~
+    #[inline]
+    fn fuse(self) -> Fuse<Self> {
+        Fuse{iter: self, done: false}
+    }
+
     /// Creates an iterator that calls a function with a reference to each
     /// element before yielding it. This is often useful for debugging an
     /// iterator pipeline.
@@ -892,9 +929,12 @@ pub struct Zip<T, U> {
 impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(A, B)> for Zip<T, U> {
     #[inline]
     fn next(&mut self) -> Option<(A, B)> {
-        match (self.a.next(), self.b.next()) {
-            (Some(x), Some(y)) => Some((x, y)),
-            _ => None
+        match self.a.next() {
+            None => None,
+            Some(x) => match self.b.next() {
+                None => None,
+                Some(y) => Some((x, y))
+            }
         }
     }
 
@@ -925,9 +965,12 @@ fn indexable(&self) -> uint {
 
     #[inline]
     fn idx(&self, index: uint) -> Option<(A, B)> {
-        match (self.a.idx(index), self.b.idx(index)) {
-            (Some(x), Some(y)) => Some((x, y)),
-            _ => None
+        match self.a.idx(index) {
+            None => None,
+            Some(x) => match self.b.idx(index) {
+                None => None,
+                Some(y) => Some((x, y))
+            }
         }
     }
 }
@@ -1421,6 +1464,79 @@ fn next_back(&mut self) -> Option<B> {
     }
 }
 
+/// An iterator that yields `None` forever after the underlying iterator
+/// yields `None` once.
+#[deriving(Clone, DeepClone)]
+pub struct Fuse<T> {
+    priv iter: T,
+    priv done: bool
+}
+
+impl<A, T: Iterator<A>> Iterator<A> for Fuse<T> {
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        if self.done {
+            None
+        } else {
+            match self.iter.next() {
+                None => {
+                    self.done = true;
+                    None
+                }
+                x => x
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        if self.done {
+            (0, Some(0))
+        } else {
+            self.iter.size_hint()
+        }
+    }
+}
+
+impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Fuse<T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        if self.done {
+            None
+        } else {
+            match self.iter.next_back() {
+                None => {
+                    self.done = true;
+                    None
+                }
+                x => x
+            }
+        }
+    }
+}
+
+// Allow RandomAccessIterators to be fused without affecting random-access behavior
+impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Fuse<T> {
+    #[inline]
+    fn indexable(&self) -> uint {
+        self.iter.indexable()
+    }
+
+    #[inline]
+    fn idx(&self, index: uint) -> Option<A> {
+        self.iter.idx(index)
+    }
+}
+
+impl<T> Fuse<T> {
+    /// Resets the fuse such that the next call to .next() or .next_back() will
+    /// call the underlying iterator again even if it prevously returned None.
+    #[inline]
+    fn reset_fuse(&mut self) {
+        self.done = false
+    }
+}
+
 /// An iterator that calls a function with a reference to each
 /// element before yielding it.
 pub struct Inspect<'self, A, T> {