1pub(crate) trait RevisitableGroupByForIterator {
50 type Item;
51 type Iter: Iterator<Item = Self::Item> + Clone;
52
53 fn revisitable_group_by<K, F>(
55 self,
56 get_key: F,
57 ) -> RevisitableGroupBy<Self::Item, K, Self::Iter, F>
58 where
59 K: PartialEq + Copy,
60 F: FnMut(&Self::Item) -> K;
61}
62
63impl<I: Iterator + Clone> RevisitableGroupByForIterator for I {
64 type Item = <I as Iterator>::Item;
65 type Iter = I;
66
67 fn revisitable_group_by<K, F>(
68 self,
69 get_key: F,
70 ) -> RevisitableGroupBy<Self::Item, K, Self::Iter, F>
71 where
72 K: PartialEq + Copy,
73 F: FnMut(&Self::Item) -> K,
74 {
75 RevisitableGroupBy {
76 iter: self,
77 get_key,
78 next_group_initial: None,
79 }
80 }
81}
82
83pub(crate) struct RevisitableGroupBy<T, K, I, F>
85where
86 K: PartialEq + Copy,
87 I: Iterator<Item = T> + Clone,
88 F: FnMut(&T) -> K,
89{
90 iter: I,
92 get_key: F,
94 next_group_initial: Option<(T, K)>,
96}
97
98impl<T, K, I, F> Iterator for RevisitableGroupBy<T, K, I, F>
99where
100 K: PartialEq + Copy,
101 I: Iterator<Item = T> + Clone,
102 F: FnMut(&T) -> K,
103{
104 type Item = RevisitableGroup<T, K, I>;
105
106 fn next(&mut self) -> Option<Self::Item> {
107 let (group_head, group_key) = if let Some((head, key)) = self.next_group_initial.take() {
108 (head, key)
111 } else {
112 let item = self.iter.next()?;
115 let key = (self.get_key)(&item);
118 (item, key)
119 };
120
121 let mut group_size = 1;
123
124 let saved_iter = self.iter.clone();
126 loop {
127 if let Some(item) = self.iter.next() {
128 let key = (self.get_key)(&item);
130 if key == group_key {
131 group_size += 1;
133 } else {
134 self.next_group_initial = Some((item, key));
136 break;
138 }
139 } else {
140 debug_assert!(self.next_group_initial.is_none());
142 break;
143 }
144 }
145
146 Some(RevisitableGroup {
147 key: group_key,
148 len: group_size,
149 head: Some(group_head),
150 iter: saved_iter,
151 remaining: group_size,
152 })
153 }
154}
155
156pub(crate) struct RevisitableGroup<T, K, I>
157where
158 K: PartialEq + Copy,
159 I: Iterator<Item = T>,
160{
161 pub key: K,
163 pub len: usize,
165 head: Option<T>,
167 iter: I,
169 remaining: usize,
171}
172
173impl<T, K, I> Iterator for RevisitableGroup<T, K, I>
174where
175 K: PartialEq + Copy,
176 I: Iterator<Item = T>,
177{
178 type Item = T;
179
180 fn next(&mut self) -> Option<Self::Item> {
181 if self.remaining == 0 {
182 None
183 } else {
184 self.remaining -= 1;
185 if let Some(item) = self.head.take() {
186 Some(item)
187 } else {
188 let result = self.iter.next();
189 debug_assert!(result.is_some());
190 result
191 }
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_simple_group_by() {
202 let nums = [1, 3, 5, 2, 4, 6, 7, 9];
203 let grouped = nums
204 .iter()
205 .revisitable_group_by(|x| *x % 2)
206 .map(|group| (group.key, group.len, group.copied().collect::<Vec<_>>()))
207 .collect::<Vec<_>>();
208 assert_eq!(
209 grouped,
210 vec![
211 (1, 3, vec![1, 3, 5]),
212 (0, 3, vec![2, 4, 6]),
213 (1, 2, vec![7, 9]),
214 ]
215 );
216 }
217
218 #[test]
219 #[allow(clippy::never_loop)] fn test_empty_outer_slice() {
221 let slice_of_slices: &[&[i32]] = &[];
222 for _group in slice_of_slices
223 .iter()
224 .copied()
225 .flatten()
226 .copied()
227 .revisitable_group_by(|_| 42)
228 {
229 panic!("There is no item!");
230 }
231 }
232
233 #[test]
234 #[allow(clippy::never_loop)] fn test_empty_inner_slice() {
236 let slice_of_slices: &[&[i32]] = &[&[], &[], &[]];
237 for _group in slice_of_slices
238 .iter()
239 .copied()
240 .flatten()
241 .copied()
242 .revisitable_group_by(|_| 42)
243 {
244 panic!("There is no item!");
245 }
246 }
247
248 #[test]
249 fn test_single_item() {
250 let slice_of_slices: &[&[i32]] = &[&[1]];
251 for group in slice_of_slices
252 .iter()
253 .copied()
254 .flatten()
255 .copied()
256 .revisitable_group_by(|_| 42)
257 {
258 assert_eq!(group.key, 42);
259 }
260 }
261
262 #[test]
263 fn test_single_slice_multi_item() {
264 let slice_of_slices: &[&[i32]] = &[&[1, 3, 5, 2, 4, 6, 7]];
265 let result = slice_of_slices
266 .iter()
267 .copied()
268 .flatten()
269 .copied()
270 .revisitable_group_by(|x| x % 2)
271 .map(|group| (group.key, group.len, group.collect::<Vec<_>>()))
272 .collect::<Vec<_>>();
273 assert_eq!(
274 result,
275 vec![
276 (1, 3, vec![1, 3, 5]),
277 (0, 3, vec![2, 4, 6]),
278 (1, 1, vec![7])
279 ]
280 );
281 }
282
283 #[test]
284 fn test_multi_slice_multi_item() {
285 let slice_of_slices: &[&[i32]] = &[&[10, 20], &[11, 21, 31], &[12, 22, 32, 42]];
286 let result = slice_of_slices
287 .iter()
288 .copied()
289 .flatten()
290 .copied()
291 .revisitable_group_by(|x| x % 10)
292 .map(|group| (group.key, group.len, group.collect::<Vec<_>>()))
293 .collect::<Vec<_>>();
294 assert_eq!(
295 result,
296 vec![
297 (0, 2, vec![10, 20]),
298 (1, 3, vec![11, 21, 31]),
299 (2, 4, vec![12, 22, 32, 42])
300 ]
301 );
302 }
303
304 #[test]
305 fn test_cross_slice_groups() {
306 let slice_of_slices: &[&[i32]] = &[&[10, 20], &[30, 40, 11, 21], &[31, 12, 22]];
307 let result = slice_of_slices
308 .iter()
309 .copied()
310 .flatten()
311 .copied()
312 .revisitable_group_by(|x| x % 10)
313 .map(|group| (group.key, group.len, group.collect::<Vec<_>>()))
314 .collect::<Vec<_>>();
315 assert_eq!(
316 result,
317 vec![
318 (0, 4, vec![10, 20, 30, 40]),
319 (1, 3, vec![11, 21, 31]),
320 (2, 2, vec![12, 22])
321 ]
322 );
323 }
324
325 #[test]
326 fn test_cross_slice_groups2() {
327 let slice_of_slices: &[&[i32]] = &[&[10, 20, 11], &[21, 31, 41], &[51, 61], &[71, 12, 22]];
328 let result = slice_of_slices
329 .iter()
330 .cloned()
331 .flatten()
332 .copied()
333 .revisitable_group_by(|x| x % 10)
334 .map(|group| (group.key, group.len, group.collect::<Vec<_>>()))
335 .collect::<Vec<_>>();
336 assert_eq!(
337 result,
338 vec![
339 (0, 2, vec![10, 20]),
340 (1, 7, vec![11, 21, 31, 41, 51, 61, 71]),
341 (2, 2, vec![12, 22])
342 ]
343 );
344 }
345
346 #[test]
347 fn test_internal_mutability() {
348 use std::sync::atomic::{AtomicUsize, Ordering};
349 let slab0 = vec![
350 AtomicUsize::new(1),
351 AtomicUsize::new(3),
352 AtomicUsize::new(2),
353 ];
354 let slab1 = vec![
355 AtomicUsize::new(4),
356 AtomicUsize::new(6),
357 AtomicUsize::new(5),
358 ];
359 let slab2 = vec![
360 AtomicUsize::new(7),
361 AtomicUsize::new(9),
362 AtomicUsize::new(10),
363 ];
364
365 let slices: Vec<&[AtomicUsize]> = vec![&slab0[0..3], &slab1[0..3], &slab2[0..2]];
368
369 let mut collected = vec![];
370
371 for group in slices
372 .iter()
373 .copied()
374 .flatten()
375 .revisitable_group_by(|x| x.load(Ordering::SeqCst) % 2)
376 {
377 let mut group_collected = vec![];
378 let key = group.key;
379 for elem in group {
380 let value = elem.load(Ordering::SeqCst);
381 group_collected.push(value);
382
383 let new_value = value * 100 + key;
384 elem.store(new_value, Ordering::SeqCst);
385 }
386
387 collected.push(group_collected);
388 }
389
390 assert_eq!(collected, vec![vec![1, 3], vec![2, 4, 6], vec![5, 7, 9]]);
391
392 let load_all = |slab: Vec<AtomicUsize>| {
393 slab.iter()
394 .map(|x| x.load(Ordering::SeqCst))
395 .collect::<Vec<_>>()
396 };
397
398 assert_eq!(load_all(slab0), vec![101, 301, 200]);
399 assert_eq!(load_all(slab1), vec![400, 600, 501]);
400 assert_eq!(load_all(slab2), vec![701, 901, 10]); }
402}