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