Skip to content

Commit 3a25b65

Browse files
authored
Auto merge of #37315 - bluss:fold-more, r=alexcrichton
Implement Iterator::fold for .chain(), .cloned(), .map() and the VecDeque iterators. Chain can do something interesting here where it passes on the fold into its inner iterators. The lets the underlying iterator's custom fold() be used, and skips the regular chain logic in next. Also implement .fold() specifically for .map() and .cloned() so that any inner fold improvements are available through map and cloned. The same way, a VecDeque iterator fold can be turned into two slice folds. These changes lend the power of the slice iterator's loop codegen to VecDeque, and to chains of slice iterators, and so on. It's an improvement for .sum() and .product(), and other uses of fold.
2 parents a5b6a9f + a16626f commit 3a25b65

File tree

3 files changed

+98
-20
lines changed

3 files changed

+98
-20
lines changed

src/libcollections/vec_deque.rs

+54-20
Original file line numberDiff line numberDiff line change
@@ -743,16 +743,8 @@ impl<T> VecDeque<T> {
743743
#[stable(feature = "deque_extras_15", since = "1.5.0")]
744744
pub fn as_slices(&self) -> (&[T], &[T]) {
745745
unsafe {
746-
let contiguous = self.is_contiguous();
747746
let buf = self.buffer_as_slice();
748-
if contiguous {
749-
let (empty, buf) = buf.split_at(0);
750-
(&buf[self.tail..self.head], empty)
751-
} else {
752-
let (mid, right) = buf.split_at(self.tail);
753-
let (left, _) = mid.split_at(self.head);
754-
(right, left)
755-
}
747+
RingSlices::ring_slices(buf, self.head, self.tail)
756748
}
757749
}
758750

@@ -780,20 +772,10 @@ impl<T> VecDeque<T> {
780772
#[stable(feature = "deque_extras_15", since = "1.5.0")]
781773
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
782774
unsafe {
783-
let contiguous = self.is_contiguous();
784775
let head = self.head;
785776
let tail = self.tail;
786777
let buf = self.buffer_as_mut_slice();
787-
788-
if contiguous {
789-
let (empty, buf) = buf.split_at_mut(0);
790-
(&mut buf[tail..head], empty)
791-
} else {
792-
let (mid, right) = buf.split_at_mut(tail);
793-
let (left, _) = mid.split_at_mut(head);
794-
795-
(right, left)
796-
}
778+
RingSlices::ring_slices(buf, head, tail)
797779
}
798780
}
799781

@@ -1829,6 +1811,42 @@ fn wrap_index(index: usize, size: usize) -> usize {
18291811
index & (size - 1)
18301812
}
18311813

1814+
/// Returns the two slices that cover the VecDeque's valid range
1815+
trait RingSlices : Sized {
1816+
fn slice(self, from: usize, to: usize) -> Self;
1817+
fn split_at(self, i: usize) -> (Self, Self);
1818+
1819+
fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) {
1820+
let contiguous = tail <= head;
1821+
if contiguous {
1822+
let (empty, buf) = buf.split_at(0);
1823+
(buf.slice(tail, head), empty)
1824+
} else {
1825+
let (mid, right) = buf.split_at(tail);
1826+
let (left, _) = mid.split_at(head);
1827+
(right, left)
1828+
}
1829+
}
1830+
}
1831+
1832+
impl<'a, T> RingSlices for &'a [T] {
1833+
fn slice(self, from: usize, to: usize) -> Self {
1834+
&self[from..to]
1835+
}
1836+
fn split_at(self, i: usize) -> (Self, Self) {
1837+
(*self).split_at(i)
1838+
}
1839+
}
1840+
1841+
impl<'a, T> RingSlices for &'a mut [T] {
1842+
fn slice(self, from: usize, to: usize) -> Self {
1843+
&mut self[from..to]
1844+
}
1845+
fn split_at(self, i: usize) -> (Self, Self) {
1846+
(*self).split_at_mut(i)
1847+
}
1848+
}
1849+
18321850
/// Calculate the number of elements left to be read in the buffer
18331851
#[inline]
18341852
fn count(tail: usize, head: usize, size: usize) -> usize {
@@ -1875,6 +1893,14 @@ impl<'a, T> Iterator for Iter<'a, T> {
18751893
let len = count(self.tail, self.head, self.ring.len());
18761894
(len, Some(len))
18771895
}
1896+
1897+
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
1898+
where F: FnMut(Acc, Self::Item) -> Acc,
1899+
{
1900+
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
1901+
accum = front.iter().fold(accum, &mut f);
1902+
back.iter().fold(accum, &mut f)
1903+
}
18781904
}
18791905

18801906
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1927,6 +1953,14 @@ impl<'a, T> Iterator for IterMut<'a, T> {
19271953
let len = count(self.tail, self.head, self.ring.len());
19281954
(len, Some(len))
19291955
}
1956+
1957+
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
1958+
where F: FnMut(Acc, Self::Item) -> Acc,
1959+
{
1960+
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
1961+
accum = front.iter_mut().fold(accum, &mut f);
1962+
back.iter_mut().fold(accum, &mut f)
1963+
}
19301964
}
19311965

19321966
#[stable(feature = "rust1", since = "1.0.0")]

src/libcore/iter/mod.rs

+32
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,12 @@ impl<'a, I, T: 'a> Iterator for Cloned<I>
399399
fn size_hint(&self) -> (usize, Option<usize>) {
400400
self.it.size_hint()
401401
}
402+
403+
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
404+
where F: FnMut(Acc, Self::Item) -> Acc,
405+
{
406+
self.it.fold(init, move |acc, elt| f(acc, elt.clone()))
407+
}
402408
}
403409

404410
#[stable(feature = "iter_cloned", since = "1.1.0")]
@@ -544,6 +550,25 @@ impl<A, B> Iterator for Chain<A, B> where
544550
}
545551
}
546552

553+
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
554+
where F: FnMut(Acc, Self::Item) -> Acc,
555+
{
556+
let mut accum = init;
557+
match self.state {
558+
ChainState::Both | ChainState::Front => {
559+
accum = self.a.fold(accum, &mut f);
560+
}
561+
_ => { }
562+
}
563+
match self.state {
564+
ChainState::Both | ChainState::Back => {
565+
accum = self.b.fold(accum, &mut f);
566+
}
567+
_ => { }
568+
}
569+
accum
570+
}
571+
547572
#[inline]
548573
fn nth(&mut self, mut n: usize) -> Option<A::Item> {
549574
match self.state {
@@ -939,6 +964,13 @@ impl<B, I: Iterator, F> Iterator for Map<I, F> where F: FnMut(I::Item) -> B {
939964
fn size_hint(&self) -> (usize, Option<usize>) {
940965
self.iter.size_hint()
941966
}
967+
968+
fn fold<Acc, G>(self, init: Acc, mut g: G) -> Acc
969+
where G: FnMut(Acc, Self::Item) -> Acc,
970+
{
971+
let mut f = self.f;
972+
self.iter.fold(init, move |acc, elt| g(acc, f(elt)))
973+
}
942974
}
943975

944976
#[stable(feature = "rust1", since = "1.0.0")]

src/libcoretest/iter.rs

+12
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,18 @@ fn test_empty() {
985985
assert_eq!(it.next(), None);
986986
}
987987

988+
#[test]
989+
fn test_chain_fold() {
990+
let xs = [1, 2, 3];
991+
let ys = [1, 2, 0];
992+
993+
let mut iter = xs.iter().chain(&ys);
994+
iter.next();
995+
let mut result = Vec::new();
996+
iter.fold((), |(), &elt| result.push(elt));
997+
assert_eq!(&[2, 3, 1, 2, 0], &result[..]);
998+
}
999+
9881000
#[bench]
9891001
fn bench_rposition(b: &mut Bencher) {
9901002
let it: Vec<usize> = (0..300).collect();

0 commit comments

Comments
 (0)