1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#![no_std]
#[inline]
pub fn hamming_iter(bits: u32) -> impl Iterator<Item = u64> {
assert!(bits <= 64);
if bits < 64 {
either::Left(
(0..=bits)
.flat_map(move |i| hamming_weight_iter(i).take_while(move |&n| n < 1 << bits)),
)
} else {
either::Right((0..=64).flat_map(hamming_weight_iter))
}
}
#[inline]
pub fn hamming_weight_iter(weight: u32) -> impl Iterator<Item = u64> {
if weight < 2 {
either::Left(if weight == 0 {
either::Left(core::iter::once(0))
} else {
either::Right((0..64).map(|b| 1 << b))
})
} else {
let combinations = (64 - weight as usize + 1..=64)
.try_fold(1usize, |acc, n| acc.checked_mul(n))
.and_then(|n| {
(2..=weight as usize)
.try_fold(1usize, |acc, n| acc.checked_mul(n))
.map(|m| n / m)
});
either::Right(if let Some(combinations) = combinations {
either::Left(hamming_ascend((1 << weight) - 1).take(combinations))
} else {
either::Right(hamming_ascend((1 << weight) - 1))
})
}
}
fn hamming_ascend(start: u64) -> impl Iterator<Item = u64> {
use core::num::Wrapping;
let mut acc = Wrapping(start);
core::iter::repeat(()).map(move |_| {
let res = acc.0;
let c = acc & ((!acc) + Wrapping(1));
let r = acc + c;
acc = (((r ^ acc) >> 2) / c) | r;
res
})
}