1 //! Some iterator that produces tuples
2
3 use std::iter::Cycle;
4 use std::iter::Fuse;
5 use std::iter::FusedIterator;
6
7 use crate::size_hint;
8
9 // `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
10 // tuple-related methods to be used by clients in generic contexts, while
11 // hiding the implementation details of `TupleCollect`.
12 // See https://github.com/rust-itertools/itertools/issues/387
13
14 /// Implemented for homogeneous tuples of size up to 12.
15 pub trait HomogeneousTuple: TupleCollect {}
16
17 impl<T: TupleCollect> HomogeneousTuple for T {}
18
19 /// An iterator over a incomplete tuple.
20 ///
21 /// See [`.tuples()`](crate::Itertools::tuples) and
22 /// [`Tuples::into_buffer()`].
23 #[derive(Clone, Debug)]
24 pub struct TupleBuffer<T>
25 where
26 T: HomogeneousTuple,
27 {
28 cur: usize,
29 buf: T::Buffer,
30 }
31
32 impl<T> TupleBuffer<T>
33 where
34 T: HomogeneousTuple,
35 {
new(buf: T::Buffer) -> Self36 fn new(buf: T::Buffer) -> Self {
37 Self { cur: 0, buf }
38 }
39 }
40
41 impl<T> Iterator for TupleBuffer<T>
42 where
43 T: HomogeneousTuple,
44 {
45 type Item = T::Item;
46
next(&mut self) -> Option<Self::Item>47 fn next(&mut self) -> Option<Self::Item> {
48 let s = self.buf.as_mut();
49 if let Some(ref mut item) = s.get_mut(self.cur) {
50 self.cur += 1;
51 item.take()
52 } else {
53 None
54 }
55 }
56
size_hint(&self) -> (usize, Option<usize>)57 fn size_hint(&self) -> (usize, Option<usize>) {
58 let buffer = &self.buf.as_ref()[self.cur..];
59 let len = if buffer.is_empty() {
60 0
61 } else {
62 buffer
63 .iter()
64 .position(|x| x.is_none())
65 .unwrap_or(buffer.len())
66 };
67 (len, Some(len))
68 }
69 }
70
71 impl<T> ExactSizeIterator for TupleBuffer<T> where T: HomogeneousTuple {}
72
73 /// An iterator that groups the items in tuples of a specific size.
74 ///
75 /// See [`.tuples()`](crate::Itertools::tuples) for more information.
76 #[derive(Clone, Debug)]
77 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
78 pub struct Tuples<I, T>
79 where
80 I: Iterator<Item = T::Item>,
81 T: HomogeneousTuple,
82 {
83 iter: Fuse<I>,
84 buf: T::Buffer,
85 }
86
87 /// Create a new tuples iterator.
tuples<I, T>(iter: I) -> Tuples<I, T> where I: Iterator<Item = T::Item>, T: HomogeneousTuple,88 pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
89 where
90 I: Iterator<Item = T::Item>,
91 T: HomogeneousTuple,
92 {
93 Tuples {
94 iter: iter.fuse(),
95 buf: Default::default(),
96 }
97 }
98
99 impl<I, T> Iterator for Tuples<I, T>
100 where
101 I: Iterator<Item = T::Item>,
102 T: HomogeneousTuple,
103 {
104 type Item = T;
105
next(&mut self) -> Option<Self::Item>106 fn next(&mut self) -> Option<Self::Item> {
107 T::collect_from_iter(&mut self.iter, &mut self.buf)
108 }
109
size_hint(&self) -> (usize, Option<usize>)110 fn size_hint(&self) -> (usize, Option<usize>) {
111 // The number of elts we've drawn from the underlying iterator, but have
112 // not yet produced as a tuple.
113 let buffered = T::buffer_len(&self.buf);
114 // To that, we must add the size estimates of the underlying iterator.
115 let (unbuffered_lo, unbuffered_hi) = self.iter.size_hint();
116 // The total low estimate is the sum of the already-buffered elements,
117 // plus the low estimate of remaining unbuffered elements, divided by
118 // the tuple size.
119 let total_lo = add_then_div(unbuffered_lo, buffered, T::num_items()).unwrap_or(usize::MAX);
120 // And likewise for the total high estimate, but using the high estimate
121 // of the remaining unbuffered elements.
122 let total_hi = unbuffered_hi.and_then(|hi| add_then_div(hi, buffered, T::num_items()));
123 (total_lo, total_hi)
124 }
125 }
126
127 /// `(n + a) / d` avoiding overflow when possible, returns `None` if it overflows.
add_then_div(n: usize, a: usize, d: usize) -> Option<usize>128 fn add_then_div(n: usize, a: usize, d: usize) -> Option<usize> {
129 debug_assert_ne!(d, 0);
130 (n / d).checked_add(a / d)?.checked_add((n % d + a % d) / d)
131 }
132
133 impl<I, T> ExactSizeIterator for Tuples<I, T>
134 where
135 I: ExactSizeIterator<Item = T::Item>,
136 T: HomogeneousTuple,
137 {
138 }
139
140 impl<I, T> Tuples<I, T>
141 where
142 I: Iterator<Item = T::Item>,
143 T: HomogeneousTuple,
144 {
145 /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
146 ///
147 /// ```
148 /// use itertools::Itertools;
149 ///
150 /// let mut iter = (0..5).tuples();
151 /// assert_eq!(Some((0, 1, 2)), iter.next());
152 /// assert_eq!(None, iter.next());
153 /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
154 /// ```
into_buffer(self) -> TupleBuffer<T>155 pub fn into_buffer(self) -> TupleBuffer<T> {
156 TupleBuffer::new(self.buf)
157 }
158 }
159
160 /// An iterator over all contiguous windows that produces tuples of a specific size.
161 ///
162 /// See [`.tuple_windows()`](crate::Itertools::tuple_windows) for more
163 /// information.
164 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
165 #[derive(Clone, Debug)]
166 pub struct TupleWindows<I, T>
167 where
168 I: Iterator<Item = T::Item>,
169 T: HomogeneousTuple,
170 {
171 iter: I,
172 last: Option<T>,
173 }
174
175 /// Create a new tuple windows iterator.
tuple_windows<I, T>(iter: I) -> TupleWindows<I, T> where I: Iterator<Item = T::Item>, T: HomogeneousTuple, T::Item: Clone,176 pub fn tuple_windows<I, T>(iter: I) -> TupleWindows<I, T>
177 where
178 I: Iterator<Item = T::Item>,
179 T: HomogeneousTuple,
180 T::Item: Clone,
181 {
182 TupleWindows { last: None, iter }
183 }
184
185 impl<I, T> Iterator for TupleWindows<I, T>
186 where
187 I: Iterator<Item = T::Item>,
188 T: HomogeneousTuple + Clone,
189 T::Item: Clone,
190 {
191 type Item = T;
192
next(&mut self) -> Option<Self::Item>193 fn next(&mut self) -> Option<Self::Item> {
194 if T::num_items() == 1 {
195 return T::collect_from_iter_no_buf(&mut self.iter);
196 }
197 if let Some(new) = self.iter.next() {
198 if let Some(ref mut last) = self.last {
199 last.left_shift_push(new);
200 Some(last.clone())
201 } else {
202 use std::iter::once;
203 let iter = once(new).chain(&mut self.iter);
204 self.last = T::collect_from_iter_no_buf(iter);
205 self.last.clone()
206 }
207 } else {
208 None
209 }
210 }
211
size_hint(&self) -> (usize, Option<usize>)212 fn size_hint(&self) -> (usize, Option<usize>) {
213 let mut sh = self.iter.size_hint();
214 // Adjust the size hint at the beginning
215 // OR when `num_items == 1` (but it does not change the size hint).
216 if self.last.is_none() {
217 sh = size_hint::sub_scalar(sh, T::num_items() - 1);
218 }
219 sh
220 }
221 }
222
223 impl<I, T> ExactSizeIterator for TupleWindows<I, T>
224 where
225 I: ExactSizeIterator<Item = T::Item>,
226 T: HomogeneousTuple + Clone,
227 T::Item: Clone,
228 {
229 }
230
231 impl<I, T> FusedIterator for TupleWindows<I, T>
232 where
233 I: FusedIterator<Item = T::Item>,
234 T: HomogeneousTuple + Clone,
235 T::Item: Clone,
236 {
237 }
238
239 /// An iterator over all windows, wrapping back to the first elements when the
240 /// window would otherwise exceed the length of the iterator, producing tuples
241 /// of a specific size.
242 ///
243 /// See [`.circular_tuple_windows()`](crate::Itertools::circular_tuple_windows) for more
244 /// information.
245 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
246 #[derive(Debug, Clone)]
247 pub struct CircularTupleWindows<I, T>
248 where
249 I: Iterator<Item = T::Item> + Clone,
250 T: TupleCollect + Clone,
251 {
252 iter: TupleWindows<Cycle<I>, T>,
253 len: usize,
254 }
255
circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T> where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator, T: TupleCollect + Clone, T::Item: Clone,256 pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
257 where
258 I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
259 T: TupleCollect + Clone,
260 T::Item: Clone,
261 {
262 let len = iter.len();
263 let iter = tuple_windows(iter.cycle());
264
265 CircularTupleWindows { iter, len }
266 }
267
268 impl<I, T> Iterator for CircularTupleWindows<I, T>
269 where
270 I: Iterator<Item = T::Item> + Clone,
271 T: TupleCollect + Clone,
272 T::Item: Clone,
273 {
274 type Item = T;
275
next(&mut self) -> Option<Self::Item>276 fn next(&mut self) -> Option<Self::Item> {
277 if self.len != 0 {
278 self.len -= 1;
279 self.iter.next()
280 } else {
281 None
282 }
283 }
284
size_hint(&self) -> (usize, Option<usize>)285 fn size_hint(&self) -> (usize, Option<usize>) {
286 (self.len, Some(self.len))
287 }
288 }
289
290 impl<I, T> ExactSizeIterator for CircularTupleWindows<I, T>
291 where
292 I: Iterator<Item = T::Item> + Clone,
293 T: TupleCollect + Clone,
294 T::Item: Clone,
295 {
296 }
297
298 impl<I, T> FusedIterator for CircularTupleWindows<I, T>
299 where
300 I: Iterator<Item = T::Item> + Clone,
301 T: TupleCollect + Clone,
302 T::Item: Clone,
303 {
304 }
305
306 pub trait TupleCollect: Sized {
307 type Item;
308 type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;
309
buffer_len(buf: &Self::Buffer) -> usize310 fn buffer_len(buf: &Self::Buffer) -> usize {
311 let s = buf.as_ref();
312 s.iter().position(Option::is_none).unwrap_or(s.len())
313 }
314
collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self> where I: IntoIterator<Item = Self::Item>315 fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
316 where
317 I: IntoIterator<Item = Self::Item>;
318
collect_from_iter_no_buf<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = Self::Item>319 fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
320 where
321 I: IntoIterator<Item = Self::Item>;
322
num_items() -> usize323 fn num_items() -> usize;
324
left_shift_push(&mut self, item: Self::Item)325 fn left_shift_push(&mut self, item: Self::Item);
326 }
327
328 macro_rules! rev_for_each_ident{
329 ($m:ident, ) => {};
330 ($m:ident, $i0:ident, $($i:ident,)*) => {
331 rev_for_each_ident!($m, $($i,)*);
332 $m!($i0);
333 };
334 }
335
336 macro_rules! impl_tuple_collect {
337 ($dummy:ident,) => {}; // stop
338 ($dummy:ident, $($Y:ident,)*) => (
339 impl_tuple_collect!($($Y,)*);
340 impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
341 type Item = A;
342 type Buffer = [Option<A>; count_ident!($($Y)*) - 1];
343
344 #[allow(unused_assignments, unused_mut)]
345 fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
346 where I: IntoIterator<Item = A>
347 {
348 let mut iter = iter.into_iter();
349 $(
350 let mut $Y = None;
351 )*
352
353 loop {
354 $(
355 $Y = iter.next();
356 if $Y.is_none() {
357 break
358 }
359 )*
360 return Some(($($Y.unwrap()),*,))
361 }
362
363 let mut i = 0;
364 let mut s = buf.as_mut();
365 $(
366 if i < s.len() {
367 s[i] = $Y;
368 i += 1;
369 }
370 )*
371 return None;
372 }
373
374 fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
375 where I: IntoIterator<Item = A>
376 {
377 let mut iter = iter.into_iter();
378
379 Some(($(
380 { let $Y = iter.next()?; $Y },
381 )*))
382 }
383
384 fn num_items() -> usize {
385 count_ident!($($Y)*)
386 }
387
388 fn left_shift_push(&mut self, mut item: A) {
389 use std::mem::replace;
390
391 let &mut ($(ref mut $Y),*,) = self;
392 macro_rules! replace_item{($i:ident) => {
393 item = replace($i, item);
394 }}
395 rev_for_each_ident!(replace_item, $($Y,)*);
396 drop(item);
397 }
398 }
399 )
400 }
401 impl_tuple_collect!(dummy, a, b, c, d, e, f, g, h, i, j, k, l,);
402