]> git.lizzy.rs Git - rust.git/commitdiff
Simplify `const` `memchr`.
authorMarkus Reiter <me@reitermark.us>
Fri, 9 Sep 2022 09:48:39 +0000 (11:48 +0200)
committerMarkus Reiter <me@reitermark.us>
Wed, 14 Sep 2022 00:00:18 +0000 (02:00 +0200)
library/core/src/slice/memchr.rs

index e0419f0ffdbaceb124a41b2c392fe6425d0d005b..7de1f48e6c9022dbe685eeb11e03b1312f28d524 100644 (file)
@@ -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);
 /// 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`.