1 //! Some iterator that produces tuples
2
3 use std::iter::Fuse;
4 use std::iter::Take;
5 use std::iter::Cycle;
6 use std::marker::PhantomData;
7
8 // `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
9 // tuple-related methods to be used by clients in generic contexts, while
10 // hiding the implementation details of `TupleCollect`.
11 // See https://github.com/rust-itertools/itertools/issues/387
12
13 /// Implemented for homogeneous tuples of size up to 4.
14 pub trait HomogeneousTuple
15 : TupleCollect
16 {}
17
18 impl<T: TupleCollect> HomogeneousTuple for T {}
19
20 /// An iterator over a incomplete tuple.
21 ///
22 /// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
23 /// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
24 #[derive(Clone, Debug)]
25 pub struct TupleBuffer<T>
26 where T: HomogeneousTuple
27 {
28 cur: usize,
29 buf: T::Buffer,
30 }
31
32 impl<T> TupleBuffer<T>
33 where T: HomogeneousTuple
34 {
new(buf: T::Buffer) -> Self35 fn new(buf: T::Buffer) -> Self {
36 TupleBuffer {
37 cur: 0,
38 buf,
39 }
40 }
41 }
42
43 impl<T> Iterator for TupleBuffer<T>
44 where T: HomogeneousTuple
45 {
46 type Item = T::Item;
47
next(&mut self) -> Option<Self::Item>48 fn next(&mut self) -> Option<Self::Item> {
49 let s = self.buf.as_mut();
50 if let Some(ref mut item) = s.get_mut(self.cur) {
51 self.cur += 1;
52 item.take()
53 } else {
54 None
55 }
56 }
57
size_hint(&self) -> (usize, Option<usize>)58 fn size_hint(&self) -> (usize, Option<usize>) {
59 let buffer = &self.buf.as_ref()[self.cur..];
60 let len = if buffer.is_empty() {
61 0
62 } else {
63 buffer.iter()
64 .position(|x| x.is_none())
65 .unwrap_or_else(|| buffer.len())
66 };
67 (len, Some(len))
68 }
69 }
70
71 impl<T> ExactSizeIterator for TupleBuffer<T>
72 where T: HomogeneousTuple
73 {
74 }
75
76 /// An iterator that groups the items in tuples of a specific size.
77 ///
78 /// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
79 #[derive(Clone)]
80 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
81 pub struct Tuples<I, T>
82 where I: Iterator<Item = T::Item>,
83 T: HomogeneousTuple
84 {
85 iter: Fuse<I>,
86 buf: T::Buffer,
87 }
88
89 /// Create a new tuples iterator.
tuples<I, T>(iter: I) -> Tuples<I, T> where I: Iterator<Item = T::Item>, T: HomogeneousTuple90 pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
91 where I: Iterator<Item = T::Item>,
92 T: HomogeneousTuple
93 {
94 Tuples {
95 iter: iter.fuse(),
96 buf: Default::default(),
97 }
98 }
99
100 impl<I, T> Iterator for Tuples<I, T>
101 where 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 }
110
111 impl<I, T> Tuples<I, T>
112 where I: Iterator<Item = T::Item>,
113 T: HomogeneousTuple
114 {
115 /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
116 ///
117 /// ```
118 /// use itertools::Itertools;
119 ///
120 /// let mut iter = (0..5).tuples();
121 /// assert_eq!(Some((0, 1, 2)), iter.next());
122 /// assert_eq!(None, iter.next());
123 /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
124 /// ```
into_buffer(self) -> TupleBuffer<T>125 pub fn into_buffer(self) -> TupleBuffer<T> {
126 TupleBuffer::new(self.buf)
127 }
128 }
129
130
131 /// An iterator over all contiguous windows that produces tuples of a specific size.
132 ///
133 /// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
134 /// information.
135 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
136 #[derive(Clone, Debug)]
137 pub struct TupleWindows<I, T>
138 where I: Iterator<Item = T::Item>,
139 T: HomogeneousTuple
140 {
141 iter: I,
142 last: Option<T>,
143 }
144
145 /// Create a new tuple windows iterator.
tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T> where I: Iterator<Item = T::Item>, T: HomogeneousTuple, T::Item: Clone146 pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
147 where I: Iterator<Item = T::Item>,
148 T: HomogeneousTuple,
149 T::Item: Clone
150 {
151 use std::iter::once;
152
153 let mut last = None;
154 if T::num_items() != 1 {
155 // put in a duplicate item in front of the tuple; this simplifies
156 // .next() function.
157 if let Some(item) = iter.next() {
158 let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
159 last = T::collect_from_iter_no_buf(iter);
160 }
161 }
162
163 TupleWindows {
164 last,
165 iter,
166 }
167 }
168
169 impl<I, T> Iterator for TupleWindows<I, T>
170 where I: Iterator<Item = T::Item>,
171 T: HomogeneousTuple + Clone,
172 T::Item: Clone
173 {
174 type Item = T;
175
next(&mut self) -> Option<Self::Item>176 fn next(&mut self) -> Option<Self::Item> {
177 if T::num_items() == 1 {
178 return T::collect_from_iter_no_buf(&mut self.iter)
179 }
180 if let Some(ref mut last) = self.last {
181 if let Some(new) = self.iter.next() {
182 last.left_shift_push(new);
183 return Some(last.clone());
184 }
185 }
186 None
187 }
188 }
189
190 /// An iterator over all windows,wrapping back to the first elements when the
191 /// window would otherwise exceed the length of the iterator, producing tuples
192 /// of a specific size.
193 ///
194 /// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
195 /// information.
196 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
197 #[derive(Debug)]
198 pub struct CircularTupleWindows<I, T: Clone>
199 where I: Iterator<Item = T::Item> + Clone,
200 T: TupleCollect + Clone
201 {
202 iter: Take<TupleWindows<Cycle<I>, T>>,
203 phantom_data: PhantomData<T>
204 }
205
circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T> where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator, T: TupleCollect + Clone, T::Item: Clone206 pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
207 where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
208 T: TupleCollect + Clone,
209 T::Item: Clone
210 {
211 let len = iter.len();
212 let iter = tuple_windows(iter.cycle()).take(len);
213
214 CircularTupleWindows {
215 iter,
216 phantom_data: PhantomData{}
217 }
218 }
219
220 impl<I, T> Iterator for CircularTupleWindows<I, T>
221 where I: Iterator<Item = T::Item> + Clone,
222 T: TupleCollect + Clone,
223 T::Item: Clone
224 {
225 type Item = T;
226
next(&mut self) -> Option<Self::Item>227 fn next(&mut self) -> Option<Self::Item> {
228 self.iter.next()
229 }
230 }
231
232 pub trait TupleCollect: Sized {
233 type Item;
234 type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;
235
collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self> where I: IntoIterator<Item = Self::Item>236 fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
237 where I: IntoIterator<Item = Self::Item>;
238
collect_from_iter_no_buf<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = Self::Item>239 fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
240 where I: IntoIterator<Item = Self::Item>;
241
num_items() -> usize242 fn num_items() -> usize;
243
left_shift_push(&mut self, item: Self::Item)244 fn left_shift_push(&mut self, item: Self::Item);
245 }
246
247 macro_rules! count_ident{
248 () => {0};
249 ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
250 }
251 macro_rules! ignore_ident{
252 ($id:ident, $($t:tt)*) => {$($t)*};
253 }
254 macro_rules! rev_for_each_ident{
255 ($m:ident, ) => {};
256 ($m:ident, $i0:ident, $($i:ident,)*) => {
257 rev_for_each_ident!($m, $($i,)*);
258 $m!($i0);
259 };
260 }
261
262 macro_rules! impl_tuple_collect {
263 ($dummy:ident,) => {}; // stop
264 ($dummy:ident, $($Y:ident,)*) => (
265 impl_tuple_collect!($($Y,)*);
266 impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
267 type Item = A;
268 type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];
269
270 #[allow(unused_assignments, unused_mut)]
271 fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
272 where I: IntoIterator<Item = A>
273 {
274 let mut iter = iter.into_iter();
275 $(
276 let mut $Y = None;
277 )*
278
279 loop {
280 $(
281 $Y = iter.next();
282 if $Y.is_none() {
283 break
284 }
285 )*
286 return Some(($($Y.unwrap()),*,))
287 }
288
289 let mut i = 0;
290 let mut s = buf.as_mut();
291 $(
292 if i < s.len() {
293 s[i] = $Y;
294 i += 1;
295 }
296 )*
297 return None;
298 }
299
300 fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
301 where I: IntoIterator<Item = A>
302 {
303 let mut iter = iter.into_iter();
304
305 Some(($(
306 { let $Y = iter.next()?; $Y },
307 )*))
308 }
309
310 fn num_items() -> usize {
311 count_ident!($($Y,)*)
312 }
313
314 fn left_shift_push(&mut self, mut item: A) {
315 use std::mem::replace;
316
317 let &mut ($(ref mut $Y),*,) = self;
318 macro_rules! replace_item{($i:ident) => {
319 item = replace($i, item);
320 }};
321 rev_for_each_ident!(replace_item, $($Y,)*);
322 drop(item);
323 }
324 }
325 )
326 }
327 impl_tuple_collect!(dummy, a, b, c, d, e, f, g, h, i, j, k, l,);
328