diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 435593749..e925db51d 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -308,7 +308,10 @@ where I: Iterator, { a: I, - a_cur: Option, + /// `a_cur` is `None` while no item have been taken out of `a` (at definition). + /// Then `a_cur` will be `Some(Some(item))` until `a` is exhausted, + /// in which case `a_cur` will be `Some(None)`. + a_cur: Option>, b: J, b_orig: J, } @@ -316,14 +319,14 @@ where /// Create a new cartesian product iterator /// /// Iterator element type is `(I::Item, J::Item)`. -pub fn cartesian_product(mut i: I, j: J) -> Product +pub fn cartesian_product(i: I, j: J) -> Product where I: Iterator, J: Clone + Iterator, I::Item: Clone, { Product { - a_cur: i.next(), + a_cur: None, a: i, b: j.clone(), b_orig: j, @@ -339,49 +342,61 @@ where type Item = (I::Item, J::Item); fn next(&mut self) -> Option { - let elt_b = match self.b.next() { + let Self { + a, + a_cur, + b, + b_orig, + } = self; + let elt_b = match b.next() { None => { - self.b = self.b_orig.clone(); - match self.b.next() { + *b = b_orig.clone(); + match b.next() { None => return None, Some(x) => { - self.a_cur = self.a.next(); + *a_cur = Some(a.next()); x } } } Some(x) => x, }; - self.a_cur.as_ref().map(|a| (a.clone(), elt_b)) + a_cur + .get_or_insert_with(|| a.next()) + .as_ref() + .map(|a| (a.clone(), elt_b)) } fn size_hint(&self) -> (usize, Option) { - let has_cur = self.a_cur.is_some() as usize; // Not ExactSizeIterator because size may be larger than usize - let (b_min, b_max) = self.b.size_hint(); - // Compute a * b_orig + b for both lower and upper bound - size_hint::add( - size_hint::mul(self.a.size_hint(), self.b_orig.size_hint()), - (b_min * has_cur, b_max.map(move |x| x * has_cur)), - ) + let mut sh = size_hint::mul(self.a.size_hint(), self.b_orig.size_hint()); + if matches!(self.a_cur, Some(Some(_))) { + sh = size_hint::add(sh, self.b.size_hint()); + } + sh } - fn fold(mut self, mut accum: Acc, mut f: G) -> Acc + fn fold(self, mut accum: Acc, mut f: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, { // use a split loop to handle the loose a_cur as well as avoiding to // clone b_orig at the end. - if let Some(mut a) = self.a_cur.take() { - let mut b = self.b; + let Self { + mut a, + a_cur, + mut b, + b_orig, + } = self; + if let Some(mut elt_a) = a_cur.unwrap_or_else(|| a.next()) { loop { - accum = b.fold(accum, |acc, elt| f(acc, (a.clone(), elt))); + accum = b.fold(accum, |acc, elt| f(acc, (elt_a.clone(), elt))); // we can only continue iterating a if we had a first element; - if let Some(next_a) = self.a.next() { - b = self.b_orig.clone(); - a = next_a; + if let Some(next_elt_a) = a.next() { + b = b_orig.clone(); + elt_a = next_elt_a; } else { break; }