1 use core::arch::x86_64::__m128i; 2 3 use crate::memmem::{genericsimd, NeedleInfo}; 4 5 /// An SSE accelerated vectorized substring search routine that only works on 6 /// small needles. 7 #[derive(Clone, Copy, Debug)] 8 pub(crate) struct Forward(genericsimd::Forward); 9 10 impl Forward { 11 /// Create a new "generic simd" forward searcher. If one could not be 12 /// created from the given inputs, then None is returned. new(ninfo: &NeedleInfo, needle: &[u8]) -> Option<Forward>13 pub(crate) fn new(ninfo: &NeedleInfo, needle: &[u8]) -> Option<Forward> { 14 if !cfg!(memchr_runtime_sse2) { 15 return None; 16 } 17 genericsimd::Forward::new(ninfo, needle).map(Forward) 18 } 19 20 /// Returns the minimum length of haystack that is needed for this searcher 21 /// to work. Passing a haystack with a length smaller than this will cause 22 /// `find` to panic. 23 #[inline(always)] min_haystack_len(&self) -> usize24 pub(crate) fn min_haystack_len(&self) -> usize { 25 self.0.min_haystack_len::<__m128i>() 26 } 27 28 #[inline(always)] find( &self, haystack: &[u8], needle: &[u8], ) -> Option<usize>29 pub(crate) fn find( 30 &self, 31 haystack: &[u8], 32 needle: &[u8], 33 ) -> Option<usize> { 34 // SAFETY: sse2 is enabled on all x86_64 targets, so this is always 35 // safe to call. 36 unsafe { self.find_impl(haystack, needle) } 37 } 38 39 /// The implementation of find marked with the appropriate target feature. 40 /// 41 /// # Safety 42 /// 43 /// This is safe to call in all cases since sse2 is guaranteed to be part 44 /// of x86_64. It is marked as unsafe because of the target feature 45 /// attribute. 46 #[target_feature(enable = "sse2")] find_impl( &self, haystack: &[u8], needle: &[u8], ) -> Option<usize>47 unsafe fn find_impl( 48 &self, 49 haystack: &[u8], 50 needle: &[u8], 51 ) -> Option<usize> { 52 genericsimd::fwd_find::<__m128i>(&self.0, haystack, needle) 53 } 54 } 55 56 #[cfg(all(test, feature = "std", not(miri)))] 57 mod tests { 58 use crate::memmem::{prefilter::PrefilterState, NeedleInfo}; 59 find( _: &mut PrefilterState, ninfo: &NeedleInfo, haystack: &[u8], needle: &[u8], ) -> Option<usize>60 fn find( 61 _: &mut PrefilterState, 62 ninfo: &NeedleInfo, 63 haystack: &[u8], 64 needle: &[u8], 65 ) -> Option<usize> { 66 super::Forward::new(ninfo, needle).unwrap().find(haystack, needle) 67 } 68 69 #[test] prefilter_permutations()70 fn prefilter_permutations() { 71 use crate::memmem::prefilter::tests::PrefilterTest; 72 73 // SAFETY: sse2 is enabled on all x86_64 targets, so this is always 74 // safe to call. 75 unsafe { 76 PrefilterTest::run_all_tests_filter(find, |t| { 77 // This substring searcher only works on certain configs, so 78 // filter our tests such that Forward::new will be guaranteed 79 // to succeed. (And also remove tests with a haystack that is 80 // too small.) 81 let fwd = match super::Forward::new(&t.ninfo, &t.needle) { 82 None => return false, 83 Some(fwd) => fwd, 84 }; 85 t.haystack.len() >= fwd.min_haystack_len() 86 }) 87 } 88 } 89 } 90