From 0f85cf180a430c066d5b86db0998d124f8dff03b Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 19 Apr 2013 06:06:33 -0400 Subject: [PATCH 1/7] iterator: add skip and take --- src/libcore/iterator.rs | 61 +++++++++++++++++++++++++++++++++++++++++ src/libcore/vec.rs | 28 +++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 8bd6c73fc7db..996951e82192 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -24,6 +24,8 @@ pub trait IteratorUtil { fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, Self>; fn dropwhile<'r>(self, predicate: &'r fn(&A) -> bool) -> DropWhileIterator<'r, A, Self>; fn takewhile<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, Self>; + fn skip(self, n: uint) -> SkipIterator; + fn take(self, n: uint) -> TakeIterator; fn enumerate(self) -> EnumerateIterator; fn advance(&mut self, f: &fn(A) -> bool); } @@ -60,6 +62,16 @@ impl> IteratorUtil for T { TakeWhileIterator{iter: self, flag: false, predicate: predicate} } + #[inline(always)] + fn skip(self, n: uint) -> SkipIterator { + SkipIterator{iter: self, n: n} + } + + #[inline(always)] + fn take(self, n: uint) -> TakeIterator { + TakeIterator{iter: self, n: n} + } + /// A shim implementing the `for` loop iteration protocol for iterator objects #[inline] fn advance(&mut self, f: &fn(A) -> bool) { @@ -199,3 +211,52 @@ impl<'self, A, T: Iterator> Iterator for TakeWhileIterator<'self, A, T> { } } } + +pub struct SkipIterator { + priv iter: T, + priv n: uint +} + +impl> Iterator for SkipIterator { + #[inline] + fn next(&mut self) -> Option { + let mut next = self.iter.next(); + if self.n == 0 { + next + } else { + let n = self.n; + for n.times { + match next { + Some(_) => { + next = self.iter.next(); + loop + } + None => { + self.n = 0; + return None + } + } + } + self.n = 0; + next + } + } +} + +pub struct TakeIterator { + priv iter: T, + priv n: uint +} + +impl> Iterator for TakeIterator { + #[inline] + fn next(&mut self) -> Option { + let next = self.iter.next(); + if self.n != 0 { + self.n -= 1; + next + } else { + None + } + } +} diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 45cc9618f59b..9ebc72c6f409 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -4512,4 +4512,32 @@ mod tests { } assert_eq!(i, ys.len()); } + + #[test] + fn test_iterator_skip() { + use iterator::*; + let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let ys = [13, 15, 16, 17, 19, 20, 30]; + let mut it = xs.iter().skip(5); + let mut i = 0; + for it.advance |&x: &uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } + + #[test] + fn test_iterator_take() { + use iterator::*; + let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [0u, 1, 2, 3, 5]; + let mut it = xs.iter().take(5); + let mut i = 0; + for it.advance |&x: &uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } } From 962a753890f801c378b3cb244b7d7ca3cae164a5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 19 Apr 2013 07:28:51 -0400 Subject: [PATCH 2/7] takewhile -> take_while, dropwhile -> skip_while --- src/libcore/iterator.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 996951e82192..1887e0cec80b 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -22,8 +22,8 @@ pub trait IteratorUtil { // FIXME: #5898: should be called map fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, Self>; - fn dropwhile<'r>(self, predicate: &'r fn(&A) -> bool) -> DropWhileIterator<'r, A, Self>; - fn takewhile<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, Self>; + fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhileIterator<'r, A, Self>; + fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, Self>; fn skip(self, n: uint) -> SkipIterator; fn take(self, n: uint) -> TakeIterator; fn enumerate(self) -> EnumerateIterator; @@ -53,12 +53,12 @@ impl> IteratorUtil for T { } #[inline(always)] - fn dropwhile<'r>(self, predicate: &'r fn(&A) -> bool) -> DropWhileIterator<'r, A, T> { - DropWhileIterator{iter: self, flag: false, predicate: predicate} + fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhileIterator<'r, A, T> { + SkipWhileIterator{iter: self, flag: false, predicate: predicate} } #[inline(always)] - fn takewhile<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, T> { + fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, T> { TakeWhileIterator{iter: self, flag: false, predicate: predicate} } @@ -154,13 +154,13 @@ impl> Iterator<(uint, A)> for EnumerateIterator { } } -pub struct DropWhileIterator<'self, A, T> { +pub struct SkipWhileIterator<'self, A, T> { priv iter: T, priv flag: bool, priv predicate: &'self fn(&A) -> bool } -impl<'self, A, T: Iterator> Iterator for DropWhileIterator<'self, A, T> { +impl<'self, A, T: Iterator> Iterator for SkipWhileIterator<'self, A, T> { #[inline] fn next(&mut self) -> Option { let mut next = self.iter.next(); From ae1c9ebf3c3a0a7e176314f742f533a788ea0dd2 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 19 Apr 2013 07:30:22 -0400 Subject: [PATCH 3/7] move iterator adaptor tests to iterator module --- src/libcore/iterator.rs | 67 +++++++++++++++++++++++++++++++++++++++++ src/libcore/vec.rs | 66 ---------------------------------------- 2 files changed, 67 insertions(+), 66 deletions(-) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 1887e0cec80b..5e0b8df8c339 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -260,3 +260,70 @@ impl> Iterator for TakeIterator { } } } + +#[cfg(test)] +mod tests { + use super::*; + use prelude::*; + + #[test] + fn test_iterator_enumerate() { + let xs = [0u, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + for it.advance |(i, &x): (uint, &uint)| { + assert_eq!(i, x); + } + } + + #[test] + fn test_iterator_take_while() { + let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [0u, 1, 2, 3, 5, 13]; + let mut it = xs.iter().take_while(|&x| *x < 15u); + let mut i = 0; + for it.advance |&x: &uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } + + #[test] + fn test_iterator_skip_while() { + let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [15, 16, 17, 19]; + let mut it = xs.iter().skip_while(|&x| *x < 15u); + let mut i = 0; + for it.advance |&x: &uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } + + #[test] + fn test_iterator_skip() { + let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let ys = [13, 15, 16, 17, 19, 20, 30]; + let mut it = xs.iter().skip(5); + let mut i = 0; + for it.advance |&x: &uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } + + #[test] + fn test_iterator_take() { + let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [0u, 1, 2, 3, 5]; + let mut it = xs.iter().take(5); + let mut i = 0; + for it.advance |&x: &uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } +} diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 9ebc72c6f409..139fcedad277 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -4474,70 +4474,4 @@ mod tests { i += 1; } } - - #[test] - fn test_iterator_enumerate() { - use iterator::*; - let xs = [0u, 1, 2, 3, 4, 5]; - let mut it = xs.iter().enumerate(); - for it.advance |(i, &x): (uint, &uint)| { - assert_eq!(i, x); - } - } - - #[test] - fn test_iterator_takewhile() { - use iterator::*; - let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [0u, 1, 2, 3, 5, 13]; - let mut it = xs.iter().takewhile(|&x| *x < 15u); - let mut i = 0; - for it.advance |&x: &uint| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - fn test_iterator_dropwhile() { - use iterator::*; - let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [15, 16, 17, 19]; - let mut it = xs.iter().dropwhile(|&x| *x < 15u); - let mut i = 0; - for it.advance |&x: &uint| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - fn test_iterator_skip() { - use iterator::*; - let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - let ys = [13, 15, 16, 17, 19, 20, 30]; - let mut it = xs.iter().skip(5); - let mut i = 0; - for it.advance |&x: &uint| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - fn test_iterator_take() { - use iterator::*; - let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [0u, 1, 2, 3, 5]; - let mut it = xs.iter().take(5); - let mut i = 0; - for it.advance |&x: &uint| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } } From d7a2ae6c42f1d9755178485fd93f234c2df8a8fe Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 19 Apr 2013 09:18:22 -0400 Subject: [PATCH 4/7] re-organize the iterator module a bit --- src/libcore/iterator.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 5e0b8df8c339..50939ba7faf6 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -22,11 +22,11 @@ pub trait IteratorUtil { // FIXME: #5898: should be called map fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, Self>; + fn enumerate(self) -> EnumerateIterator; fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhileIterator<'r, A, Self>; fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, Self>; fn skip(self, n: uint) -> SkipIterator; fn take(self, n: uint) -> TakeIterator; - fn enumerate(self) -> EnumerateIterator; fn advance(&mut self, f: &fn(A) -> bool); } @@ -101,6 +101,21 @@ impl, U: Iterator> Iterator<(A, B)> for ZipIterator { + priv iter: T, + priv f: &'self fn(A) -> B +} + +impl<'self, A, B, T: Iterator> Iterator for MapIterator<'self, A, B, T> { + #[inline] + fn next(&mut self) -> Option { + match self.iter.next() { + Some(a) => Some((self.f)(a)), + _ => None + } + } +} + pub struct FilterIterator<'self, A, T> { priv iter: T, priv predicate: &'self fn(&A) -> bool @@ -120,21 +135,6 @@ impl<'self, A, T: Iterator> Iterator for FilterIterator<'self, A, T> { } } -pub struct MapIterator<'self, A, B, T> { - priv iter: T, - priv f: &'self fn(A) -> B -} - -impl<'self, A, B, T: Iterator> Iterator for MapIterator<'self, A, B, T> { - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - Some(a) => Some((self.f)(a)), - _ => None - } - } -} - pub struct EnumerateIterator { priv iter: T, priv count: uint From 90313b789c1d057dcc4aeed0374359f4927214c5 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sat, 20 Apr 2013 00:07:07 +1000 Subject: [PATCH 5/7] libcore: add an UnfoldrIterator like Haskell's `unfoldr` --- src/libcore/iterator.rs | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 50939ba7faf6..7ca40ae3a300 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -261,6 +261,28 @@ impl> Iterator for TakeIterator { } } +pub struct UnfoldrIterator<'self, A, St> { + priv f: &'self fn(&mut St) -> Option, + priv state: St +} + +pub impl<'self, A, St> UnfoldrIterator<'self, A, St> { + #[inline] + fn new(f: &'self fn(&mut St) -> Option, initial_state: St) -> UnfoldrIterator<'self, A, St> { + UnfoldrIterator { + f: f, + state: initial_state + } + } +} + +impl<'self, A, St> Iterator for UnfoldrIterator<'self, A, St> { + #[inline] + fn next(&mut self) -> Option { + (self.f)(&mut self.state) + } +} + #[cfg(test)] mod tests { use super::*; @@ -326,4 +348,25 @@ mod tests { } assert_eq!(i, ys.len()); } + + #[test] + fn test_unfoldr() { + fn count(st: &mut uint) -> Option { + if *st < 10 { + let ret = Some(*st); + *st += 1; + ret + } else { + None + } + } + + let mut it = UnfoldrIterator::new(count, 0); + let mut i = 0; + for it.advance |counted| { + assert_eq!(counted, i); + i += 1; + } + assert_eq!(i, 10); + } } From 1d81b7b286d2be46474022935c5ac111dafd5c4d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 19 Apr 2013 11:29:38 -0400 Subject: [PATCH 6/7] iterator: add a chain adaptor --- src/libcore/iterator.rs | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 7ca40ae3a300..e233eb7feed6 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -18,6 +18,7 @@ pub trait Iterator { } pub trait IteratorUtil { + fn chain(self, other: Self) -> ChainIterator; fn zip>(self, other: U) -> ZipIterator; // FIXME: #5898: should be called map fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; @@ -31,6 +32,11 @@ pub trait IteratorUtil { } impl> IteratorUtil for T { + #[inline(always)] + fn chain(self, other: T) -> ChainIterator { + ChainIterator{a: self, b: other, flag: false} + } + #[inline(always)] fn zip>(self, other: U) -> ZipIterator { ZipIterator{a: self, b: other} @@ -86,6 +92,28 @@ impl> IteratorUtil for T { } } +pub struct ChainIterator { + priv a: T, + priv b: T, + priv flag: bool +} + +impl> Iterator for ChainIterator { + #[inline] + fn next(&mut self) -> Option { + if self.flag { + self.b.next() + } else { + match self.a.next() { + Some(x) => return Some(x), + _ => () + } + self.flag = true; + self.b.next() + } + } +} + pub struct ZipIterator { priv a: T, priv b: U @@ -288,6 +316,20 @@ mod tests { use super::*; use prelude::*; + #[test] + fn test_iterator_chain() { + let xs = [0u, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + let mut it = xs.iter().chain(ys.iter()); + let mut i = 0; + for it.advance |&x: &uint| { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); + } + #[test] fn test_iterator_enumerate() { let xs = [0u, 1, 2, 3, 4, 5]; From a2e535028471b715b5a3aaf7cbeb3e6d77a07af6 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 19 Apr 2013 12:17:24 -0400 Subject: [PATCH 7/7] iterator: add a bit of documentation --- src/libcore/iterator.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index e233eb7feed6..4929b1b8dba3 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -8,7 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Composable iterator objects +/*! Composable external iterators + +The `Iterator` trait defines an interface for objects which implement iteration as a state machine. + +Algorithms like `zip` are provided as `Iterator` implementations which wrap other objects +implementing the `Iterator` trait. + +*/ use prelude::*; @@ -17,6 +24,10 @@ pub trait Iterator { fn next(&mut self) -> Option; } +/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also +/// implementations of the `Iterator` trait. +/// +/// In the future these will be default methods instead of a utility trait. pub trait IteratorUtil { fn chain(self, other: Self) -> ChainIterator; fn zip>(self, other: U) -> ZipIterator; @@ -31,6 +42,10 @@ pub trait IteratorUtil { fn advance(&mut self, f: &fn(A) -> bool); } +/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also +/// implementations of the `Iterator` trait. +/// +/// In the future these will be default methods instead of a utility trait. impl> IteratorUtil for T { #[inline(always)] fn chain(self, other: T) -> ChainIterator {