Skip to content
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

Add DoubleEndedIterator::nth_back #56802

Merged
merged 1 commit into from
Dec 23, 2018
Merged
Show file tree
Hide file tree
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
6 changes: 6 additions & 0 deletions src/libcore/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator {
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }

#[inline]
fn nth(&mut self, n: usize) -> Option<<I as Iterator>::Item> { self.iter.nth_back(n) }

fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R where
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
{
Expand Down Expand Up @@ -461,6 +464,9 @@ impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
#[inline]
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }

#[inline]
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> { self.iter.nth(n) }

fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R where
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
{
Expand Down
79 changes: 73 additions & 6 deletions src/libcore/iter/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,62 @@ pub trait DoubleEndedIterator: Iterator {
#[stable(feature = "rust1", since = "1.0.0")]
fn next_back(&mut self) -> Option<Self::Item>;

/// Returns the `n`th element from the end of the iterator.
///
/// This is essentially the reversed version of [`nth`]. Although like most indexing
/// operations, the count starts from zero, so `nth_back(0)` returns the first value fro
/// the end, `nth_back(1)` the second, and so on.
///
/// Note that all elements between the end and the returned element will be
/// consumed, including the returned element. This also means that calling
/// `nth_back(0)` multiple times on the same iterator will return different
/// elements.
///
/// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
/// iterator.
///
/// [`None`]: ../../std/option/enum.Option.html#variant.None
/// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
/// assert_eq!(a.iter().nth_back(2), Some(&1));
/// ```
///
/// Calling `nth_back()` multiple times doesn't rewind the iterator:
///
/// ```
/// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
///
/// let mut iter = a.iter();
///
/// assert_eq!(iter.nth_back(1), Some(&2));
/// assert_eq!(iter.nth_back(1), None);
/// ```
///
/// Returning `None` if there are less than `n + 1` elements:
///
/// ```
/// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
/// assert_eq!(a.iter().nth_back(10), None);
/// ```
#[inline]
#[unstable(feature = "iter_nth_back", issue = "56995")]
fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
for x in self.rev() {
if n == 0 { return Some(x) }
n -= 1;
}
None
}

/// This is the reverse version of [`try_fold()`]: it takes elements
/// starting from the back of the iterator.
///
Expand Down Expand Up @@ -461,8 +517,11 @@ pub trait DoubleEndedIterator: Iterator {
/// ```
#[inline]
#[stable(feature = "iterator_try_fold", since = "1.27.0")]
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Ok=B>
{
let mut accum = init;
while let Some(x) = self.next_back() {
Expand Down Expand Up @@ -524,8 +583,10 @@ pub trait DoubleEndedIterator: Iterator {
/// ```
#[inline]
#[stable(feature = "iter_rfold", since = "1.27.0")]
fn rfold<B, F>(mut self, accum: B, mut f: F) -> B where
Self: Sized, F: FnMut(B, Self::Item) -> B,
fn rfold<B, F>(mut self, accum: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
self.try_rfold(accum, move |acc, x| Ok::<B, !>(f(acc, x))).unwrap()
}
Expand Down Expand Up @@ -574,7 +635,8 @@ pub trait DoubleEndedIterator: Iterator {
/// ```
#[inline]
#[stable(feature = "iter_rfind", since = "1.27.0")]
fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool
{
Expand All @@ -587,7 +649,12 @@ pub trait DoubleEndedIterator: Iterator {

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
fn next_back(&mut self) -> Option<I::Item> {
(**self).next_back()
}
fn nth_back(&mut self, n: usize) -> Option<I::Item> {
(**self).nth_back(n)
}
}

/// An iterator that knows its exact length.
Expand Down
27 changes: 27 additions & 0 deletions src/libcore/tests/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,33 @@ fn test_iterator_nth() {
assert_eq!(v.iter().nth(v.len()), None);
}

#[test]
fn test_iterator_nth_back() {
let v: &[_] = &[0, 1, 2, 3, 4];
for i in 0..v.len() {
assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]);
}
assert_eq!(v.iter().nth_back(v.len()), None);
}

#[test]
fn test_iterator_rev_nth_back() {
let v: &[_] = &[0, 1, 2, 3, 4];
for i in 0..v.len() {
assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]);
}
assert_eq!(v.iter().rev().nth_back(v.len()), None);
}

#[test]
fn test_iterator_rev_nth() {
let v: &[_] = &[0, 1, 2, 3, 4];
for i in 0..v.len() {
assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]);
}
assert_eq!(v.iter().rev().nth(v.len()), None);
}

#[test]
fn test_iterator_last() {
let v: &[_] = &[0, 1, 2, 3, 4];
Expand Down
1 change: 1 addition & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
#![feature(iter_nth_back)]
#![feature(iter_unfold)]
#![feature(pattern)]
#![feature(range_is_empty)]
Expand Down