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