about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-17 08:15:35 +0000
committerbors <bors@rust-lang.org>2022-09-17 08:15:35 +0000
commitb195f5349a5f7b01369e7bba2f9fff250e62d36d (patch)
tree7f34bd97a16f0682dd141ce557640dd7974a99a5
parent4a12d10bcc4536108efad1613b57f725302c207e (diff)
parentdb29de7745047383031231857745c5ec9b0bb4e8 (diff)
downloadrust-b195f5349a5f7b01369e7bba2f9fff250e62d36d.tar.gz
rust-b195f5349a5f7b01369e7bba2f9fff250e62d36d.zip
Auto merge of #101784 - reitermarkus:const-memchr, r=thomcc
Simplify `const` `memchr`.

Extracted from https://github.com/rust-lang/rust/pull/101607.

Removes the need for `const_eval_select`.
-rw-r--r--library/core/src/slice/memchr.rs48
1 files changed, 23 insertions, 25 deletions
diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs
index e0419f0ffdb..7de1f48e6c9 100644
--- a/library/core/src/slice/memchr.rs
+++ b/library/core/src/slice/memchr.rs
@@ -2,7 +2,6 @@
 // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
 
 use crate::cmp;
-use crate::intrinsics;
 use crate::mem;
 
 const LO_USIZE: usize = usize::repeat_u8(0x01);
@@ -17,19 +16,19 @@ const USIZE_BYTES: usize = mem::size_of::<usize>();
 /// bytes where the borrow propagated all the way to the most significant
 /// bit."
 #[inline]
-fn contains_zero_byte(x: usize) -> bool {
+const fn contains_zero_byte(x: usize) -> bool {
     x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
 }
 
 #[cfg(target_pointer_width = "16")]
 #[inline]
-fn repeat_byte(b: u8) -> usize {
+const fn repeat_byte(b: u8) -> usize {
     (b as usize) << 8 | b as usize
 }
 
 #[cfg(not(target_pointer_width = "16"))]
 #[inline]
-fn repeat_byte(b: u8) -> usize {
+const fn repeat_byte(b: u8) -> usize {
     (b as usize) * (usize::MAX / 255)
 }
 
@@ -37,33 +36,31 @@ fn repeat_byte(b: u8) -> usize {
 #[must_use]
 #[inline]
 pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
-    #[inline]
-    fn rt_impl(x: u8, text: &[u8]) -> Option<usize> {
-        // Fast path for small slices
-        if text.len() < 2 * USIZE_BYTES {
-            return text.iter().position(|elt| *elt == x);
-        }
-
-        memchr_general_case(x, text)
+    // Fast path for small slices.
+    if text.len() < 2 * USIZE_BYTES {
+        return memchr_naive(x, text);
     }
 
-    const fn const_impl(x: u8, bytes: &[u8]) -> Option<usize> {
-        let mut i = 0;
-        while i < bytes.len() {
-            if bytes[i] == x {
-                return Some(i);
-            }
-            i += 1;
+    memchr_aligned(x, text)
+}
+
+#[inline]
+const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
+    let mut i = 0;
+
+    // FIXME(const-hack): Replace with `text.iter().pos(|c| *c == x)`.
+    while i < text.len() {
+        if text[i] == x {
+            return Some(i);
         }
 
-        None
+        i += 1;
     }
 
-    // SAFETY: The const and runtime versions have identical behavior
-    unsafe { intrinsics::const_eval_select((x, text), const_impl, rt_impl) }
+    None
 }
 
-fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
+const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
     // Scan for a single byte value by reading two `usize` words at a time.
     //
     // Split `text` in three parts
@@ -78,7 +75,7 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
 
     if offset > 0 {
         offset = cmp::min(offset, len);
-        if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
+        if let Some(index) = memchr_naive(x, &text[..offset]) {
             return Some(index);
         }
     }
@@ -103,7 +100,8 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
     }
 
     // Find the byte after the point the body loop stopped.
-    text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
+    // FIXME(const-hack): Use `?` instead.
+    if let Some(i) = memchr_naive(x, &text[offset..]) { Some(offset + i) } else { None }
 }
 
 /// Returns the last index matching the byte `x` in `text`.