Skip to content

Commit ecacc75

Browse files
committed
Add advance_by and advance_back_by
1 parent a2c82df commit ecacc75

File tree

5 files changed

+161
-16
lines changed

5 files changed

+161
-16
lines changed

library/core/src/iter/adapters/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ where
124124
self.iter.size_hint()
125125
}
126126

127+
#[inline]
128+
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
129+
self.iter.advance_back_by(n)
130+
}
131+
127132
#[inline]
128133
fn nth(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
129134
self.iter.nth_back(n)
@@ -164,6 +169,11 @@ where
164169
self.iter.next()
165170
}
166171

172+
#[inline]
173+
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
174+
self.iter.advance_by(n)
175+
}
176+
167177
#[inline]
168178
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
169179
self.iter.nth(n)

library/core/src/iter/traits/double_ended.rs

+46-8
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,46 @@ pub trait DoubleEndedIterator: Iterator {
9191
#[stable(feature = "rust1", since = "1.0.0")]
9292
fn next_back(&mut self) -> Option<Self::Item>;
9393

94+
/// Advances the iterator from the back by `n` elements.
95+
///
96+
/// `advance_back_by` is the reverse version of [`advance_by`]. This method will
97+
/// eagerly skip `n` elements starting from the back by calling [`next_back`] up
98+
/// to `n` times until [`None`] is encountered.
99+
///
100+
/// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by
101+
/// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number of
102+
/// elements the iterator is advanced by before running out of elements (i.e. the length
103+
/// of the iterator). Note that `k` is always less than `n`.
104+
///
105+
/// Calling `advance_back_by(0)` does not consume any elements and always returns [`Ok(())`].
106+
///
107+
/// [`advance_by`]: Iterator::advance_by
108+
/// [`next_back`]: DoubleEndedIterator::next_back
109+
///
110+
/// # Examples
111+
///
112+
/// Basic usage:
113+
///
114+
/// ```
115+
/// #![feature(iter_advance_by)]
116+
///
117+
/// let a = [3, 4, 5, 6];
118+
/// let mut iter = a.iter();
119+
///
120+
/// assert_eq!(iter.advance_back_by(2), Ok(()));
121+
/// assert_eq!(iter.next_back(), Some(&4));
122+
/// assert_eq!(iter.advance_back_by(0), Ok(()));
123+
/// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped
124+
/// ```
125+
#[inline]
126+
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "none")]
127+
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
128+
for i in 0..n {
129+
self.next_back().ok_or(i)?;
130+
}
131+
Ok(())
132+
}
133+
94134
/// Returns the `n`th element from the end of the iterator.
95135
///
96136
/// This is essentially the reversed version of [`nth`]. Although like most indexing
@@ -135,14 +175,9 @@ pub trait DoubleEndedIterator: Iterator {
135175
/// ```
136176
#[inline]
137177
#[stable(feature = "iter_nth_back", since = "1.37.0")]
138-
fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
139-
for x in self.rev() {
140-
if n == 0 {
141-
return Some(x);
142-
}
143-
n -= 1;
144-
}
145-
None
178+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
179+
self.advance_back_by(n).ok()?;
180+
self.next_back()
146181
}
147182

148183
/// This is the reverse version of [`try_fold()`]: it takes elements
@@ -323,6 +358,9 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
323358
fn next_back(&mut self) -> Option<I::Item> {
324359
(**self).next_back()
325360
}
361+
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
362+
(**self).advance_back_by(n)
363+
}
326364
fn nth_back(&mut self, n: usize) -> Option<I::Item> {
327365
(**self).nth_back(n)
328366
}

library/core/src/iter/traits/iterator.rs

+44-8
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,44 @@ pub trait Iterator {
284284
self.fold(None, some)
285285
}
286286

287+
/// Advances the iterator by `n` elements.
288+
///
289+
/// This method will eagerly skip `n` elements by calling [`next`] up to `n`
290+
/// times until [`None`] is encountered.
291+
///
292+
/// `advance_by(n)` will return [`Ok(())`] if the iterator successfully advances by
293+
/// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number
294+
/// of elements the iterator is advanced by before running out of elements (i.e. the
295+
/// length of the iterator). Note that `k` is always less than `n`.
296+
///
297+
/// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`].
298+
///
299+
/// [`next`]: Iterator::next
300+
///
301+
/// # Examples
302+
///
303+
/// Basic usage:
304+
///
305+
/// ```
306+
/// #![feature(iter_advance_by)]
307+
///
308+
/// let a = [1, 2, 3, 4];
309+
/// let mut iter = a.iter();
310+
///
311+
/// assert_eq!(iter.advance_by(2), Ok(()));
312+
/// assert_eq!(iter.next(), Some(&3));
313+
/// assert_eq!(iter.advance_by(0), Ok(()));
314+
/// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped
315+
/// ```
316+
#[inline]
317+
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "none")]
318+
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
319+
for i in 0..n {
320+
self.next().ok_or(i)?;
321+
}
322+
Ok(())
323+
}
324+
287325
/// Returns the `n`th element of the iterator.
288326
///
289327
/// Like most indexing operations, the count starts from zero, so `nth(0)`
@@ -325,14 +363,9 @@ pub trait Iterator {
325363
/// ```
326364
#[inline]
327365
#[stable(feature = "rust1", since = "1.0.0")]
328-
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
329-
while let Some(x) = self.next() {
330-
if n == 0 {
331-
return Some(x);
332-
}
333-
n -= 1;
334-
}
335-
None
366+
fn nth(&mut self, n: usize) -> Option<Self::Item> {
367+
self.advance_by(n).ok()?;
368+
self.next()
336369
}
337370

338371
/// Creates an iterator starting at the same point, but stepping by
@@ -3262,6 +3295,9 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
32623295
fn size_hint(&self) -> (usize, Option<usize>) {
32633296
(**self).size_hint()
32643297
}
3298+
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
3299+
(**self).advance_by(n)
3300+
}
32653301
fn nth(&mut self, n: usize) -> Option<Self::Item> {
32663302
(**self).nth(n)
32673303
}

library/core/tests/iter.rs

+60
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,66 @@ fn test_iterator_rev_nth() {
14731473
assert_eq!(v.iter().rev().nth(v.len()), None);
14741474
}
14751475

1476+
#[test]
1477+
fn test_iterator_advance_by() {
1478+
let v: &[_] = &[0, 1, 2, 3, 4];
1479+
1480+
for i in 0..v.len() {
1481+
let mut iter = v.iter();
1482+
assert_eq!(iter.advance_by(i), Ok(()));
1483+
assert_eq!(iter.next().unwrap(), &v[i]);
1484+
assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
1485+
}
1486+
1487+
assert_eq!(v.iter().advance_by(v.len()), Ok(()));
1488+
assert_eq!(v.iter().advance_by(100), Err(v.len()));
1489+
}
1490+
1491+
#[test]
1492+
fn test_iterator_advance_back_by() {
1493+
let v: &[_] = &[0, 1, 2, 3, 4];
1494+
1495+
for i in 0..v.len() {
1496+
let mut iter = v.iter();
1497+
assert_eq!(iter.advance_back_by(i), Ok(()));
1498+
assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
1499+
assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
1500+
}
1501+
1502+
assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
1503+
assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
1504+
}
1505+
1506+
#[test]
1507+
fn test_iterator_rev_advance_by() {
1508+
let v: &[_] = &[0, 1, 2, 3, 4];
1509+
1510+
for i in 0..v.len() {
1511+
let mut iter = v.iter().rev();
1512+
assert_eq!(iter.advance_by(i), Ok(()));
1513+
assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
1514+
assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
1515+
}
1516+
1517+
assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
1518+
assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
1519+
}
1520+
1521+
#[test]
1522+
fn test_iterator_rev_advance_back_by() {
1523+
let v: &[_] = &[0, 1, 2, 3, 4];
1524+
1525+
for i in 0..v.len() {
1526+
let mut iter = v.iter().rev();
1527+
assert_eq!(iter.advance_back_by(i), Ok(()));
1528+
assert_eq!(iter.next_back().unwrap(), &v[i]);
1529+
assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
1530+
}
1531+
1532+
assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
1533+
assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
1534+
}
1535+
14761536
#[test]
14771537
fn test_iterator_last() {
14781538
let v: &[_] = &[0, 1, 2, 3, 4];

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#![feature(slice_partition_dedup)]
3939
#![feature(int_error_matching)]
4040
#![feature(array_value_iter)]
41+
#![feature(iter_advance_by)]
4142
#![feature(iter_partition_in_place)]
4243
#![feature(iter_is_partitioned)]
4344
#![feature(iter_order_by)]

0 commit comments

Comments
 (0)