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