@@ -12,6 +12,7 @@ const HI_U64: u64 = 0x8080808080808080;
12
12
// Use truncation.
13
13
const LO_USIZE : usize = LO_U64 as usize ;
14
14
const HI_USIZE : usize = HI_U64 as usize ;
15
+ const USIZE_BYTES : usize = mem:: size_of :: < usize > ( ) ;
15
16
16
17
/// Returns `true` if `x` contains any zero byte.
17
18
///
@@ -38,19 +39,29 @@ fn repeat_byte(b: u8) -> usize {
38
39
}
39
40
40
41
/// Returns the first index matching the byte `x` in `text`.
42
+ #[ inline]
41
43
pub fn memchr ( x : u8 , text : & [ u8 ] ) -> Option < usize > {
44
+ // Fast path for small slices
45
+ if text. len ( ) < 2 * USIZE_BYTES {
46
+ return text. iter ( ) . position ( |elt| * elt == x) ;
47
+ }
48
+
49
+ memchr_general_case ( x, text)
50
+ }
51
+
52
+ fn memchr_general_case ( x : u8 , text : & [ u8 ] ) -> Option < usize > {
42
53
// Scan for a single byte value by reading two `usize` words at a time.
43
54
//
44
55
// Split `text` in three parts
45
56
// - unaligned initial part, before the first word aligned address in text
46
57
// - body, scan by 2 words at a time
47
58
// - the last remaining part, < 2 word size
59
+
60
+ // search up to an aligned boundary
48
61
let len = text. len ( ) ;
49
62
let ptr = text. as_ptr ( ) ;
50
- let usize_bytes = mem :: size_of :: < usize > ( ) ;
63
+ let mut offset = ptr . align_offset ( USIZE_BYTES ) ;
51
64
52
- // search up to an aligned boundary
53
- let mut offset = ptr. align_offset ( usize_bytes) ;
54
65
if offset > 0 {
55
66
offset = cmp:: min ( offset, len) ;
56
67
if let Some ( index) = text[ ..offset] . iter ( ) . position ( |elt| * elt == x) {
@@ -60,22 +71,19 @@ pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
60
71
61
72
// search the body of the text
62
73
let repeated_x = repeat_byte ( x) ;
74
+ while offset <= len - 2 * USIZE_BYTES {
75
+ unsafe {
76
+ let u = * ( ptr. add ( offset) as * const usize ) ;
77
+ let v = * ( ptr. add ( offset + USIZE_BYTES ) as * const usize ) ;
63
78
64
- if len >= 2 * usize_bytes {
65
- while offset <= len - 2 * usize_bytes {
66
- unsafe {
67
- let u = * ( ptr. add ( offset) as * const usize ) ;
68
- let v = * ( ptr. add ( offset + usize_bytes) as * const usize ) ;
69
-
70
- // break if there is a matching byte
71
- let zu = contains_zero_byte ( u ^ repeated_x) ;
72
- let zv = contains_zero_byte ( v ^ repeated_x) ;
73
- if zu || zv {
74
- break ;
75
- }
79
+ // break if there is a matching byte
80
+ let zu = contains_zero_byte ( u ^ repeated_x) ;
81
+ let zv = contains_zero_byte ( v ^ repeated_x) ;
82
+ if zu || zv {
83
+ break ;
76
84
}
77
- offset += usize_bytes * 2 ;
78
85
}
86
+ offset += USIZE_BYTES * 2 ;
79
87
}
80
88
81
89
// Find the byte after the point the body loop stopped.
0 commit comments