Skip to content

Make Take and Skip iterators DoubleEnded when constructed from ExactSize #12785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 67 additions & 4 deletions src/libstd/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ pub trait Iterator<A> {
/// ```
#[inline]
fn skip(self, n: uint) -> Skip<Self> {
Skip{iter: self, n: n}
Skip{iter: self, n: n, consumed_back: 0}
}

/// Creates an iterator which yields the first `n` elements of this
Expand All @@ -303,7 +303,7 @@ pub trait Iterator<A> {
/// ```
#[inline]
fn take(self, n: uint) -> Take<Self> {
Take{iter: self, n: n}
Take{iter: self, n: n, consumed_back: 0}
}

/// Creates a new iterator which behaves in a similar fashion to foldl.
Expand Down Expand Up @@ -762,6 +762,8 @@ impl<'a, A, T: ExactSize<A>> ExactSize<A> for Inspect<'a, A, T> {}
impl<A, T: ExactSize<A>> ExactSize<A> for Rev<T> {}
impl<'a, A, B, T: ExactSize<A>> ExactSize<B> for Map<'a, A, B, T> {}
impl<A, B, T: ExactSize<A>, U: ExactSize<B>> ExactSize<(A, B)> for Zip<T, U> {}
impl<A, T: ExactSize<A>> ExactSize<A> for Skip<T> {}
impl<A, T: ExactSize<A>> ExactSize<A> for Take<T> {}

/// An double-ended iterator with the direction inverted
#[deriving(Clone)]
Expand Down Expand Up @@ -1564,7 +1566,8 @@ impl<'a, A, T: Iterator<A>> Iterator<A> for TakeWhile<'a, A, T> {
#[deriving(Clone)]
pub struct Skip<T> {
priv iter: T,
priv n: uint
priv n: uint,
priv consumed_back: uint
}

impl<A, T: Iterator<A>> Iterator<A> for Skip<T> {
Expand Down Expand Up @@ -1608,6 +1611,21 @@ impl<A, T: Iterator<A>> Iterator<A> for Skip<T> {
}
}

impl<A, T: ExactSize<A>> DoubleEndedIterator<A> for Skip<T> {
#[inline]
fn next_back(&mut self) -> Option<A> {
let (lower, upper) = self.iter.size_hint();
assert_eq!(upper, Some(lower));

if lower >= self.n + self.consumed_back {
self.consumed_back += 1;
self.iter.next_back()
} else {
None
}
}
}

impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {
#[inline]
fn indexable(&self) -> uint {
Expand All @@ -1628,7 +1646,8 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {
#[deriving(Clone)]
pub struct Take<T> {
priv iter: T,
priv n: uint
priv n: uint,
priv consumed_back: uint
}

impl<A, T: Iterator<A>> Iterator<A> for Take<T> {
Expand Down Expand Up @@ -1657,6 +1676,20 @@ impl<A, T: Iterator<A>> Iterator<A> for Take<T> {
}
}

impl<A, T: ExactSize<A>> DoubleEndedIterator<A> for Take<T> {
#[inline]
fn next_back(&mut self) -> Option<A> {
let (lower, upper) = self.iter.size_hint();
assert_eq!(upper, Some(lower));

while self.consumed_back + self.n < lower {
self.consumed_back += 1;
self.iter.next_back();
}
self.iter.next_back()
}
}

impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Take<T> {
#[inline]
fn indexable(&self) -> uint {
Expand Down Expand Up @@ -2792,6 +2825,36 @@ mod tests {
assert_eq!(it.next_back(), None)
}

#[test]
fn test_double_ended_skip() {
let xs = [1, 2, 3, 4, 5, 6];
let mut it = xs.iter().skip(3);
assert_eq!(it.next_back().unwrap(), &6);
assert_eq!(it.next_back().unwrap(), &5);
assert_eq!(it.next_back().unwrap(), &4);
assert_eq!(it.next_back(), None);

let mut it = xs.iter().skip(7);
assert_eq!(it.next_back(), None);
}

#[test]
fn test_double_ended_take() {
let xs = [1, 2, 3, 4];
let mut it = xs.iter().take(3);
assert_eq!(it.next_back().unwrap(), &3);
assert_eq!(it.next_back().unwrap(), &2);
assert_eq!(it.next_back().unwrap(), &1);
assert_eq!(it.next_back(), None);

let mut it = xs.iter().take(7);
assert_eq!(it.next_back().unwrap(), &4);
assert_eq!(it.next_back().unwrap(), &3);
assert_eq!(it.next_back().unwrap(), &2);
assert_eq!(it.next_back().unwrap(), &1);
assert_eq!(it.next_back(), None);
}

#[test]
fn test_rposition() {
fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' }
Expand Down