Skip to content

Commit 56ebfb1

Browse files
committed
Implement DoubleEndedIterator for iter::{StepBy, Peekable, Take}
1 parent 538e17a commit 56ebfb1

File tree

2 files changed

+296
-13
lines changed

2 files changed

+296
-13
lines changed

src/libcore/iter/adapters/mod.rs

+117
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,39 @@ impl<I> Iterator for StepBy<I> where I: Iterator {
485485
}
486486
}
487487

488+
impl<I> StepBy<I> where I: ExactSizeIterator {
489+
// The zero-based index starting from the end of the iterator of the
490+
// last element. Used in the `DoubleEndedIterator` implementation.
491+
fn next_back_index(&self) -> usize {
492+
let rem = self.iter.len() % (self.step + 1);
493+
if self.first_take {
494+
if rem == 0 { self.step } else { rem - 1 }
495+
} else {
496+
rem
497+
}
498+
}
499+
}
500+
501+
#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
502+
impl<I> DoubleEndedIterator for StepBy<I> where I: DoubleEndedIterator + ExactSizeIterator {
503+
#[inline]
504+
fn next_back(&mut self) -> Option<Self::Item> {
505+
self.iter.nth_back(self.next_back_index())
506+
}
507+
508+
#[inline]
509+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
510+
// `self.iter.nth_back(usize::MAX)` does the right thing here when `n`
511+
// is out of bounds because the length of `self.iter` does not exceed
512+
// `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
513+
// zero-indexed
514+
let n = n
515+
.saturating_mul(self.step + 1)
516+
.saturating_add(self.next_back_index());
517+
self.iter.nth_back(n)
518+
}
519+
}
520+
488521
// StepBy can only make the iterator shorter, so the len will still fit.
489522
#[stable(feature = "iterator_step_by", since = "1.28.0")]
490523
impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
@@ -1158,6 +1191,45 @@ impl<I: Iterator> Iterator for Peekable<I> {
11581191
}
11591192
}
11601193

1194+
#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
1195+
impl<I> DoubleEndedIterator for Peekable<I> where I: DoubleEndedIterator {
1196+
#[inline]
1197+
fn next_back(&mut self) -> Option<Self::Item> {
1198+
self.iter.next_back().or_else(|| self.peeked.take().and_then(|x| x))
1199+
}
1200+
1201+
#[inline]
1202+
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
1203+
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
1204+
{
1205+
match self.peeked.take() {
1206+
Some(None) => return Try::from_ok(init),
1207+
Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
1208+
Ok(acc) => f(acc, v),
1209+
Err(e) => {
1210+
self.peeked = Some(Some(v));
1211+
Try::from_error(e)
1212+
}
1213+
},
1214+
None => self.iter.try_rfold(init, f),
1215+
}
1216+
}
1217+
1218+
#[inline]
1219+
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1220+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1221+
{
1222+
match self.peeked {
1223+
Some(None) => return init,
1224+
Some(Some(v)) => {
1225+
let acc = self.iter.rfold(init, &mut fold);
1226+
fold(acc, v)
1227+
}
1228+
None => self.iter.rfold(init, fold),
1229+
}
1230+
}
1231+
}
1232+
11611233
#[stable(feature = "rust1", since = "1.0.0")]
11621234
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}
11631235

@@ -1613,6 +1685,51 @@ impl<I> Iterator for Take<I> where I: Iterator{
16131685
}
16141686
}
16151687

1688+
#[stable(feature = "double_ended_take_iterator", since = "1.38.0")]
1689+
impl<I> DoubleEndedIterator for Take<I> where I: DoubleEndedIterator + ExactSizeIterator {
1690+
#[inline]
1691+
fn next_back(&mut self) -> Option<Self::Item> {
1692+
if self.n == 0 {
1693+
None
1694+
} else {
1695+
let n = self.n;
1696+
self.n -= 1;
1697+
self.iter.nth_back(self.iter.len().saturating_sub(n))
1698+
}
1699+
}
1700+
1701+
#[inline]
1702+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1703+
let len = self.iter.len();
1704+
if self.n > n {
1705+
let m = len.saturating_sub(self.n) + n;
1706+
self.n -= n + 1;
1707+
self.iter.nth_back(m)
1708+
} else {
1709+
if len > 0 {
1710+
self.iter.nth_back(len - 1);
1711+
}
1712+
None
1713+
}
1714+
}
1715+
1716+
#[inline]
1717+
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
1718+
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok = Acc>
1719+
{
1720+
if self.n == 0 {
1721+
Try::from_ok(init)
1722+
} else {
1723+
let len = self.iter.len();
1724+
if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
1725+
Try::from_ok(init)
1726+
} else {
1727+
self.iter.try_rfold(init, fold)
1728+
}
1729+
}
1730+
}
1731+
}
1732+
16161733
#[stable(feature = "rust1", since = "1.0.0")]
16171734
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
16181735

0 commit comments

Comments
 (0)