Auto merge of #44682 - bluss:iter-rfold, r=dtolnay
Add iterator method .rfold(init, function); the reverse of fold rfold is the reverse version of fold. Fold allows iterators to implement a different (non-resumable) internal iteration when it is more efficient than the external iteration implemented through the next method. (Common examples are VecDeque and .chain()). Introduce rfold() so that the same customization is available for reverse iteration. This is achieved by both adding the method, and by having the Rev\<I> adaptor connect Rev::rfold → I::fold and Rev::fold → I::rfold. On the surface, rfold(..) is just .rev().fold(..), but the special case implementations allow a data structure specific fold to be used through for example .iter().rev(); we thus have gains even for users never calling exactly rfold themselves.
This commit is contained in:
commit
17600c1ea7
@ -98,6 +98,7 @@
|
||||
#![feature(generic_param_attrs)]
|
||||
#![feature(i128_type)]
|
||||
#![feature(inclusive_range)]
|
||||
#![feature(iter_rfold)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(needs_allocator)]
|
||||
#![feature(nonzero)]
|
||||
|
@ -1973,6 +1973,14 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
|
||||
self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len());
|
||||
unsafe { Some(self.ring.get_unchecked(self.head)) }
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc
|
||||
{
|
||||
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
|
||||
accum = back.iter().rfold(accum, &mut f);
|
||||
front.iter().rfold(accum, &mut f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -2058,6 +2066,14 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
|
||||
Some(&mut *(elem as *mut _))
|
||||
}
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc
|
||||
{
|
||||
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
|
||||
accum = back.iter_mut().rfold(accum, &mut f);
|
||||
front.iter_mut().rfold(accum, &mut f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -1337,7 +1337,7 @@ pub trait Iterator {
|
||||
(left, right)
|
||||
}
|
||||
|
||||
/// An iterator adaptor that applies a function, producing a single, final value.
|
||||
/// An iterator method that applies a function, producing a single, final value.
|
||||
///
|
||||
/// `fold()` takes two arguments: an initial value, and a closure with two
|
||||
/// arguments: an 'accumulator', and an element. The closure returns the value that
|
||||
|
@ -359,6 +359,12 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator {
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
|
||||
fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.rfold(init, f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where P: FnMut(&Self::Item) -> bool
|
||||
@ -379,6 +385,12 @@ impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.fold(init, f)
|
||||
}
|
||||
|
||||
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where P: FnMut(&Self::Item) -> bool
|
||||
{
|
||||
@ -449,6 +461,12 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
self.it.next_back().cloned()
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.it.rfold(init, move |acc, elt| f(acc, elt.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||
@ -761,6 +779,26 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
|
||||
ChainState::Back => self.b.next_back(),
|
||||
}
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut accum = init;
|
||||
match self.state {
|
||||
ChainState::Both | ChainState::Back => {
|
||||
accum = self.b.rfold(accum, &mut f);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
match self.state {
|
||||
ChainState::Both | ChainState::Front => {
|
||||
accum = self.a.rfold(accum, &mut f);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
accum
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Note: *both* must be fused to handle double-ended iterators.
|
||||
@ -1094,6 +1132,13 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F> where
|
||||
fn next_back(&mut self) -> Option<B> {
|
||||
self.iter.next_back().map(&mut self.f)
|
||||
}
|
||||
|
||||
fn rfold<Acc, G>(self, init: Acc, mut g: G) -> Acc
|
||||
where G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, elt| g(acc, f(elt)))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -415,6 +415,70 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn next_back(&mut self) -> Option<Self::Item>;
|
||||
|
||||
/// An iterator method that reduces the iterator's elements to a single,
|
||||
/// final value, starting from the back.
|
||||
///
|
||||
/// This is the reverse version of [`fold()`]: it takes elements starting from
|
||||
/// the back of the iterator.
|
||||
///
|
||||
/// `rfold()` takes two arguments: an initial value, and a closure with two
|
||||
/// arguments: an 'accumulator', and an element. The closure returns the value that
|
||||
/// the accumulator should have for the next iteration.
|
||||
///
|
||||
/// The initial value is the value the accumulator will have on the first
|
||||
/// call.
|
||||
///
|
||||
/// After applying this closure to every element of the iterator, `rfold()`
|
||||
/// returns the accumulator.
|
||||
///
|
||||
/// This operation is sometimes called 'reduce' or 'inject'.
|
||||
///
|
||||
/// Folding is useful whenever you have a collection of something, and want
|
||||
/// to produce a single value from it.
|
||||
///
|
||||
/// [`fold()`]: trait.Iterator.html#method.fold
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_rfold)]
|
||||
/// let a = [1, 2, 3];
|
||||
///
|
||||
/// // the sum of all of the elements of a
|
||||
/// let sum = a.iter()
|
||||
/// .rfold(0, |acc, &x| acc + x);
|
||||
///
|
||||
/// assert_eq!(sum, 6);
|
||||
/// ```
|
||||
///
|
||||
/// This example builds a string, starting with an initial value
|
||||
/// and continuing with each element from the back until the front:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_rfold)]
|
||||
/// let numbers = [1, 2, 3, 4, 5];
|
||||
///
|
||||
/// let zero = "0".to_string();
|
||||
///
|
||||
/// let result = numbers.iter().rfold(zero, |acc, &x| {
|
||||
/// format!("({} + {})", x, acc)
|
||||
/// });
|
||||
///
|
||||
/// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_rfold", issue = "44705")]
|
||||
fn rfold<B, F>(mut self, mut accum: B, mut f: F) -> B where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
while let Some(x) = self.next_back() {
|
||||
accum = f(accum, x);
|
||||
}
|
||||
accum
|
||||
}
|
||||
|
||||
/// Searches for an element of an iterator from the right that satisfies a predicate.
|
||||
///
|
||||
/// `rfind()` takes a closure that returns `true` or `false`. It applies
|
||||
|
Loading…
Reference in New Issue
Block a user