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