diff --git a/src/cartesian_power.rs b/src/cartesian_power.rs index 3cf3562ab..3d2b7ef30 100644 --- a/src/cartesian_power.rs +++ b/src/cartesian_power.rs @@ -1,6 +1,58 @@ use alloc::vec::Vec; use std::fmt; -use std::iter::FusedIterator; + +// (base: 0) pow: 0 +// iter indices items +// init S 路 N +// next(C) N 馃棛 路 [] -> [] +// next(K) N 路 N -> None +// next(L) N 路 [] -> [] + +// (base: 2) pow: 0 +// iter indices items +// init S 路 N +// next(C) N 馃棛 路 [] -> [] +// next(K) N 路 N -> None +// next(L) N 路 [] -> [] + +// (base: 0) pow: 2 +// iter indices items +// init S 路 N +// next(D) N! 路 N -> None +// next(B) N 路 N -> None +// next(B) N 路 N -> None + +// (base: 1) pow: 1 +// iter indices items +// init S 路 N +// next(D) S 0 a -> [a] +// next(E) N! 1 ! a -> None +// next(G) N 0 a -> [a] +// next(G) N 1 ! a -> None + +// (base: 2) pow: 1 +// iter indices items +// init S 路 N +// next(D) S 0 a -> [a] +// next(E) S 1 a b -> [b] +// next(E) N! 2 ! a b -> None +// next(G) N 0 a b -> [a] +// next(G) N 1 a b -> [b] +// next(G) N 2 ! a b -> None + +// (base: 2) pow: 3 +// iter indices items +// init S 路 N +// next(D) S 0 0 0 a -> [a, a, a] +// next(E) S 0 0 1 a b -> [a, a, b] +// next(E) N! 0 1 0 a b -> [a, b, a] +// next(G) N 0 1 1 a b -> [a, b, b] +// next(G) N 1 0 0 a b -> [b, a, a] +// next(G) N 1 0 1 a b -> [b, a, b] +// next(G) N 1 1 0 a b -> [b, b, a] +// next(G) N 1 1 1 a b -> [b, b, b] +// next(G) N 2 0 0 ! a b -> None +// next(G) N 0 0 0 a b -> [a, a, a] /// An adaptor iterating through all the ordered `n`-length lists of items /// yielded by the underlying iterator, including repetitions. @@ -15,9 +67,19 @@ where I::Item: Clone, { pow: usize, - iter: Option, // Inner iterator. Forget once consumed after 'base' iterations. - items: Vec, // Fill from iter. Clear once adaptor is exhausted. Final length is 'base'. - indices: Vec, // Indices just yielded. Clear once adaptor is exhausted. Length is 'pow'. + iter: Option, // Inner iterator. Forget once consumed after 'base' iterations. + items: Option>, // Fill from iter. Final length is 'base'. + // None means that collection has not started yet. + // Some(empty) means that collection would have started but pow = 0. + + // Indices just yielded. Length is 'pow'. + // 0 0 .. 0 0 means that the first combination has been yielded. + // 0 0 .. 0 1 means that the second combination has been yielded. + // m m .. m m means that the last combination has just been yielded (m = base - 1). + // b 0 .. 0 0 means that 'None' has just been yielded (b = base). + // The latter is a special value marking the renewal of the iterator, + // which can cycle again through another full round, ad libitum. + indices: Vec, } /// Create a new `CartesianPower` from an iterator of clonables. @@ -29,7 +91,7 @@ where CartesianPower { pow, iter: Some(iter), - items: Vec::new(), + items: None, indices: Vec::new(), } } @@ -53,35 +115,63 @@ where items, indices, } = self; - match (*pow, iter, items.len()) { - // Final stable state: underlying iterator and items forgotten. - (_, None, 0) => None, + println!( + "^{pow}: {indices:?}\t{}\t{:?}", + if iter.is_some() { 'S' } else { 'N' }, + items.as_ref().map(|v| v.len()) + ); + match (*pow, iter, items) { + // BBBBBBBBBBBB + // Stable degenerated state: 0^pow with pow > 0; + (_, None, None) => None, + // CCCCCCCCCCCC // Degenerated 0th power iteration. - (0, Some(_), _) => { - self.iter = None; // Forget without even consuming. - Some((indices, items)) + (0, Some(_), None) => { + self.iter = None; // Forget about underlying iteration immediately. + *items = Some(Vec::new()); // Raise this value as a boolean flag. + Some((indices, &[])) // Yield empty list. } - (pow, Some(it), 0) => { + // KKKKKKKKKKKK + // Degenerated 0th power iteration, after the dummy item was collected. + // Use the Some<(empty)Vec> as a flag to alternate between yielding [] or None. + (0, None, Some(_)) => { + *items = None; + None + } + // LLLLLLLLLLLL + (0, None, None) => { + *items = Some(Vec::new()); + Some((indices, &[])) + } + + // DDDDDDDDDDDD + // First iteration. + (pow, Some(it), None) => { // Check whether there is at least one element in the iterator. if let Some(first) = it.next() { // Allocate buffer to hold items about to be yielded. - items.reserve_exact(it.size_hint().0); - items.push(first); + *items = Some({ + let mut v = Vec::with_capacity(it.size_hint().0); + v.push(first); + v + }); // Same for indices to be yielded. indices.reserve_exact(pow); for _ in 0..pow { indices.push(0); } - return Some((indices, items)); + Some((indices, &items.unwrap())) // HERE: can I rebase to get a smarter borrowck? + } else { + // Degenerated iteration over an empty set, yet with non-null power. + self.iter = None; + None } - // Degenerated iteration over an empty set, yet with non-null power. - self.iter = None; - None } - (pow, Some(it), base) => { + // EEEEEEEEEEEE + (pow, Some(it), Some(items)) => { // We are still unsure whether all items have been collected. // As a consequence, 'base' is still uncertain, // but then we know that indices haven't started wrapping around yet. @@ -91,32 +181,55 @@ where return Some((indices, items)); } - // All items have just been collected. - self.iter = None; - if base == 1 || pow == 1 { + // The item collected on previous call was the last one. + self.iter = None; // Forget about the underlying iterator. + if pow == 1 { // End of iteration. - items.clear(); - indices.clear(); + let base = items.len(); + indices[0] = base; // Mark to cycle again on next iteration. return None; } // First wrap around. indices[pow - 1] = 0; - indices[pow - 2] += 1; + indices[pow - 2] = 1; Some((indices, items)) } - (_, None, b) => { + // // FFFFFFFFFFFF + // (_, None, 1) => { + // // Flip the only indice to keep cycling. + // let ind = &mut indices[0]; + // if *ind == 1 { + // *ind = 0; + // Some((indices, items)) + // } else { + // *ind = 1; + // None + // } + // } + + // GGGGGGGGGGGG + (_, None, Some(items)) => { + let base = items.len(); + if indices[0] == base { + // Special marker that iteration can start over for a new round. + indices[0] = 0; + return Some((indices, items)); + } // Keep yielding items list, incrementing indices rightmost first. for index in indices.iter_mut().rev() { *index += 1; - if *index < b { + if *index < base { return Some((indices, items)); } *index = 0; // Wrap and increment left. } - items.clear(); - indices.clear(); + // Iteration is over. + // But don't clear the collected items, + // and mark a special index value to not fuse the iterator + // but make it possibly cycle through all again. + indices[0] = base; None } } @@ -187,13 +300,6 @@ where } } -impl FusedIterator for CartesianPower -where - I: Iterator, - I::Item: Clone, -{ -} - #[cfg(test)] mod tests { //! Use chars and string to ease testing of every yielded iterator values. @@ -202,37 +308,46 @@ mod tests { use crate::Itertools; use core::str::Chars; - fn check_fused(mut exhausted_it: CartesianPower, context: String) { - for i in 0..100 { - let act = exhausted_it.next(); - assert!( - act.is_none(), - "Iteration {} after expected exhaustion of {} \ - yielded {:?} instead of None. ", - i, - context, - act, - ); - } - } - #[test] fn basic() { fn check(origin: &str, pow: usize, expected: &[&str]) { - let mut it = origin.chars().cartesian_power(pow); - let mut i = 0; - for exp in expected { - let act = it.next(); - if act != Some(exp.chars().collect()) { - panic!( - "Failed iteration {} for {:?}^{}. \ - Expected {:?}, got {:?} instead.", - i, origin, pow, exp, act, - ); + println!("================== ({origin:?}^{pow})"); + let mut it_act = origin.chars().cartesian_power(pow); + // Check thrice that it's cycling. + for r in 1..=3 { + println!("- - {r} - - - - - -"); + let mut it_exp = expected.iter(); + let mut i = 0; + loop { + match (it_exp.next(), it_act.next()) { + (Some(exp), Some(act)) => { + if act != exp.chars().collect::>() { + panic!( + "Failed iteration {} (repetition {}) for {:?}^{}. \ + Expected {:?}, got {:?} instead.", + i, r, origin, pow, exp, act, + ); + } + i += 1; + } + (None, Some(act)) => { + panic!( + "Failed iteration {} (repetition {}) for {:?}^{}. \ + Expected None, got {:?} instead.", + i, r, origin, pow, act, + ); + } + (Some(exp), None) => { + panic!( + "Failed iteration {} (repetition {}) for {:?}^{}. \ + Expected {:?}, got None instead.", + i, r, origin, pow, exp, + ); + } + (None, None) => break, + } } - i += 1; } - check_fused(it, format!("iteration {} or {:?}^{}", i, origin, pow)); } // Empty underlying iterator. @@ -281,38 +396,28 @@ mod tests { fn check(origin: &str, pow: usize, expected: &[(usize, Option<&str>)]) { let mut it = origin.chars().cartesian_power(pow); let mut total_n = Vec::new(); - for &(n, exp) in expected { - let act = it.nth(n); - total_n.push(n); - if act != exp.map(|s| s.chars().collect::>()) { - panic!( - "Failed nth({}) iteration for {:?}^{}. \ - Expected {:?}, got {:?} instead.", - total_n - .iter() - .map(ToString::to_string) - .collect::>() - .join(", "), - origin, - pow, - exp, - act, - ); + for r in 1..=3 { + for &(n, exp) in expected { + let act = it.nth(n); + total_n.push(n); + if act != exp.map(|s| s.chars().collect::>()) { + panic!( + "Failed nth({}) iteration (repetition {}) for {:?}^{}. \ + Expected {:?}, got {:?} instead.", + total_n + .iter() + .map(ToString::to_string) + .collect::>() + .join(", "), + r, + origin, + pow, + exp, + act + ); + } } } - check_fused( - it, - format!( - "nth({}) iteration of {:?}^{}", - total_n - .iter() - .map(ToString::to_string) - .collect::>() - .join(", "), - origin, - pow - ), - ); } // HERE: make it work with the new implementation.