Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
16 changes: 16 additions & 0 deletions src/liballoc/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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")]
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/iter/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,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
Expand Down
45 changes: 45 additions & 0 deletions src/libcore/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
{
Expand Down Expand Up @@ -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")]
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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")]
Expand Down
64 changes: 64 additions & 0 deletions src/libcore/iter/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,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 = "0")]
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
Expand Down