From 90b0ea0a28d64353096b8a262dbfdc3a8d6ed934 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 8 Aug 2013 20:46:36 +0100 Subject: [PATCH 1/2] Add a "peekable" iterator adaptor, with a peek() method that returns the next element. --- src/libstd/iterator.rs | 75 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 29f54bd10fba1..7cb969393c572 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -221,6 +221,26 @@ pub trait IteratorUtil { /// ~~~ fn enumerate(self) -> Enumerate; + + /// Creates an iterator that has a `.peek()` method + /// that returns a optional reference to the next element. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [100, 200, 300]; + /// let mut it = a.consume_iter().peekable(); + /// assert_eq!(it.peek().unwrap(), &100); + /// assert_eq!(it.next().unwrap(), 100); + /// assert_eq!(it.next().unwrap(), 200); + /// assert_eq!(it.peek().unwrap(), &300); + /// assert_eq!(it.peek().unwrap(), &300); + /// assert_eq!(it.next().unwrap(), 300); + /// assert!(it.peek().is_none()); + /// assert!(it.next().is_none()); + /// ~~~ + fn peekable(self) -> PeekableIterator; + /// Creates an iterator which invokes the predicate on elements until it /// returns false. Once the predicate returns false, all further elements are /// yielded. @@ -520,6 +540,11 @@ impl> IteratorUtil for T { Enumerate{iter: self, count: 0} } + #[inline] + fn peekable(self) -> PeekableIterator { + PeekableIterator{iter: self, peeked: None} + } + #[inline] fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhile<'r, A, T> { SkipWhile{iter: self, flag: false, predicate: predicate} @@ -1154,6 +1179,38 @@ impl> RandomAccessIterator<(uint, A)> for Enumerat } } +/// An iterator with a `peek()` that returns an optional reference to the next element. +pub struct PeekableIterator { + priv iter: T, + priv peeked: Option, +} + +impl> Iterator for PeekableIterator { + #[inline] + fn next(&mut self) -> Option { + if self.peeked.is_some() { self.peeked.take() } + else { self.iter.next() } + } +} + +impl<'self, A, T: Iterator> PeekableIterator { + /// Return a reference to the next element of the iterator with out advancing it, + /// or None if the iterator is exhausted. + #[inline] + pub fn peek(&'self mut self) -> Option<&'self A> { + match self.peeked { + Some(ref value) => Some(value), + None => { + self.peeked = self.iter.next(); + match self.peeked { + Some(ref value) => Some(value), + None => None, + } + }, + } + } +} + /// An iterator which rejects elements while `predicate` is true pub struct SkipWhile<'self, A, T> { priv iter: T, @@ -1645,6 +1702,24 @@ mod tests { } } + #[test] + fn test_iterator_peekable() { + let xs = ~[0u, 1, 2, 3, 4, 5]; + let mut it = xs.consume_iter().peekable(); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.next().unwrap(), 0); + assert_eq!(it.next().unwrap(), 1); + assert_eq!(it.next().unwrap(), 2); + assert_eq!(it.peek().unwrap(), &3); + assert_eq!(it.peek().unwrap(), &3); + assert_eq!(it.next().unwrap(), 3); + assert_eq!(it.next().unwrap(), 4); + assert_eq!(it.peek().unwrap(), &5); + assert_eq!(it.next().unwrap(), 5); + assert!(it.peek().is_none()); + assert!(it.next().is_none()); + } + #[test] fn test_iterator_take_while() { let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; From 06cb434249ea3cef8ec79a5ba0184566a2bcabc7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 9 Aug 2013 23:42:28 +0100 Subject: [PATCH 2/2] Add a .peek_clone() method to std::iterator::Peekable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … that copies the returned value, and thus does not freeze the iterator.. --- src/libstd/iterator.rs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 7cb969393c572..1ef7380c8e258 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -223,7 +223,8 @@ pub trait IteratorUtil { /// Creates an iterator that has a `.peek()` method - /// that returns a optional reference to the next element. + /// that returns a optional reference to the next element, + /// and a `.peek_clone()` method that returns an optional copy. /// /// # Example /// @@ -235,11 +236,12 @@ pub trait IteratorUtil { /// assert_eq!(it.next().unwrap(), 200); /// assert_eq!(it.peek().unwrap(), &300); /// assert_eq!(it.peek().unwrap(), &300); + /// assert_eq!(it.peek_clone().unwrap(), 300); /// assert_eq!(it.next().unwrap(), 300); /// assert!(it.peek().is_none()); /// assert!(it.next().is_none()); /// ~~~ - fn peekable(self) -> PeekableIterator; + fn peekable(self) -> Peekable; /// Creates an iterator which invokes the predicate on elements until it /// returns false. Once the predicate returns false, all further elements are @@ -541,8 +543,8 @@ impl> IteratorUtil for T { } #[inline] - fn peekable(self) -> PeekableIterator { - PeekableIterator{iter: self, peeked: None} + fn peekable(self) -> Peekable { + Peekable{iter: self, peeked: None} } #[inline] @@ -1180,12 +1182,12 @@ impl> RandomAccessIterator<(uint, A)> for Enumerat } /// An iterator with a `peek()` that returns an optional reference to the next element. -pub struct PeekableIterator { +pub struct Peekable { priv iter: T, priv peeked: Option, } -impl> Iterator for PeekableIterator { +impl> Iterator for Peekable { #[inline] fn next(&mut self) -> Option { if self.peeked.is_some() { self.peeked.take() } @@ -1193,7 +1195,7 @@ impl> Iterator for PeekableIterator { } } -impl<'self, A, T: Iterator> PeekableIterator { +impl<'self, A, T: Iterator> Peekable { /// Return a reference to the next element of the iterator with out advancing it, /// or None if the iterator is exhausted. #[inline] @@ -1211,6 +1213,24 @@ impl<'self, A, T: Iterator> PeekableIterator { } } +impl> Peekable { + /// Return a copy of the next element of the iterator with out advancing it, + /// or None if the iterator is exhausted. + #[inline] + pub fn peek_clone(&mut self) -> Option { + match self.peeked { + Some(ref value) => Some(value.clone()), + None => { + self.peeked = self.iter.next(); + match self.peeked { + Some(ref value) => Some(value.clone()), + None => None, + } + }, + } + } +} + /// An iterator which rejects elements while `predicate` is true pub struct SkipWhile<'self, A, T> { priv iter: T, @@ -1715,6 +1735,7 @@ mod tests { assert_eq!(it.next().unwrap(), 3); assert_eq!(it.next().unwrap(), 4); assert_eq!(it.peek().unwrap(), &5); + assert_eq!(it.peek_clone().unwrap(), 5); assert_eq!(it.next().unwrap(), 5); assert!(it.peek().is_none()); assert!(it.next().is_none());