1 #[cfg(not(feature = "std"))] 2 pub(crate) use self::nostd::Forward; 3 #[cfg(feature = "std")] 4 pub(crate) use self::std::Forward; 5 6 #[cfg(feature = "std")] 7 mod std { 8 use core::arch::x86_64::{__m128i, __m256i}; 9 10 use crate::memmem::{genericsimd, NeedleInfo}; 11 12 /// An AVX accelerated vectorized substring search routine that only works 13 /// on small needles. 14 #[derive(Clone, Copy, Debug)] 15 pub(crate) struct Forward(genericsimd::Forward); 16 17 impl Forward { 18 /// Create a new "generic simd" forward searcher. If one could not be 19 /// created from the given inputs, then None is returned. new( ninfo: &NeedleInfo, needle: &[u8], ) -> Option<Forward>20 pub(crate) fn new( 21 ninfo: &NeedleInfo, 22 needle: &[u8], 23 ) -> Option<Forward> { 24 if !cfg!(memchr_runtime_avx) || !is_x86_feature_detected!("avx2") { 25 return None; 26 } 27 genericsimd::Forward::new(ninfo, needle).map(Forward) 28 } 29 30 /// Returns the minimum length of haystack that is needed for this 31 /// searcher to work. Passing a haystack with a length smaller than 32 /// this will cause `find` to panic. 33 #[inline(always)] min_haystack_len(&self) -> usize34 pub(crate) fn min_haystack_len(&self) -> usize { 35 self.0.min_haystack_len::<__m128i>() 36 } 37 38 #[inline(always)] find( &self, haystack: &[u8], needle: &[u8], ) -> Option<usize>39 pub(crate) fn find( 40 &self, 41 haystack: &[u8], 42 needle: &[u8], 43 ) -> Option<usize> { 44 // SAFETY: The only way a Forward value can exist is if the avx2 45 // target feature is enabled. This is the only safety requirement 46 // for calling the genericsimd searcher. 47 unsafe { self.find_impl(haystack, needle) } 48 } 49 50 /// The implementation of find marked with the appropriate target 51 /// feature. 52 /// 53 /// # Safety 54 /// 55 /// Callers must ensure that the avx2 CPU feature is enabled in the 56 /// current environment. 57 #[target_feature(enable = "avx2")] find_impl( &self, haystack: &[u8], needle: &[u8], ) -> Option<usize>58 unsafe fn find_impl( 59 &self, 60 haystack: &[u8], 61 needle: &[u8], 62 ) -> Option<usize> { 63 if haystack.len() < self.0.min_haystack_len::<__m256i>() { 64 genericsimd::fwd_find::<__m128i>(&self.0, haystack, needle) 65 } else { 66 genericsimd::fwd_find::<__m256i>(&self.0, haystack, needle) 67 } 68 } 69 } 70 } 71 72 // We still define the avx "forward" type on nostd to make caller code a bit 73 // simpler. This avoids needing a lot more conditional compilation. 74 #[cfg(not(feature = "std"))] 75 mod nostd { 76 use crate::memmem::NeedleInfo; 77 78 #[derive(Clone, Copy, Debug)] 79 pub(crate) struct Forward(()); 80 81 impl Forward { new( ninfo: &NeedleInfo, needle: &[u8], ) -> Option<Forward>82 pub(crate) fn new( 83 ninfo: &NeedleInfo, 84 needle: &[u8], 85 ) -> Option<Forward> { 86 None 87 } 88 min_haystack_len(&self) -> usize89 pub(crate) fn min_haystack_len(&self) -> usize { 90 unreachable!() 91 } 92 find( &self, haystack: &[u8], needle: &[u8], ) -> Option<usize>93 pub(crate) fn find( 94 &self, 95 haystack: &[u8], 96 needle: &[u8], 97 ) -> Option<usize> { 98 unreachable!() 99 } 100 } 101 } 102 103 #[cfg(all(test, feature = "std", not(miri)))] 104 mod tests { 105 use crate::memmem::{prefilter::PrefilterState, NeedleInfo}; 106 find( _: &mut PrefilterState, ninfo: &NeedleInfo, haystack: &[u8], needle: &[u8], ) -> Option<usize>107 fn find( 108 _: &mut PrefilterState, 109 ninfo: &NeedleInfo, 110 haystack: &[u8], 111 needle: &[u8], 112 ) -> Option<usize> { 113 super::Forward::new(ninfo, needle).unwrap().find(haystack, needle) 114 } 115 116 #[test] prefilter_permutations()117 fn prefilter_permutations() { 118 use crate::memmem::prefilter::tests::PrefilterTest; 119 120 if !is_x86_feature_detected!("avx2") { 121 return; 122 } 123 // SAFETY: The safety of find only requires that the current CPU 124 // support AVX2, which we checked above. 125 unsafe { 126 PrefilterTest::run_all_tests_filter(find, |t| { 127 // This substring searcher only works on certain configs, so 128 // filter our tests such that Forward::new will be guaranteed 129 // to succeed. (And also remove tests with a haystack that is 130 // too small.) 131 let fwd = match super::Forward::new(&t.ninfo, &t.needle) { 132 None => return false, 133 Some(fwd) => fwd, 134 }; 135 t.haystack.len() >= fwd.min_haystack_len() 136 }) 137 } 138 } 139 } 140