/rust/registry/src/index.crates.io-1949cf8c6b5b557f/memchr-2.4.1/src/memmem/mod.rs
Line | Count | Source |
1 | | /*! |
2 | | This module provides forward and reverse substring search routines. |
3 | | |
4 | | Unlike the standard library's substring search routines, these work on |
5 | | arbitrary bytes. For all non-empty needles, these routines will report exactly |
6 | | the same values as the corresponding routines in the standard library. For |
7 | | the empty needle, the standard library reports matches only at valid UTF-8 |
8 | | boundaries, where as these routines will report matches at every position. |
9 | | |
10 | | Other than being able to work on arbitrary bytes, the primary reason to prefer |
11 | | these routines over the standard library routines is that these will generally |
12 | | be faster. In some cases, significantly so. |
13 | | |
14 | | # Example: iterating over substring matches |
15 | | |
16 | | This example shows how to use [`find_iter`] to find occurrences of a substring |
17 | | in a haystack. |
18 | | |
19 | | ``` |
20 | | use memchr::memmem; |
21 | | |
22 | | let haystack = b"foo bar foo baz foo"; |
23 | | |
24 | | let mut it = memmem::find_iter(haystack, "foo"); |
25 | | assert_eq!(Some(0), it.next()); |
26 | | assert_eq!(Some(8), it.next()); |
27 | | assert_eq!(Some(16), it.next()); |
28 | | assert_eq!(None, it.next()); |
29 | | ``` |
30 | | |
31 | | # Example: iterating over substring matches in reverse |
32 | | |
33 | | This example shows how to use [`rfind_iter`] to find occurrences of a substring |
34 | | in a haystack starting from the end of the haystack. |
35 | | |
36 | | **NOTE:** This module does not implement double ended iterators, so reverse |
37 | | searches aren't done by calling `rev` on a forward iterator. |
38 | | |
39 | | ``` |
40 | | use memchr::memmem; |
41 | | |
42 | | let haystack = b"foo bar foo baz foo"; |
43 | | |
44 | | let mut it = memmem::rfind_iter(haystack, "foo"); |
45 | | assert_eq!(Some(16), it.next()); |
46 | | assert_eq!(Some(8), it.next()); |
47 | | assert_eq!(Some(0), it.next()); |
48 | | assert_eq!(None, it.next()); |
49 | | ``` |
50 | | |
51 | | # Example: repeating a search for the same needle |
52 | | |
53 | | It may be possible for the overhead of constructing a substring searcher to be |
54 | | measurable in some workloads. In cases where the same needle is used to search |
55 | | many haystacks, it is possible to do construction once and thus to avoid it for |
56 | | subsequent searches. This can be done with a [`Finder`] (or a [`FinderRev`] for |
57 | | reverse searches). |
58 | | |
59 | | ``` |
60 | | use memchr::memmem; |
61 | | |
62 | | let finder = memmem::Finder::new("foo"); |
63 | | |
64 | | assert_eq!(Some(4), finder.find(b"baz foo quux")); |
65 | | assert_eq!(None, finder.find(b"quux baz bar")); |
66 | | ``` |
67 | | */ |
68 | | |
69 | | pub use self::prefilter::Prefilter; |
70 | | |
71 | | use crate::{ |
72 | | cow::CowBytes, |
73 | | memmem::{ |
74 | | prefilter::{Pre, PrefilterFn, PrefilterState}, |
75 | | rabinkarp::NeedleHash, |
76 | | rarebytes::RareNeedleBytes, |
77 | | }, |
78 | | }; |
79 | | |
80 | | /// Defines a suite of quickcheck properties for forward and reverse |
81 | | /// substring searching. |
82 | | /// |
83 | | /// This is defined in this specific spot so that it can be used freely among |
84 | | /// the different substring search implementations. I couldn't be bothered to |
85 | | /// fight with the macro-visibility rules enough to figure out how to stuff it |
86 | | /// somewhere more convenient. |
87 | | #[cfg(all(test, feature = "std"))] |
88 | | macro_rules! define_memmem_quickcheck_tests { |
89 | | ($fwd:expr, $rev:expr) => { |
90 | | use crate::memmem::proptests; |
91 | | |
92 | | quickcheck::quickcheck! { |
93 | | fn qc_fwd_prefix_is_substring(bs: Vec<u8>) -> bool { |
94 | | proptests::prefix_is_substring(false, &bs, $fwd) |
95 | | } |
96 | | |
97 | | fn qc_fwd_suffix_is_substring(bs: Vec<u8>) -> bool { |
98 | | proptests::suffix_is_substring(false, &bs, $fwd) |
99 | | } |
100 | | |
101 | | fn qc_fwd_matches_naive( |
102 | | haystack: Vec<u8>, |
103 | | needle: Vec<u8> |
104 | | ) -> bool { |
105 | | proptests::matches_naive(false, &haystack, &needle, $fwd) |
106 | | } |
107 | | |
108 | | fn qc_rev_prefix_is_substring(bs: Vec<u8>) -> bool { |
109 | | proptests::prefix_is_substring(true, &bs, $rev) |
110 | | } |
111 | | |
112 | | fn qc_rev_suffix_is_substring(bs: Vec<u8>) -> bool { |
113 | | proptests::suffix_is_substring(true, &bs, $rev) |
114 | | } |
115 | | |
116 | | fn qc_rev_matches_naive( |
117 | | haystack: Vec<u8>, |
118 | | needle: Vec<u8> |
119 | | ) -> bool { |
120 | | proptests::matches_naive(true, &haystack, &needle, $rev) |
121 | | } |
122 | | } |
123 | | }; |
124 | | } |
125 | | |
126 | | /// Defines a suite of "simple" hand-written tests for a substring |
127 | | /// implementation. |
128 | | /// |
129 | | /// This is defined here for the same reason that |
130 | | /// define_memmem_quickcheck_tests is defined here. |
131 | | #[cfg(test)] |
132 | | macro_rules! define_memmem_simple_tests { |
133 | | ($fwd:expr, $rev:expr) => { |
134 | | use crate::memmem::testsimples; |
135 | | |
136 | | #[test] |
137 | | fn simple_forward() { |
138 | | testsimples::run_search_tests_fwd($fwd); |
139 | | } |
140 | | |
141 | | #[test] |
142 | | fn simple_reverse() { |
143 | | testsimples::run_search_tests_rev($rev); |
144 | | } |
145 | | }; |
146 | | } |
147 | | |
148 | | mod byte_frequencies; |
149 | | #[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] |
150 | | mod genericsimd; |
151 | | mod prefilter; |
152 | | mod rabinkarp; |
153 | | mod rarebytes; |
154 | | mod twoway; |
155 | | mod util; |
156 | | // SIMD is only supported on x86_64 currently. |
157 | | #[cfg(target_arch = "x86_64")] |
158 | | mod vector; |
159 | | #[cfg(all(not(miri), target_arch = "x86_64", memchr_runtime_simd))] |
160 | | mod x86; |
161 | | |
162 | | /// Returns an iterator over all occurrences of a substring in a haystack. |
163 | | /// |
164 | | /// # Complexity |
165 | | /// |
166 | | /// This routine is guaranteed to have worst case linear time complexity |
167 | | /// with respect to both the needle and the haystack. That is, this runs |
168 | | /// in `O(needle.len() + haystack.len())` time. |
169 | | /// |
170 | | /// This routine is also guaranteed to have worst case constant space |
171 | | /// complexity. |
172 | | /// |
173 | | /// # Examples |
174 | | /// |
175 | | /// Basic usage: |
176 | | /// |
177 | | /// ``` |
178 | | /// use memchr::memmem; |
179 | | /// |
180 | | /// let haystack = b"foo bar foo baz foo"; |
181 | | /// let mut it = memmem::find_iter(haystack, b"foo"); |
182 | | /// assert_eq!(Some(0), it.next()); |
183 | | /// assert_eq!(Some(8), it.next()); |
184 | | /// assert_eq!(Some(16), it.next()); |
185 | | /// assert_eq!(None, it.next()); |
186 | | /// ``` |
187 | | #[inline] |
188 | 0 | pub fn find_iter<'h, 'n, N: 'n + ?Sized + AsRef<[u8]>>( |
189 | 0 | haystack: &'h [u8], |
190 | 0 | needle: &'n N, |
191 | 0 | ) -> FindIter<'h, 'n> { |
192 | 0 | FindIter::new(haystack, Finder::new(needle)) |
193 | 0 | } |
194 | | |
195 | | /// Returns a reverse iterator over all occurrences of a substring in a |
196 | | /// haystack. |
197 | | /// |
198 | | /// # Complexity |
199 | | /// |
200 | | /// This routine is guaranteed to have worst case linear time complexity |
201 | | /// with respect to both the needle and the haystack. That is, this runs |
202 | | /// in `O(needle.len() + haystack.len())` time. |
203 | | /// |
204 | | /// This routine is also guaranteed to have worst case constant space |
205 | | /// complexity. |
206 | | /// |
207 | | /// # Examples |
208 | | /// |
209 | | /// Basic usage: |
210 | | /// |
211 | | /// ``` |
212 | | /// use memchr::memmem; |
213 | | /// |
214 | | /// let haystack = b"foo bar foo baz foo"; |
215 | | /// let mut it = memmem::rfind_iter(haystack, b"foo"); |
216 | | /// assert_eq!(Some(16), it.next()); |
217 | | /// assert_eq!(Some(8), it.next()); |
218 | | /// assert_eq!(Some(0), it.next()); |
219 | | /// assert_eq!(None, it.next()); |
220 | | /// ``` |
221 | | #[inline] |
222 | 0 | pub fn rfind_iter<'h, 'n, N: 'n + ?Sized + AsRef<[u8]>>( |
223 | 0 | haystack: &'h [u8], |
224 | 0 | needle: &'n N, |
225 | 0 | ) -> FindRevIter<'h, 'n> { |
226 | 0 | FindRevIter::new(haystack, FinderRev::new(needle)) |
227 | 0 | } |
228 | | |
229 | | /// Returns the index of the first occurrence of the given needle. |
230 | | /// |
231 | | /// Note that if you're are searching for the same needle in many different |
232 | | /// small haystacks, it may be faster to initialize a [`Finder`] once, |
233 | | /// and reuse it for each search. |
234 | | /// |
235 | | /// # Complexity |
236 | | /// |
237 | | /// This routine is guaranteed to have worst case linear time complexity |
238 | | /// with respect to both the needle and the haystack. That is, this runs |
239 | | /// in `O(needle.len() + haystack.len())` time. |
240 | | /// |
241 | | /// This routine is also guaranteed to have worst case constant space |
242 | | /// complexity. |
243 | | /// |
244 | | /// # Examples |
245 | | /// |
246 | | /// Basic usage: |
247 | | /// |
248 | | /// ``` |
249 | | /// use memchr::memmem; |
250 | | /// |
251 | | /// let haystack = b"foo bar baz"; |
252 | | /// assert_eq!(Some(0), memmem::find(haystack, b"foo")); |
253 | | /// assert_eq!(Some(4), memmem::find(haystack, b"bar")); |
254 | | /// assert_eq!(None, memmem::find(haystack, b"quux")); |
255 | | /// ``` |
256 | | #[inline] |
257 | 0 | pub fn find(haystack: &[u8], needle: &[u8]) -> Option<usize> { |
258 | 0 | if haystack.len() < 64 { |
259 | 0 | rabinkarp::find(haystack, needle) |
260 | | } else { |
261 | 0 | Finder::new(needle).find(haystack) |
262 | | } |
263 | 0 | } |
264 | | |
265 | | /// Returns the index of the last occurrence of the given needle. |
266 | | /// |
267 | | /// Note that if you're are searching for the same needle in many different |
268 | | /// small haystacks, it may be faster to initialize a [`FinderRev`] once, |
269 | | /// and reuse it for each search. |
270 | | /// |
271 | | /// # Complexity |
272 | | /// |
273 | | /// This routine is guaranteed to have worst case linear time complexity |
274 | | /// with respect to both the needle and the haystack. That is, this runs |
275 | | /// in `O(needle.len() + haystack.len())` time. |
276 | | /// |
277 | | /// This routine is also guaranteed to have worst case constant space |
278 | | /// complexity. |
279 | | /// |
280 | | /// # Examples |
281 | | /// |
282 | | /// Basic usage: |
283 | | /// |
284 | | /// ``` |
285 | | /// use memchr::memmem; |
286 | | /// |
287 | | /// let haystack = b"foo bar baz"; |
288 | | /// assert_eq!(Some(0), memmem::rfind(haystack, b"foo")); |
289 | | /// assert_eq!(Some(4), memmem::rfind(haystack, b"bar")); |
290 | | /// assert_eq!(Some(8), memmem::rfind(haystack, b"ba")); |
291 | | /// assert_eq!(None, memmem::rfind(haystack, b"quux")); |
292 | | /// ``` |
293 | | #[inline] |
294 | 0 | pub fn rfind(haystack: &[u8], needle: &[u8]) -> Option<usize> { |
295 | 0 | if haystack.len() < 64 { |
296 | 0 | rabinkarp::rfind(haystack, needle) |
297 | | } else { |
298 | 0 | FinderRev::new(needle).rfind(haystack) |
299 | | } |
300 | 0 | } |
301 | | |
302 | | /// An iterator over non-overlapping substring matches. |
303 | | /// |
304 | | /// Matches are reported by the byte offset at which they begin. |
305 | | /// |
306 | | /// `'h` is the lifetime of the haystack while `'n` is the lifetime of the |
307 | | /// needle. |
308 | | #[derive(Debug)] |
309 | | pub struct FindIter<'h, 'n> { |
310 | | haystack: &'h [u8], |
311 | | prestate: PrefilterState, |
312 | | finder: Finder<'n>, |
313 | | pos: usize, |
314 | | } |
315 | | |
316 | | impl<'h, 'n> FindIter<'h, 'n> { |
317 | | #[inline(always)] |
318 | 0 | pub(crate) fn new( |
319 | 0 | haystack: &'h [u8], |
320 | 0 | finder: Finder<'n>, |
321 | 0 | ) -> FindIter<'h, 'n> { |
322 | 0 | let prestate = finder.searcher.prefilter_state(); |
323 | 0 | FindIter { haystack, prestate, finder, pos: 0 } |
324 | 0 | } |
325 | | } |
326 | | |
327 | | impl<'h, 'n> Iterator for FindIter<'h, 'n> { |
328 | | type Item = usize; |
329 | | |
330 | 0 | fn next(&mut self) -> Option<usize> { |
331 | 0 | if self.pos > self.haystack.len() { |
332 | 0 | return None; |
333 | 0 | } |
334 | 0 | let result = self |
335 | 0 | .finder |
336 | 0 | .searcher |
337 | 0 | .find(&mut self.prestate, &self.haystack[self.pos..]); |
338 | 0 | match result { |
339 | 0 | None => None, |
340 | 0 | Some(i) => { |
341 | 0 | let pos = self.pos + i; |
342 | 0 | self.pos = pos + core::cmp::max(1, self.finder.needle().len()); |
343 | 0 | Some(pos) |
344 | | } |
345 | | } |
346 | 0 | } |
347 | | } |
348 | | |
349 | | /// An iterator over non-overlapping substring matches in reverse. |
350 | | /// |
351 | | /// Matches are reported by the byte offset at which they begin. |
352 | | /// |
353 | | /// `'h` is the lifetime of the haystack while `'n` is the lifetime of the |
354 | | /// needle. |
355 | | #[derive(Debug)] |
356 | | pub struct FindRevIter<'h, 'n> { |
357 | | haystack: &'h [u8], |
358 | | finder: FinderRev<'n>, |
359 | | /// When searching with an empty needle, this gets set to `None` after |
360 | | /// we've yielded the last element at `0`. |
361 | | pos: Option<usize>, |
362 | | } |
363 | | |
364 | | impl<'h, 'n> FindRevIter<'h, 'n> { |
365 | | #[inline(always)] |
366 | 0 | pub(crate) fn new( |
367 | 0 | haystack: &'h [u8], |
368 | 0 | finder: FinderRev<'n>, |
369 | 0 | ) -> FindRevIter<'h, 'n> { |
370 | 0 | let pos = Some(haystack.len()); |
371 | 0 | FindRevIter { haystack, finder, pos } |
372 | 0 | } |
373 | | } |
374 | | |
375 | | impl<'h, 'n> Iterator for FindRevIter<'h, 'n> { |
376 | | type Item = usize; |
377 | | |
378 | 0 | fn next(&mut self) -> Option<usize> { |
379 | 0 | let pos = match self.pos { |
380 | 0 | None => return None, |
381 | 0 | Some(pos) => pos, |
382 | | }; |
383 | 0 | let result = self.finder.rfind(&self.haystack[..pos]); |
384 | 0 | match result { |
385 | 0 | None => None, |
386 | 0 | Some(i) => { |
387 | 0 | if pos == i { |
388 | 0 | self.pos = pos.checked_sub(1); |
389 | 0 | } else { |
390 | 0 | self.pos = Some(i); |
391 | 0 | } |
392 | 0 | Some(i) |
393 | | } |
394 | | } |
395 | 0 | } |
396 | | } |
397 | | |
398 | | /// A single substring searcher fixed to a particular needle. |
399 | | /// |
400 | | /// The purpose of this type is to permit callers to construct a substring |
401 | | /// searcher that can be used to search haystacks without the overhead of |
402 | | /// constructing the searcher in the first place. This is a somewhat niche |
403 | | /// concern when it's necessary to re-use the same needle to search multiple |
404 | | /// different haystacks with as little overhead as possible. In general, using |
405 | | /// [`find`] is good enough, but `Finder` is useful when you can meaningfully |
406 | | /// observe searcher construction time in a profile. |
407 | | /// |
408 | | /// When the `std` feature is enabled, then this type has an `into_owned` |
409 | | /// version which permits building a `Finder` that is not connected to |
410 | | /// the lifetime of its needle. |
411 | | #[derive(Clone, Debug)] |
412 | | pub struct Finder<'n> { |
413 | | searcher: Searcher<'n>, |
414 | | } |
415 | | |
416 | | impl<'n> Finder<'n> { |
417 | | /// Create a new finder for the given needle. |
418 | | #[inline] |
419 | 60 | pub fn new<B: ?Sized + AsRef<[u8]>>(needle: &'n B) -> Finder<'n> { |
420 | 60 | FinderBuilder::new().build_forward(needle) |
421 | 60 | } <memchr::memmem::Finder>::new::<[u8]> Line | Count | Source | 419 | 60 | pub fn new<B: ?Sized + AsRef<[u8]>>(needle: &'n B) -> Finder<'n> { | 420 | 60 | FinderBuilder::new().build_forward(needle) | 421 | 60 | } |
Unexecuted instantiation: <memchr::memmem::Finder>::new::<_> |
422 | | |
423 | | /// Returns the index of the first occurrence of this needle in the given |
424 | | /// haystack. |
425 | | /// |
426 | | /// # Complexity |
427 | | /// |
428 | | /// This routine is guaranteed to have worst case linear time complexity |
429 | | /// with respect to both the needle and the haystack. That is, this runs |
430 | | /// in `O(needle.len() + haystack.len())` time. |
431 | | /// |
432 | | /// This routine is also guaranteed to have worst case constant space |
433 | | /// complexity. |
434 | | /// |
435 | | /// # Examples |
436 | | /// |
437 | | /// Basic usage: |
438 | | /// |
439 | | /// ``` |
440 | | /// use memchr::memmem::Finder; |
441 | | /// |
442 | | /// let haystack = b"foo bar baz"; |
443 | | /// assert_eq!(Some(0), Finder::new("foo").find(haystack)); |
444 | | /// assert_eq!(Some(4), Finder::new("bar").find(haystack)); |
445 | | /// assert_eq!(None, Finder::new("quux").find(haystack)); |
446 | | /// ``` |
447 | 0 | pub fn find(&self, haystack: &[u8]) -> Option<usize> { |
448 | 0 | self.searcher.find(&mut self.searcher.prefilter_state(), haystack) |
449 | 0 | } |
450 | | |
451 | | /// Returns an iterator over all occurrences of a substring in a haystack. |
452 | | /// |
453 | | /// # Complexity |
454 | | /// |
455 | | /// This routine is guaranteed to have worst case linear time complexity |
456 | | /// with respect to both the needle and the haystack. That is, this runs |
457 | | /// in `O(needle.len() + haystack.len())` time. |
458 | | /// |
459 | | /// This routine is also guaranteed to have worst case constant space |
460 | | /// complexity. |
461 | | /// |
462 | | /// # Examples |
463 | | /// |
464 | | /// Basic usage: |
465 | | /// |
466 | | /// ``` |
467 | | /// use memchr::memmem::Finder; |
468 | | /// |
469 | | /// let haystack = b"foo bar foo baz foo"; |
470 | | /// let finder = Finder::new(b"foo"); |
471 | | /// let mut it = finder.find_iter(haystack); |
472 | | /// assert_eq!(Some(0), it.next()); |
473 | | /// assert_eq!(Some(8), it.next()); |
474 | | /// assert_eq!(Some(16), it.next()); |
475 | | /// assert_eq!(None, it.next()); |
476 | | /// ``` |
477 | | #[inline] |
478 | 0 | pub fn find_iter<'a, 'h>( |
479 | 0 | &'a self, |
480 | 0 | haystack: &'h [u8], |
481 | 0 | ) -> FindIter<'h, 'a> { |
482 | 0 | FindIter::new(haystack, self.as_ref()) |
483 | 0 | } |
484 | | |
485 | | /// Convert this finder into its owned variant, such that it no longer |
486 | | /// borrows the needle. |
487 | | /// |
488 | | /// If this is already an owned finder, then this is a no-op. Otherwise, |
489 | | /// this copies the needle. |
490 | | /// |
491 | | /// This is only available when the `std` feature is enabled. |
492 | | #[cfg(feature = "std")] |
493 | | #[inline] |
494 | 60 | pub fn into_owned(self) -> Finder<'static> { |
495 | 60 | Finder { searcher: self.searcher.into_owned() } |
496 | 60 | } |
497 | | |
498 | | /// Convert this finder into its borrowed variant. |
499 | | /// |
500 | | /// This is primarily useful if your finder is owned and you'd like to |
501 | | /// store its borrowed variant in some intermediate data structure. |
502 | | /// |
503 | | /// Note that the lifetime parameter of the returned finder is tied to the |
504 | | /// lifetime of `self`, and may be shorter than the `'n` lifetime of the |
505 | | /// needle itself. Namely, a finder's needle can be either borrowed or |
506 | | /// owned, so the lifetime of the needle returned must necessarily be the |
507 | | /// shorter of the two. |
508 | | #[inline] |
509 | 0 | pub fn as_ref(&self) -> Finder<'_> { |
510 | 0 | Finder { searcher: self.searcher.as_ref() } |
511 | 0 | } |
512 | | |
513 | | /// Returns the needle that this finder searches for. |
514 | | /// |
515 | | /// Note that the lifetime of the needle returned is tied to the lifetime |
516 | | /// of the finder, and may be shorter than the `'n` lifetime. Namely, a |
517 | | /// finder's needle can be either borrowed or owned, so the lifetime of the |
518 | | /// needle returned must necessarily be the shorter of the two. |
519 | | #[inline] |
520 | 0 | pub fn needle(&self) -> &[u8] { |
521 | 0 | self.searcher.needle() |
522 | 0 | } |
523 | | } |
524 | | |
525 | | /// A single substring reverse searcher fixed to a particular needle. |
526 | | /// |
527 | | /// The purpose of this type is to permit callers to construct a substring |
528 | | /// searcher that can be used to search haystacks without the overhead of |
529 | | /// constructing the searcher in the first place. This is a somewhat niche |
530 | | /// concern when it's necessary to re-use the same needle to search multiple |
531 | | /// different haystacks with as little overhead as possible. In general, |
532 | | /// using [`rfind`] is good enough, but `FinderRev` is useful when you can |
533 | | /// meaningfully observe searcher construction time in a profile. |
534 | | /// |
535 | | /// When the `std` feature is enabled, then this type has an `into_owned` |
536 | | /// version which permits building a `FinderRev` that is not connected to |
537 | | /// the lifetime of its needle. |
538 | | #[derive(Clone, Debug)] |
539 | | pub struct FinderRev<'n> { |
540 | | searcher: SearcherRev<'n>, |
541 | | } |
542 | | |
543 | | impl<'n> FinderRev<'n> { |
544 | | /// Create a new reverse finder for the given needle. |
545 | | #[inline] |
546 | 0 | pub fn new<B: ?Sized + AsRef<[u8]>>(needle: &'n B) -> FinderRev<'n> { |
547 | 0 | FinderBuilder::new().build_reverse(needle) |
548 | 0 | } |
549 | | |
550 | | /// Returns the index of the last occurrence of this needle in the given |
551 | | /// haystack. |
552 | | /// |
553 | | /// The haystack may be any type that can be cheaply converted into a |
554 | | /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. |
555 | | /// |
556 | | /// # Complexity |
557 | | /// |
558 | | /// This routine is guaranteed to have worst case linear time complexity |
559 | | /// with respect to both the needle and the haystack. That is, this runs |
560 | | /// in `O(needle.len() + haystack.len())` time. |
561 | | /// |
562 | | /// This routine is also guaranteed to have worst case constant space |
563 | | /// complexity. |
564 | | /// |
565 | | /// # Examples |
566 | | /// |
567 | | /// Basic usage: |
568 | | /// |
569 | | /// ``` |
570 | | /// use memchr::memmem::FinderRev; |
571 | | /// |
572 | | /// let haystack = b"foo bar baz"; |
573 | | /// assert_eq!(Some(0), FinderRev::new("foo").rfind(haystack)); |
574 | | /// assert_eq!(Some(4), FinderRev::new("bar").rfind(haystack)); |
575 | | /// assert_eq!(None, FinderRev::new("quux").rfind(haystack)); |
576 | | /// ``` |
577 | 0 | pub fn rfind<B: AsRef<[u8]>>(&self, haystack: B) -> Option<usize> { |
578 | 0 | self.searcher.rfind(haystack.as_ref()) |
579 | 0 | } |
580 | | |
581 | | /// Returns a reverse iterator over all occurrences of a substring in a |
582 | | /// haystack. |
583 | | /// |
584 | | /// # Complexity |
585 | | /// |
586 | | /// This routine is guaranteed to have worst case linear time complexity |
587 | | /// with respect to both the needle and the haystack. That is, this runs |
588 | | /// in `O(needle.len() + haystack.len())` time. |
589 | | /// |
590 | | /// This routine is also guaranteed to have worst case constant space |
591 | | /// complexity. |
592 | | /// |
593 | | /// # Examples |
594 | | /// |
595 | | /// Basic usage: |
596 | | /// |
597 | | /// ``` |
598 | | /// use memchr::memmem::FinderRev; |
599 | | /// |
600 | | /// let haystack = b"foo bar foo baz foo"; |
601 | | /// let finder = FinderRev::new(b"foo"); |
602 | | /// let mut it = finder.rfind_iter(haystack); |
603 | | /// assert_eq!(Some(16), it.next()); |
604 | | /// assert_eq!(Some(8), it.next()); |
605 | | /// assert_eq!(Some(0), it.next()); |
606 | | /// assert_eq!(None, it.next()); |
607 | | /// ``` |
608 | | #[inline] |
609 | 0 | pub fn rfind_iter<'a, 'h>( |
610 | 0 | &'a self, |
611 | 0 | haystack: &'h [u8], |
612 | 0 | ) -> FindRevIter<'h, 'a> { |
613 | 0 | FindRevIter::new(haystack, self.as_ref()) |
614 | 0 | } |
615 | | |
616 | | /// Convert this finder into its owned variant, such that it no longer |
617 | | /// borrows the needle. |
618 | | /// |
619 | | /// If this is already an owned finder, then this is a no-op. Otherwise, |
620 | | /// this copies the needle. |
621 | | /// |
622 | | /// This is only available when the `std` feature is enabled. |
623 | | #[cfg(feature = "std")] |
624 | | #[inline] |
625 | 0 | pub fn into_owned(self) -> FinderRev<'static> { |
626 | 0 | FinderRev { searcher: self.searcher.into_owned() } |
627 | 0 | } |
628 | | |
629 | | /// Convert this finder into its borrowed variant. |
630 | | /// |
631 | | /// This is primarily useful if your finder is owned and you'd like to |
632 | | /// store its borrowed variant in some intermediate data structure. |
633 | | /// |
634 | | /// Note that the lifetime parameter of the returned finder is tied to the |
635 | | /// lifetime of `self`, and may be shorter than the `'n` lifetime of the |
636 | | /// needle itself. Namely, a finder's needle can be either borrowed or |
637 | | /// owned, so the lifetime of the needle returned must necessarily be the |
638 | | /// shorter of the two. |
639 | | #[inline] |
640 | 0 | pub fn as_ref(&self) -> FinderRev<'_> { |
641 | 0 | FinderRev { searcher: self.searcher.as_ref() } |
642 | 0 | } |
643 | | |
644 | | /// Returns the needle that this finder searches for. |
645 | | /// |
646 | | /// Note that the lifetime of the needle returned is tied to the lifetime |
647 | | /// of the finder, and may be shorter than the `'n` lifetime. Namely, a |
648 | | /// finder's needle can be either borrowed or owned, so the lifetime of the |
649 | | /// needle returned must necessarily be the shorter of the two. |
650 | | #[inline] |
651 | 0 | pub fn needle(&self) -> &[u8] { |
652 | 0 | self.searcher.needle() |
653 | 0 | } |
654 | | } |
655 | | |
656 | | /// A builder for constructing non-default forward or reverse memmem finders. |
657 | | /// |
658 | | /// A builder is primarily useful for configuring a substring searcher. |
659 | | /// Currently, the only configuration exposed is the ability to disable |
660 | | /// heuristic prefilters used to speed up certain searches. |
661 | | #[derive(Clone, Debug, Default)] |
662 | | pub struct FinderBuilder { |
663 | | config: SearcherConfig, |
664 | | } |
665 | | |
666 | | impl FinderBuilder { |
667 | | /// Create a new finder builder with default settings. |
668 | 60 | pub fn new() -> FinderBuilder { |
669 | 60 | FinderBuilder::default() |
670 | 60 | } |
671 | | |
672 | | /// Build a forward finder using the given needle from the current |
673 | | /// settings. |
674 | 60 | pub fn build_forward<'n, B: ?Sized + AsRef<[u8]>>( |
675 | 60 | &self, |
676 | 60 | needle: &'n B, |
677 | 60 | ) -> Finder<'n> { |
678 | 60 | Finder { searcher: Searcher::new(self.config, needle.as_ref()) } |
679 | 60 | } <memchr::memmem::FinderBuilder>::build_forward::<[u8]> Line | Count | Source | 674 | 60 | pub fn build_forward<'n, B: ?Sized + AsRef<[u8]>>( | 675 | 60 | &self, | 676 | 60 | needle: &'n B, | 677 | 60 | ) -> Finder<'n> { | 678 | 60 | Finder { searcher: Searcher::new(self.config, needle.as_ref()) } | 679 | 60 | } |
Unexecuted instantiation: <memchr::memmem::FinderBuilder>::build_forward::<_> |
680 | | |
681 | | /// Build a reverse finder using the given needle from the current |
682 | | /// settings. |
683 | 0 | pub fn build_reverse<'n, B: ?Sized + AsRef<[u8]>>( |
684 | 0 | &self, |
685 | 0 | needle: &'n B, |
686 | 0 | ) -> FinderRev<'n> { |
687 | 0 | FinderRev { searcher: SearcherRev::new(needle.as_ref()) } |
688 | 0 | } |
689 | | |
690 | | /// Configure the prefilter setting for the finder. |
691 | | /// |
692 | | /// See the documentation for [`Prefilter`] for more discussion on why |
693 | | /// you might want to configure this. |
694 | 0 | pub fn prefilter(&mut self, prefilter: Prefilter) -> &mut FinderBuilder { |
695 | 0 | self.config.prefilter = prefilter; |
696 | 0 | self |
697 | 0 | } |
698 | | } |
699 | | |
700 | | /// The internal implementation of a forward substring searcher. |
701 | | /// |
702 | | /// The reality is that this is a "meta" searcher. Namely, depending on a |
703 | | /// variety of parameters (CPU support, target, needle size, haystack size and |
704 | | /// even dynamic properties such as prefilter effectiveness), the actual |
705 | | /// algorithm employed to do substring search may change. |
706 | | #[derive(Clone, Debug)] |
707 | | struct Searcher<'n> { |
708 | | /// The actual needle we're searching for. |
709 | | /// |
710 | | /// A CowBytes is like a Cow<[u8]>, except in no_std environments, it is |
711 | | /// specialized to a single variant (the borrowed form). |
712 | | needle: CowBytes<'n>, |
713 | | /// A collection of facts computed on the needle that are useful for more |
714 | | /// than one substring search algorithm. |
715 | | ninfo: NeedleInfo, |
716 | | /// A prefilter function, if it was deemed appropriate. |
717 | | /// |
718 | | /// Some substring search implementations (like Two-Way) benefit greatly |
719 | | /// if we can quickly find candidate starting positions for a match. |
720 | | prefn: Option<PrefilterFn>, |
721 | | /// The actual substring implementation in use. |
722 | | kind: SearcherKind, |
723 | | } |
724 | | |
725 | | /// A collection of facts computed about a search needle. |
726 | | /// |
727 | | /// We group these things together because it's useful to be able to hand them |
728 | | /// to prefilters or substring algorithms that want them. |
729 | | #[derive(Clone, Copy, Debug)] |
730 | | pub(crate) struct NeedleInfo { |
731 | | /// The offsets of "rare" bytes detected in the needle. |
732 | | /// |
733 | | /// This is meant to be a heuristic in order to maximize the effectiveness |
734 | | /// of vectorized code. Namely, vectorized code tends to focus on only |
735 | | /// one or two bytes. If we pick bytes from the needle that occur |
736 | | /// infrequently, then more time will be spent in the vectorized code and |
737 | | /// will likely make the overall search (much) faster. |
738 | | /// |
739 | | /// Of course, this is only a heuristic based on a background frequency |
740 | | /// distribution of bytes. But it tends to work very well in practice. |
741 | | pub(crate) rarebytes: RareNeedleBytes, |
742 | | /// A Rabin-Karp hash of the needle. |
743 | | /// |
744 | | /// This is store here instead of in a more specific Rabin-Karp search |
745 | | /// since Rabin-Karp may be used even if another SearchKind corresponds |
746 | | /// to some other search implementation. e.g., If measurements suggest RK |
747 | | /// is faster in some cases or if a search implementation can't handle |
748 | | /// particularly small haystack. (Moreover, we cannot use RK *generally*, |
749 | | /// since its worst case time is multiplicative. Instead, we only use it |
750 | | /// some small haystacks, where "small" is a constant.) |
751 | | pub(crate) nhash: NeedleHash, |
752 | | } |
753 | | |
754 | | /// Configuration for substring search. |
755 | | #[derive(Clone, Copy, Debug, Default)] |
756 | | struct SearcherConfig { |
757 | | /// This permits changing the behavior of the prefilter, since it can have |
758 | | /// a variable impact on performance. |
759 | | prefilter: Prefilter, |
760 | | } |
761 | | |
762 | | #[derive(Clone, Debug)] |
763 | | enum SearcherKind { |
764 | | /// A special case for empty needles. An empty needle always matches, even |
765 | | /// in an empty haystack. |
766 | | Empty, |
767 | | /// This is used whenever the needle is a single byte. In this case, we |
768 | | /// always use memchr. |
769 | | OneByte(u8), |
770 | | /// Two-Way is the generic work horse and is what provides our additive |
771 | | /// linear time guarantee. In general, it's used when the needle is bigger |
772 | | /// than 8 bytes or so. |
773 | | TwoWay(twoway::Forward), |
774 | | #[cfg(all(not(miri), target_arch = "x86_64", memchr_runtime_simd))] |
775 | | GenericSIMD128(x86::sse::Forward), |
776 | | #[cfg(all(not(miri), target_arch = "x86_64", memchr_runtime_simd))] |
777 | | GenericSIMD256(x86::avx::Forward), |
778 | | } |
779 | | |
780 | | impl<'n> Searcher<'n> { |
781 | | #[cfg(all(not(miri), target_arch = "x86_64", memchr_runtime_simd))] |
782 | 60 | fn new(config: SearcherConfig, needle: &'n [u8]) -> Searcher<'n> { |
783 | | use self::SearcherKind::*; |
784 | | |
785 | 60 | let ninfo = NeedleInfo::new(needle); |
786 | 60 | let prefn = |
787 | 60 | prefilter::forward(&config.prefilter, &ninfo.rarebytes, needle); |
788 | 60 | let kind = if needle.len() == 0 { |
789 | 60 | Empty |
790 | 0 | } else if needle.len() == 1 { |
791 | 0 | OneByte(needle[0]) |
792 | 0 | } else if let Some(fwd) = x86::avx::Forward::new(&ninfo, needle) { |
793 | 0 | GenericSIMD256(fwd) |
794 | 0 | } else if let Some(fwd) = x86::sse::Forward::new(&ninfo, needle) { |
795 | 0 | GenericSIMD128(fwd) |
796 | | } else { |
797 | 0 | TwoWay(twoway::Forward::new(needle)) |
798 | | }; |
799 | 60 | Searcher { needle: CowBytes::new(needle), ninfo, prefn, kind } |
800 | 60 | } |
801 | | |
802 | | #[cfg(not(all(not(miri), target_arch = "x86_64", memchr_runtime_simd)))] |
803 | | fn new(config: SearcherConfig, needle: &'n [u8]) -> Searcher<'n> { |
804 | | use self::SearcherKind::*; |
805 | | |
806 | | let ninfo = NeedleInfo::new(needle); |
807 | | let prefn = |
808 | | prefilter::forward(&config.prefilter, &ninfo.rarebytes, needle); |
809 | | let kind = if needle.len() == 0 { |
810 | | Empty |
811 | | } else if needle.len() == 1 { |
812 | | OneByte(needle[0]) |
813 | | } else { |
814 | | TwoWay(twoway::Forward::new(needle)) |
815 | | }; |
816 | | Searcher { needle: CowBytes::new(needle), ninfo, prefn, kind } |
817 | | } |
818 | | |
819 | | /// Return a fresh prefilter state that can be used with this searcher. |
820 | | /// A prefilter state is used to track the effectiveness of a searcher's |
821 | | /// prefilter for speeding up searches. Therefore, the prefilter state |
822 | | /// should generally be reused on subsequent searches (such as in an |
823 | | /// iterator). For searches on a different haystack, then a new prefilter |
824 | | /// state should be used. |
825 | | /// |
826 | | /// This always initializes a valid (but possibly inert) prefilter state |
827 | | /// even if this searcher does not have a prefilter enabled. |
828 | 0 | fn prefilter_state(&self) -> PrefilterState { |
829 | 0 | if self.prefn.is_none() { |
830 | 0 | PrefilterState::inert() |
831 | | } else { |
832 | 0 | PrefilterState::new() |
833 | | } |
834 | 0 | } |
835 | | |
836 | 0 | fn needle(&self) -> &[u8] { |
837 | 0 | self.needle.as_slice() |
838 | 0 | } |
839 | | |
840 | 0 | fn as_ref(&self) -> Searcher<'_> { |
841 | | use self::SearcherKind::*; |
842 | | |
843 | 0 | let kind = match self.kind { |
844 | 0 | Empty => Empty, |
845 | 0 | OneByte(b) => OneByte(b), |
846 | 0 | TwoWay(tw) => TwoWay(tw), |
847 | | #[cfg(all( |
848 | | not(miri), |
849 | | target_arch = "x86_64", |
850 | | memchr_runtime_simd |
851 | | ))] |
852 | 0 | GenericSIMD128(gs) => GenericSIMD128(gs), |
853 | | #[cfg(all( |
854 | | not(miri), |
855 | | target_arch = "x86_64", |
856 | | memchr_runtime_simd |
857 | | ))] |
858 | 0 | GenericSIMD256(gs) => GenericSIMD256(gs), |
859 | | }; |
860 | 0 | Searcher { |
861 | 0 | needle: CowBytes::new(self.needle()), |
862 | 0 | ninfo: self.ninfo, |
863 | 0 | prefn: self.prefn, |
864 | 0 | kind, |
865 | 0 | } |
866 | 0 | } |
867 | | |
868 | | #[cfg(feature = "std")] |
869 | 60 | fn into_owned(self) -> Searcher<'static> { |
870 | | use self::SearcherKind::*; |
871 | | |
872 | 60 | let kind = match self.kind { |
873 | 60 | Empty => Empty, |
874 | 0 | OneByte(b) => OneByte(b), |
875 | 0 | TwoWay(tw) => TwoWay(tw), |
876 | | #[cfg(all( |
877 | | not(miri), |
878 | | target_arch = "x86_64", |
879 | | memchr_runtime_simd |
880 | | ))] |
881 | 0 | GenericSIMD128(gs) => GenericSIMD128(gs), |
882 | | #[cfg(all( |
883 | | not(miri), |
884 | | target_arch = "x86_64", |
885 | | memchr_runtime_simd |
886 | | ))] |
887 | 0 | GenericSIMD256(gs) => GenericSIMD256(gs), |
888 | | }; |
889 | 60 | Searcher { |
890 | 60 | needle: self.needle.into_owned(), |
891 | 60 | ninfo: self.ninfo, |
892 | 60 | prefn: self.prefn, |
893 | 60 | kind, |
894 | 60 | } |
895 | 60 | } |
896 | | |
897 | | /// Implements forward substring search by selecting the implementation |
898 | | /// chosen at construction and executing it on the given haystack with the |
899 | | /// prefilter's current state of effectiveness. |
900 | | #[inline(always)] |
901 | 0 | fn find( |
902 | 0 | &self, |
903 | 0 | state: &mut PrefilterState, |
904 | 0 | haystack: &[u8], |
905 | 0 | ) -> Option<usize> { |
906 | | use self::SearcherKind::*; |
907 | | |
908 | 0 | let needle = self.needle(); |
909 | 0 | if haystack.len() < needle.len() { |
910 | 0 | return None; |
911 | 0 | } |
912 | 0 | match self.kind { |
913 | 0 | Empty => Some(0), |
914 | 0 | OneByte(b) => crate::memchr(b, haystack), |
915 | 0 | TwoWay(ref tw) => { |
916 | | // For very short haystacks (e.g., where the prefilter probably |
917 | | // can't run), it's faster to just run RK. |
918 | 0 | if rabinkarp::is_fast(haystack, needle) { |
919 | 0 | rabinkarp::find_with(&self.ninfo.nhash, haystack, needle) |
920 | | } else { |
921 | 0 | self.find_tw(tw, state, haystack, needle) |
922 | | } |
923 | | } |
924 | | #[cfg(all( |
925 | | not(miri), |
926 | | target_arch = "x86_64", |
927 | | memchr_runtime_simd |
928 | | ))] |
929 | 0 | GenericSIMD128(ref gs) => { |
930 | | // The SIMD matcher can't handle particularly short haystacks, |
931 | | // so we fall back to RK in these cases. |
932 | 0 | if haystack.len() < gs.min_haystack_len() { |
933 | 0 | rabinkarp::find_with(&self.ninfo.nhash, haystack, needle) |
934 | | } else { |
935 | 0 | gs.find(haystack, needle) |
936 | | } |
937 | | } |
938 | | #[cfg(all( |
939 | | not(miri), |
940 | | target_arch = "x86_64", |
941 | | memchr_runtime_simd |
942 | | ))] |
943 | 0 | GenericSIMD256(ref gs) => { |
944 | | // The SIMD matcher can't handle particularly short haystacks, |
945 | | // so we fall back to RK in these cases. |
946 | 0 | if haystack.len() < gs.min_haystack_len() { |
947 | 0 | rabinkarp::find_with(&self.ninfo.nhash, haystack, needle) |
948 | | } else { |
949 | 0 | gs.find(haystack, needle) |
950 | | } |
951 | | } |
952 | | } |
953 | 0 | } |
954 | | |
955 | | /// Calls Two-Way on the given haystack/needle. |
956 | | /// |
957 | | /// This is marked as unlineable since it seems to have a better overall |
958 | | /// effect on benchmarks. However, this is one of those cases where |
959 | | /// inlining it results an improvement in other benchmarks too, so I |
960 | | /// suspect we just don't have enough data yet to make the right call here. |
961 | | /// |
962 | | /// I suspect the main problem is that this function contains two different |
963 | | /// inlined copies of Two-Way: one with and one without prefilters enabled. |
964 | | #[inline(never)] |
965 | 0 | fn find_tw( |
966 | 0 | &self, |
967 | 0 | tw: &twoway::Forward, |
968 | 0 | state: &mut PrefilterState, |
969 | 0 | haystack: &[u8], |
970 | 0 | needle: &[u8], |
971 | 0 | ) -> Option<usize> { |
972 | 0 | if let Some(prefn) = self.prefn { |
973 | | // We used to look at the length of a haystack here. That is, if |
974 | | // it was too small, then don't bother with the prefilter. But two |
975 | | // things changed: the prefilter falls back to memchr for small |
976 | | // haystacks, and, above, Rabin-Karp is employed for tiny haystacks |
977 | | // anyway. |
978 | 0 | if state.is_effective() { |
979 | 0 | let mut pre = Pre { state, prefn, ninfo: &self.ninfo }; |
980 | 0 | return tw.find(Some(&mut pre), haystack, needle); |
981 | 0 | } |
982 | 0 | } |
983 | 0 | tw.find(None, haystack, needle) |
984 | 0 | } |
985 | | } |
986 | | |
987 | | impl NeedleInfo { |
988 | 60 | pub(crate) fn new(needle: &[u8]) -> NeedleInfo { |
989 | 60 | NeedleInfo { |
990 | 60 | rarebytes: RareNeedleBytes::forward(needle), |
991 | 60 | nhash: NeedleHash::forward(needle), |
992 | 60 | } |
993 | 60 | } |
994 | | } |
995 | | |
996 | | /// The internal implementation of a reverse substring searcher. |
997 | | /// |
998 | | /// See the forward searcher docs for more details. Currently, the reverse |
999 | | /// searcher is considerably simpler since it lacks prefilter support. This |
1000 | | /// was done because it adds a lot of code, and more surface area to test. And |
1001 | | /// in particular, it's not clear whether a prefilter on reverse searching is |
1002 | | /// worth it. (If you have a compelling use case, please file an issue!) |
1003 | | #[derive(Clone, Debug)] |
1004 | | struct SearcherRev<'n> { |
1005 | | /// The actual needle we're searching for. |
1006 | | needle: CowBytes<'n>, |
1007 | | /// A Rabin-Karp hash of the needle. |
1008 | | nhash: NeedleHash, |
1009 | | /// The actual substring implementation in use. |
1010 | | kind: SearcherRevKind, |
1011 | | } |
1012 | | |
1013 | | #[derive(Clone, Debug)] |
1014 | | enum SearcherRevKind { |
1015 | | /// A special case for empty needles. An empty needle always matches, even |
1016 | | /// in an empty haystack. |
1017 | | Empty, |
1018 | | /// This is used whenever the needle is a single byte. In this case, we |
1019 | | /// always use memchr. |
1020 | | OneByte(u8), |
1021 | | /// Two-Way is the generic work horse and is what provides our additive |
1022 | | /// linear time guarantee. In general, it's used when the needle is bigger |
1023 | | /// than 8 bytes or so. |
1024 | | TwoWay(twoway::Reverse), |
1025 | | } |
1026 | | |
1027 | | impl<'n> SearcherRev<'n> { |
1028 | 0 | fn new(needle: &'n [u8]) -> SearcherRev<'n> { |
1029 | | use self::SearcherRevKind::*; |
1030 | | |
1031 | 0 | let kind = if needle.len() == 0 { |
1032 | 0 | Empty |
1033 | 0 | } else if needle.len() == 1 { |
1034 | 0 | OneByte(needle[0]) |
1035 | | } else { |
1036 | 0 | TwoWay(twoway::Reverse::new(needle)) |
1037 | | }; |
1038 | 0 | SearcherRev { |
1039 | 0 | needle: CowBytes::new(needle), |
1040 | 0 | nhash: NeedleHash::reverse(needle), |
1041 | 0 | kind, |
1042 | 0 | } |
1043 | 0 | } |
1044 | | |
1045 | 0 | fn needle(&self) -> &[u8] { |
1046 | 0 | self.needle.as_slice() |
1047 | 0 | } |
1048 | | |
1049 | 0 | fn as_ref(&self) -> SearcherRev<'_> { |
1050 | | use self::SearcherRevKind::*; |
1051 | | |
1052 | 0 | let kind = match self.kind { |
1053 | 0 | Empty => Empty, |
1054 | 0 | OneByte(b) => OneByte(b), |
1055 | 0 | TwoWay(tw) => TwoWay(tw), |
1056 | | }; |
1057 | 0 | SearcherRev { |
1058 | 0 | needle: CowBytes::new(self.needle()), |
1059 | 0 | nhash: self.nhash, |
1060 | 0 | kind, |
1061 | 0 | } |
1062 | 0 | } |
1063 | | |
1064 | | #[cfg(feature = "std")] |
1065 | 0 | fn into_owned(self) -> SearcherRev<'static> { |
1066 | | use self::SearcherRevKind::*; |
1067 | | |
1068 | 0 | let kind = match self.kind { |
1069 | 0 | Empty => Empty, |
1070 | 0 | OneByte(b) => OneByte(b), |
1071 | 0 | TwoWay(tw) => TwoWay(tw), |
1072 | | }; |
1073 | 0 | SearcherRev { |
1074 | 0 | needle: self.needle.into_owned(), |
1075 | 0 | nhash: self.nhash, |
1076 | 0 | kind, |
1077 | 0 | } |
1078 | 0 | } |
1079 | | |
1080 | | /// Implements reverse substring search by selecting the implementation |
1081 | | /// chosen at construction and executing it on the given haystack with the |
1082 | | /// prefilter's current state of effectiveness. |
1083 | | #[inline(always)] |
1084 | 0 | fn rfind(&self, haystack: &[u8]) -> Option<usize> { |
1085 | | use self::SearcherRevKind::*; |
1086 | | |
1087 | 0 | let needle = self.needle(); |
1088 | 0 | if haystack.len() < needle.len() { |
1089 | 0 | return None; |
1090 | 0 | } |
1091 | 0 | match self.kind { |
1092 | 0 | Empty => Some(haystack.len()), |
1093 | 0 | OneByte(b) => crate::memrchr(b, haystack), |
1094 | 0 | TwoWay(ref tw) => { |
1095 | | // For very short haystacks (e.g., where the prefilter probably |
1096 | | // can't run), it's faster to just run RK. |
1097 | 0 | if rabinkarp::is_fast(haystack, needle) { |
1098 | 0 | rabinkarp::rfind_with(&self.nhash, haystack, needle) |
1099 | | } else { |
1100 | 0 | tw.rfind(haystack, needle) |
1101 | | } |
1102 | | } |
1103 | | } |
1104 | 0 | } |
1105 | | } |
1106 | | |
1107 | | /// This module defines some generic quickcheck properties useful for testing |
1108 | | /// any substring search algorithm. It also runs those properties for the |
1109 | | /// top-level public API memmem routines. (The properties are also used to |
1110 | | /// test various substring search implementations more granularly elsewhere as |
1111 | | /// well.) |
1112 | | #[cfg(all(test, feature = "std", not(miri)))] |
1113 | | mod proptests { |
1114 | | // N.B. This defines the quickcheck tests using the properties defined |
1115 | | // below. Because of macro-visibility weirdness, the actual macro is |
1116 | | // defined at the top of this file. |
1117 | | define_memmem_quickcheck_tests!(super::find, super::rfind); |
1118 | | |
1119 | | /// Check that every prefix of the given byte string is a substring. |
1120 | | pub(crate) fn prefix_is_substring( |
1121 | | reverse: bool, |
1122 | | bs: &[u8], |
1123 | | mut search: impl FnMut(&[u8], &[u8]) -> Option<usize>, |
1124 | | ) -> bool { |
1125 | | if bs.is_empty() { |
1126 | | return true; |
1127 | | } |
1128 | | for i in 0..(bs.len() - 1) { |
1129 | | let prefix = &bs[..i]; |
1130 | | if reverse { |
1131 | | assert_eq!(naive_rfind(bs, prefix), search(bs, prefix)); |
1132 | | } else { |
1133 | | assert_eq!(naive_find(bs, prefix), search(bs, prefix)); |
1134 | | } |
1135 | | } |
1136 | | true |
1137 | | } |
1138 | | |
1139 | | /// Check that every suffix of the given byte string is a substring. |
1140 | | pub(crate) fn suffix_is_substring( |
1141 | | reverse: bool, |
1142 | | bs: &[u8], |
1143 | | mut search: impl FnMut(&[u8], &[u8]) -> Option<usize>, |
1144 | | ) -> bool { |
1145 | | if bs.is_empty() { |
1146 | | return true; |
1147 | | } |
1148 | | for i in 0..(bs.len() - 1) { |
1149 | | let suffix = &bs[i..]; |
1150 | | if reverse { |
1151 | | assert_eq!(naive_rfind(bs, suffix), search(bs, suffix)); |
1152 | | } else { |
1153 | | assert_eq!(naive_find(bs, suffix), search(bs, suffix)); |
1154 | | } |
1155 | | } |
1156 | | true |
1157 | | } |
1158 | | |
1159 | | /// Check that naive substring search matches the result of the given search |
1160 | | /// algorithm. |
1161 | | pub(crate) fn matches_naive( |
1162 | | reverse: bool, |
1163 | | haystack: &[u8], |
1164 | | needle: &[u8], |
1165 | | mut search: impl FnMut(&[u8], &[u8]) -> Option<usize>, |
1166 | | ) -> bool { |
1167 | | if reverse { |
1168 | | naive_rfind(haystack, needle) == search(haystack, needle) |
1169 | | } else { |
1170 | | naive_find(haystack, needle) == search(haystack, needle) |
1171 | | } |
1172 | | } |
1173 | | |
1174 | | /// Naively search forwards for the given needle in the given haystack. |
1175 | | fn naive_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { |
1176 | | if needle.is_empty() { |
1177 | | return Some(0); |
1178 | | } else if haystack.len() < needle.len() { |
1179 | | return None; |
1180 | | } |
1181 | | for i in 0..(haystack.len() - needle.len() + 1) { |
1182 | | if needle == &haystack[i..i + needle.len()] { |
1183 | | return Some(i); |
1184 | | } |
1185 | | } |
1186 | | None |
1187 | | } |
1188 | | |
1189 | | /// Naively search in reverse for the given needle in the given haystack. |
1190 | | fn naive_rfind(haystack: &[u8], needle: &[u8]) -> Option<usize> { |
1191 | | if needle.is_empty() { |
1192 | | return Some(haystack.len()); |
1193 | | } else if haystack.len() < needle.len() { |
1194 | | return None; |
1195 | | } |
1196 | | for i in (0..(haystack.len() - needle.len() + 1)).rev() { |
1197 | | if needle == &haystack[i..i + needle.len()] { |
1198 | | return Some(i); |
1199 | | } |
1200 | | } |
1201 | | None |
1202 | | } |
1203 | | } |
1204 | | |
1205 | | /// This module defines some hand-written "simple" substring tests. It |
1206 | | /// also provides routines for easily running them on any substring search |
1207 | | /// implementation. |
1208 | | #[cfg(test)] |
1209 | | mod testsimples { |
1210 | | define_memmem_simple_tests!(super::find, super::rfind); |
1211 | | |
1212 | | /// Each test is a (needle, haystack, expected_fwd, expected_rev) tuple. |
1213 | | type SearchTest = |
1214 | | (&'static str, &'static str, Option<usize>, Option<usize>); |
1215 | | |
1216 | | const SEARCH_TESTS: &'static [SearchTest] = &[ |
1217 | | ("", "", Some(0), Some(0)), |
1218 | | ("", "a", Some(0), Some(1)), |
1219 | | ("", "ab", Some(0), Some(2)), |
1220 | | ("", "abc", Some(0), Some(3)), |
1221 | | ("a", "", None, None), |
1222 | | ("a", "a", Some(0), Some(0)), |
1223 | | ("a", "aa", Some(0), Some(1)), |
1224 | | ("a", "ba", Some(1), Some(1)), |
1225 | | ("a", "bba", Some(2), Some(2)), |
1226 | | ("a", "bbba", Some(3), Some(3)), |
1227 | | ("a", "bbbab", Some(3), Some(3)), |
1228 | | ("a", "bbbabb", Some(3), Some(3)), |
1229 | | ("a", "bbbabbb", Some(3), Some(3)), |
1230 | | ("a", "bbbbbb", None, None), |
1231 | | ("ab", "", None, None), |
1232 | | ("ab", "a", None, None), |
1233 | | ("ab", "b", None, None), |
1234 | | ("ab", "ab", Some(0), Some(0)), |
1235 | | ("ab", "aab", Some(1), Some(1)), |
1236 | | ("ab", "aaab", Some(2), Some(2)), |
1237 | | ("ab", "abaab", Some(0), Some(3)), |
1238 | | ("ab", "baaab", Some(3), Some(3)), |
1239 | | ("ab", "acb", None, None), |
1240 | | ("ab", "abba", Some(0), Some(0)), |
1241 | | ("abc", "ab", None, None), |
1242 | | ("abc", "abc", Some(0), Some(0)), |
1243 | | ("abc", "abcz", Some(0), Some(0)), |
1244 | | ("abc", "abczz", Some(0), Some(0)), |
1245 | | ("abc", "zabc", Some(1), Some(1)), |
1246 | | ("abc", "zzabc", Some(2), Some(2)), |
1247 | | ("abc", "azbc", None, None), |
1248 | | ("abc", "abzc", None, None), |
1249 | | ("abczdef", "abczdefzzzzzzzzzzzzzzzzzzzz", Some(0), Some(0)), |
1250 | | ("abczdef", "zzzzzzzzzzzzzzzzzzzzabczdef", Some(20), Some(20)), |
1251 | | ("xyz", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaxyz", Some(32), Some(32)), |
1252 | | // Failures caught by quickcheck. |
1253 | | ("\u{0}\u{15}", "\u{0}\u{15}\u{15}\u{0}", Some(0), Some(0)), |
1254 | | ("\u{0}\u{1e}", "\u{1e}\u{0}", None, None), |
1255 | | ]; |
1256 | | |
1257 | | /// Run the substring search tests. `search` should be a closure that |
1258 | | /// accepts a haystack and a needle and returns the starting position |
1259 | | /// of the first occurrence of needle in the haystack, or `None` if one |
1260 | | /// doesn't exist. |
1261 | | pub(crate) fn run_search_tests_fwd( |
1262 | | mut search: impl FnMut(&[u8], &[u8]) -> Option<usize>, |
1263 | | ) { |
1264 | | for &(needle, haystack, expected_fwd, _) in SEARCH_TESTS { |
1265 | | let (n, h) = (needle.as_bytes(), haystack.as_bytes()); |
1266 | | assert_eq!( |
1267 | | expected_fwd, |
1268 | | search(h, n), |
1269 | | "needle: {:?}, haystack: {:?}, expected: {:?}", |
1270 | | n, |
1271 | | h, |
1272 | | expected_fwd |
1273 | | ); |
1274 | | } |
1275 | | } |
1276 | | |
1277 | | /// Run the substring search tests. `search` should be a closure that |
1278 | | /// accepts a haystack and a needle and returns the starting position of |
1279 | | /// the last occurrence of needle in the haystack, or `None` if one doesn't |
1280 | | /// exist. |
1281 | | pub(crate) fn run_search_tests_rev( |
1282 | | mut search: impl FnMut(&[u8], &[u8]) -> Option<usize>, |
1283 | | ) { |
1284 | | for &(needle, haystack, _, expected_rev) in SEARCH_TESTS { |
1285 | | let (n, h) = (needle.as_bytes(), haystack.as_bytes()); |
1286 | | assert_eq!( |
1287 | | expected_rev, |
1288 | | search(h, n), |
1289 | | "needle: {:?}, haystack: {:?}, expected: {:?}", |
1290 | | n, |
1291 | | h, |
1292 | | expected_rev |
1293 | | ); |
1294 | | } |
1295 | | } |
1296 | | } |