1fb6c1f39Sopenharmony_ci/*
2fb6c1f39Sopenharmony_ciThis module defines benchmarks for the memmem family of functions.
3fb6c1f39Sopenharmony_ciBenchmarking a substring algorithm is particularly difficult, especially
4fb6c1f39Sopenharmony_ciwhen implementations (like this one, and others) use heuristics to speed up
5fb6c1f39Sopenharmony_cicommon cases, typically at the expense of less common cases. The job of this
6fb6c1f39Sopenharmony_cibenchmark suite is to not only highlight the fast common cases, but to also put
7fb6c1f39Sopenharmony_cia spotlight on the less common or pathological cases. While some things are
8fb6c1f39Sopenharmony_cigenerally expected to be slower because of these heuristics, the benchmarks
9fb6c1f39Sopenharmony_cihelp us make sure they we don't let things get too slow.
10fb6c1f39Sopenharmony_ci
11fb6c1f39Sopenharmony_ciThe naming scheme is as follows:
12fb6c1f39Sopenharmony_ci
13fb6c1f39Sopenharmony_ci  memr?mem/{impl}/{config}/{corpus}/{needle}
14fb6c1f39Sopenharmony_ci
15fb6c1f39Sopenharmony_ciWhere {...} is a variable. Variables should never contain slashes. They are as
16fb6c1f39Sopenharmony_cifollows:
17fb6c1f39Sopenharmony_ci
18fb6c1f39Sopenharmony_ci  impl
19fb6c1f39Sopenharmony_ci    A brief name describing the implementation under test. Possible values:
20fb6c1f39Sopenharmony_ci
21fb6c1f39Sopenharmony_ci    krate
22fb6c1f39Sopenharmony_ci      The implementation provided by this crate.
23fb6c1f39Sopenharmony_ci    krate-nopre
24fb6c1f39Sopenharmony_ci      The implementation provided by this crate without prefilters enabled.
25fb6c1f39Sopenharmony_ci    bstr
26fb6c1f39Sopenharmony_ci      The implementation provided by the bstr crate.
27fb6c1f39Sopenharmony_ci      N.B. This is only applicable at time of writing, since bstr will
28fb6c1f39Sopenharmony_ci      eventually just use this crate.
29fb6c1f39Sopenharmony_ci    regex
30fb6c1f39Sopenharmony_ci      The implementation of substring search provided by the regex crate.
31fb6c1f39Sopenharmony_ci      N.B. This is only applicable at time of writing, since regex will
32fb6c1f39Sopenharmony_ci      eventually just use this crate.
33fb6c1f39Sopenharmony_ci    stud
34fb6c1f39Sopenharmony_ci      The implementation of substring search provided by the standard
35fb6c1f39Sopenharmony_ci      library. This implementation only works on valid UTF-8 by virtue of
36fb6c1f39Sopenharmony_ci      how its API is exposed.
37fb6c1f39Sopenharmony_ci    twoway
38fb6c1f39Sopenharmony_ci      The implementation of substring search provided by the twoway crate.
39fb6c1f39Sopenharmony_ci    sliceslice
40fb6c1f39Sopenharmony_ci      The implementation of substring search provided by the sliceslice crate.
41fb6c1f39Sopenharmony_ci    libc
42fb6c1f39Sopenharmony_ci      The implementation of memmem in your friendly neighborhood libc.
43fb6c1f39Sopenharmony_ci
44fb6c1f39Sopenharmony_ci    Note that there is also a 'memmem' crate, but it is unmaintained and
45fb6c1f39Sopenharmony_ci    appears to just be a snapshot of std's implementation at a particular
46fb6c1f39Sopenharmony_ci    point in time (but exposed in a way to permit it to search arbitrary
47fb6c1f39Sopenharmony_ci    bytes).
48fb6c1f39Sopenharmony_ci
49fb6c1f39Sopenharmony_ci  config
50fb6c1f39Sopenharmony_ci    This should be a brief description of the configuration of the search. Not
51fb6c1f39Sopenharmony_ci    all implementations can be benchmarked in all configurations. It depends on
52fb6c1f39Sopenharmony_ci    the API they expose. Possible values:
53fb6c1f39Sopenharmony_ci
54fb6c1f39Sopenharmony_ci    oneshot
55fb6c1f39Sopenharmony_ci      Executes a single search without pre-building a searcher. That
56fb6c1f39Sopenharmony_ci      this measurement includes the time it takes to initialize a
57fb6c1f39Sopenharmony_ci      searcher.
58fb6c1f39Sopenharmony_ci    prebuilt
59fb6c1f39Sopenharmony_ci      Executes a single search without measuring the time it takes to
60fb6c1f39Sopenharmony_ci      build a searcher.
61fb6c1f39Sopenharmony_ci    iter-oneshot
62fb6c1f39Sopenharmony_ci      Counts the total number of matches. This measures the time it takes to
63fb6c1f39Sopenharmony_ci      build the searcher.
64fb6c1f39Sopenharmony_ci    iter-prebuilt
65fb6c1f39Sopenharmony_ci      Counts the total number of matches. This does not measure the time it
66fb6c1f39Sopenharmony_ci      takes to build the searcher.
67fb6c1f39Sopenharmony_ci
68fb6c1f39Sopenharmony_ci  corpus
69fb6c1f39Sopenharmony_ci    A brief name describing the corpus or haystack used in the benchmark. In
70fb6c1f39Sopenharmony_ci    general, we vary this with regard to size and language. Possible values:
71fb6c1f39Sopenharmony_ci
72fb6c1f39Sopenharmony_ci    subtitles-{en,ru,zh}
73fb6c1f39Sopenharmony_ci      Text from the OpenSubtitles project, in one of English, Russian or
74fb6c1f39Sopenharmony_ci      Chinese. This is the primary input meant to represent most kinds of
75fb6c1f39Sopenharmony_ci      haystacks.
76fb6c1f39Sopenharmony_ci    pathological-{...}
77fb6c1f39Sopenharmony_ci      A haystack that has been specifically constructed to exploit a
78fb6c1f39Sopenharmony_ci      pathological case in or more substring search implementations.
79fb6c1f39Sopenharmony_ci    sliceslice-words
80fb6c1f39Sopenharmony_ci      The haystack is varied across words in an English dictionary. Using
81fb6c1f39Sopenharmony_ci      this corpus means the benchmark is measuring performance on very small
82fb6c1f39Sopenharmony_ci      haystacks. This was taken from the sliceslice crate benchmarks.
83fb6c1f39Sopenharmony_ci    sliceslice-i386
84fb6c1f39Sopenharmony_ci      The haystack is an Intel 80386 reference manual.
85fb6c1f39Sopenharmony_ci      This was also taken from the sliceslice crate benchmarks.
86fb6c1f39Sopenharmony_ci
87fb6c1f39Sopenharmony_ci  needle
88fb6c1f39Sopenharmony_ci    A brief name describing the needle used. Unlike other variables, there
89fb6c1f39Sopenharmony_ci    isn't a strong controlled vocabularly for this parameter. The needle
90fb6c1f39Sopenharmony_ci    variable is meant to be largely self explanatory. For example, a needle
91fb6c1f39Sopenharmony_ci    named "rare" probably means that the number of occurrences of the needle
92fb6c1f39Sopenharmony_ci    is expected to be particularly low.
93fb6c1f39Sopenharmony_ci*/
94fb6c1f39Sopenharmony_ci
95fb6c1f39Sopenharmony_ciuse criterion::Criterion;
96fb6c1f39Sopenharmony_ci
97fb6c1f39Sopenharmony_ciuse crate::{define, memmem::inputs::INPUTS};
98fb6c1f39Sopenharmony_ci
99fb6c1f39Sopenharmony_cimod imp;
100fb6c1f39Sopenharmony_cimod inputs;
101fb6c1f39Sopenharmony_cimod sliceslice;
102fb6c1f39Sopenharmony_ci
103fb6c1f39Sopenharmony_cipub fn all(c: &mut Criterion) {
104fb6c1f39Sopenharmony_ci    oneshot(c);
105fb6c1f39Sopenharmony_ci    prebuilt(c);
106fb6c1f39Sopenharmony_ci    oneshot_iter(c);
107fb6c1f39Sopenharmony_ci    prebuilt_iter(c);
108fb6c1f39Sopenharmony_ci    sliceslice::all(c);
109fb6c1f39Sopenharmony_ci}
110fb6c1f39Sopenharmony_ci
111fb6c1f39Sopenharmony_cifn oneshot(c: &mut Criterion) {
112fb6c1f39Sopenharmony_ci    macro_rules! def_impl {
113fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr, $impl:ident) => {
114fb6c1f39Sopenharmony_ci            let config = "oneshot";
115fb6c1f39Sopenharmony_ci            let available = imp::$impl::available($q.needle);
116fb6c1f39Sopenharmony_ci            // We only define non-iter benchmarks when the count is <=1. Such
117fb6c1f39Sopenharmony_ci            // queries are usually constructed to only appear at the end.
118fb6c1f39Sopenharmony_ci            // Otherwise, for more common queries, the benchmark would be
119fb6c1f39Sopenharmony_ci            // approximately duplicative with benchmarks on shorter haystacks
120fb6c1f39Sopenharmony_ci            // for the implementations we benchmark.
121fb6c1f39Sopenharmony_ci            if $q.count <= 1 && available.contains(&config) {
122fb6c1f39Sopenharmony_ci                let expected = $q.count > 0;
123fb6c1f39Sopenharmony_ci                macro_rules! define {
124fb6c1f39Sopenharmony_ci                    ($dir:expr, $find:expr) => {
125fb6c1f39Sopenharmony_ci                        let name = format!(
126fb6c1f39Sopenharmony_ci                            "{dir}/{imp}/{config}/{inp}/{freq}-{q}",
127fb6c1f39Sopenharmony_ci                            dir = $dir,
128fb6c1f39Sopenharmony_ci                            imp = stringify!($impl),
129fb6c1f39Sopenharmony_ci                            config = config,
130fb6c1f39Sopenharmony_ci                            inp = $inp.name,
131fb6c1f39Sopenharmony_ci                            freq = $freq,
132fb6c1f39Sopenharmony_ci                            q = $q.name,
133fb6c1f39Sopenharmony_ci                        );
134fb6c1f39Sopenharmony_ci                        define(
135fb6c1f39Sopenharmony_ci                            c,
136fb6c1f39Sopenharmony_ci                            &name,
137fb6c1f39Sopenharmony_ci                            $inp.corpus.as_bytes(),
138fb6c1f39Sopenharmony_ci                            Box::new(move |b| {
139fb6c1f39Sopenharmony_ci                                b.iter(|| {
140fb6c1f39Sopenharmony_ci                                    assert_eq!(
141fb6c1f39Sopenharmony_ci                                        expected,
142fb6c1f39Sopenharmony_ci                                        $find($inp.corpus, $q.needle)
143fb6c1f39Sopenharmony_ci                                    );
144fb6c1f39Sopenharmony_ci                                });
145fb6c1f39Sopenharmony_ci                            }),
146fb6c1f39Sopenharmony_ci                        );
147fb6c1f39Sopenharmony_ci                    };
148fb6c1f39Sopenharmony_ci                }
149fb6c1f39Sopenharmony_ci                define!("memmem", imp::$impl::fwd::oneshot);
150fb6c1f39Sopenharmony_ci                if available.contains(&"reverse") {
151fb6c1f39Sopenharmony_ci                    define!("memrmem", imp::$impl::rev::oneshot);
152fb6c1f39Sopenharmony_ci                }
153fb6c1f39Sopenharmony_ci            }
154fb6c1f39Sopenharmony_ci        };
155fb6c1f39Sopenharmony_ci    }
156fb6c1f39Sopenharmony_ci    macro_rules! def_all_impls {
157fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr) => {
158fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate);
159fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate_nopre);
160fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, bstr);
161fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, regex);
162fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, stud);
163fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, twoway);
164fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, sliceslice);
165fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, libc);
166fb6c1f39Sopenharmony_ci        };
167fb6c1f39Sopenharmony_ci    }
168fb6c1f39Sopenharmony_ci    for inp in INPUTS {
169fb6c1f39Sopenharmony_ci        for q in inp.never {
170fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "never");
171fb6c1f39Sopenharmony_ci        }
172fb6c1f39Sopenharmony_ci        for q in inp.rare {
173fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "rare");
174fb6c1f39Sopenharmony_ci        }
175fb6c1f39Sopenharmony_ci        for q in inp.common {
176fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "common");
177fb6c1f39Sopenharmony_ci        }
178fb6c1f39Sopenharmony_ci    }
179fb6c1f39Sopenharmony_ci}
180fb6c1f39Sopenharmony_ci
181fb6c1f39Sopenharmony_cifn prebuilt(c: &mut Criterion) {
182fb6c1f39Sopenharmony_ci    macro_rules! def_impl {
183fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr, $impl:ident) => {
184fb6c1f39Sopenharmony_ci            let config = "prebuilt";
185fb6c1f39Sopenharmony_ci            let available = imp::$impl::available($q.needle);
186fb6c1f39Sopenharmony_ci            // We only define non-iter benchmarks when the count is <=1. Such
187fb6c1f39Sopenharmony_ci            // queries are usually constructed to only appear at the end.
188fb6c1f39Sopenharmony_ci            // Otherwise, for more common queries, the benchmark would be
189fb6c1f39Sopenharmony_ci            // approximately duplicative with benchmarks on shorter haystacks
190fb6c1f39Sopenharmony_ci            // for the implementations we benchmark.
191fb6c1f39Sopenharmony_ci            if $q.count <= 1 && available.contains(&config) {
192fb6c1f39Sopenharmony_ci                let expected = $q.count > 0;
193fb6c1f39Sopenharmony_ci                macro_rules! define {
194fb6c1f39Sopenharmony_ci                    ($dir:expr, $new_finder:expr) => {
195fb6c1f39Sopenharmony_ci                        let name = format!(
196fb6c1f39Sopenharmony_ci                            "{dir}/{imp}/{config}/{inp}/{freq}-{q}",
197fb6c1f39Sopenharmony_ci                            dir = $dir,
198fb6c1f39Sopenharmony_ci                            imp = stringify!($impl),
199fb6c1f39Sopenharmony_ci                            config = config,
200fb6c1f39Sopenharmony_ci                            inp = $inp.name,
201fb6c1f39Sopenharmony_ci                            freq = $freq,
202fb6c1f39Sopenharmony_ci                            q = $q.name,
203fb6c1f39Sopenharmony_ci                        );
204fb6c1f39Sopenharmony_ci                        define(
205fb6c1f39Sopenharmony_ci                            c,
206fb6c1f39Sopenharmony_ci                            &name,
207fb6c1f39Sopenharmony_ci                            $inp.corpus.as_bytes(),
208fb6c1f39Sopenharmony_ci                            Box::new(move |b| {
209fb6c1f39Sopenharmony_ci                                let find = $new_finder($q.needle);
210fb6c1f39Sopenharmony_ci                                b.iter(|| {
211fb6c1f39Sopenharmony_ci                                    assert_eq!(expected, find($inp.corpus));
212fb6c1f39Sopenharmony_ci                                });
213fb6c1f39Sopenharmony_ci                            }),
214fb6c1f39Sopenharmony_ci                        );
215fb6c1f39Sopenharmony_ci                    };
216fb6c1f39Sopenharmony_ci                }
217fb6c1f39Sopenharmony_ci                define!("memmem", imp::$impl::fwd::prebuilt);
218fb6c1f39Sopenharmony_ci                if available.contains(&"reverse") {
219fb6c1f39Sopenharmony_ci                    define!("memrmem", imp::$impl::rev::prebuilt);
220fb6c1f39Sopenharmony_ci                }
221fb6c1f39Sopenharmony_ci            }
222fb6c1f39Sopenharmony_ci        };
223fb6c1f39Sopenharmony_ci    }
224fb6c1f39Sopenharmony_ci    macro_rules! def_all_impls {
225fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr) => {
226fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate);
227fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate_nopre);
228fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, bstr);
229fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, regex);
230fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, stud);
231fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, twoway);
232fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, sliceslice);
233fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, libc);
234fb6c1f39Sopenharmony_ci        };
235fb6c1f39Sopenharmony_ci    }
236fb6c1f39Sopenharmony_ci    for inp in INPUTS {
237fb6c1f39Sopenharmony_ci        for q in inp.never {
238fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "never");
239fb6c1f39Sopenharmony_ci        }
240fb6c1f39Sopenharmony_ci        for q in inp.rare {
241fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "rare");
242fb6c1f39Sopenharmony_ci        }
243fb6c1f39Sopenharmony_ci        for q in inp.common {
244fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "common");
245fb6c1f39Sopenharmony_ci        }
246fb6c1f39Sopenharmony_ci    }
247fb6c1f39Sopenharmony_ci}
248fb6c1f39Sopenharmony_ci
249fb6c1f39Sopenharmony_cifn oneshot_iter(c: &mut Criterion) {
250fb6c1f39Sopenharmony_ci    macro_rules! def_impl {
251fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr, $impl:ident) => {
252fb6c1f39Sopenharmony_ci            let config = "oneshotiter";
253fb6c1f39Sopenharmony_ci            let available = imp::$impl::available($q.needle);
254fb6c1f39Sopenharmony_ci            // We only define iter benchmarks when the count is >1. Since
255fb6c1f39Sopenharmony_ci            // queries with count<=1 are usually constructed such that the
256fb6c1f39Sopenharmony_ci            // match appears at the end of the haystack, it doesn't make much
257fb6c1f39Sopenharmony_ci            // sense to also benchmark iteration for that case. Instead, we only
258fb6c1f39Sopenharmony_ci            // benchmark iteration for queries that match more frequently.
259fb6c1f39Sopenharmony_ci            if $q.count > 1 && available.contains(&config) {
260fb6c1f39Sopenharmony_ci                macro_rules! define {
261fb6c1f39Sopenharmony_ci                    ($dir:expr, $find_iter:expr) => {
262fb6c1f39Sopenharmony_ci                        let name = format!(
263fb6c1f39Sopenharmony_ci                            "{dir}/{imp}/{config}/{inp}/{freq}-{q}",
264fb6c1f39Sopenharmony_ci                            dir = $dir,
265fb6c1f39Sopenharmony_ci                            imp = stringify!($impl),
266fb6c1f39Sopenharmony_ci                            config = config,
267fb6c1f39Sopenharmony_ci                            inp = $inp.name,
268fb6c1f39Sopenharmony_ci                            freq = $freq,
269fb6c1f39Sopenharmony_ci                            q = $q.name,
270fb6c1f39Sopenharmony_ci                        );
271fb6c1f39Sopenharmony_ci                        define(
272fb6c1f39Sopenharmony_ci                            c,
273fb6c1f39Sopenharmony_ci                            &name,
274fb6c1f39Sopenharmony_ci                            $inp.corpus.as_bytes(),
275fb6c1f39Sopenharmony_ci                            Box::new(move |b| {
276fb6c1f39Sopenharmony_ci                                b.iter(|| {
277fb6c1f39Sopenharmony_ci                                    let it =
278fb6c1f39Sopenharmony_ci                                        $find_iter($inp.corpus, $q.needle);
279fb6c1f39Sopenharmony_ci                                    assert_eq!($q.count, it.count());
280fb6c1f39Sopenharmony_ci                                });
281fb6c1f39Sopenharmony_ci                            }),
282fb6c1f39Sopenharmony_ci                        );
283fb6c1f39Sopenharmony_ci                    };
284fb6c1f39Sopenharmony_ci                }
285fb6c1f39Sopenharmony_ci                define!("memmem", imp::$impl::fwd::oneshotiter);
286fb6c1f39Sopenharmony_ci                if available.contains(&"reverse") {
287fb6c1f39Sopenharmony_ci                    define!("memrmem", imp::$impl::rev::oneshotiter);
288fb6c1f39Sopenharmony_ci                }
289fb6c1f39Sopenharmony_ci            }
290fb6c1f39Sopenharmony_ci        };
291fb6c1f39Sopenharmony_ci    }
292fb6c1f39Sopenharmony_ci    macro_rules! def_all_impls {
293fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr) => {
294fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate);
295fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate_nopre);
296fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, bstr);
297fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, regex);
298fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, stud);
299fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, twoway);
300fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, sliceslice);
301fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, libc);
302fb6c1f39Sopenharmony_ci        };
303fb6c1f39Sopenharmony_ci    }
304fb6c1f39Sopenharmony_ci    for inp in INPUTS {
305fb6c1f39Sopenharmony_ci        for q in inp.never {
306fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "never");
307fb6c1f39Sopenharmony_ci        }
308fb6c1f39Sopenharmony_ci        for q in inp.rare {
309fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "rare");
310fb6c1f39Sopenharmony_ci        }
311fb6c1f39Sopenharmony_ci        for q in inp.common {
312fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "common");
313fb6c1f39Sopenharmony_ci        }
314fb6c1f39Sopenharmony_ci    }
315fb6c1f39Sopenharmony_ci}
316fb6c1f39Sopenharmony_ci
317fb6c1f39Sopenharmony_cifn prebuilt_iter(c: &mut Criterion) {
318fb6c1f39Sopenharmony_ci    macro_rules! def_impl {
319fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr, $impl:ident) => {
320fb6c1f39Sopenharmony_ci            let config = "prebuiltiter";
321fb6c1f39Sopenharmony_ci            let available = imp::$impl::available($q.needle);
322fb6c1f39Sopenharmony_ci            // We only define iter benchmarks when the count is >1. Since
323fb6c1f39Sopenharmony_ci            // queries with count<=1 are usually constructed such that the
324fb6c1f39Sopenharmony_ci            // match appears at the end of the haystack, it doesn't make much
325fb6c1f39Sopenharmony_ci            // sense to also benchmark iteration for that case. Instead, we only
326fb6c1f39Sopenharmony_ci            // benchmark iteration for queries that match more frequently.
327fb6c1f39Sopenharmony_ci            if $q.count > 1 && available.contains(&config) {
328fb6c1f39Sopenharmony_ci                macro_rules! define {
329fb6c1f39Sopenharmony_ci                    ($dir:expr, $new_finder:expr) => {
330fb6c1f39Sopenharmony_ci                        let name = format!(
331fb6c1f39Sopenharmony_ci                            "{dir}/{imp}/{config}/{inp}/{freq}-{q}",
332fb6c1f39Sopenharmony_ci                            dir = $dir,
333fb6c1f39Sopenharmony_ci                            imp = stringify!($impl),
334fb6c1f39Sopenharmony_ci                            config = config,
335fb6c1f39Sopenharmony_ci                            inp = $inp.name,
336fb6c1f39Sopenharmony_ci                            freq = $freq,
337fb6c1f39Sopenharmony_ci                            q = $q.name,
338fb6c1f39Sopenharmony_ci                        );
339fb6c1f39Sopenharmony_ci                        define(
340fb6c1f39Sopenharmony_ci                            c,
341fb6c1f39Sopenharmony_ci                            &name,
342fb6c1f39Sopenharmony_ci                            $inp.corpus.as_bytes(),
343fb6c1f39Sopenharmony_ci                            Box::new(move |b| {
344fb6c1f39Sopenharmony_ci                                let finder = $new_finder($q.needle);
345fb6c1f39Sopenharmony_ci                                b.iter(|| {
346fb6c1f39Sopenharmony_ci                                    let it = finder.iter($inp.corpus);
347fb6c1f39Sopenharmony_ci                                    assert_eq!($q.count, it.count());
348fb6c1f39Sopenharmony_ci                                });
349fb6c1f39Sopenharmony_ci                            }),
350fb6c1f39Sopenharmony_ci                        );
351fb6c1f39Sopenharmony_ci                    };
352fb6c1f39Sopenharmony_ci                }
353fb6c1f39Sopenharmony_ci                define!("memmem", imp::$impl::fwd::prebuiltiter);
354fb6c1f39Sopenharmony_ci                if available.contains(&"reverse") {
355fb6c1f39Sopenharmony_ci                    define!("memrmem", imp::$impl::rev::prebuiltiter);
356fb6c1f39Sopenharmony_ci                }
357fb6c1f39Sopenharmony_ci            }
358fb6c1f39Sopenharmony_ci        };
359fb6c1f39Sopenharmony_ci    }
360fb6c1f39Sopenharmony_ci    macro_rules! def_all_impls {
361fb6c1f39Sopenharmony_ci        ($inp:expr, $q:expr, $freq:expr) => {
362fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate);
363fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, krate_nopre);
364fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, bstr);
365fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, regex);
366fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, stud);
367fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, twoway);
368fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, sliceslice);
369fb6c1f39Sopenharmony_ci            def_impl!($inp, $q, $freq, libc);
370fb6c1f39Sopenharmony_ci        };
371fb6c1f39Sopenharmony_ci    }
372fb6c1f39Sopenharmony_ci    for inp in INPUTS {
373fb6c1f39Sopenharmony_ci        for q in inp.never {
374fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "never");
375fb6c1f39Sopenharmony_ci        }
376fb6c1f39Sopenharmony_ci        for q in inp.rare {
377fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "rare");
378fb6c1f39Sopenharmony_ci        }
379fb6c1f39Sopenharmony_ci        for q in inp.common {
380fb6c1f39Sopenharmony_ci            def_all_impls!(inp, q, "common");
381fb6c1f39Sopenharmony_ci        }
382fb6c1f39Sopenharmony_ci    }
383fb6c1f39Sopenharmony_ci}
384