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