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