diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index dc64a787ae9ae..ac2f72d5fa187 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -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)] diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 00def2a1eac49..6836fbb7c4de3 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -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(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(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")] diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 7c009114afefb..aacc29406b626 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -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 diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ebedfe1d743bb..cee345d52ca29 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -359,6 +359,12 @@ impl Iterator for Rev where I: DoubleEndedIterator { #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + fn fold(self, init: Acc, f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, f) + } + #[inline] fn find

(&mut self, predicate: P) -> Option where P: FnMut(&Self::Item) -> bool @@ -379,6 +385,12 @@ impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option<::Item> { self.iter.next() } + fn rfold(self, init: Acc, f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, f) + } + fn rfind

(&mut self, predicate: P) -> Option where P: FnMut(&Self::Item) -> bool { @@ -449,6 +461,12 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned fn next_back(&mut self) -> Option { self.it.next_back().cloned() } + + fn rfold(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 DoubleEndedIterator for Chain where ChainState::Back => self.b.next_back(), } } + + fn rfold(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 DoubleEndedIterator for Map where fn next_back(&mut self) -> Option { self.iter.next_back().map(&mut self.f) } + + fn rfold(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")] diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 2af129a67bddf..4386b0a64565c 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -398,6 +398,70 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; + /// 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(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