Skip to content

Commit 83c0f04

Browse files
committed
Add Iterator::size_hint() method impl. for Powerset
1 parent 8c5d32c commit 83c0f04

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

src/combinations.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ impl<I: Iterator> Combinations<I> {
5353
#[inline]
5454
pub fn n(&self) -> usize { self.pool.len() }
5555

56+
/// Returns a reference to the source iterator.
57+
#[inline]
58+
pub(crate) fn src(&self) -> &I { &self.pool.it }
59+
5660
/// Resets this `Combinations` back to an initial state for combinations of length
5761
/// `k` over the same pool data source. If `k` is larger than the current length
5862
/// of the data pool an attempt is made to prefill the pool so that it holds `k`

src/powerset.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::fmt;
2+
use std::usize;
23
use alloc::vec::Vec;
34

45
use super::combinations::{Combinations, combinations};
6+
use super::size_hint;
57

68
/// An iterator to iterate through the powerset of the elements from an iterator.
79
///
@@ -10,28 +12,33 @@ use super::combinations::{Combinations, combinations};
1012
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1113
pub struct Powerset<I: Iterator> {
1214
combs: Combinations<I>,
15+
// Iterator `position` (equal to count of yielded elements).
16+
pos: usize,
1317
}
1418

1519
impl<I> Clone for Powerset<I>
1620
where I: Clone + Iterator,
1721
I::Item: Clone,
1822
{
19-
clone_fields!(combs);
23+
clone_fields!(combs, pos);
2024
}
2125

2226
impl<I> fmt::Debug for Powerset<I>
2327
where I: Iterator + fmt::Debug,
2428
I::Item: fmt::Debug,
2529
{
26-
debug_fmt_fields!(Powerset, combs);
30+
debug_fmt_fields!(Powerset, combs, pos);
2731
}
2832

2933
/// Create a new `Powerset` from a clonable iterator.
3034
pub fn powerset<I>(src: I) -> Powerset<I>
3135
where I: Iterator,
3236
I::Item: Clone,
3337
{
34-
Powerset { combs: combinations(src, 0) }
38+
Powerset {
39+
combs: combinations(src, 0),
40+
pos: 0,
41+
}
3542
}
3643

3744
impl<I> Iterator for Powerset<I>
@@ -43,14 +50,34 @@ impl<I> Iterator for Powerset<I>
4350

4451
fn next(&mut self) -> Option<Self::Item> {
4552
if let Some(elt) = self.combs.next() {
53+
self.pos = self.pos.saturating_add(1);
4654
Some(elt)
4755
} else if self.combs.k() < self.combs.n()
4856
|| self.combs.k() == 0
4957
{
5058
self.combs.reset(self.combs.k() + 1);
51-
self.combs.next()
59+
self.combs.next().map(|elt| {
60+
self.pos = self.pos.saturating_add(1);
61+
elt
62+
})
5263
} else {
5364
None
5465
}
5566
}
67+
68+
fn size_hint(&self) -> (usize, Option<usize>) {
69+
// Total bounds for source iterator.
70+
let src_total = size_hint::add_scalar(self.combs.src().size_hint(), self.combs.n());
71+
72+
// Total bounds for self ( length(powerset(set) == 2 ^ length(set) )
73+
let self_total = size_hint::pow_scalar_base(2, src_total);
74+
75+
if self.pos < usize::MAX {
76+
// Subtract count of elements already yielded from total.
77+
size_hint::sub_scalar(self_total, self.pos)
78+
} else {
79+
// Fallback: self.pos is saturated and no longer reliable.
80+
(0, self_total.1)
81+
}
82+
}
5683
}

src/size_hint.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use std::usize;
55
use std::cmp;
6+
use std::u32;
67

78
/// **SizeHint** is the return type of **Iterator::size_hint()**.
89
pub type SizeHint = (usize, Option<usize>);
@@ -74,6 +75,20 @@ pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint {
7475
(low, hi)
7576
}
7677

78+
/// Raise `base` correctly by a **`SizeHint`** exponent.
79+
#[inline]
80+
pub fn pow_scalar_base(base: usize, exp: SizeHint) -> SizeHint {
81+
let exp_low = cmp::min(exp.0, u32::MAX as usize) as u32;
82+
let low = base.saturating_pow(exp_low);
83+
84+
let hi = exp.1.and_then(|exp| {
85+
let exp_hi = cmp::min(exp, u32::MAX as usize) as u32;
86+
base.checked_pow(exp_hi)
87+
});
88+
89+
(low, hi)
90+
}
91+
7792
/// Return the maximum
7893
#[inline]
7994
pub fn max(a: SizeHint, b: SizeHint) -> SizeHint {

0 commit comments

Comments
 (0)