use std::fmt;
#[derive(Eq, PartialEq, Clone, Copy)]
#[repr(transparent)]
pub struct VariableSet {
bits: u128,
}
impl VariableSet {
#[must_use]
pub const fn new_empty() -> Self {
VariableSet { bits: 0 }
}
#[must_use]
pub const fn new_full() -> Self {
VariableSet { bits: !0 }
}
#[must_use]
pub fn new_singleton(index: usize) -> Self {
let mut set = Self::new_empty();
set.set(index);
set
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.bits == 0
}
#[must_use]
pub fn count(&self) -> usize {
self.bits.count_ones() as usize
}
pub fn set(&mut self, index: usize) {
self.bits |= 1 << index;
}
pub fn unset(&mut self, index: usize) {
self.bits &= !(1 << index);
}
pub fn set_value(&mut self, index: usize, value: bool) {
if value {
self.set(index);
} else {
self.unset(index);
}
}
pub fn set_all(&mut self) {
self.bits = !0;
}
pub fn unset_all(&mut self) {
self.bits = 0;
}
#[must_use]
pub fn is_set(&self, index: usize) -> bool {
0 != (self.bits & (1 << index))
}
#[must_use]
pub fn find_first_set(&self) -> Option<usize> {
if self.bits != 0 {
return Some(self.bits.trailing_zeros() as usize);
}
None
}
#[must_use]
pub fn find_last_set(&self) -> Option<usize> {
if self.bits != 0 {
return Some(127 - (self.bits.leading_zeros() as usize));
}
None
}
pub fn drain_next_ascending(&mut self) -> Option<usize> {
if let Some(next_index) = self.find_first_set() {
self.unset(next_index);
Some(next_index)
} else {
None
}
}
pub fn drain_next_descending(&mut self) -> Option<usize> {
if let Some(next_index) = self.find_last_set() {
self.unset(next_index);
Some(next_index)
} else {
None
}
}
#[must_use]
pub fn is_superset_of(&self, other: &Self) -> bool {
((self.bits & other.bits) ^ other.bits) == 0
}
#[must_use]
pub fn is_subset_of(&self, other: &Self) -> bool {
((self.bits & other.bits) ^ self.bits) == 0
}
#[must_use]
pub fn intersect(self, other: Self) -> Self {
Self {
bits: self.bits & other.bits,
}
}
#[must_use]
pub fn union(self, other: Self) -> Self {
Self {
bits: self.bits | other.bits,
}
}
#[must_use]
pub fn subtract(self, other: Self) -> Self {
Self {
bits: self.bits & !other.bits,
}
}
#[must_use]
pub fn difference(self, other: Self) -> Self {
Self {
bits: self.bits ^ other.bits,
}
}
#[must_use]
pub fn complement(self) -> Self {
Self { bits: !self.bits }
}
pub fn keep_single(&mut self, index: usize) {
let had_bit = self.is_set(index);
self.unset_all();
if had_bit {
self.set(index);
}
}
pub fn keep_range(&mut self, from_index: usize, to_index: usize) {
self.bits &= !0 << from_index;
self.bits &= !(!1 << to_index);
}
}
impl fmt::Debug for VariableSet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VariableSet: {{")?;
let mut needs_comma = false;
for byte in 0..128 {
if self.is_set(byte) {
if needs_comma {
write!(f, ", ",)?;
}
write!(f, "{byte}")?;
needs_comma = true;
}
}
writeln!(f, "}}")?;
Ok(())
}
}
pub struct VariableSetIterator(VariableSet);
impl Iterator for VariableSetIterator {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
self.0.drain_next_ascending()
}
}
impl IntoIterator for VariableSet {
type Item = usize;
type IntoIter = VariableSetIterator;
fn into_iter(self) -> Self::IntoIter {
VariableSetIterator(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
#[test]
fn new_empty_is_empty() {
let set = VariableSet::new_empty();
assert!(set.is_empty());
}
#[test]
fn new_full_is_not_empty() {
let set = VariableSet::new_full();
assert!(!set.is_empty());
}
#[test]
fn after_set_is_not_empty() {
let mut set = VariableSet::new_empty();
set.set(5);
assert!(!set.is_empty());
}
#[test]
fn after_set_unset_is_empty() {
let mut set = VariableSet::new_empty();
set.set(5);
set.unset(5);
assert!(set.is_empty());
}
#[test]
fn after_set_is_set() {
let mut set = VariableSet::new_empty();
set.set(5);
assert!(set.is_set(5));
}
#[test]
fn after_unset_is_not_set() {
let mut set = VariableSet::new_full();
set.unset(5);
assert!(!set.is_set(5));
}
#[test]
fn find_first_set_none() {
let set = VariableSet::new_empty();
assert_eq!(None, set.find_first_set());
}
#[test]
fn find_last_set_none() {
let set = VariableSet::new_empty();
assert_eq!(None, set.find_last_set());
}
#[test]
fn superset_full_of_empty() {
let empty = VariableSet::new_empty();
let full = VariableSet::new_full();
assert!(full.is_superset_of(&empty));
}
#[test]
fn superset_not_empty_of_full() {
let empty = VariableSet::new_empty();
let full = VariableSet::new_full();
assert!(!empty.is_superset_of(&full));
}
#[test]
fn subset_empty_of_full() {
let empty = VariableSet::new_empty();
let full = VariableSet::new_full();
assert!(empty.is_subset_of(&full));
}
#[test]
fn subset_not_full_of_empty() {
let empty = VariableSet::new_empty();
let full = VariableSet::new_full();
assert!(!full.is_subset_of(&empty));
}
proptest! {
#[test]
fn find_first_set(n in 0..128usize) {
let mut set = VariableSet::new_empty();
set.set(n);
prop_assert_eq!(Some(n), set.find_first_set());
}
#[test]
fn find_last_set(n in 0..128usize) {
let mut set = VariableSet::new_empty();
set.set(n);
prop_assert_eq!(Some(n), set.find_last_set());
}
#[test]
fn drain_ascending_drains(n in 0..128usize) {
let mut set = VariableSet::new_empty();
set.set(n);
prop_assert_eq!(Some(n), set.drain_next_ascending());
prop_assert!(!set.is_set(n));
}
#[test]
fn drain_descending_drains(n in 0..128usize) {
let mut set = VariableSet::new_empty();
set.set(n);
prop_assert_eq!(Some(n), set.drain_next_descending());
prop_assert!(!set.is_set(n));
}
#[test]
fn intersect(n in 0..128usize, m in 0..128usize) {
let mut left = VariableSet::new_empty();
let mut right = VariableSet::new_empty();
left.set(n);
right.set(m);
let out = left.intersect(right);
prop_assert_eq!(n == m, out.is_set(n));
}
#[test]
fn union(n in 0..128usize, m in 0..128usize) {
let mut left = VariableSet::new_empty();
let mut right = VariableSet::new_empty();
left.set(n);
right.set(m);
let out = left.union(right);
prop_assert!(out.is_set(n));
prop_assert!(out.is_set(m));
}
#[test]
fn subtract(n in 0..128usize, m in 0..128usize) {
let mut left = VariableSet::new_empty();
let mut right = VariableSet::new_empty();
left.set(n);
right.set(m);
let out = left.subtract(right);
prop_assert_eq!(n != m, out.is_set(n));
}
#[test]
fn difference(n in 0..128usize, m in 0..128usize) {
let mut left = VariableSet::new_empty();
let mut right = VariableSet::new_empty();
left.set(n);
right.set(m);
let out = left.difference(right);
prop_assert_eq!(n != m, out.is_set(n));
prop_assert_eq!(n != m, out.is_set(m));
}
#[test]
fn complement(n in 0..128usize, m in 0..128usize) {
let mut input = VariableSet::new_empty();
input.set(n);
let out = input.complement();
prop_assert!(!out.is_set(n));
if n != m {
prop_assert!(out.is_set(m));
}
}
#[test]
fn keep_single(n in 0..128usize, m in 0..128usize) {
let mut set = VariableSet::new_full();
set.keep_single(n);
prop_assert!(set.is_set(n));
if n != m {
prop_assert!(!set.is_set(m));
}
}
#[test]
fn keep_range(from in 0..128usize, to in 0..128usize) {
let mut set = VariableSet::new_full();
set.keep_range(from, to);
for n in 0..128 {
prop_assert_eq!(from <= n && n <= to, set.is_set(n));
}
}
}
}