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:
commit
543691d0eb
@ -0,0 +1,7 @@
|
||||
# `iterator_step_by`
|
||||
|
||||
The tracking issue for this feature is: [#27741]
|
||||
|
||||
[#27741]: https://github.com/rust-lang/rust/issues/27741
|
||||
|
||||
------------------------
|
@ -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 @@ pub trait Iterator {
|
||||
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
|
||||
|
@ -313,7 +313,7 @@ pub use self::iterator::Iterator;
|
||||
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 @@ impl<I> Iterator for Cycle<I> where I: Clone + Iterator {
|
||||
#[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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
Loading…
Reference in New Issue
Block a user