1 | use core::iter::Rev; |
2 | |
3 | use crate::arch::generic::memchr as generic; |
4 | |
5 | /// Search for the first occurrence of a byte in a slice. |
6 | /// |
7 | /// This returns the index corresponding to the first occurrence of `needle` in |
8 | /// `haystack`, or `None` if one is not found. If an index is returned, it is |
9 | /// guaranteed to be less than `haystack.len()`. |
10 | /// |
11 | /// While this is semantically the same as something like |
12 | /// `haystack.iter().position(|&b| b == needle)`, this routine will attempt to |
13 | /// use highly optimized vector operations that can be an order of magnitude |
14 | /// faster (or more). |
15 | /// |
16 | /// # Example |
17 | /// |
18 | /// This shows how to find the first position of a byte in a byte string. |
19 | /// |
20 | /// ``` |
21 | /// use memchr::memchr; |
22 | /// |
23 | /// let haystack = b"the quick brown fox" ; |
24 | /// assert_eq!(memchr(b'k' , haystack), Some(8)); |
25 | /// ``` |
26 | #[inline ] |
27 | pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { |
28 | // SAFETY: memchr_raw, when a match is found, always returns a valid |
29 | // pointer between start and end. |
30 | unsafe { |
31 | generic::search_slice_with_raw(haystack, |start: *const u8, end: *const u8| { |
32 | memchr_raw(needle, start, end) |
33 | }) |
34 | } |
35 | } |
36 | |
37 | /// Search for the last occurrence of a byte in a slice. |
38 | /// |
39 | /// This returns the index corresponding to the last occurrence of `needle` in |
40 | /// `haystack`, or `None` if one is not found. If an index is returned, it is |
41 | /// guaranteed to be less than `haystack.len()`. |
42 | /// |
43 | /// While this is semantically the same as something like |
44 | /// `haystack.iter().rposition(|&b| b == needle)`, this routine will attempt to |
45 | /// use highly optimized vector operations that can be an order of magnitude |
46 | /// faster (or more). |
47 | /// |
48 | /// # Example |
49 | /// |
50 | /// This shows how to find the last position of a byte in a byte string. |
51 | /// |
52 | /// ``` |
53 | /// use memchr::memrchr; |
54 | /// |
55 | /// let haystack = b"the quick brown fox" ; |
56 | /// assert_eq!(memrchr(b'o' , haystack), Some(17)); |
57 | /// ``` |
58 | #[inline ] |
59 | pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> { |
60 | // SAFETY: memrchr_raw, when a match is found, always returns a valid |
61 | // pointer between start and end. |
62 | unsafe { |
63 | generic::search_slice_with_raw(haystack, |start: *const u8, end: *const u8| { |
64 | memrchr_raw(needle, start, end) |
65 | }) |
66 | } |
67 | } |
68 | |
69 | /// Search for the first occurrence of two possible bytes in a haystack. |
70 | /// |
71 | /// This returns the index corresponding to the first occurrence of one of the |
72 | /// needle bytes in `haystack`, or `None` if one is not found. If an index is |
73 | /// returned, it is guaranteed to be less than `haystack.len()`. |
74 | /// |
75 | /// While this is semantically the same as something like |
76 | /// `haystack.iter().position(|&b| b == needle1 || b == needle2)`, this routine |
77 | /// will attempt to use highly optimized vector operations that can be an order |
78 | /// of magnitude faster (or more). |
79 | /// |
80 | /// # Example |
81 | /// |
82 | /// This shows how to find the first position of one of two possible bytes in a |
83 | /// haystack. |
84 | /// |
85 | /// ``` |
86 | /// use memchr::memchr2; |
87 | /// |
88 | /// let haystack = b"the quick brown fox" ; |
89 | /// assert_eq!(memchr2(b'k' , b'q' , haystack), Some(4)); |
90 | /// ``` |
91 | #[inline ] |
92 | pub fn memchr2(needle1: u8, needle2: u8, haystack: &[u8]) -> Option<usize> { |
93 | // SAFETY: memchr2_raw, when a match is found, always returns a valid |
94 | // pointer between start and end. |
95 | unsafe { |
96 | generic::search_slice_with_raw(haystack, |start: *const u8, end: *const u8| { |
97 | memchr2_raw(needle1, needle2, start, end) |
98 | }) |
99 | } |
100 | } |
101 | |
102 | /// Search for the last occurrence of two possible bytes in a haystack. |
103 | /// |
104 | /// This returns the index corresponding to the last occurrence of one of the |
105 | /// needle bytes in `haystack`, or `None` if one is not found. If an index is |
106 | /// returned, it is guaranteed to be less than `haystack.len()`. |
107 | /// |
108 | /// While this is semantically the same as something like |
109 | /// `haystack.iter().rposition(|&b| b == needle1 || b == needle2)`, this |
110 | /// routine will attempt to use highly optimized vector operations that can be |
111 | /// an order of magnitude faster (or more). |
112 | /// |
113 | /// # Example |
114 | /// |
115 | /// This shows how to find the last position of one of two possible bytes in a |
116 | /// haystack. |
117 | /// |
118 | /// ``` |
119 | /// use memchr::memrchr2; |
120 | /// |
121 | /// let haystack = b"the quick brown fox" ; |
122 | /// assert_eq!(memrchr2(b'k' , b'o' , haystack), Some(17)); |
123 | /// ``` |
124 | #[inline ] |
125 | pub fn memrchr2(needle1: u8, needle2: u8, haystack: &[u8]) -> Option<usize> { |
126 | // SAFETY: memrchr2_raw, when a match is found, always returns a valid |
127 | // pointer between start and end. |
128 | unsafe { |
129 | generic::search_slice_with_raw(haystack, |start: *const u8, end: *const u8| { |
130 | memrchr2_raw(needle1, needle2, start, end) |
131 | }) |
132 | } |
133 | } |
134 | |
135 | /// Search for the first occurrence of three possible bytes in a haystack. |
136 | /// |
137 | /// This returns the index corresponding to the first occurrence of one of the |
138 | /// needle bytes in `haystack`, or `None` if one is not found. If an index is |
139 | /// returned, it is guaranteed to be less than `haystack.len()`. |
140 | /// |
141 | /// While this is semantically the same as something like |
142 | /// `haystack.iter().position(|&b| b == needle1 || b == needle2 || b == needle3)`, |
143 | /// this routine will attempt to use highly optimized vector operations that |
144 | /// can be an order of magnitude faster (or more). |
145 | /// |
146 | /// # Example |
147 | /// |
148 | /// This shows how to find the first position of one of three possible bytes in |
149 | /// a haystack. |
150 | /// |
151 | /// ``` |
152 | /// use memchr::memchr3; |
153 | /// |
154 | /// let haystack = b"the quick brown fox" ; |
155 | /// assert_eq!(memchr3(b'k' , b'q' , b'u' , haystack), Some(4)); |
156 | /// ``` |
157 | #[inline ] |
158 | pub fn memchr3( |
159 | needle1: u8, |
160 | needle2: u8, |
161 | needle3: u8, |
162 | haystack: &[u8], |
163 | ) -> Option<usize> { |
164 | // SAFETY: memchr3_raw, when a match is found, always returns a valid |
165 | // pointer between start and end. |
166 | unsafe { |
167 | generic::search_slice_with_raw(haystack, |start: *const u8, end: *const u8| { |
168 | memchr3_raw(needle1, needle2, needle3, start, end) |
169 | }) |
170 | } |
171 | } |
172 | |
173 | /// Search for the last occurrence of three possible bytes in a haystack. |
174 | /// |
175 | /// This returns the index corresponding to the last occurrence of one of the |
176 | /// needle bytes in `haystack`, or `None` if one is not found. If an index is |
177 | /// returned, it is guaranteed to be less than `haystack.len()`. |
178 | /// |
179 | /// While this is semantically the same as something like |
180 | /// `haystack.iter().rposition(|&b| b == needle1 || b == needle2 || b == needle3)`, |
181 | /// this routine will attempt to use highly optimized vector operations that |
182 | /// can be an order of magnitude faster (or more). |
183 | /// |
184 | /// # Example |
185 | /// |
186 | /// This shows how to find the last position of one of three possible bytes in |
187 | /// a haystack. |
188 | /// |
189 | /// ``` |
190 | /// use memchr::memrchr3; |
191 | /// |
192 | /// let haystack = b"the quick brown fox" ; |
193 | /// assert_eq!(memrchr3(b'k' , b'o' , b'n' , haystack), Some(17)); |
194 | /// ``` |
195 | #[inline ] |
196 | pub fn memrchr3( |
197 | needle1: u8, |
198 | needle2: u8, |
199 | needle3: u8, |
200 | haystack: &[u8], |
201 | ) -> Option<usize> { |
202 | // SAFETY: memrchr3_raw, when a match is found, always returns a valid |
203 | // pointer between start and end. |
204 | unsafe { |
205 | generic::search_slice_with_raw(haystack, |start: *const u8, end: *const u8| { |
206 | memrchr3_raw(needle1, needle2, needle3, start, end) |
207 | }) |
208 | } |
209 | } |
210 | |
211 | /// Returns an iterator over all occurrences of the needle in a haystack. |
212 | /// |
213 | /// The iterator returned implements `DoubleEndedIterator`. This means it |
214 | /// can also be used to find occurrences in reverse order. |
215 | #[inline ] |
216 | pub fn memchr_iter<'h>(needle: u8, haystack: &'h [u8]) -> Memchr<'h> { |
217 | Memchr::new(needle1:needle, haystack) |
218 | } |
219 | |
220 | /// Returns an iterator over all occurrences of the needle in a haystack, in |
221 | /// reverse. |
222 | #[inline ] |
223 | pub fn memrchr_iter(needle: u8, haystack: &[u8]) -> Rev<Memchr<'_>> { |
224 | Memchr::new(needle1:needle, haystack).rev() |
225 | } |
226 | |
227 | /// Returns an iterator over all occurrences of the needles in a haystack. |
228 | /// |
229 | /// The iterator returned implements `DoubleEndedIterator`. This means it |
230 | /// can also be used to find occurrences in reverse order. |
231 | #[inline ] |
232 | pub fn memchr2_iter<'h>( |
233 | needle1: u8, |
234 | needle2: u8, |
235 | haystack: &'h [u8], |
236 | ) -> Memchr2<'h> { |
237 | Memchr2::new(needle1, needle2, haystack) |
238 | } |
239 | |
240 | /// Returns an iterator over all occurrences of the needles in a haystack, in |
241 | /// reverse. |
242 | #[inline ] |
243 | pub fn memrchr2_iter( |
244 | needle1: u8, |
245 | needle2: u8, |
246 | haystack: &[u8], |
247 | ) -> Rev<Memchr2<'_>> { |
248 | Memchr2::new(needle1, needle2, haystack).rev() |
249 | } |
250 | |
251 | /// Returns an iterator over all occurrences of the needles in a haystack. |
252 | /// |
253 | /// The iterator returned implements `DoubleEndedIterator`. This means it |
254 | /// can also be used to find occurrences in reverse order. |
255 | #[inline ] |
256 | pub fn memchr3_iter<'h>( |
257 | needle1: u8, |
258 | needle2: u8, |
259 | needle3: u8, |
260 | haystack: &'h [u8], |
261 | ) -> Memchr3<'h> { |
262 | Memchr3::new(needle1, needle2, needle3, haystack) |
263 | } |
264 | |
265 | /// Returns an iterator over all occurrences of the needles in a haystack, in |
266 | /// reverse. |
267 | #[inline ] |
268 | pub fn memrchr3_iter( |
269 | needle1: u8, |
270 | needle2: u8, |
271 | needle3: u8, |
272 | haystack: &[u8], |
273 | ) -> Rev<Memchr3<'_>> { |
274 | Memchr3::new(needle1, needle2, needle3, haystack).rev() |
275 | } |
276 | |
277 | /// An iterator over all occurrences of a single byte in a haystack. |
278 | /// |
279 | /// This iterator implements `DoubleEndedIterator`, which means it can also be |
280 | /// used to find occurrences in reverse order. |
281 | /// |
282 | /// This iterator is created by the [`memchr_iter`] or `[memrchr_iter`] |
283 | /// functions. It can also be created with the [`Memchr::new`] method. |
284 | /// |
285 | /// The lifetime parameter `'h` refers to the lifetime of the haystack being |
286 | /// searched. |
287 | #[derive (Clone, Debug)] |
288 | pub struct Memchr<'h> { |
289 | needle1: u8, |
290 | it: crate::arch::generic::memchr::Iter<'h>, |
291 | } |
292 | |
293 | impl<'h> Memchr<'h> { |
294 | /// Returns an iterator over all occurrences of the needle byte in the |
295 | /// given haystack. |
296 | /// |
297 | /// The iterator returned implements `DoubleEndedIterator`. This means it |
298 | /// can also be used to find occurrences in reverse order. |
299 | #[inline ] |
300 | pub fn new(needle1: u8, haystack: &'h [u8]) -> Memchr<'h> { |
301 | Memchr { |
302 | needle1, |
303 | it: crate::arch::generic::memchr::Iter::new(haystack), |
304 | } |
305 | } |
306 | } |
307 | |
308 | impl<'h> Iterator for Memchr<'h> { |
309 | type Item = usize; |
310 | |
311 | #[inline ] |
312 | fn next(&mut self) -> Option<usize> { |
313 | // SAFETY: All of our implementations of memchr ensure that any |
314 | // pointers returns will fall within the start and end bounds, and this |
315 | // upholds the safety contract of `self.it.next`. |
316 | unsafe { |
317 | // NOTE: I attempted to define an enum of previously created |
318 | // searchers and then switch on those here instead of just |
319 | // calling `memchr_raw` (or `One::new(..).find_raw(..)`). But |
320 | // that turned out to have a fair bit of extra overhead when |
321 | // searching very small haystacks. |
322 | self.it.next(|s, e| memchr_raw(self.needle1, s, e)) |
323 | } |
324 | } |
325 | |
326 | #[inline ] |
327 | fn count(self) -> usize { |
328 | self.it.count(|s, e| { |
329 | // SAFETY: We rely on our generic iterator to return valid start |
330 | // and end pointers. |
331 | unsafe { count_raw(self.needle1, s, e) } |
332 | }) |
333 | } |
334 | |
335 | #[inline ] |
336 | fn size_hint(&self) -> (usize, Option<usize>) { |
337 | self.it.size_hint() |
338 | } |
339 | } |
340 | |
341 | impl<'h> DoubleEndedIterator for Memchr<'h> { |
342 | #[inline ] |
343 | fn next_back(&mut self) -> Option<usize> { |
344 | // SAFETY: All of our implementations of memchr ensure that any |
345 | // pointers returns will fall within the start and end bounds, and this |
346 | // upholds the safety contract of `self.it.next_back`. |
347 | unsafe { self.it.next_back(|s: *const u8, e: *const u8| memrchr_raw(self.needle1, start:s, end:e)) } |
348 | } |
349 | } |
350 | |
351 | impl<'h> core::iter::FusedIterator for Memchr<'h> {} |
352 | |
353 | /// An iterator over all occurrences of two possible bytes in a haystack. |
354 | /// |
355 | /// This iterator implements `DoubleEndedIterator`, which means it can also be |
356 | /// used to find occurrences in reverse order. |
357 | /// |
358 | /// This iterator is created by the [`memchr2_iter`] or `[memrchr2_iter`] |
359 | /// functions. It can also be created with the [`Memchr2::new`] method. |
360 | /// |
361 | /// The lifetime parameter `'h` refers to the lifetime of the haystack being |
362 | /// searched. |
363 | #[derive (Clone, Debug)] |
364 | pub struct Memchr2<'h> { |
365 | needle1: u8, |
366 | needle2: u8, |
367 | it: crate::arch::generic::memchr::Iter<'h>, |
368 | } |
369 | |
370 | impl<'h> Memchr2<'h> { |
371 | /// Returns an iterator over all occurrences of the needle bytes in the |
372 | /// given haystack. |
373 | /// |
374 | /// The iterator returned implements `DoubleEndedIterator`. This means it |
375 | /// can also be used to find occurrences in reverse order. |
376 | #[inline ] |
377 | pub fn new(needle1: u8, needle2: u8, haystack: &'h [u8]) -> Memchr2<'h> { |
378 | Memchr2 { |
379 | needle1, |
380 | needle2, |
381 | it: crate::arch::generic::memchr::Iter::new(haystack), |
382 | } |
383 | } |
384 | } |
385 | |
386 | impl<'h> Iterator for Memchr2<'h> { |
387 | type Item = usize; |
388 | |
389 | #[inline ] |
390 | fn next(&mut self) -> Option<usize> { |
391 | // SAFETY: All of our implementations of memchr ensure that any |
392 | // pointers returns will fall within the start and end bounds, and this |
393 | // upholds the safety contract of `self.it.next`. |
394 | unsafe { |
395 | self.it.next(|s: *const u8, e: *const u8| memchr2_raw(self.needle1, self.needle2, start:s, end:e)) |
396 | } |
397 | } |
398 | |
399 | #[inline ] |
400 | fn size_hint(&self) -> (usize, Option<usize>) { |
401 | self.it.size_hint() |
402 | } |
403 | } |
404 | |
405 | impl<'h> DoubleEndedIterator for Memchr2<'h> { |
406 | #[inline ] |
407 | fn next_back(&mut self) -> Option<usize> { |
408 | // SAFETY: All of our implementations of memchr ensure that any |
409 | // pointers returns will fall within the start and end bounds, and this |
410 | // upholds the safety contract of `self.it.next_back`. |
411 | unsafe { |
412 | self.it.next_back(|s: *const u8, e: *const u8| { |
413 | memrchr2_raw(self.needle1, self.needle2, start:s, end:e) |
414 | }) |
415 | } |
416 | } |
417 | } |
418 | |
419 | impl<'h> core::iter::FusedIterator for Memchr2<'h> {} |
420 | |
421 | /// An iterator over all occurrences of three possible bytes in a haystack. |
422 | /// |
423 | /// This iterator implements `DoubleEndedIterator`, which means it can also be |
424 | /// used to find occurrences in reverse order. |
425 | /// |
426 | /// This iterator is created by the [`memchr2_iter`] or `[memrchr2_iter`] |
427 | /// functions. It can also be created with the [`Memchr3::new`] method. |
428 | /// |
429 | /// The lifetime parameter `'h` refers to the lifetime of the haystack being |
430 | /// searched. |
431 | #[derive (Clone, Debug)] |
432 | pub struct Memchr3<'h> { |
433 | needle1: u8, |
434 | needle2: u8, |
435 | needle3: u8, |
436 | it: crate::arch::generic::memchr::Iter<'h>, |
437 | } |
438 | |
439 | impl<'h> Memchr3<'h> { |
440 | /// Returns an iterator over all occurrences of the needle bytes in the |
441 | /// given haystack. |
442 | /// |
443 | /// The iterator returned implements `DoubleEndedIterator`. This means it |
444 | /// can also be used to find occurrences in reverse order. |
445 | #[inline ] |
446 | pub fn new( |
447 | needle1: u8, |
448 | needle2: u8, |
449 | needle3: u8, |
450 | haystack: &'h [u8], |
451 | ) -> Memchr3<'h> { |
452 | Memchr3 { |
453 | needle1, |
454 | needle2, |
455 | needle3, |
456 | it: crate::arch::generic::memchr::Iter::new(haystack), |
457 | } |
458 | } |
459 | } |
460 | |
461 | impl<'h> Iterator for Memchr3<'h> { |
462 | type Item = usize; |
463 | |
464 | #[inline ] |
465 | fn next(&mut self) -> Option<usize> { |
466 | // SAFETY: All of our implementations of memchr ensure that any |
467 | // pointers returns will fall within the start and end bounds, and this |
468 | // upholds the safety contract of `self.it.next`. |
469 | unsafe { |
470 | self.it.next(|s: *const u8, e: *const u8| { |
471 | memchr3_raw(self.needle1, self.needle2, self.needle3, start:s, end:e) |
472 | }) |
473 | } |
474 | } |
475 | |
476 | #[inline ] |
477 | fn size_hint(&self) -> (usize, Option<usize>) { |
478 | self.it.size_hint() |
479 | } |
480 | } |
481 | |
482 | impl<'h> DoubleEndedIterator for Memchr3<'h> { |
483 | #[inline ] |
484 | fn next_back(&mut self) -> Option<usize> { |
485 | // SAFETY: All of our implementations of memchr ensure that any |
486 | // pointers returns will fall within the start and end bounds, and this |
487 | // upholds the safety contract of `self.it.next_back`. |
488 | unsafe { |
489 | self.it.next_back(|s: *const u8, e: *const u8| { |
490 | memrchr3_raw(self.needle1, self.needle2, self.needle3, start:s, end:e) |
491 | }) |
492 | } |
493 | } |
494 | } |
495 | |
496 | impl<'h> core::iter::FusedIterator for Memchr3<'h> {} |
497 | |
498 | /// memchr, but using raw pointers to represent the haystack. |
499 | /// |
500 | /// # Safety |
501 | /// |
502 | /// Pointers must be valid. See `One::find_raw`. |
503 | #[inline ] |
504 | unsafe fn memchr_raw( |
505 | needle: u8, |
506 | start: *const u8, |
507 | end: *const u8, |
508 | ) -> Option<*const u8> { |
509 | #[cfg (target_arch = "x86_64" )] |
510 | { |
511 | // x86_64 does CPU feature detection at runtime in order to use AVX2 |
512 | // instructions even when the `avx2` feature isn't enabled at compile |
513 | // time. This function also handles using a fallback if neither AVX2 |
514 | // nor SSE2 (unusual) are available. |
515 | crate::arch::x86_64::memchr::memchr_raw(needle, start, end) |
516 | } |
517 | #[cfg (target_arch = "wasm32" )] |
518 | { |
519 | crate::arch::wasm32::memchr::memchr_raw(needle, start, end) |
520 | } |
521 | #[cfg (target_arch = "aarch64" )] |
522 | { |
523 | crate::arch::aarch64::memchr::memchr_raw(needle, start, end) |
524 | } |
525 | #[cfg (not(any( |
526 | target_arch = "x86_64" , |
527 | target_arch = "wasm32" , |
528 | target_arch = "aarch64" |
529 | )))] |
530 | { |
531 | crate::arch::all::memchr::One::new(needle).find_raw(start, end) |
532 | } |
533 | } |
534 | |
535 | /// memrchr, but using raw pointers to represent the haystack. |
536 | /// |
537 | /// # Safety |
538 | /// |
539 | /// Pointers must be valid. See `One::rfind_raw`. |
540 | #[inline ] |
541 | unsafe fn memrchr_raw( |
542 | needle: u8, |
543 | start: *const u8, |
544 | end: *const u8, |
545 | ) -> Option<*const u8> { |
546 | #[cfg (target_arch = "x86_64" )] |
547 | { |
548 | crate::arch::x86_64::memchr::memrchr_raw(n1:needle, start, end) |
549 | } |
550 | #[cfg (target_arch = "wasm32" )] |
551 | { |
552 | crate::arch::wasm32::memchr::memrchr_raw(needle, start, end) |
553 | } |
554 | #[cfg (target_arch = "aarch64" )] |
555 | { |
556 | crate::arch::aarch64::memchr::memrchr_raw(needle, start, end) |
557 | } |
558 | #[cfg (not(any( |
559 | target_arch = "x86_64" , |
560 | target_arch = "wasm32" , |
561 | target_arch = "aarch64" |
562 | )))] |
563 | { |
564 | crate::arch::all::memchr::One::new(needle).rfind_raw(start, end) |
565 | } |
566 | } |
567 | |
568 | /// memchr2, but using raw pointers to represent the haystack. |
569 | /// |
570 | /// # Safety |
571 | /// |
572 | /// Pointers must be valid. See `Two::find_raw`. |
573 | #[inline ] |
574 | unsafe fn memchr2_raw( |
575 | needle1: u8, |
576 | needle2: u8, |
577 | start: *const u8, |
578 | end: *const u8, |
579 | ) -> Option<*const u8> { |
580 | #[cfg (target_arch = "x86_64" )] |
581 | { |
582 | crate::arch::x86_64::memchr::memchr2_raw(n1:needle1, n2:needle2, start, end) |
583 | } |
584 | #[cfg (target_arch = "wasm32" )] |
585 | { |
586 | crate::arch::wasm32::memchr::memchr2_raw(needle1, needle2, start, end) |
587 | } |
588 | #[cfg (target_arch = "aarch64" )] |
589 | { |
590 | crate::arch::aarch64::memchr::memchr2_raw(needle1, needle2, start, end) |
591 | } |
592 | #[cfg (not(any( |
593 | target_arch = "x86_64" , |
594 | target_arch = "wasm32" , |
595 | target_arch = "aarch64" |
596 | )))] |
597 | { |
598 | crate::arch::all::memchr::Two::new(needle1, needle2) |
599 | .find_raw(start, end) |
600 | } |
601 | } |
602 | |
603 | /// memrchr2, but using raw pointers to represent the haystack. |
604 | /// |
605 | /// # Safety |
606 | /// |
607 | /// Pointers must be valid. See `Two::rfind_raw`. |
608 | #[inline ] |
609 | unsafe fn memrchr2_raw( |
610 | needle1: u8, |
611 | needle2: u8, |
612 | start: *const u8, |
613 | end: *const u8, |
614 | ) -> Option<*const u8> { |
615 | #[cfg (target_arch = "x86_64" )] |
616 | { |
617 | crate::arch::x86_64::memchr::memrchr2_raw(needle1, needle2, start, end) |
618 | } |
619 | #[cfg (target_arch = "wasm32" )] |
620 | { |
621 | crate::arch::wasm32::memchr::memrchr2_raw(needle1, needle2, start, end) |
622 | } |
623 | #[cfg (target_arch = "aarch64" )] |
624 | { |
625 | crate::arch::aarch64::memchr::memrchr2_raw( |
626 | needle1, needle2, start, end, |
627 | ) |
628 | } |
629 | #[cfg (not(any( |
630 | target_arch = "x86_64" , |
631 | target_arch = "wasm32" , |
632 | target_arch = "aarch64" |
633 | )))] |
634 | { |
635 | crate::arch::all::memchr::Two::new(needle1, needle2) |
636 | .rfind_raw(start, end) |
637 | } |
638 | } |
639 | |
640 | /// memchr3, but using raw pointers to represent the haystack. |
641 | /// |
642 | /// # Safety |
643 | /// |
644 | /// Pointers must be valid. See `Three::find_raw`. |
645 | #[inline ] |
646 | unsafe fn memchr3_raw( |
647 | needle1: u8, |
648 | needle2: u8, |
649 | needle3: u8, |
650 | start: *const u8, |
651 | end: *const u8, |
652 | ) -> Option<*const u8> { |
653 | #[cfg (target_arch = "x86_64" )] |
654 | { |
655 | crate::arch::x86_64::memchr::memchr3_raw( |
656 | needle1, needle2, needle3, start, end, |
657 | ) |
658 | } |
659 | #[cfg (target_arch = "wasm32" )] |
660 | { |
661 | crate::arch::wasm32::memchr::memchr3_raw( |
662 | needle1, needle2, needle3, start, end, |
663 | ) |
664 | } |
665 | #[cfg (target_arch = "aarch64" )] |
666 | { |
667 | crate::arch::aarch64::memchr::memchr3_raw( |
668 | needle1, needle2, needle3, start, end, |
669 | ) |
670 | } |
671 | #[cfg (not(any( |
672 | target_arch = "x86_64" , |
673 | target_arch = "wasm32" , |
674 | target_arch = "aarch64" |
675 | )))] |
676 | { |
677 | crate::arch::all::memchr::Three::new(needle1, needle2, needle3) |
678 | .find_raw(start, end) |
679 | } |
680 | } |
681 | |
682 | /// memrchr3, but using raw pointers to represent the haystack. |
683 | /// |
684 | /// # Safety |
685 | /// |
686 | /// Pointers must be valid. See `Three::rfind_raw`. |
687 | #[inline ] |
688 | unsafe fn memrchr3_raw( |
689 | needle1: u8, |
690 | needle2: u8, |
691 | needle3: u8, |
692 | start: *const u8, |
693 | end: *const u8, |
694 | ) -> Option<*const u8> { |
695 | #[cfg (target_arch = "x86_64" )] |
696 | { |
697 | crate::arch::x86_64::memchr::memrchr3_raw( |
698 | needle1, needle2, needle3, start, end, |
699 | ) |
700 | } |
701 | #[cfg (target_arch = "wasm32" )] |
702 | { |
703 | crate::arch::wasm32::memchr::memrchr3_raw( |
704 | needle1, needle2, needle3, start, end, |
705 | ) |
706 | } |
707 | #[cfg (target_arch = "aarch64" )] |
708 | { |
709 | crate::arch::aarch64::memchr::memrchr3_raw( |
710 | needle1, needle2, needle3, start, end, |
711 | ) |
712 | } |
713 | #[cfg (not(any( |
714 | target_arch = "x86_64" , |
715 | target_arch = "wasm32" , |
716 | target_arch = "aarch64" |
717 | )))] |
718 | { |
719 | crate::arch::all::memchr::Three::new(needle1, needle2, needle3) |
720 | .rfind_raw(start, end) |
721 | } |
722 | } |
723 | |
724 | /// Count all matching bytes, but using raw pointers to represent the haystack. |
725 | /// |
726 | /// # Safety |
727 | /// |
728 | /// Pointers must be valid. See `One::count_raw`. |
729 | #[inline ] |
730 | unsafe fn count_raw(needle: u8, start: *const u8, end: *const u8) -> usize { |
731 | #[cfg (target_arch = "x86_64" )] |
732 | { |
733 | crate::arch::x86_64::memchr::count_raw(n1:needle, start, end) |
734 | } |
735 | #[cfg (target_arch = "wasm32" )] |
736 | { |
737 | crate::arch::wasm32::memchr::count_raw(needle, start, end) |
738 | } |
739 | #[cfg (target_arch = "aarch64" )] |
740 | { |
741 | crate::arch::aarch64::memchr::count_raw(needle, start, end) |
742 | } |
743 | #[cfg (not(any( |
744 | target_arch = "x86_64" , |
745 | target_arch = "wasm32" , |
746 | target_arch = "aarch64" |
747 | )))] |
748 | { |
749 | crate::arch::all::memchr::One::new(needle).count_raw(start, end) |
750 | } |
751 | } |
752 | |
753 | #[cfg (test)] |
754 | mod tests { |
755 | use super::*; |
756 | |
757 | #[test ] |
758 | fn forward1_iter() { |
759 | crate::tests::memchr::Runner::new(1).forward_iter( |
760 | |haystack, needles| { |
761 | Some(memchr_iter(needles[0], haystack).collect()) |
762 | }, |
763 | ) |
764 | } |
765 | |
766 | #[test ] |
767 | fn forward1_oneshot() { |
768 | crate::tests::memchr::Runner::new(1).forward_oneshot( |
769 | |haystack, needles| Some(memchr(needles[0], haystack)), |
770 | ) |
771 | } |
772 | |
773 | #[test ] |
774 | fn reverse1_iter() { |
775 | crate::tests::memchr::Runner::new(1).reverse_iter( |
776 | |haystack, needles| { |
777 | Some(memrchr_iter(needles[0], haystack).collect()) |
778 | }, |
779 | ) |
780 | } |
781 | |
782 | #[test ] |
783 | fn reverse1_oneshot() { |
784 | crate::tests::memchr::Runner::new(1).reverse_oneshot( |
785 | |haystack, needles| Some(memrchr(needles[0], haystack)), |
786 | ) |
787 | } |
788 | |
789 | #[test ] |
790 | fn count1_iter() { |
791 | crate::tests::memchr::Runner::new(1).count_iter(|haystack, needles| { |
792 | Some(memchr_iter(needles[0], haystack).count()) |
793 | }) |
794 | } |
795 | |
796 | #[test ] |
797 | fn forward2_iter() { |
798 | crate::tests::memchr::Runner::new(2).forward_iter( |
799 | |haystack, needles| { |
800 | let n1 = needles.get(0).copied()?; |
801 | let n2 = needles.get(1).copied()?; |
802 | Some(memchr2_iter(n1, n2, haystack).collect()) |
803 | }, |
804 | ) |
805 | } |
806 | |
807 | #[test ] |
808 | fn forward2_oneshot() { |
809 | crate::tests::memchr::Runner::new(2).forward_oneshot( |
810 | |haystack, needles| { |
811 | let n1 = needles.get(0).copied()?; |
812 | let n2 = needles.get(1).copied()?; |
813 | Some(memchr2(n1, n2, haystack)) |
814 | }, |
815 | ) |
816 | } |
817 | |
818 | #[test ] |
819 | fn reverse2_iter() { |
820 | crate::tests::memchr::Runner::new(2).reverse_iter( |
821 | |haystack, needles| { |
822 | let n1 = needles.get(0).copied()?; |
823 | let n2 = needles.get(1).copied()?; |
824 | Some(memrchr2_iter(n1, n2, haystack).collect()) |
825 | }, |
826 | ) |
827 | } |
828 | |
829 | #[test ] |
830 | fn reverse2_oneshot() { |
831 | crate::tests::memchr::Runner::new(2).reverse_oneshot( |
832 | |haystack, needles| { |
833 | let n1 = needles.get(0).copied()?; |
834 | let n2 = needles.get(1).copied()?; |
835 | Some(memrchr2(n1, n2, haystack)) |
836 | }, |
837 | ) |
838 | } |
839 | |
840 | #[test ] |
841 | fn forward3_iter() { |
842 | crate::tests::memchr::Runner::new(3).forward_iter( |
843 | |haystack, needles| { |
844 | let n1 = needles.get(0).copied()?; |
845 | let n2 = needles.get(1).copied()?; |
846 | let n3 = needles.get(2).copied()?; |
847 | Some(memchr3_iter(n1, n2, n3, haystack).collect()) |
848 | }, |
849 | ) |
850 | } |
851 | |
852 | #[test ] |
853 | fn forward3_oneshot() { |
854 | crate::tests::memchr::Runner::new(3).forward_oneshot( |
855 | |haystack, needles| { |
856 | let n1 = needles.get(0).copied()?; |
857 | let n2 = needles.get(1).copied()?; |
858 | let n3 = needles.get(2).copied()?; |
859 | Some(memchr3(n1, n2, n3, haystack)) |
860 | }, |
861 | ) |
862 | } |
863 | |
864 | #[test ] |
865 | fn reverse3_iter() { |
866 | crate::tests::memchr::Runner::new(3).reverse_iter( |
867 | |haystack, needles| { |
868 | let n1 = needles.get(0).copied()?; |
869 | let n2 = needles.get(1).copied()?; |
870 | let n3 = needles.get(2).copied()?; |
871 | Some(memrchr3_iter(n1, n2, n3, haystack).collect()) |
872 | }, |
873 | ) |
874 | } |
875 | |
876 | #[test ] |
877 | fn reverse3_oneshot() { |
878 | crate::tests::memchr::Runner::new(3).reverse_oneshot( |
879 | |haystack, needles| { |
880 | let n1 = needles.get(0).copied()?; |
881 | let n2 = needles.get(1).copied()?; |
882 | let n3 = needles.get(2).copied()?; |
883 | Some(memrchr3(n1, n2, n3, haystack)) |
884 | }, |
885 | ) |
886 | } |
887 | |
888 | // Prior to memchr 2.6, the memchr iterators both implemented Send and |
889 | // Sync. But in memchr 2.6, the iterator changed to use raw pointers |
890 | // internally and I didn't add explicit Send/Sync impls. This ended up |
891 | // regressing the API. This test ensures we don't do that again. |
892 | // |
893 | // See: https://github.com/BurntSushi/memchr/issues/133 |
894 | #[test ] |
895 | fn sync_regression() { |
896 | use core::panic::{RefUnwindSafe, UnwindSafe}; |
897 | |
898 | fn assert_send_sync<T: Send + Sync + UnwindSafe + RefUnwindSafe>() {} |
899 | assert_send_sync::<Memchr>(); |
900 | assert_send_sync::<Memchr2>(); |
901 | assert_send_sync::<Memchr3>() |
902 | } |
903 | } |
904 | |