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: &B| n.as_ref().len() == 1) {
83 return None;
84 }
85 let b1: u8 = needles[0].as_ref()[0];
86 let b2: u8 = 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: &B| n.as_ref().len() == 1) {
144 return None;
145 }
146 let b1: u8 = needles[0].as_ref()[0];
147 let b2: u8 = needles[1].as_ref()[0];
148 let b3: u8 = 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}
187