Skip to content

Commit db29de7

Browse files
committed
Simplify const memchr.
1 parent c84083b commit db29de7

File tree

1 file changed

+23
-25
lines changed

1 file changed

+23
-25
lines changed

Diff for: library/core/src/slice/memchr.rs

+23-25
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
33

44
use crate::cmp;
5-
use crate::intrinsics;
65
use crate::mem;
76

87
const 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]
3938
pub 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

Comments
 (0)