about summary refs log tree commit diff
path: root/src/libcore/slice
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-01-18 01:57:13 +0800
committerGitHub <noreply@github.com>2018-01-18 01:57:13 +0800
commit175dd84ed8969fe136a4da1c7e5fe1d9c7693f2d (patch)
treee273945750e0615538bc5314972aeee154425c71 /src/libcore/slice
parent283ee544586a0952a9a45782f42addc9dbac3392 (diff)
parent0b56ab0f7b0c5e01611b7ea6a28c77bc09c26275 (diff)
downloadrust-175dd84ed8969fe136a4da1c7e5fe1d9c7693f2d.tar.gz
rust-175dd84ed8969fe136a4da1c7e5fe1d9c7693f2d.zip
Rollup merge of #47333 - arthurprs:iter-position-bounds-check, r=dtolnay
Optimize slice.{r}position result bounds check

Second attempt of https://github.com/rust-lang/rust/pull/45501
Fixes https://github.com/rust-lang/rust/issues/45964

Demo: https://godbolt.org/g/N4mBHp
Diffstat (limited to 'src/libcore/slice')
-rw-r--r--src/libcore/slice/mod.rs37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 48e82666d35..5bf73014347 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -1237,6 +1237,43 @@ macro_rules! iterator {
                 }
                 accum
             }
+
+            #[inline]
+            #[rustc_inherit_overflow_checks]
+            fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
+                Self: Sized,
+                P: FnMut(Self::Item) -> bool,
+            {
+                // The addition might panic on overflow
+                let n = self.len();
+                self.try_fold(0, move |i, x| {
+                    if predicate(x) { Err(i) }
+                    else { Ok(i + 1) }
+                }).err()
+                    .map(|i| {
+                        unsafe { assume(i < n) };
+                        i
+                    })
+            }
+
+            #[inline]
+            fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
+                P: FnMut(Self::Item) -> bool,
+                Self: Sized + ExactSizeIterator + DoubleEndedIterator
+            {
+                // No need for an overflow check here, because `ExactSizeIterator`
+                // implies that the number of elements fits into a `usize`.
+                let n = self.len();
+                self.try_rfold(n, move |i, x| {
+                    let i = i - 1;
+                    if predicate(x) { Err(i) }
+                    else { Ok(i) }
+                }).err()
+                    .map(|i| {
+                        unsafe { assume(i < n) };
+                        i
+                    })
+            }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]