use crate::truth_table::gray_code_flips::gray_code_flips;
use super::gray_code_flips::GrayCodeFlips;
pub trait BitFlippable {
fn num_bits(&self) -> usize;
fn flip_bit(&mut self, bit_idx: usize);
}
pub struct BitFlipIter<T> {
state: T,
flip_indices: GrayCodeFlips,
remaining: usize,
}
impl<T> Iterator for BitFlipIter<T>
where
T: BitFlippable + Clone,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining > 0 {
let output = self.state.clone();
self.remaining -= 1;
if self.remaining > 0 {
self.flip_indices
.next()
.into_iter()
.for_each(|i| self.state.flip_bit(i));
}
Some(output)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
pub fn bitflips<T>(t: T) -> BitFlipIter<T>
where
T: BitFlippable + Clone,
{
let n = t.num_bits();
let remaining = 1 << n;
assert!(remaining > 0);
BitFlipIter {
state: t,
flip_indices: gray_code_flips(n),
remaining,
}
}
#[test]
fn test_bitflips() {
#[derive(Clone, Hash, Eq, PartialEq)]
struct Bits {
bits: usize,
num_bits: usize,
}
impl BitFlippable for Bits {
fn num_bits(&self) -> usize {
self.num_bits
}
fn flip_bit(&mut self, bit_idx: usize) {
self.bits ^= 1 << bit_idx
}
}
let bits = Bits {
bits: 0,
num_bits: 4,
};
let all_bitflips: std::collections::HashSet<_> = bitflips(bits).collect();
assert_eq!(all_bitflips.len(), 16);
}