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