Skip to content

Commit 5b51535

Browse files
committed
🚧 Test cycling iterator instead.
1 parent 8957f70 commit 5b51535

File tree

1 file changed

+197
-92
lines changed

1 file changed

+197
-92
lines changed

src/cartesian_power.rs

+197-92
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,58 @@
11
use alloc::vec::Vec;
22
use std::fmt;
3-
use std::iter::FusedIterator;
3+
4+
// (base: 0) pow: 0
5+
// iter indices items
6+
// init S · N
7+
// next(C) N 🗙 · [] -> []
8+
// next(K) N · N -> None
9+
// next(L) N · [] -> []
10+
11+
// (base: 2) pow: 0
12+
// iter indices items
13+
// init S · N
14+
// next(C) N 🗙 · [] -> []
15+
// next(K) N · N -> None
16+
// next(L) N · [] -> []
17+
18+
// (base: 0) pow: 2
19+
// iter indices items
20+
// init S · N
21+
// next(D) N! · N -> None
22+
// next(B) N · N -> None
23+
// next(B) N · N -> None
24+
25+
// (base: 1) pow: 1
26+
// iter indices items
27+
// init S · N
28+
// next(D) S 0 a -> [a]
29+
// next(E) N! 1 ! a -> None
30+
// next(G) N 0 a -> [a]
31+
// next(G) N 1 ! a -> None
32+
33+
// (base: 2) pow: 1
34+
// iter indices items
35+
// init S · N
36+
// next(D) S 0 a -> [a]
37+
// next(E) S 1 a b -> [b]
38+
// next(E) N! 2 ! a b -> None
39+
// next(G) N 0 a b -> [a]
40+
// next(G) N 1 a b -> [b]
41+
// next(G) N 2 ! a b -> None
42+
43+
// (base: 2) pow: 3
44+
// iter indices items
45+
// init S · N
46+
// next(D) S 0 0 0 a -> [a, a, a]
47+
// next(E) S 0 0 1 a b -> [a, a, b]
48+
// next(E) N! 0 1 0 a b -> [a, b, a]
49+
// next(G) N 0 1 1 a b -> [a, b, b]
50+
// next(G) N 1 0 0 a b -> [b, a, a]
51+
// next(G) N 1 0 1 a b -> [b, a, b]
52+
// next(G) N 1 1 0 a b -> [b, b, a]
53+
// next(G) N 1 1 1 a b -> [b, b, b]
54+
// next(G) N 2 0 0 ! a b -> None
55+
// next(G) N 0 0 0 a b -> [a, a, a]
456

557
/// An adaptor iterating through all the ordered `n`-length lists of items
658
/// yielded by the underlying iterator, including repetitions.
@@ -15,9 +67,19 @@ where
1567
I::Item: Clone,
1668
{
1769
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'.
70+
iter: Option<I>, // Inner iterator. Forget once consumed after 'base' iterations.
71+
items: Option<Vec<I::Item>>, // Fill from iter. Final length is 'base'.
72+
// None means that collection has not started yet.
73+
// Some(empty) means that collection would have started but pow = 0.
74+
75+
// Indices just yielded. Length is 'pow'.
76+
// 0 0 .. 0 0 means that the first combination has been yielded.
77+
// 0 0 .. 0 1 means that the second combination has been yielded.
78+
// m m .. m m means that the last combination has just been yielded (m = base - 1).
79+
// b 0 .. 0 0 means that 'None' has just been yielded (b = base).
80+
// The latter is a special value marking the renewal of the iterator,
81+
// which can cycle again through another full round, ad libitum.
82+
indices: Vec<usize>,
2183
}
2284

2385
/// Create a new `CartesianPower` from an iterator of clonables.
@@ -29,7 +91,7 @@ where
2991
CartesianPower {
3092
pow,
3193
iter: Some(iter),
32-
items: Vec::new(),
94+
items: None,
3395
indices: Vec::new(),
3496
}
3597
}
@@ -53,35 +115,63 @@ where
53115
items,
54116
indices,
55117
} = self;
56-
match (*pow, iter, items.len()) {
57-
// Final stable state: underlying iterator and items forgotten.
58-
(_, None, 0) => None,
118+
println!(
119+
"^{pow}: {indices:?}\t{}\t{:?}",
120+
if iter.is_some() { 'S' } else { 'N' },
121+
items.as_ref().map(|v| v.len())
122+
);
123+
match (*pow, iter, items) {
124+
// BBBBBBBBBBBB
125+
// Stable degenerated state: 0^pow with pow > 0;
126+
(_, None, None) => None,
59127

128+
// CCCCCCCCCCCC
60129
// Degenerated 0th power iteration.
61-
(0, Some(_), _) => {
62-
self.iter = None; // Forget without even consuming.
63-
Some((indices, items))
130+
(0, Some(_), None) => {
131+
self.iter = None; // Forget about underlying iteration immediately.
132+
*items = Some(Vec::new()); // Raise this value as a boolean flag.
133+
Some((indices, &[])) // Yield empty list.
64134
}
65135

66-
(pow, Some(it), 0) => {
136+
// KKKKKKKKKKKK
137+
// Degenerated 0th power iteration, after the dummy item was collected.
138+
// Use the Some<(empty)Vec> as a flag to alternate between yielding [] or None.
139+
(0, None, Some(_)) => {
140+
*items = None;
141+
None
142+
}
143+
// LLLLLLLLLLLL
144+
(0, None, None) => {
145+
*items = Some(Vec::new());
146+
Some((indices, &[]))
147+
}
148+
149+
// DDDDDDDDDDDD
150+
// First iteration.
151+
(pow, Some(it), None) => {
67152
// Check whether there is at least one element in the iterator.
68153
if let Some(first) = it.next() {
69154
// Allocate buffer to hold items about to be yielded.
70-
items.reserve_exact(it.size_hint().0);
71-
items.push(first);
155+
*items = Some({
156+
let mut v = Vec::with_capacity(it.size_hint().0);
157+
v.push(first);
158+
v
159+
});
72160
// Same for indices to be yielded.
73161
indices.reserve_exact(pow);
74162
for _ in 0..pow {
75163
indices.push(0);
76164
}
77-
return Some((indices, items));
165+
Some((indices, &items.unwrap())) // HERE: can I rebase to get a smarter borrowck?
166+
} else {
167+
// Degenerated iteration over an empty set, yet with non-null power.
168+
self.iter = None;
169+
None
78170
}
79-
// Degenerated iteration over an empty set, yet with non-null power.
80-
self.iter = None;
81-
None
82171
}
83172

84-
(pow, Some(it), base) => {
173+
// EEEEEEEEEEEE
174+
(pow, Some(it), Some(items)) => {
85175
// We are still unsure whether all items have been collected.
86176
// As a consequence, 'base' is still uncertain,
87177
// but then we know that indices haven't started wrapping around yet.
@@ -91,32 +181,55 @@ where
91181
return Some((indices, items));
92182
}
93183

94-
// All items have just been collected.
95-
self.iter = None;
96-
if base == 1 || pow == 1 {
184+
// The item collected on previous call was the last one.
185+
self.iter = None; // Forget about the underlying iterator.
186+
if pow == 1 {
97187
// End of iteration.
98-
items.clear();
99-
indices.clear();
188+
let base = items.len();
189+
indices[0] = base; // Mark to cycle again on next iteration.
100190
return None;
101191
}
102192

103193
// First wrap around.
104194
indices[pow - 1] = 0;
105-
indices[pow - 2] += 1;
195+
indices[pow - 2] = 1;
106196
Some((indices, items))
107197
}
108198

109-
(_, None, b) => {
199+
// // FFFFFFFFFFFF
200+
// (_, None, 1) => {
201+
// // Flip the only indice to keep cycling.
202+
// let ind = &mut indices[0];
203+
// if *ind == 1 {
204+
// *ind = 0;
205+
// Some((indices, items))
206+
// } else {
207+
// *ind = 1;
208+
// None
209+
// }
210+
// }
211+
212+
// GGGGGGGGGGGG
213+
(_, None, Some(items)) => {
214+
let base = items.len();
215+
if indices[0] == base {
216+
// Special marker that iteration can start over for a new round.
217+
indices[0] = 0;
218+
return Some((indices, items));
219+
}
110220
// Keep yielding items list, incrementing indices rightmost first.
111221
for index in indices.iter_mut().rev() {
112222
*index += 1;
113-
if *index < b {
223+
if *index < base {
114224
return Some((indices, items));
115225
}
116226
*index = 0; // Wrap and increment left.
117227
}
118-
items.clear();
119-
indices.clear();
228+
// Iteration is over.
229+
// But don't clear the collected items,
230+
// and mark a special index value to not fuse the iterator
231+
// but make it possibly cycle through all again.
232+
indices[0] = base;
120233
None
121234
}
122235
}
@@ -187,13 +300,6 @@ where
187300
}
188301
}
189302

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

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-
219311
#[test]
220312
fn basic() {
221313
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-
);
314+
println!("================== ({origin:?}^{pow})");
315+
let mut it_act = origin.chars().cartesian_power(pow);
316+
// Check thrice that it's cycling.
317+
for r in 1..=3 {
318+
println!("- - {r} - - - - - -");
319+
let mut it_exp = expected.iter();
320+
let mut i = 0;
321+
loop {
322+
match (it_exp.next(), it_act.next()) {
323+
(Some(exp), Some(act)) => {
324+
if act != exp.chars().collect::<Vec<_>>() {
325+
panic!(
326+
"Failed iteration {} (repetition {}) for {:?}^{}. \
327+
Expected {:?}, got {:?} instead.",
328+
i, r, origin, pow, exp, act,
329+
);
330+
}
331+
i += 1;
332+
}
333+
(None, Some(act)) => {
334+
panic!(
335+
"Failed iteration {} (repetition {}) for {:?}^{}. \
336+
Expected None, got {:?} instead.",
337+
i, r, origin, pow, act,
338+
);
339+
}
340+
(Some(exp), None) => {
341+
panic!(
342+
"Failed iteration {} (repetition {}) for {:?}^{}. \
343+
Expected {:?}, got None instead.",
344+
i, r, origin, pow, exp,
345+
);
346+
}
347+
(None, None) => break,
348+
}
232349
}
233-
i += 1;
234350
}
235-
check_fused(it, format!("iteration {} or {:?}^{}", i, origin, pow));
236351
}
237352

238353
// Empty underlying iterator.
@@ -281,38 +396,28 @@ mod tests {
281396
fn check(origin: &str, pow: usize, expected: &[(usize, Option<&str>)]) {
282397
let mut it = origin.chars().cartesian_power(pow);
283398
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-
);
399+
for r in 1..=3 {
400+
for &(n, exp) in expected {
401+
let act = it.nth(n);
402+
total_n.push(n);
403+
if act != exp.map(|s| s.chars().collect::<Vec<_>>()) {
404+
panic!(
405+
"Failed nth({}) iteration (repetition {}) for {:?}^{}. \
406+
Expected {:?}, got {:?} instead.",
407+
total_n
408+
.iter()
409+
.map(ToString::to_string)
410+
.collect::<Vec<_>>()
411+
.join(", "),
412+
r,
413+
origin,
414+
pow,
415+
exp,
416+
act
417+
);
418+
}
301419
}
302420
}
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-
);
316421
}
317422

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

0 commit comments

Comments
 (0)