Skip to content

Commit bed8bdf

Browse files
iago-litophimuemue
authored andcommitted
🚧 Implement .size_hint() (untested yet).
1 parent 9f75490 commit bed8bdf

File tree

2 files changed

+87
-22
lines changed

2 files changed

+87
-22
lines changed

Diff for: src/cartesian_power.rs

+86-21
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ where
1313
I: Iterator,
1414
I::Item: Clone,
1515
{
16-
pow: usize,
16+
pow: u32,
1717
iter: Option<I>, // Inner iterator. Forget once consumed after 'base' iterations.
1818
items: Option<Vec<I::Item>>, // Fill from iter. Final length is 'base'.
1919
// None means that collection has not started yet.
@@ -30,7 +30,7 @@ where
3030
}
3131

3232
/// Create a new `CartesianPower` from an iterator of clonables.
33-
pub fn cartesian_power<I>(iter: I, pow: usize) -> CartesianPower<I>
33+
pub fn cartesian_power<I>(iter: I, pow: u32) -> CartesianPower<I>
3434
where
3535
I: Iterator,
3636
I::Item: Clone,
@@ -62,14 +62,11 @@ where
6262
items,
6363
indices,
6464
} = self;
65-
println!(
66-
"^{pow}: {} {indices:?}\t\t{:?}",
67-
if iter.is_some() { 'S' } else { 'N' },
68-
items.as_ref().map(Vec::len)
69-
);
65+
66+
let pow = *pow as usize;
7067

7168
// (weird 'items @' bindings circumvent NLL limitations, unneeded with polonius)
72-
match (*pow, iter, &mut *items) {
69+
match (pow, iter, &mut *items) {
7370
// First iteration with degenerated 0th power.
7471
(0, Some(_), items @ None) => {
7572
self.iter = None; // Forget about underlying iteration immediately.
@@ -197,7 +194,9 @@ where
197194
indices,
198195
} = self;
199196

200-
match (*pow, iter, &mut *items, n) {
197+
let pow = *pow as usize;
198+
199+
match (pow, iter, &mut *items, n) {
201200
// First iteration with degenerated 0th power.
202201
(0, Some(_), items @ None, 0) => {
203202
// Same as .next().
@@ -213,9 +212,7 @@ where
213212

214213
// Subsequent degenerated 0th power iteration.
215214
// Same as `.next()`.
216-
(0, None, items @ None, 0) => {
217-
Some((indices, items.insert(Vec::new())))
218-
}
215+
(0, None, items @ None, 0) => Some((indices, items.insert(Vec::new()))),
219216
// Saturate.
220217
(0, None, items, _) => {
221218
*items = None;
@@ -264,9 +261,7 @@ where
264261
}
265262

266263
// Stable iteration in the degenerated case 'base = 0'.
267-
(_, None, None, _) => {
268-
None
269-
}
264+
(_, None, None, _) => None,
270265

271266
// Subsequent iteration in the general case.
272267
// Again, immediate saturation is an option.
@@ -348,7 +343,77 @@ where
348343
}
349344

350345
fn size_hint(&self) -> (usize, Option<usize>) {
351-
todo!()
346+
let Self {
347+
pow,
348+
iter,
349+
items,
350+
indices,
351+
} = self;
352+
353+
// The following case analysis matches implementation of `.next()`.
354+
match (*pow, iter, items) {
355+
// First iteration with degenerated 0th power.
356+
(0, Some(_), None) => (1, Some(1)),
357+
358+
// Subsequent degenerated 0th power iteration.
359+
// Alternating for cycling behaviour.
360+
(0, None, Some(_)) => (0, Some(0)),
361+
(0, None, None) => (1, Some(1)),
362+
363+
// First iteration in the general case.
364+
(pow, Some(it), None) => {
365+
let (a, b) = it.size_hint();
366+
(
367+
a.checked_pow(pow).unwrap_or(usize::MAX),
368+
b.map(|b| b.checked_pow(pow)).flatten(),
369+
)
370+
}
371+
372+
// Stable iteration in the degenerated case 'base = 0'.
373+
(_, None, None) => (0, Some(0)),
374+
375+
// Subsequent iteration in the general case.
376+
(pow, Some(it), Some(items)) => {
377+
let already = items.len();
378+
let minus_already = |total| total - already;
379+
let (a, b) = it.size_hint();
380+
(
381+
(a + already)
382+
.checked_pow(pow)
383+
.map(minus_already)
384+
.unwrap_or(usize::MAX),
385+
b.map(|b| (b + already).checked_pow(pow).map(minus_already))
386+
.flatten(),
387+
)
388+
}
389+
390+
// Subsequent iteration in the general case after all items have been collected.
391+
(pow, None, Some(items)) => {
392+
let base = items.len();
393+
if indices[0] == base {
394+
// Fresh re-start.
395+
let r = base.checked_pow(pow);
396+
return (r.unwrap_or(usize::MAX), r);
397+
}
398+
// Count what's left from current indices.
399+
// This is subtracting the current iteration number base^pow,
400+
// using the complement method.
401+
let calc = || -> Option<usize> {
402+
// (closure-wrap to ease interruption on overflow with ?-operator)
403+
let comp = base - 1;
404+
let mut r = 1usize;
405+
for (&i, rank) in indices.iter().rev().zip(0u32..) {
406+
let increment = (comp - i).checked_pow(rank)?;
407+
r = r.checked_add(increment)?;
408+
}
409+
Some(r)
410+
};
411+
let Some(r) = calc() else {
412+
return (usize::MAX, None);
413+
};
414+
(r, Some(r))
415+
}
416+
}
352417
}
353418

354419
fn count(self) -> usize {
@@ -378,19 +443,19 @@ where
378443
}
379444
}
380445

446+
/// Use chars and string to ease testing of every yielded iterator values.
381447
#[cfg(test)]
382448
mod tests {
383-
//! Use chars and string to ease testing of every yielded iterator values.
384449

385-
use super::CartesianPower;
386450
use crate::Itertools;
387-
use core::str::Chars;
388451

389452
#[test]
390453
fn basic() {
391-
fn check(origin: &str, pow: usize, expected: &[&str]) {
454+
fn check(origin: &str, pow: u32, expected: &[&str]) {
392455
println!("================== ({origin:?}^{pow})");
393456
let mut it_act = origin.chars().cartesian_power(pow);
457+
// Check size_hint on the fly.
458+
let e_hint = expected.len(); // HERE: do.
394459
// Check thrice that it's cycling.
395460
for r in 1..=3 {
396461
println!("- - {r} - - - - - -");
@@ -473,7 +538,7 @@ mod tests {
473538

474539
#[test]
475540
fn nth() {
476-
fn check(origin: &str, pow: usize, expected: &[(usize, Option<&str>)]) {
541+
fn check(origin: &str, pow: u32, expected: &[(usize, Option<&str>)]) {
477542
println!("================== ({origin:?}^{pow})");
478543
let mut it = origin.chars().cartesian_power(pow);
479544
let mut total_n = Vec::new();

Diff for: src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1804,7 +1804,7 @@ pub trait Itertools: Iterator {
18041804
/// TODO: illustrative example.
18051805
/// ```
18061806
#[cfg(feature = "use_alloc")]
1807-
fn cartesian_power(self, pow: usize) -> CartesianPower<Self>
1807+
fn cartesian_power(self, pow: u32) -> CartesianPower<Self>
18081808
where
18091809
Self: Sized,
18101810
Self::Item: Clone,

0 commit comments

Comments
 (0)