Skip to content

Commit 8d07f6b

Browse files
Philippe-Choletjswrenn
authored andcommitted
Make Product lazy
Similar to what is done by `core::iter::Peekable`, a nested option is now used.
1 parent d7e6bab commit 8d07f6b

File tree

1 file changed

+30
-16
lines changed

1 file changed

+30
-16
lines changed

src/adaptors/mod.rs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -308,22 +308,22 @@ where
308308
I: Iterator,
309309
{
310310
a: I,
311-
a_cur: Option<I::Item>,
311+
a_cur: Option<Option<I::Item>>,
312312
b: J,
313313
b_orig: J,
314314
}
315315

316316
/// Create a new cartesian product iterator
317317
///
318318
/// Iterator element type is `(I::Item, J::Item)`.
319-
pub fn cartesian_product<I, J>(mut i: I, j: J) -> Product<I, J>
319+
pub fn cartesian_product<I, J>(i: I, j: J) -> Product<I, J>
320320
where
321321
I: Iterator,
322322
J: Clone + Iterator,
323323
I::Item: Clone,
324324
{
325325
Product {
326-
a_cur: i.next(),
326+
a_cur: None,
327327
a: i,
328328
b: j.clone(),
329329
b_orig: j,
@@ -339,24 +339,33 @@ where
339339
type Item = (I::Item, J::Item);
340340

341341
fn next(&mut self) -> Option<Self::Item> {
342-
let elt_b = match self.b.next() {
342+
let Self {
343+
a,
344+
a_cur,
345+
b,
346+
b_orig,
347+
} = self;
348+
let elt_b = match b.next() {
343349
None => {
344-
self.b = self.b_orig.clone();
345-
match self.b.next() {
350+
*b = b_orig.clone();
351+
match b.next() {
346352
None => return None,
347353
Some(x) => {
348-
self.a_cur = self.a.next();
354+
*a_cur = Some(a.next());
349355
x
350356
}
351357
}
352358
}
353359
Some(x) => x,
354360
};
355-
self.a_cur.as_ref().map(|a| (a.clone(), elt_b))
361+
a_cur
362+
.get_or_insert_with(|| a.next())
363+
.as_ref()
364+
.map(|a| (a.clone(), elt_b))
356365
}
357366

358367
fn size_hint(&self) -> (usize, Option<usize>) {
359-
let has_cur = self.a_cur.is_some() as usize;
368+
let has_cur = matches!(self.a_cur, Some(Some(_))) as usize;
360369
// Not ExactSizeIterator because size may be larger than usize
361370
let (b_min, b_max) = self.b.size_hint();
362371

@@ -367,21 +376,26 @@ where
367376
)
368377
}
369378

370-
fn fold<Acc, G>(mut self, mut accum: Acc, mut f: G) -> Acc
379+
fn fold<Acc, G>(self, mut accum: Acc, mut f: G) -> Acc
371380
where
372381
G: FnMut(Acc, Self::Item) -> Acc,
373382
{
374383
// use a split loop to handle the loose a_cur as well as avoiding to
375384
// clone b_orig at the end.
376-
if let Some(mut a) = self.a_cur.take() {
377-
let mut b = self.b;
385+
let Self {
386+
mut a,
387+
a_cur,
388+
mut b,
389+
b_orig,
390+
} = self;
391+
if let Some(mut elt_a) = a_cur.unwrap_or_else(|| a.next()) {
378392
loop {
379-
accum = b.fold(accum, |acc, elt| f(acc, (a.clone(), elt)));
393+
accum = b.fold(accum, |acc, elt| f(acc, (elt_a.clone(), elt)));
380394

381395
// we can only continue iterating a if we had a first element;
382-
if let Some(next_a) = self.a.next() {
383-
b = self.b_orig.clone();
384-
a = next_a;
396+
if let Some(next_elt_a) = a.next() {
397+
b = b_orig.clone();
398+
elt_a = next_elt_a;
385399
} else {
386400
break;
387401
}

0 commit comments

Comments
 (0)