1 | #![cfg (feature = "use_alloc" )] |
2 | |
3 | use crate::size_hint; |
4 | use crate::Itertools; |
5 | |
6 | use alloc::vec::Vec; |
7 | |
8 | #[derive(Clone)] |
9 | /// An iterator adaptor that iterates over the cartesian product of |
10 | /// multiple iterators of type `I`. |
11 | /// |
12 | /// An iterator element type is `Vec<I>`. |
13 | /// |
14 | /// See [`.multi_cartesian_product()`](crate::Itertools::multi_cartesian_product) |
15 | /// for more information. |
16 | #[must_use = "iterator adaptors are lazy and do nothing unless consumed" ] |
17 | pub struct MultiProduct<I>(Vec<MultiProductIter<I>>) |
18 | where I: Iterator + Clone, |
19 | I::Item: Clone; |
20 | |
21 | impl<I> std::fmt::Debug for MultiProduct<I> |
22 | where |
23 | I: Iterator + Clone + std::fmt::Debug, |
24 | I::Item: Clone + std::fmt::Debug, |
25 | { |
26 | debug_fmt_fields!(CoalesceBy, 0); |
27 | } |
28 | |
29 | /// Create a new cartesian product iterator over an arbitrary number |
30 | /// of iterators of the same type. |
31 | /// |
32 | /// Iterator element is of type `Vec<H::Item::Item>`. |
33 | pub fn multi_cartesian_product<H>(iters: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter> |
34 | where H: Iterator, |
35 | H::Item: IntoIterator, |
36 | <H::Item as IntoIterator>::IntoIter: Clone, |
37 | <H::Item as IntoIterator>::Item: Clone |
38 | { |
39 | MultiProduct(iters.map(|i| MultiProductIter::new(i.into_iter())).collect()) |
40 | } |
41 | |
42 | #[derive(Clone, Debug)] |
43 | /// Holds the state of a single iterator within a `MultiProduct`. |
44 | struct MultiProductIter<I> |
45 | where I: Iterator + Clone, |
46 | I::Item: Clone |
47 | { |
48 | cur: Option<I::Item>, |
49 | iter: I, |
50 | iter_orig: I, |
51 | } |
52 | |
53 | /// Holds the current state during an iteration of a `MultiProduct`. |
54 | #[derive(Debug)] |
55 | enum MultiProductIterState { |
56 | StartOfIter, |
57 | MidIter { on_first_iter: bool }, |
58 | } |
59 | |
60 | impl<I> MultiProduct<I> |
61 | where I: Iterator + Clone, |
62 | I::Item: Clone |
63 | { |
64 | /// Iterates the rightmost iterator, then recursively iterates iterators |
65 | /// to the left if necessary. |
66 | /// |
67 | /// Returns true if the iteration succeeded, else false. |
68 | fn iterate_last( |
69 | multi_iters: &mut [MultiProductIter<I>], |
70 | mut state: MultiProductIterState |
71 | ) -> bool { |
72 | use self::MultiProductIterState::*; |
73 | |
74 | if let Some((last, rest)) = multi_iters.split_last_mut() { |
75 | let on_first_iter = match state { |
76 | StartOfIter => { |
77 | let on_first_iter = !last.in_progress(); |
78 | state = MidIter { on_first_iter }; |
79 | on_first_iter |
80 | }, |
81 | MidIter { on_first_iter } => on_first_iter |
82 | }; |
83 | |
84 | if !on_first_iter { |
85 | last.iterate(); |
86 | } |
87 | |
88 | if last.in_progress() { |
89 | true |
90 | } else if MultiProduct::iterate_last(rest, state) { |
91 | last.reset(); |
92 | last.iterate(); |
93 | // If iterator is None twice consecutively, then iterator is |
94 | // empty; whole product is empty. |
95 | last.in_progress() |
96 | } else { |
97 | false |
98 | } |
99 | } else { |
100 | // Reached end of iterator list. On initialisation, return true. |
101 | // At end of iteration (final iterator finishes), finish. |
102 | match state { |
103 | StartOfIter => false, |
104 | MidIter { on_first_iter } => on_first_iter |
105 | } |
106 | } |
107 | } |
108 | |
109 | /// Returns the unwrapped value of the next iteration. |
110 | fn curr_iterator(&self) -> Vec<I::Item> { |
111 | self.0.iter().map(|multi_iter| { |
112 | multi_iter.cur.clone().unwrap() |
113 | }).collect() |
114 | } |
115 | |
116 | /// Returns true if iteration has started and has not yet finished; false |
117 | /// otherwise. |
118 | fn in_progress(&self) -> bool { |
119 | if let Some(last) = self.0.last() { |
120 | last.in_progress() |
121 | } else { |
122 | false |
123 | } |
124 | } |
125 | } |
126 | |
127 | impl<I> MultiProductIter<I> |
128 | where I: Iterator + Clone, |
129 | I::Item: Clone |
130 | { |
131 | fn new(iter: I) -> Self { |
132 | MultiProductIter { |
133 | cur: None, |
134 | iter: iter.clone(), |
135 | iter_orig: iter |
136 | } |
137 | } |
138 | |
139 | /// Iterate the managed iterator. |
140 | fn iterate(&mut self) { |
141 | self.cur = self.iter.next(); |
142 | } |
143 | |
144 | /// Reset the managed iterator. |
145 | fn reset(&mut self) { |
146 | self.iter = self.iter_orig.clone(); |
147 | } |
148 | |
149 | /// Returns true if the current iterator has been started and has not yet |
150 | /// finished; false otherwise. |
151 | fn in_progress(&self) -> bool { |
152 | self.cur.is_some() |
153 | } |
154 | } |
155 | |
156 | impl<I> Iterator for MultiProduct<I> |
157 | where I: Iterator + Clone, |
158 | I::Item: Clone |
159 | { |
160 | type Item = Vec<I::Item>; |
161 | |
162 | fn next(&mut self) -> Option<Self::Item> { |
163 | if MultiProduct::iterate_last( |
164 | &mut self.0, |
165 | MultiProductIterState::StartOfIter |
166 | ) { |
167 | Some(self.curr_iterator()) |
168 | } else { |
169 | None |
170 | } |
171 | } |
172 | |
173 | fn count(self) -> usize { |
174 | if self.0.is_empty() { |
175 | return 0; |
176 | } |
177 | |
178 | if !self.in_progress() { |
179 | return self.0.into_iter().fold(1, |acc, multi_iter| { |
180 | acc * multi_iter.iter.count() |
181 | }); |
182 | } |
183 | |
184 | self.0.into_iter().fold( |
185 | 0, |
186 | |acc, MultiProductIter { iter, iter_orig, cur: _ }| { |
187 | let total_count = iter_orig.count(); |
188 | let cur_count = iter.count(); |
189 | acc * total_count + cur_count |
190 | } |
191 | ) |
192 | } |
193 | |
194 | fn size_hint(&self) -> (usize, Option<usize>) { |
195 | // Not ExactSizeIterator because size may be larger than usize |
196 | if self.0.is_empty() { |
197 | return (0, Some(0)); |
198 | } |
199 | |
200 | if !self.in_progress() { |
201 | return self.0.iter().fold((1, Some(1)), |acc, multi_iter| { |
202 | size_hint::mul(acc, multi_iter.iter.size_hint()) |
203 | }); |
204 | } |
205 | |
206 | self.0.iter().fold( |
207 | (0, Some(0)), |
208 | |acc, &MultiProductIter { ref iter, ref iter_orig, cur: _ }| { |
209 | let cur_size = iter.size_hint(); |
210 | let total_size = iter_orig.size_hint(); |
211 | size_hint::add(size_hint::mul(acc, total_size), cur_size) |
212 | } |
213 | ) |
214 | } |
215 | |
216 | fn last(self) -> Option<Self::Item> { |
217 | let iter_count = self.0.len(); |
218 | |
219 | let lasts: Self::Item = self.0.into_iter() |
220 | .map(|multi_iter| multi_iter.iter.last()) |
221 | .while_some() |
222 | .collect(); |
223 | |
224 | if lasts.len() == iter_count { |
225 | Some(lasts) |
226 | } else { |
227 | None |
228 | } |
229 | } |
230 | } |
231 | |