1 use quickcheck::quickcheck;
2 
3 use crate::{tests::memchr::testdata::memchr_tests, Memchr, Memchr2, Memchr3};
4 
5 #[test]
memchr1_iter()6 fn memchr1_iter() {
7     for test in memchr_tests() {
8         test.iter_one(false, Memchr::new);
9     }
10 }
11 
12 #[test]
memchr2_iter()13 fn memchr2_iter() {
14     for test in memchr_tests() {
15         test.iter_two(false, Memchr2::new);
16     }
17 }
18 
19 #[test]
memchr3_iter()20 fn memchr3_iter() {
21     for test in memchr_tests() {
22         test.iter_three(false, Memchr3::new);
23     }
24 }
25 
26 #[test]
memrchr1_iter()27 fn memrchr1_iter() {
28     for test in memchr_tests() {
29         test.iter_one(true, |n1, corpus| Memchr::new(n1, corpus).rev());
30     }
31 }
32 
33 #[test]
memrchr2_iter()34 fn memrchr2_iter() {
35     for test in memchr_tests() {
36         test.iter_two(true, |n1, n2, corpus| {
37             Memchr2::new(n1, n2, corpus).rev()
38         })
39     }
40 }
41 
42 #[test]
memrchr3_iter()43 fn memrchr3_iter() {
44     for test in memchr_tests() {
45         test.iter_three(true, |n1, n2, n3, corpus| {
46             Memchr3::new(n1, n2, n3, corpus).rev()
47         })
48     }
49 }
50 
51 quickcheck! {
52     fn qc_memchr_double_ended_iter(
53         needle: u8, data: Vec<u8>, take_side: Vec<bool>
54     ) -> bool {
55         // make nonempty
56         let mut take_side = take_side;
57         if take_side.is_empty() { take_side.push(true) };
58 
59         let iter = Memchr::new(needle, &data);
60         let all_found = double_ended_take(
61             iter, take_side.iter().cycle().cloned());
62 
63         all_found.iter().cloned().eq(positions1(needle, &data))
64     }
65 
66     fn qc_memchr2_double_ended_iter(
67         needle1: u8, needle2: u8, data: Vec<u8>, take_side: Vec<bool>
68     ) -> bool {
69         // make nonempty
70         let mut take_side = take_side;
71         if take_side.is_empty() { take_side.push(true) };
72 
73         let iter = Memchr2::new(needle1, needle2, &data);
74         let all_found = double_ended_take(
75             iter, take_side.iter().cycle().cloned());
76 
77         all_found.iter().cloned().eq(positions2(needle1, needle2, &data))
78     }
79 
80     fn qc_memchr3_double_ended_iter(
81         needle1: u8, needle2: u8, needle3: u8,
82         data: Vec<u8>, take_side: Vec<bool>
83     ) -> bool {
84         // make nonempty
85         let mut take_side = take_side;
86         if take_side.is_empty() { take_side.push(true) };
87 
88         let iter = Memchr3::new(needle1, needle2, needle3, &data);
89         let all_found = double_ended_take(
90             iter, take_side.iter().cycle().cloned());
91 
92         all_found
93             .iter()
94             .cloned()
95             .eq(positions3(needle1, needle2, needle3, &data))
96     }
97 
98     fn qc_memchr1_iter(data: Vec<u8>) -> bool {
99         let needle = 0;
100         let answer = positions1(needle, &data);
101         answer.eq(Memchr::new(needle, &data))
102     }
103 
104     fn qc_memchr1_rev_iter(data: Vec<u8>) -> bool {
105         let needle = 0;
106         let answer = positions1(needle, &data);
107         answer.rev().eq(Memchr::new(needle, &data).rev())
108     }
109 
110     fn qc_memchr2_iter(data: Vec<u8>) -> bool {
111         let needle1 = 0;
112         let needle2 = 1;
113         let answer = positions2(needle1, needle2, &data);
114         answer.eq(Memchr2::new(needle1, needle2, &data))
115     }
116 
117     fn qc_memchr2_rev_iter(data: Vec<u8>) -> bool {
118         let needle1 = 0;
119         let needle2 = 1;
120         let answer = positions2(needle1, needle2, &data);
121         answer.rev().eq(Memchr2::new(needle1, needle2, &data).rev())
122     }
123 
124     fn qc_memchr3_iter(data: Vec<u8>) -> bool {
125         let needle1 = 0;
126         let needle2 = 1;
127         let needle3 = 2;
128         let answer = positions3(needle1, needle2, needle3, &data);
129         answer.eq(Memchr3::new(needle1, needle2, needle3, &data))
130     }
131 
132     fn qc_memchr3_rev_iter(data: Vec<u8>) -> bool {
133         let needle1 = 0;
134         let needle2 = 1;
135         let needle3 = 2;
136         let answer = positions3(needle1, needle2, needle3, &data);
137         answer.rev().eq(Memchr3::new(needle1, needle2, needle3, &data).rev())
138     }
139 
140     fn qc_memchr1_iter_size_hint(data: Vec<u8>) -> bool {
141         // test that the size hint is within reasonable bounds
142         let needle = 0;
143         let mut iter = Memchr::new(needle, &data);
144         let mut real_count = data
145             .iter()
146             .filter(|&&elt| elt == needle)
147             .count();
148 
149         while let Some(index) = iter.next() {
150             real_count -= 1;
151             let (lower, upper) = iter.size_hint();
152             assert!(lower <= real_count);
153             assert!(upper.unwrap() >= real_count);
154             assert!(upper.unwrap() <= data.len() - index);
155         }
156         true
157     }
158 }
159 
160 // take items from a DEI, taking front for each true and back for each false.
161 // Return a vector with the concatenation of the fronts and the reverse of the
162 // backs.
double_ended_take<I, J>(mut iter: I, take_side: J) -> Vec<I::Item> where I: DoubleEndedIterator, J: Iterator<Item = bool>,163 fn double_ended_take<I, J>(mut iter: I, take_side: J) -> Vec<I::Item>
164 where
165     I: DoubleEndedIterator,
166     J: Iterator<Item = bool>,
167 {
168     let mut found_front = Vec::new();
169     let mut found_back = Vec::new();
170 
171     for take_front in take_side {
172         if take_front {
173             if let Some(pos) = iter.next() {
174                 found_front.push(pos);
175             } else {
176                 break;
177             }
178         } else {
179             if let Some(pos) = iter.next_back() {
180                 found_back.push(pos);
181             } else {
182                 break;
183             }
184         };
185     }
186 
187     let mut all_found = found_front;
188     all_found.extend(found_back.into_iter().rev());
189     all_found
190 }
191 
192 // return an iterator of the 0-based indices of haystack that match the needle
positions1<'a>( n1: u8, haystack: &'a [u8], ) -> Box<dyn DoubleEndedIterator<Item = usize> + 'a>193 fn positions1<'a>(
194     n1: u8,
195     haystack: &'a [u8],
196 ) -> Box<dyn DoubleEndedIterator<Item = usize> + 'a> {
197     let it = haystack
198         .iter()
199         .enumerate()
200         .filter(move |&(_, &b)| b == n1)
201         .map(|t| t.0);
202     Box::new(it)
203 }
204 
positions2<'a>( n1: u8, n2: u8, haystack: &'a [u8], ) -> Box<dyn DoubleEndedIterator<Item = usize> + 'a>205 fn positions2<'a>(
206     n1: u8,
207     n2: u8,
208     haystack: &'a [u8],
209 ) -> Box<dyn DoubleEndedIterator<Item = usize> + 'a> {
210     let it = haystack
211         .iter()
212         .enumerate()
213         .filter(move |&(_, &b)| b == n1 || b == n2)
214         .map(|t| t.0);
215     Box::new(it)
216 }
217 
positions3<'a>( n1: u8, n2: u8, n3: u8, haystack: &'a [u8], ) -> Box<dyn DoubleEndedIterator<Item = usize> + 'a>218 fn positions3<'a>(
219     n1: u8,
220     n2: u8,
221     n3: u8,
222     haystack: &'a [u8],
223 ) -> Box<dyn DoubleEndedIterator<Item = usize> + 'a> {
224     let it = haystack
225         .iter()
226         .enumerate()
227         .filter(move |&(_, &b)| b == n1 || b == n2 || b == n3)
228         .map(|t| t.0);
229     Box::new(it)
230 }
231