about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Nethercote <nnethercote@mozilla.com>2020-05-18 09:34:34 +1000
committerNicholas Nethercote <nnethercote@mozilla.com>2020-05-18 16:51:39 +1000
commit959bd48887d431a0f30090af18ef40d8c5606d77 (patch)
tree7a05666990075e52f6389696bc7be72ab3a159e4
parentc2abf8f9c30a979ca756ed84e085e3507c3227e9 (diff)
downloadrust-959bd48887d431a0f30090af18ef40d8c5606d77.tar.gz
rust-959bd48887d431a0f30090af18ef40d8c5606d77.zip
Add some more `rfold` implementations.
-rw-r--r--src/libcore/iter/adapters/mod.rs53
-rw-r--r--src/libcore/iter/range.rs15
2 files changed, 68 insertions, 0 deletions
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index 939a26cb702..195847ee98d 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -724,6 +724,29 @@ where
             }
         }
     }
+
+    #[inline]
+    fn rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
+    where
+        Self: Sized,
+        F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        #[inline]
+        fn nth_back<I: DoubleEndedIterator>(
+            iter: &mut I,
+            step: usize,
+        ) -> impl FnMut() -> Option<I::Item> + '_ {
+            move || iter.nth_back(step)
+        }
+
+        match self.next_back() {
+            None => init,
+            Some(x) => {
+                let acc = f(init, x);
+                from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f)
+            }
+        }
+    }
 }
 
 // StepBy can only make the iterator shorter, so the len will still fit.
@@ -2056,6 +2079,18 @@ where
             self.iter.try_rfold(init, check(n, fold)).into_try()
         }
     }
+
+    fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+    where
+        Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        #[inline]
+        fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
+            move |acc, x| Ok(f(acc, x))
+        }
+
+        self.try_rfold(init, ok(fold)).unwrap()
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -2220,6 +2255,24 @@ where
             }
         }
     }
+
+    #[inline]
+    fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+    where
+        Self: Sized,
+        Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        if self.n == 0 {
+            init
+        } else {
+            let len = self.iter.len();
+            if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
+                init
+            } else {
+                self.iter.rfold(init, fold)
+            }
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs
index 6ac9576a46d..388a5548a31 100644
--- a/src/libcore/iter/range.rs
+++ b/src/libcore/iter/range.rs
@@ -671,6 +671,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
 
         self.try_fold(init, ok(f)).unwrap()
     }
+
     #[inline]
     fn last(mut self) -> Option<A> {
         self.next_back()
@@ -759,6 +760,20 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
 
         Try::from_ok(accum)
     }
+
+    #[inline]
+    fn rfold<B, F>(mut self, init: B, f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        #[inline]
+        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
+            move |acc, x| Ok(f(acc, x))
+        }
+
+        self.try_rfold(init, ok(f)).unwrap()
+    }
 }
 
 #[unstable(feature = "trusted_len", issue = "37572")]