Skip to content

Commit 009b594

Browse files
committed
🚧 Test cycling iterator instead.
1 parent 8957f70 commit 009b594

File tree

1 file changed

+158
-81
lines changed

1 file changed

+158
-81
lines changed

src/cartesian_power.rs

+158-81
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,48 @@
11
use alloc::vec::Vec;
22
use std::fmt;
3-
use std::iter::FusedIterator;
3+
4+
// (base: 0) pow: 0
5+
// indices iter items
6+
// init · S ·
7+
// next(C) N 🗙 dot // HERE should not behave the same as right below.
8+
9+
// (base: 2) pow: 0
10+
// indices iter items
11+
// init · S ·
12+
// next(C) · N 🗙 · -> None
13+
// next(C) · N · -> None
14+
15+
// (base: 1) pow: 1
16+
// indices iter items
17+
// init · S ·
18+
// next(D) 0 S a -> [a]
19+
// next(E) 1 ! N! a -> None
20+
// next(G) 0 N a -> [a]
21+
// next(G) 1 ! N a -> None
22+
23+
// (base: 2) pow: 1
24+
// indices iter items
25+
// init · S ·
26+
// next(D) 0 S a -> [a]
27+
// next(E) 1 S a b -> [b]
28+
// next(E) 2 ! N! a b -> None
29+
// next(G) 0 N a b -> [a]
30+
// next(G) 1 N a b -> [b]
31+
// next(G) 2 ! N a b -> None
32+
33+
// (base: 2) pow: 3
34+
// indices iter items
35+
// init · S ·
36+
// next(D) 0 0 0 S a -> [a, a, a]
37+
// next(E) 0 0 1 S a b -> [a, a, b]
38+
// next(E) 0 1 0 N! a b -> [a, b, a]
39+
// next(G) 0 1 1 N a b -> [a, b, b]
40+
// next(G) 1 0 0 N a b -> [b, a, a]
41+
// next(G) 1 0 1 N a b -> [b, a, b]
42+
// next(G) 1 1 0 N a b -> [b, b, a]
43+
// next(G) 1 1 1 N a b -> [b, b, b]
44+
// next(G) 2 0 0 ! N a b -> None
45+
// next(G) 0 0 0 N a b -> [a, a, a]
446

547
/// An adaptor iterating through all the ordered `n`-length lists of items
648
/// yielded by the underlying iterator, including repetitions.
@@ -15,9 +57,17 @@ where
1557
I::Item: Clone,
1658
{
1759
pow: usize,
18-
iter: Option<I>, // Inner iterator. Forget once consumed after 'base' iterations.
19-
items: Vec<I::Item>, // Fill from iter. Clear once adaptor is exhausted. Final length is 'base'.
20-
indices: Vec<usize>, // Indices just yielded. Clear once adaptor is exhausted. Length is 'pow'.
60+
iter: Option<I>, // Inner iterator. Forget once consumed after 'base' iterations.
61+
items: Vec<I::Item>, // Fill from iter. Final length is 'base'.
62+
63+
// Indices just yielded. Length is 'pow'.
64+
// 0 0 .. 0 0 means that the first combination has been yielded.
65+
// 0 0 .. 0 1 means that the second combination has been yielded.
66+
// m m .. m m means that the last combination has just been yielded (m = base - 1).
67+
// b 0 .. 0 0 means that 'None' has just been yielded (b = base).
68+
// The latter is a special value marking the renewal of the iterator,
69+
// which can cycle again through another full round etc.
70+
indices: Vec<usize>,
2171
}
2272

2373
/// Create a new `CartesianPower` from an iterator of clonables.
@@ -53,16 +103,28 @@ where
53103
items,
54104
indices,
55105
} = self;
106+
println!(
107+
"^{pow}: {indices:?}\t{}\t{}",
108+
if iter.is_some() { 'S' } else { 'N' },
109+
items.len()
110+
);
56111
match (*pow, iter, items.len()) {
57-
// Final stable state: underlying iterator and items forgotten.
112+
// AAAAAAAAAAAA
113+
(0, None, 0) => Some((indices, items)),
114+
115+
// BBBBBBBBBBBB
116+
// Stable degenerated state.
58117
(_, None, 0) => None,
59118

119+
// CCCCCCCCCCCC
60120
// Degenerated 0th power iteration.
61121
(0, Some(_), _) => {
62122
self.iter = None; // Forget without even consuming.
63123
Some((indices, items))
64124
}
65125

126+
// DDDDDDDDDDDD
127+
// First iteration.
66128
(pow, Some(it), 0) => {
67129
// Check whether there is at least one element in the iterator.
68130
if let Some(first) = it.next() {
@@ -74,13 +136,15 @@ where
74136
for _ in 0..pow {
75137
indices.push(0);
76138
}
77-
return Some((indices, items));
139+
Some((indices, items))
140+
} else {
141+
// Degenerated iteration over an empty set, yet with non-null power.
142+
self.iter = None;
143+
None
78144
}
79-
// Degenerated iteration over an empty set, yet with non-null power.
80-
self.iter = None;
81-
None
82145
}
83146

147+
// EEEEEEEEEEEE
84148
(pow, Some(it), base) => {
85149
// We are still unsure whether all items have been collected.
86150
// As a consequence, 'base' is still uncertain,
@@ -92,31 +156,52 @@ where
92156
}
93157

94158
// All items have just been collected.
95-
self.iter = None;
96-
if base == 1 || pow == 1 {
159+
self.iter = None; // Forget about the underlying iterator.
160+
if pow == 1 {
97161
// End of iteration.
98-
items.clear();
99-
indices.clear();
162+
indices[0] = base; // Mark to cycle again on next iteration.
100163
return None;
101164
}
102165

103166
// First wrap around.
104167
indices[pow - 1] = 0;
105-
indices[pow - 2] += 1;
168+
indices[pow - 2] = 1;
106169
Some((indices, items))
107170
}
108171

109-
(_, None, b) => {
172+
// FFFFFFFFFFFF
173+
(_, None, 1) => {
174+
// Flip the only indice to keep cycling.
175+
let ind = &mut indices[0];
176+
if *ind == 1 {
177+
*ind = 0;
178+
Some((indices, items))
179+
} else {
180+
*ind = 1;
181+
None
182+
}
183+
}
184+
185+
// GGGGGGGGGGGG
186+
(_, None, base) => {
187+
if indices[0] == base {
188+
// Special marker that iteration can start over for a new round.
189+
indices[0] = 0;
190+
return Some((indices, items));
191+
}
110192
// Keep yielding items list, incrementing indices rightmost first.
111193
for index in indices.iter_mut().rev() {
112194
*index += 1;
113-
if *index < b {
195+
if *index < base {
114196
return Some((indices, items));
115197
}
116198
*index = 0; // Wrap and increment left.
117199
}
118-
items.clear();
119-
indices.clear();
200+
// Iteration is over.
201+
// But don't clear the collected items,
202+
// and mark a special index value to not fuse the iterator
203+
// but make it possibly cycle through all again.
204+
indices[0] = base;
120205
None
121206
}
122207
}
@@ -187,13 +272,6 @@ where
187272
}
188273
}
189274

190-
impl<I> FusedIterator for CartesianPower<I>
191-
where
192-
I: Iterator,
193-
I::Item: Clone,
194-
{
195-
}
196-
197275
#[cfg(test)]
198276
mod tests {
199277
//! Use chars and string to ease testing of every yielded iterator values.
@@ -202,37 +280,46 @@ mod tests {
202280
use crate::Itertools;
203281
use core::str::Chars;
204282

205-
fn check_fused(mut exhausted_it: CartesianPower<Chars>, context: String) {
206-
for i in 0..100 {
207-
let act = exhausted_it.next();
208-
assert!(
209-
act.is_none(),
210-
"Iteration {} after expected exhaustion of {} \
211-
yielded {:?} instead of None. ",
212-
i,
213-
context,
214-
act,
215-
);
216-
}
217-
}
218-
219283
#[test]
220284
fn basic() {
221285
fn check(origin: &str, pow: usize, expected: &[&str]) {
222-
let mut it = origin.chars().cartesian_power(pow);
223-
let mut i = 0;
224-
for exp in expected {
225-
let act = it.next();
226-
if act != Some(exp.chars().collect()) {
227-
panic!(
228-
"Failed iteration {} for {:?}^{}. \
229-
Expected {:?}, got {:?} instead.",
230-
i, origin, pow, exp, act,
231-
);
286+
println!("================== ({origin:?}^{pow})");
287+
let mut it_act = origin.chars().cartesian_power(pow);
288+
// Check thrice that it's cycling.
289+
for r in 1..=3 {
290+
println!("- - {r} - - - - - -");
291+
let mut it_exp = expected.iter();
292+
let mut i = 0;
293+
loop {
294+
match (it_exp.next(), it_act.next()) {
295+
(Some(exp), Some(act)) => {
296+
if act != exp.chars().collect::<Vec<_>>() {
297+
panic!(
298+
"Failed iteration {} (repetition {}) for {:?}^{}. \
299+
Expected {:?}, got {:?} instead.",
300+
i, r, origin, pow, exp, act,
301+
);
302+
}
303+
i += 1;
304+
}
305+
(None, Some(act)) => {
306+
panic!(
307+
"Failed iteration {} (repetition {}) for {:?}^{}. \
308+
Expected None, got {:?} instead.",
309+
i, r, origin, pow, act,
310+
);
311+
}
312+
(Some(exp), None) => {
313+
panic!(
314+
"Failed iteration {} (repetition {}) for {:?}^{}. \
315+
Expected {:?}, got None instead.",
316+
i, r, origin, pow, exp,
317+
);
318+
}
319+
(None, None) => break,
320+
}
232321
}
233-
i += 1;
234322
}
235-
check_fused(it, format!("iteration {} or {:?}^{}", i, origin, pow));
236323
}
237324

238325
// Empty underlying iterator.
@@ -281,38 +368,28 @@ mod tests {
281368
fn check(origin: &str, pow: usize, expected: &[(usize, Option<&str>)]) {
282369
let mut it = origin.chars().cartesian_power(pow);
283370
let mut total_n = Vec::new();
284-
for &(n, exp) in expected {
285-
let act = it.nth(n);
286-
total_n.push(n);
287-
if act != exp.map(|s| s.chars().collect::<Vec<_>>()) {
288-
panic!(
289-
"Failed nth({}) iteration for {:?}^{}. \
290-
Expected {:?}, got {:?} instead.",
291-
total_n
292-
.iter()
293-
.map(ToString::to_string)
294-
.collect::<Vec<_>>()
295-
.join(", "),
296-
origin,
297-
pow,
298-
exp,
299-
act,
300-
);
371+
for r in 1..=3 {
372+
for &(n, exp) in expected {
373+
let act = it.nth(n);
374+
total_n.push(n);
375+
if act != exp.map(|s| s.chars().collect::<Vec<_>>()) {
376+
panic!(
377+
"Failed nth({}) iteration (repetition {}) for {:?}^{}. \
378+
Expected {:?}, got {:?} instead.",
379+
total_n
380+
.iter()
381+
.map(ToString::to_string)
382+
.collect::<Vec<_>>()
383+
.join(", "),
384+
r,
385+
origin,
386+
pow,
387+
exp,
388+
act
389+
);
390+
}
301391
}
302392
}
303-
check_fused(
304-
it,
305-
format!(
306-
"nth({}) iteration of {:?}^{}",
307-
total_n
308-
.iter()
309-
.map(ToString::to_string)
310-
.collect::<Vec<_>>()
311-
.join(", "),
312-
origin,
313-
pow
314-
),
315-
);
316393
}
317394

318395
// HERE: make it work with the new implementation.

0 commit comments

Comments
 (0)