Skip to main content

regex_automata/util/prefilter/
memchr.rs

1use crate::util::{
2    prefilter::PrefilterI,
3    search::{MatchKind, Span},
4};
5
6#[derive(Clone, Debug)]
7pub(crate) struct Memchr(u8);
8
9impl Memchr {
10    pub(crate) fn new<B: AsRef<[u8]>>(
11        _kind: MatchKind,
12        needles: &[B],
13    ) -> Option<Memchr> {
14        #[cfg(not(feature = "perf-literal-substring"))]
15        {
16            None
17        }
18        #[cfg(feature = "perf-literal-substring")]
19        {
20            if needles.len() != 1 {
21                return None;
22            }
23            if needles[0].as_ref().len() != 1 {
24                return None;
25            }
26            Some(Memchr(needles[0].as_ref()[0]))
27        }
28    }
29}
30
31impl PrefilterI for Memchr {
32    fn name(&self) -> &'static str {
33        "memchr"
34    }
35
36    fn find(&self, haystack: &[u8], span: Span) -> Option<Span> {
37        #[cfg(not(feature = "perf-literal-substring"))]
38        {
39            unreachable!()
40        }
41        #[cfg(feature = "perf-literal-substring")]
42        {
43            memchr::memchr(self.0, &haystack[span]).map(|i| {
44                let start = span.start + i;
45                let end = start + 1;
46                Span { start, end }
47            })
48        }
49    }
50
51    fn prefix(&self, haystack: &[u8], span: Span) -> Option<Span> {
52        let b = *haystack.get(span.start)?;
53        if self.0 == b {
54            Some(Span { start: span.start, end: span.start + 1 })
55        } else {
56            None
57        }
58    }
59
60    fn memory_usage(&self) -> usize {
61        0
62    }
63
64    fn is_fast(&self) -> bool {
65        true
66    }
67}
68
69#[derive(Clone, Debug)]
70pub(crate) struct Memchr2(u8, u8);
71
72impl Memchr2 {
73    pub(crate) fn new<B: AsRef<[u8]>>(
74        _kind: MatchKind,
75        needles: &[B],
76    ) -> Option<Memchr2> {
77        #[cfg(not(feature = "perf-literal-substring"))]
78        {
79            None
80        }
81        #[cfg(feature = "perf-literal-substring")]
82        {
83            if needles.len() != 2 {
84                return None;
85            }
86            if !needles.iter().all(|n| n.as_ref().len() == 1) {
87                return None;
88            }
89            let b1 = needles[0].as_ref()[0];
90            let b2 = needles[1].as_ref()[0];
91            Some(Memchr2(b1, b2))
92        }
93    }
94}
95
96impl PrefilterI for Memchr2 {
97    fn name(&self) -> &'static str {
98        "memchr2"
99    }
100
101    fn find(&self, haystack: &[u8], span: Span) -> Option<Span> {
102        #[cfg(not(feature = "perf-literal-substring"))]
103        {
104            unreachable!()
105        }
106        #[cfg(feature = "perf-literal-substring")]
107        {
108            memchr::memchr2(self.0, self.1, &haystack[span]).map(|i| {
109                let start = span.start + i;
110                let end = start + 1;
111                Span { start, end }
112            })
113        }
114    }
115
116    fn prefix(&self, haystack: &[u8], span: Span) -> Option<Span> {
117        let b = *haystack.get(span.start)?;
118        if self.0 == b || self.1 == b {
119            Some(Span { start: span.start, end: span.start + 1 })
120        } else {
121            None
122        }
123    }
124
125    fn memory_usage(&self) -> usize {
126        0
127    }
128
129    fn is_fast(&self) -> bool {
130        true
131    }
132}
133
134#[derive(Clone, Debug)]
135pub(crate) struct Memchr3(u8, u8, u8);
136
137impl Memchr3 {
138    pub(crate) fn new<B: AsRef<[u8]>>(
139        _kind: MatchKind,
140        needles: &[B],
141    ) -> Option<Memchr3> {
142        #[cfg(not(feature = "perf-literal-substring"))]
143        {
144            None
145        }
146        #[cfg(feature = "perf-literal-substring")]
147        {
148            if needles.len() != 3 {
149                return None;
150            }
151            if !needles.iter().all(|n| n.as_ref().len() == 1) {
152                return None;
153            }
154            let b1 = needles[0].as_ref()[0];
155            let b2 = needles[1].as_ref()[0];
156            let b3 = needles[2].as_ref()[0];
157            Some(Memchr3(b1, b2, b3))
158        }
159    }
160}
161
162impl PrefilterI for Memchr3 {
163    fn name(&self) -> &'static str {
164        "memchr3"
165    }
166
167    fn find(&self, haystack: &[u8], span: Span) -> Option<Span> {
168        #[cfg(not(feature = "perf-literal-substring"))]
169        {
170            unreachable!()
171        }
172        #[cfg(feature = "perf-literal-substring")]
173        {
174            memchr::memchr3(self.0, self.1, self.2, &haystack[span]).map(|i| {
175                let start = span.start + i;
176                let end = start + 1;
177                Span { start, end }
178            })
179        }
180    }
181
182    fn prefix(&self, haystack: &[u8], span: Span) -> Option<Span> {
183        let b = *haystack.get(span.start)?;
184        if self.0 == b || self.1 == b || self.2 == b {
185            Some(Span { start: span.start, end: span.start + 1 })
186        } else {
187            None
188        }
189    }
190
191    fn memory_usage(&self) -> usize {
192        0
193    }
194
195    fn is_fast(&self) -> bool {
196        true
197    }
198}