use core::fmt;
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index};
#[cfg(feature = "serde")]
use {
sequential_storage::map::PostcardValue,
serde::{Deserialize, Serialize},
};
#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BitSet128(u64, u64);
impl BitSet128 {
#[must_use]
pub const fn new() -> Self {
Self(0, 0)
}
}
#[cfg(feature = "serde")]
impl PostcardValue<'_> for BitSet128 {}
impl Default for BitSet128 {
fn default() -> Self {
Self::new()
}
}
impl BitSet128 {
#[inline]
pub fn reset_all(&mut self) {
self.0 = 0;
self.1 = 0;
}
#[inline]
pub fn reset(&mut self, index: u8) {
if index < 64 {
self.0 &= !(1u64 << index);
} else if index < 128 {
self.1 &= !(1u64 << (index - 64));
}
}
#[inline]
pub fn set_all(&mut self) {
self.0 = u64::MAX;
self.1 = u64::MAX;
}
#[inline]
pub fn set(&mut self, index: u8) {
if index < 64 {
self.0 |= 1u64 << index;
} else if index < 128 {
self.1 |= 1u64 << (index - 64);
}
}
#[inline]
pub fn flip(&mut self, index: u8) {
if index < 64 {
self.0 ^= 1u64 << index;
} else if index < 128 {
self.1 ^= 1u64 << (index - 64);
}
}
#[inline]
pub fn flip_all(&mut self) {
self.0 = !self.0;
self.1 = !self.1;
}
#[inline]
pub fn and_not(&mut self, other: Self) {
self.0 &= !other.0;
self.1 &= !other.1;
}
#[inline]
#[must_use]
pub fn test(&self, index: u8) -> bool {
if index < 64 {
(self.0 & (1u64 << index)) != 0
} else if index < 128 {
(self.1 & (1u64 << (index - 64))) != 0
} else {
false
}
}
#[inline]
#[must_use]
pub const fn count_ones(&self) -> u32 {
self.0.count_ones() + self.1.count_ones()
}
#[inline]
#[must_use]
pub const fn leading_zeros(&self) -> u32 {
if self.1 == 0 {
64 + self.0.leading_zeros()
} else {
self.1.leading_zeros()
}
}
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.0 == 0 && self.1 == 0
}
#[inline]
#[must_use]
pub const fn last_set(&self) -> Option<u8> {
let leading = self.leading_zeros();
if leading == 128 {
None
} else {
#[allow(clippy::cast_possible_truncation)]
Some((127 - leading) as u8)
}
}
#[inline]
#[must_use]
pub const fn is_superset(&self, other: &Self) -> bool {
(self.0 & other.0) == other.0 && (self.1 & other.1) == other.1
}
#[inline]
#[must_use]
pub const fn is_subset(&self, other: &BitSet128) -> bool {
other.is_superset(self)
}
#[inline]
#[must_use]
pub const fn intersects(&self, other: &Self) -> bool {
(self.0 & other.0) != 0 || (self.1 & other.1) != 0
}
#[inline]
#[must_use]
pub fn iter(&self) -> BitSet128Iter {
self.into_iter()
}
}
impl BitOr for BitSet128 {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0, self.1 | rhs.1)
}
}
impl BitAnd for BitSet128 {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0, self.1 & rhs.1)
}
}
impl BitXor for BitSet128 {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
Self(self.0 ^ rhs.0, self.1 ^ rhs.1)
}
}
impl BitOrAssign for BitSet128 {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
self.1 |= rhs.1;
}
}
impl BitAndAssign for BitSet128 {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
self.1 &= rhs.1;
}
}
impl BitXorAssign for BitSet128 {
fn bitxor_assign(&mut self, rhs: Self) {
self.0 ^= rhs.0;
self.1 ^= rhs.1;
}
}
impl Index<u8> for BitSet128 {
type Output = bool;
fn index(&self, index: u8) -> &Self::Output {
if self.test(index) { &true } else { &false }
}
}
impl Index<usize> for BitSet128 {
type Output = bool;
#[allow(clippy::cast_possible_truncation)]
fn index(&self, index: usize) -> &Self::Output {
if self.test(index as u8) { &true } else { &false }
}
}
impl From<u32> for BitSet128 {
#[inline]
fn from(a: u32) -> Self {
Self(u64::from(a), 0)
}
}
impl From<(u32, u32)> for BitSet128 {
#[inline]
fn from((a, b): (u32, u32)) -> Self {
Self(u64::from(a) << 32 | u64::from(b), 0)
}
}
impl From<(u32, u32, u32, u32)> for BitSet128 {
#[inline]
fn from((a, b, c, d): (u32, u32, u32, u32)) -> Self {
Self(u64::from(a) << 32 | u64::from(b), u64::from(c) << 32 | u64::from(d))
}
}
#[derive(Debug, Default, Eq, PartialEq)]
pub struct BitSet128Iter(u64, u64);
impl Iterator for BitSet128Iter {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if self.0 == 0 {
if self.1 == 0 {
None
} else {
#[allow(clippy::cast_possible_truncation)]
let index = self.1.trailing_zeros() as u8;
self.1 &= self.1 - 1;
Some(index + 64)
}
} else {
#[allow(clippy::cast_possible_truncation)]
let index = self.0.trailing_zeros() as u8;
self.0 &= self.0 - 1;
Some(index)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = (self.0.count_ones() + self.1.count_ones()) as usize;
(len, Some(len))
}
}
impl ExactSizeIterator for BitSet128Iter {}
impl core::iter::FusedIterator for BitSet128Iter {}
impl IntoIterator for &BitSet128 {
type Item = u8;
type IntoIter = BitSet128Iter;
fn into_iter(self) -> Self::IntoIter {
BitSet128Iter(self.0, self.1)
}
}
impl IntoIterator for BitSet128 {
type Item = u8;
type IntoIter = BitSet128Iter;
fn into_iter(self) -> Self::IntoIter {
BitSet128Iter(self.0, self.1)
}
}
impl FromIterator<u8> for BitSet128 {
fn from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Self {
let mut bitset = Self::new();
for index in iter {
bitset.set(index);
}
bitset
}
}
impl Extend<u8> for BitSet128 {
fn extend<I: IntoIterator<Item = u8>>(&mut self, iter: I) {
for index in iter {
self.set(index);
}
}
}
impl fmt::Binary for BitSet128 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.write_str("0b")?;
}
for i in (0..64).rev() {
let val = (self.1 >> i) & 1;
write!(f, "{val}")?;
}
for i in (0..64).rev() {
let val = (self.0 >> i) & 1;
write!(f, "{val}")?;
}
Ok(())
}
}
impl fmt::UpperHex for BitSet128 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.write_str("0x")?;
}
write!(f, "{:016X}{:016X}", self.1, self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn is_normal<T: Sized + Send + Sync + Unpin>() {}
fn is_full<T: Sized + Send + Sync + Unpin + Copy + Clone + Default + PartialEq>() {}
#[cfg(feature = "serde")]
fn is_config<T: Serialize + for<'a> Deserialize<'a>>() {}
#[test]
fn normal_types() {
is_full::<BitSet128>();
#[cfg(feature = "serde")]
is_config::<BitSet128>();
is_normal::<BitSet128Iter>();
}
#[test]
fn new() {
let mut bits = BitSet128::new();
bits.set(42);
assert!(bits[42u8]);
assert!(bits.test(42));
}
#[test]
fn const_new() {
const FLAGS: BitSet128 = BitSet128::new();
const EMPTY_CHECK: bool = FLAGS.is_empty(); assert_eq!(0, FLAGS.0);
#[allow(clippy::assertions_on_constants)]
{
assert!(EMPTY_CHECK);
}
}
#[test]
fn assign() {
let mut bits = BitSet128::new();
bits.set(42);
assert!(bits[42u8]);
assert!(bits.test(42));
let mask = bits;
assert!(mask.test(42));
}
#[test]
fn from() {
let _bits = BitSet128::from((0xab_u32, 0x12_u32));
}
#[test]
fn flip_all() {
let mut bitset = BitSet128::new();
bitset.set(0);
bitset.set(64);
bitset.flip_all();
assert!(!bitset.test(0));
assert!(!bitset.test(64));
assert!(bitset.test(1));
assert!(bitset.test(65));
let mut empty_set = BitSet128::new();
empty_set.flip_all();
let mut full_set = BitSet128::new();
full_set.set_all();
assert_eq!(empty_set, full_set);
empty_set.flip_all(); assert!(empty_set.is_empty());
}
#[test]
fn leading_zeros() {
let mut bitset = BitSet128::new();
assert_eq!(bitset.leading_zeros(), 128);
bitset.set(127);
assert_eq!(bitset.leading_zeros(), 0);
bitset.reset_all();
bitset.set(126);
assert_eq!(bitset.leading_zeros(), 1);
bitset.reset_all();
bitset.set(64);
assert_eq!(bitset.leading_zeros(), 63);
bitset.reset_all();
bitset.set(63);
assert_eq!(bitset.leading_zeros(), 64);
bitset.reset_all();
bitset.set(0);
assert_eq!(bitset.leading_zeros(), 127);
}
#[test]
fn last_set() {
let mut bitset = BitSet128::new();
assert_eq!(bitset.last_set(), None);
bitset.set(0);
assert_eq!(bitset.last_set(), Some(0));
bitset.set(10);
bitset.set(45);
assert_eq!(bitset.last_set(), Some(45));
bitset.reset_all();
bitset.set(63);
assert_eq!(bitset.last_set(), Some(63));
bitset.set(64);
assert_eq!(bitset.last_set(), Some(64));
bitset.set(100);
bitset.set(127);
assert_eq!(bitset.last_set(), Some(127));
}
#[test]
fn is_superset() {
let mut set_a = BitSet128::new();
let mut set_b = BitSet128::new();
assert!(set_a.is_superset(&set_b));
set_a.set(10);
set_a.set(80);
set_b.set(10);
assert!(set_a.is_superset(&set_b));
assert!(!set_b.is_superset(&set_a));
set_b.set(80);
assert!(set_a.is_superset(&set_b));
let mut set_c = BitSet128::new();
let mut set_d = BitSet128::new();
set_c.set(15);
set_d.set(15);
set_d.set(95);
assert!(!set_c.is_superset(&set_d));
}
#[test]
fn intersects() {
let mut set_a = BitSet128::new();
let mut set_b = BitSet128::new();
assert!(!set_a.intersects(&set_b));
set_a.set(15);
assert!(!set_a.intersects(&set_b));
set_b.set(15);
assert!(set_a.intersects(&set_b));
assert!(set_b.intersects(&set_a));
set_a.reset_all();
set_b.reset_all();
set_a.set(10); set_b.set(80); assert!(!set_a.intersects(&set_b));
set_a.set(80);
assert!(set_a.intersects(&set_b));
}
#[test]
fn inplace_logical_ops() {
let mut set_a = BitSet128::new();
let mut set_b = BitSet128::new();
set_a.set(10);
set_a.set(70);
set_b.set(10);
set_b.set(80);
let mut result = set_a;
result &= set_b;
assert!(result.test(10));
assert!(!result.test(70));
assert!(!result.test(80));
let mut result = set_a;
result |= set_b;
assert!(result.test(10));
assert!(result.test(70));
assert!(result.test(80));
let mut result = set_a;
result ^= set_b;
assert!(!result.test(10)); assert!(result.test(70));
assert!(result.test(80));
let mut result = set_a;
result.and_not(set_b);
assert!(!result.test(10)); assert!(result.test(70)); assert!(!result.test(80)); }
#[test]
fn exercise() {
let mut system_flags = BitSet128::new();
let error_mask = BitSet128::new();
system_flags |= error_mask;
system_flags ^= error_mask;
let mut set_a = BitSet128::new();
set_a.set(10);
set_a.set(20);
let mut set_b = BitSet128::new();
set_b.set(20);
set_b.set(30);
let common = set_a & set_b;
assert!(!common.test(10));
assert!(common.test(20));
assert!(!common.test(30));
let all = set_a | set_b;
assert!(all.test(10));
assert!(all.test(20));
assert!(all.test(30));
let diff = set_a ^ set_b;
assert!(diff.test(10));
assert!(!diff.test(20));
assert!(diff.test(30));
}
#[test]
fn test_iterator_empty() {
let bitset = BitSet128::new();
let mut iter = bitset.iter();
assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.next(), None);
}
#[test]
fn test_iterator_single_bits() {
let mut bitset = BitSet128::new();
bitset.set(0);
let mut iter = bitset.iter();
assert_eq!(iter.next(), Some(0));
assert_eq!(iter.next(), None);
bitset.reset_all();
bitset.set(63);
let mut iter = bitset.iter();
assert_eq!(iter.next(), Some(63));
assert_eq!(iter.next(), None);
bitset.reset_all();
bitset.set(64);
let mut iter = bitset.iter();
assert_eq!(iter.next(), Some(64));
assert_eq!(iter.next(), None);
bitset.reset_all();
bitset.set(127);
let mut iter = bitset.iter();
assert_eq!(iter.next(), Some(127));
assert_eq!(iter.next(), None);
}
#[test]
fn test_iterator_multiple_scattered_bits() {
let mut bitset = BitSet128::new();
let expected_indices = [5, 12, 63, 64, 99, 127];
for &idx in &expected_indices {
bitset.set(idx);
}
let mut iter = bitset.iter();
assert_eq!(iter.size_hint(), (expected_indices.len(), Some(expected_indices.len())));
for &expected in &expected_indices {
assert_eq!(iter.next(), Some(expected));
}
assert_eq!(iter.next(), None);
}
#[test]
fn test_iterator_size_hint_drainage() {
let mut bitset = BitSet128::new();
bitset.set(10);
bitset.set(90);
let mut iter = bitset.iter();
assert_eq!(iter.size_hint(), (2, Some(2)));
assert_eq!(iter.len(), 2);
assert_eq!(iter.next(), Some(10));
assert_eq!(iter.size_hint(), (1, Some(1)));
assert_eq!(iter.len(), 1);
assert_eq!(iter.next(), Some(90));
assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.len(), 0);
assert_eq!(iter.next(), None);
}
#[test]
fn test_iterator_all_bits_set() {
let mut bitset = BitSet128::new();
bitset.set_all();
let mut count = 0;
#[allow(clippy::cast_possible_truncation)]
for (expected_idx, actual_idx) in bitset.iter().enumerate() {
assert_eq!(expected_idx as u8, actual_idx);
count += 1;
}
assert_eq!(count, 128);
}
#[test]
fn test_consuming_into_iter() {
let mut bitset = BitSet128::new();
bitset.set(42);
let mut count = 0;
for idx in bitset {
assert_eq!(idx, 42);
count += 1;
}
assert_eq!(count, 1);
}
#[test]
fn from_iterator() {
let indices = [5, 63, 64, 120];
let bitset: BitSet128 = indices.into_iter().collect();
assert!(bitset.test(5));
assert!(bitset.test(63));
assert!(bitset.test(64));
assert!(bitset.test(120));
assert_eq!(bitset.count_ones(), 4);
let invalid_indices = [20, 200, 255];
let safe_bitset: BitSet128 = invalid_indices.into_iter().collect();
assert!(safe_bitset.test(20));
assert_eq!(safe_bitset.count_ones(), 1); }
#[test]
fn empty_and_full() {
let empty = BitSet128::new();
assert_eq!(empty.iter().count(), 0);
let mut full = BitSet128::new();
full.set_all();
assert_eq!(full.iter().count(), 128);
}
}