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