22// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
33
44use crate::cmp;
5- use crate::intrinsics;
65use crate::mem;
76
87const LO_USIZE: usize = usize::repeat_u8(0x01);
@@ -17,53 +16,51 @@ const USIZE_BYTES: usize = mem::size_of::<usize>();
1716/// bytes where the borrow propagated all the way to the most significant
1817/// bit."
1918#[inline]
20- fn contains_zero_byte(x: usize) -> bool {
19+ const fn contains_zero_byte(x: usize) -> bool {
2120 x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
2221}
2322
2423#[cfg(target_pointer_width = "16")]
2524#[inline]
26- fn repeat_byte(b: u8) -> usize {
25+ const fn repeat_byte(b: u8) -> usize {
2726 (b as usize) << 8 | b as usize
2827}
2928
3029#[cfg(not(target_pointer_width = "16"))]
3130#[inline]
32- fn repeat_byte(b: u8) -> usize {
31+ const fn repeat_byte(b: u8) -> usize {
3332 (b as usize) * (usize::MAX / 255)
3433}
3534
3635/// Returns the first index matching the byte `x` in `text`.
3736#[must_use]
3837#[inline]
3938pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
40- #[inline]
41- fn rt_impl(x: u8, text: &[u8]) -> Option<usize> {
42- // Fast path for small slices
43- if text.len() < 2 * USIZE_BYTES {
44- return text.iter().position(|elt| *elt == x);
45- }
46-
47- memchr_general_case(x, text)
39+ // Fast path for small slices.
40+ if text.len() < 2 * USIZE_BYTES {
41+ return memchr_naive(x, text);
4842 }
4943
50- const fn const_impl(x: u8, bytes: &[u8]) -> Option<usize> {
51- let mut i = 0;
52- while i < bytes.len() {
53- if bytes[i] == x {
54- return Some(i);
55- }
56- i += 1;
44+ memchr_aligned(x, text)
45+ }
46+
47+ #[inline]
48+ const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
49+ let mut i = 0;
50+
51+ // FIXME(const-hack): Replace with `text.iter().pos(|c| *c == x)`.
52+ while i < text.len() {
53+ if text[i] == x {
54+ return Some(i);
5755 }
5856
59- None
57+ i += 1;
6058 }
6159
62- // SAFETY: The const and runtime versions have identical behavior
63- unsafe { intrinsics::const_eval_select((x, text), const_impl, rt_impl) }
60+ None
6461}
6562
66- fn memchr_general_case (x: u8, text: &[u8]) -> Option<usize> {
63+ const fn memchr_aligned (x: u8, text: &[u8]) -> Option<usize> {
6764 // Scan for a single byte value by reading two `usize` words at a time.
6865 //
6966 // Split `text` in three parts
@@ -78,7 +75,7 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
7875
7976 if offset > 0 {
8077 offset = cmp::min(offset, len);
81- if let Some(index) = text[..offset].iter().position(|elt| *elt == x ) {
78+ if let Some(index) = memchr_naive(x, & text[..offset]) {
8279 return Some(index);
8380 }
8481 }
@@ -103,7 +100,8 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
103100 }
104101
105102 // Find the byte after the point the body loop stopped.
106- text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
103+ // FIXME(const-hack): Use `?` instead.
104+ if let Some(i) = memchr_naive(x, &text[offset..]) { Some(offset + i) } else { None }
107105}
108106
109107/// Returns the last index matching the byte `x` in `text`.
0 commit comments