Auto merge of #41439 - ivandardi:master, r=BurntSushi

Stabilize step_by by adding it to Iterator (issue #27741)

Inspired by itertools' `take()` method. See issue #27741
This commit is contained in:
bors 2017-05-19 17:42:28 +00:00
commit 543691d0eb
5 changed files with 106 additions and 3 deletions

View File

@ -0,0 +1,7 @@
# `iterator_step_by`
The tracking issue for this feature is: [#27741]
[#27741]: https://github.com/rust-lang/rust/issues/27741
------------------------

View File

@ -11,7 +11,7 @@
use cmp::Ordering;
use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile, Rev};
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
use super::{Zip, Sum, Product};
use super::{ChainState, FromIterator, ZipImpl};
@ -258,6 +258,39 @@ fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
None
}
/// Creates an iterator starting at the same point, but stepping by
/// the given amount at each iteration.
///
/// Note that it will always return the first element of the range,
/// regardless of the step given.
///
/// # Panics
///
/// The method will panic if the given step is `0`.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(iterator_step_by)]
/// let a = [0, 1, 2, 3, 4, 5];
/// let mut iter = a.into_iter().step_by(2);
///
/// assert_eq!(iter.next(), Some(&0));
/// assert_eq!(iter.next(), Some(&2));
/// assert_eq!(iter.next(), Some(&4));
/// assert_eq!(iter.next(), None);
/// ```
#[inline]
#[unstable(feature = "iterator_step_by",
reason = "unstable replacement of Range::step_by",
issue = "27741")]
fn step_by(self, step: usize) -> StepBy<Self> where Self: Sized {
assert!(step != 0);
StepBy{iter: self, step: step - 1, first_take: true}
}
/// Takes two iterators and creates a new iterator over both in sequence.
///
/// `chain()` will return a new iterator which will first iterate over

View File

@ -313,7 +313,7 @@
pub use self::range::Step;
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
pub use self::range::StepBy;
pub use self::range::StepBy as DeprecatedStepBy;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::sources::{Repeat, repeat};
@ -520,6 +520,41 @@ fn size_hint(&self) -> (usize, Option<usize>) {
#[unstable(feature = "fused", issue = "35602")]
impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
/// An iterator that steps by n elements every iteration.
///
/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
/// its documentation for more.
///
/// [`step_by`]: trait.Iterator.html#method.step_by
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[unstable(feature = "iterator_step_by",
reason = "unstable replacement of Range::step_by",
issue = "27741")]
#[derive(Clone, Debug)]
pub struct StepBy<I> {
iter: I,
step: usize,
first_take: bool,
}
#[unstable(feature = "iterator_step_by",
reason = "unstable replacement of Range::step_by",
issue = "27741")]
impl<I> Iterator for StepBy<I> where I: Iterator {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.first_take {
self.first_take = false;
self.iter.next()
} else {
self.iter.nth(self.step)
}
}
}
/// An iterator that strings two iterators together.
///
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its

View File

@ -144,6 +144,33 @@ fn test_iterator_chain_find() {
assert_eq!(iter.next(), None);
}
#[test]
fn test_iterator_step_by() {
// Identity
// Replace with (0..).step_by(1) after Range::step_by gets removed
let mut it = Iterator::step_by((0..), 1).take(3);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(1));
assert_eq!(it.next(), Some(2));
assert_eq!(it.next(), None);
// Replace with (0..).step_by(3) after Range::step_by gets removed
let mut it = Iterator::step_by((0..), 3).take(4);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(3));
assert_eq!(it.next(), Some(6));
assert_eq!(it.next(), Some(9));
assert_eq!(it.next(), None);
}
#[test]
#[should_panic]
fn test_iterator_step_by_zero() {
// Replace with (0..).step_by(0) after Range::step_by gets removed
let mut it = Iterator::step_by((0..), 0);
it.next();
}
#[test]
fn test_filter_map() {
let it = (0..).step_by(1).take(10)
@ -1119,4 +1146,4 @@ fn test_step_replace_no_between() {
let y = x.replace_one();
assert_eq!(x, 1);
assert_eq!(y, 5);
}
}

View File

@ -20,6 +20,7 @@
#![feature(fixed_size_array)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(iterator_step_by)]
#![feature(i128_type)]
#![feature(iter_rfind)]
#![feature(libc)]