• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>`.
multi_cartesian_product<H>(iters: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter> where H: Iterator, H::Item: IntoIterator, <H::Item as IntoIterator>::IntoIter: Clone, <H::Item as IntoIterator>::Item: Clone33 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.
iterate_last( multi_iters: &mut [MultiProductIter<I>], mut state: MultiProductIterState ) -> bool68     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.
curr_iterator(&self) -> Vec<I::Item>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.
in_progress(&self) -> bool118     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 {
new(iter: I) -> Self131     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.
iterate(&mut self)140     fn iterate(&mut self) {
141         self.cur = self.iter.next();
142     }
143 
144     /// Reset the managed iterator.
reset(&mut self)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.
in_progress(&self) -> bool151     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 
next(&mut self) -> Option<Self::Item>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 
count(self) -> usize173     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 
size_hint(&self) -> (usize, Option<usize>)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 
last(self) -> Option<Self::Item>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