blob: 912573ceca6b6e31d03be00c275802db239376b1 [file] [edit]
// Copyright © 2022 Collabora, Ltd.
// SPDX-License-Identifier: MIT
//! A set of usizes, represented as a bit vector
//!
//! In addition to some basic operations like `insert()` and `remove()`, this
//! module also lets you write expressions on sets that are lazily evaluated. To
//! do so, call `.s(..)` on the set to reference the bitset in a
//! lazily-evaluated `BitSetStream`, and then use typical binary operators on
//! the `BitSetStream`s.
//! ```rust
//! let a = BitSet::new();
//! let b = BitSet::new();
//! let c = BitSet::new();
//!
//! c.assign(a.s(..) | b.s(..));
//! c ^= a.s(..);
//! ```
//! Supported binary operations are `&`, `|`, `^`, `-`. Note that there is no
//! unary negation, because that would result in an infinite result set. For
//! patterns like `a & !b`, instead use set subtraction `a - b`.
use std::cmp::{max, min};
use std::marker::PhantomData;
use std::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor,
BitXorAssign, Range, RangeFull, Sub, SubAssign,
};
/// Converts a value into a bit index
///
/// Unlike a hashing algorithm that attempts to scatter the data through
/// the integer range, implementations of IntoBitIndex should attempt to
/// compact the resulting range as much as possible because it will be used
/// to index into an array of bits. The better the compaction, the better
/// the memory efficiency of [BitSet] will be.
///
/// Because the index is used blindly to index bits, implementations must
/// ensure that `a == b` if and only if
/// `a.into_bit_index() == b.into_bit_index()`.
pub trait IntoBitIndex {
/// Converts a self to a bit index
fn into_bit_index(self) -> usize;
}
/// Converts a bit index back into a value
///
/// The implementation must ensure that
/// `x.into_bit_index().from_bit_index() == x` and
/// `X::from_bit_index(i).into_bit_index() == i`.
pub trait FromBitIndex: IntoBitIndex {
fn from_bit_index(i: usize) -> Self;
}
/// Implements IntoBitIndex and FromBitIndex for the given basic data type.
///
/// This can only be used on data types with less than or fewer bits than
/// usize, guaranteeing that the conversion in both directions is lossless.
/// See also the invariant specified on FromBitIndex.
macro_rules! impl_into_from_bit_index {
($t:ident) => {
impl IntoBitIndex for $t {
fn into_bit_index(self) -> usize {
const _: () = {
assert!(size_of::<$t>() <= size_of::<usize>());
};
self as usize
}
}
impl FromBitIndex for $t {
fn from_bit_index(i: usize) -> Self {
// We know i will alweays have come from into_bit_index() so
// it's safe to do an `as` cast here.
i as $t
}
}
};
}
impl_into_from_bit_index!(u8);
impl_into_from_bit_index!(u16);
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
impl_into_from_bit_index!(u32);
impl_into_from_bit_index!(usize);
#[derive(Clone, Copy)]
struct BitIndex {
word: usize,
bit: u8,
}
impl BitIndex {
const ZERO: BitIndex = BitIndex { word: 0, bit: 0 };
const fn flatten(self) -> usize {
self.word * 32 + (self.bit as usize)
}
const fn from_flat_index(idx: usize) -> BitIndex {
BitIndex {
word: idx / 32,
bit: (idx % 32) as u8,
}
}
const fn from_word(word: usize) -> BitIndex {
BitIndex { word, bit: 0 }
}
}
impl<K: IntoBitIndex> From<K> for BitIndex {
fn from(key: K) -> BitIndex {
BitIndex::from_flat_index(key.into_bit_index())
}
}
impl From<BitIndex> for usize {
fn from(idx: BitIndex) -> usize {
idx.flatten()
}
}
impl AddAssign<usize> for BitIndex {
fn add_assign(&mut self, rhs: usize) {
let bit = usize::from(self.bit) + rhs;
self.bit = (bit % 32) as u8;
self.word += bit / 32;
}
}
impl Add<usize> for BitIndex {
type Output = BitIndex;
fn add(mut self, rhs: usize) -> BitIndex {
self += rhs;
self
}
}
struct WordIdxMaskIter {
word_idx: usize,
mask: u32,
end: BitIndex,
}
impl WordIdxMaskIter {
const fn new(start: BitIndex, end: BitIndex) -> WordIdxMaskIter {
WordIdxMaskIter {
word_idx: start.word,
mask: u32::MAX << start.bit,
end,
}
}
const fn next_const(&mut self) -> Option<(usize, u32)> {
if self.word_idx < self.end.word {
let item = (self.word_idx, self.mask);
self.mask = u32::MAX;
self.word_idx += 1;
Some(item)
} else if self.word_idx == self.end.word {
let mask = self.mask & !(u32::MAX << self.end.bit);
if mask != 0 {
let item = (self.word_idx, mask);
self.mask = 0;
self.word_idx += 1;
Some(item)
} else {
None
}
} else {
None
}
}
}
impl Iterator for WordIdxMaskIter {
type Item = (usize, u32);
fn next(&mut self) -> Option<(usize, u32)> {
self.next_const()
}
}
impl std::iter::FusedIterator for WordIdxMaskIter {}
const fn any_set_in_range(
words: &[u32],
start: BitIndex,
end: BitIndex,
) -> bool {
let mut iter = WordIdxMaskIter::new(start, end);
while let Some((word, mask)) = iter.next_const() {
if words[word] & mask != 0 {
return true;
}
}
false
}
const fn all_set_in_range(
words: &[u32],
start: BitIndex,
end: BitIndex,
) -> bool {
let mut iter = WordIdxMaskIter::new(start, end);
while let Some((word, mask)) = iter.next_const() {
if (!words[word]) & mask != 0 {
return false;
}
}
true
}
const fn count_set_in_range(
words: &[u32],
start: BitIndex,
end: BitIndex,
) -> usize {
let mut count = 0_usize;
let mut iter = WordIdxMaskIter::new(start, end);
while let Some((word, mask)) = iter.next_const() {
count += (words[word] & mask).count_ones() as usize;
}
count
}
const fn set_range(words: &mut [u32], start: BitIndex, end: BitIndex) {
let mut iter = WordIdxMaskIter::new(start, end);
while let Some((word, mask)) = iter.next_const() {
words[word] |= mask;
}
}
const fn unset_range(words: &mut [u32], start: BitIndex, end: BitIndex) {
let mut iter = WordIdxMaskIter::new(start, end);
while let Some((word, mask)) = iter.next_const() {
words[word] &= !mask;
}
}
#[inline]
fn find_next_set(
word_fn: impl Fn(usize) -> Option<u32>,
start: BitIndex,
) -> Option<BitIndex> {
let mut word = start.word;
let mut mask = u32::MAX << start.bit;
loop {
let bit = (word_fn(word)? & mask).trailing_zeros();
if bit < 32 {
return Some(BitIndex {
word,
bit: bit as u8,
});
}
mask = u32::MAX;
word += 1;
}
}
fn every_nth_bit(n: usize) -> u32 {
assert!(0 < n && n < 32);
assert!(n.is_power_of_two());
u32::MAX / ((1 << n) - 1)
}
#[inline]
fn find_small_aligned_set_range(
word_fn: impl Fn(usize) -> Option<u32>,
start: BitIndex,
count: usize,
align_mul: usize,
align_offset: usize,
) -> Option<BitIndex> {
debug_assert!(align_mul <= 16);
debug_assert!(align_offset + count <= align_mul);
debug_assert!(count > 0);
let every_n = every_nth_bit(align_mul) << align_offset;
let mut word_idx = start.word;
let mut mask = u32::MAX << start.bit;
loop {
let word = u64::from(word_fn(word_idx)? & mask);
let every_n_64 = u64::from(every_n);
// If every bit in a sequence is set, then adding one to the bottom
// bit will cause it to carry past the top bit. Carry-in for a bit
// is true if the bit in the addition result does not match the same
// bit in a ^ b. We do this in u64 to handle the case where we carry
// past the top bit.
let carry = (word + every_n_64) ^ (word ^ every_n_64);
let found = u32::try_from(carry >> count).unwrap() & every_n;
if found != 0 {
return Some(BitIndex {
word: word_idx,
bit: found.trailing_zeros() as u8,
});
}
mask = u32::MAX;
word_idx += 1;
}
}
#[inline]
fn find_large_aligned_set_range(
word_fn: impl Fn(usize) -> Option<u32>,
start: BitIndex,
count: usize,
align_mul: usize,
align_offset: usize,
) -> Option<BitIndex> {
debug_assert!(count > 0);
debug_assert!(align_mul >= 32);
debug_assert!(align_offset < align_mul);
let start = start.flatten();
let start = if start < align_offset {
align_offset
} else {
(start - align_offset).next_multiple_of(align_mul) + align_offset
};
let word_stride = align_mul / 32;
let mut cur = BitIndex::from(start);
loop {
let mut fail_word_idx = None;
for (word_idx, mask) in WordIdxMaskIter::new(cur, cur + count) {
let word = word_fn(word_idx)?;
if (!word) & mask != 0 {
fail_word_idx = Some(word_idx);
break;
}
}
let Some(fail_word_idx) = fail_word_idx else {
return Some(cur);
};
cur.word += word_stride;
// If we found unset bits at fail_word, then we can't find a set
// range any earlier than that.
while cur.word < fail_word_idx {
cur.word += word_stride;
}
}
}
#[inline]
fn find_aligned_set_range(
word_fn: impl Fn(usize) -> Option<u32>,
start: BitIndex,
count: usize,
align_mul: usize,
align_offset: usize,
) -> Option<BitIndex> {
assert!(count > 0);
assert!(align_mul.is_power_of_two());
assert!(align_offset < align_mul);
if align_mul >= 32 {
find_large_aligned_set_range(
word_fn,
start,
count,
align_mul,
align_offset,
)
} else if align_offset + count <= align_mul {
find_small_aligned_set_range(
word_fn,
start,
count,
align_mul,
align_offset,
)
} else {
let search_count = align_mul - align_offset;
debug_assert!(search_count < count);
let mut cur = start;
loop {
let idx = find_small_aligned_set_range(
&word_fn,
cur,
search_count,
align_mul,
align_offset,
)?;
// That only checked for the first search_count bits. Nowe we
// have to check for the rest.
let mut fail_word_idx = None;
for (word_idx, mask) in WordIdxMaskIter::new(idx, idx + count) {
let word = word_fn(word_idx)?;
if (!word) & mask != 0 {
fail_word_idx = Some(word_idx);
break;
}
}
let Some(fail_word_idx) = fail_word_idx else {
return Some(idx);
};
cur = idx + align_mul;
// If we found unset bits at fail_word, then we can't find a set
// range any earlier than that. However, the next set range may be
// in words[fail_word_idx], just later in the word so we can't
// increment any higher.
if cur.word < fail_word_idx {
debug_assert!(align_mul <= 16);
debug_assert!(align_offset < 16);
cur = BitIndex {
word: fail_word_idx,
bit: align_offset as u8,
};
}
}
}
}
/// A set implemented as an array of bits, able to be used as constant data
///
/// The fixed size W is in units of 32-bit words. This is due to a Rust
/// restriction which prevents us from doing math on constants which size
/// arrays.
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct ConstBitSet<const W: usize, K = usize> {
words: [u32; W],
phantom: PhantomData<K>,
}
impl<const W: usize, K> ConstBitSet<W, K> {
pub const fn new() -> Self {
ConstBitSet {
words: [0_u32; W],
phantom: PhantomData,
}
}
pub const fn clear(&mut self) {
let mut w = 0_usize;
while w < W {
self.words[w] = 0;
w += 1;
}
}
pub const fn is_empty(&self) -> bool {
let mut w = 0_usize;
while w < W {
if self.words[w] != 0 {
return false;
}
w += 1;
}
true
}
pub const fn len(&self) -> usize {
let mut count = 0;
let mut w = 0_usize;
while w < W {
count += self.words[w].count_ones() as usize;
w += 1;
}
count
}
}
macro_rules! impl_const_bit_set_binop {
(
$K:ident,
$BinOp:ident,
$bin_op:ident,
$AssignBinOp:ident,
$assign_bin_op:ident,
|$a:ident, $b:ident| $impl:expr,
) => {
impl<const W: usize> $AssignBinOp<&ConstBitSet<W, $K>>
for ConstBitSet<W, $K>
{
fn $assign_bin_op(&mut self, rhs: &ConstBitSet<W, $K>) {
for w in 0..W {
let $a = self.words[w];
let $b = rhs.words[w];
self.words[w] = $impl;
}
}
}
impl<const W: usize> $AssignBinOp<ConstBitSet<W, $K>>
for ConstBitSet<W, $K>
{
fn $assign_bin_op(&mut self, rhs: ConstBitSet<W, $K>) {
self.$assign_bin_op(&rhs);
}
}
impl<const W: usize> $BinOp<&ConstBitSet<W, $K>>
for ConstBitSet<W, $K>
{
type Output = ConstBitSet<W, $K>;
fn $bin_op(
mut self,
rhs: &ConstBitSet<W, $K>,
) -> ConstBitSet<W, $K> {
self.$assign_bin_op(rhs);
self
}
}
impl<const W: usize> $BinOp<ConstBitSet<W, $K>> for ConstBitSet<W, $K> {
type Output = ConstBitSet<W, $K>;
fn $bin_op(
mut self,
rhs: ConstBitSet<W, $K>,
) -> ConstBitSet<W, $K> {
self.$assign_bin_op(rhs);
self
}
}
};
}
macro_rules! impl_const_bit_set {
($K:ident) => {
impl<const W: usize> ConstBitSet<W, $K> {
pub const fn contains(&self, key: $K) -> bool {
let idx = BitIndex::from_flat_index(key as usize);
if idx.word < self.words.len() {
self.words[idx.word] & (1_u32 << idx.bit) != 0
} else {
false
}
}
pub const fn insert(&mut self, key: $K) -> bool {
let idx = BitIndex::from_flat_index(key as usize);
assert!(idx.word < W, "ConstBitSet index out of bounds");
let exists = self.contains(key);
self.words[idx.word] |= 1_u32 << idx.bit;
!exists
}
pub const fn insert_range(&mut self, range: Range<$K>) {
assert!(
range.end as usize <= W * 32,
"ConstBitSet index out of bounds",
);
if range.start < range.end {
let start = BitIndex::from_flat_index(range.start as usize);
let end = BitIndex::from_flat_index(range.end as usize);
set_range(&mut self.words, start, end);
}
}
pub const fn remove(&mut self, key: $K) -> bool {
let idx = BitIndex::from_flat_index(key as usize);
if idx.word < self.words.len() {
let exists = self.contains(key);
self.words[idx.word] &= !(1_u32 << idx.bit);
exists
} else {
false
}
}
pub const fn from_array<const N: usize>(arr: [$K; N]) -> Self {
let mut set = ConstBitSet::<W, $K>::new();
let mut i = 0_usize;
while i < N {
set.insert(arr[i]);
i += 1;
}
set
}
pub const fn from_range(range: Range<$K>) -> Self {
let mut set = ConstBitSet::<W, $K>::new();
set.insert_range(range);
set
}
pub fn iter(&self) -> impl '_ + Iterator<Item = $K> {
BitSetIter::new(&self.words)
}
}
impl<const W: usize> From<Range<$K>> for ConstBitSet<W, $K> {
fn from(range: Range<$K>) -> ConstBitSet<W, $K> {
ConstBitSet::<W, $K>::from_range(range)
}
}
impl_const_bit_set_binop!(
$K,
BitAnd,
bitand,
BitAndAssign,
bitand_assign,
|a, b| a & b,
);
impl_const_bit_set_binop!(
$K,
BitOr,
bitor,
BitOrAssign,
bitor_assign,
|a, b| a | b,
);
impl_const_bit_set_binop!(
$K,
BitXor,
bitxor,
BitXorAssign,
bitxor_assign,
|a, b| a ^ b,
);
impl_const_bit_set_binop!(
$K,
Sub,
sub,
SubAssign,
sub_assign,
|a, b| a & !b,
);
};
}
impl_const_bit_set!(u8);
impl_const_bit_set!(u16);
impl_const_bit_set!(usize);
/// A set implemented as an array of bits
///
/// Unlike `HashSet` and similar containers which actually store the provided
/// data, `BitSet` only stores an array of bits with one bit per potential set
/// item. By default, a `BitSet` is a set of `usize`. However, it can be used
/// to store any type which implementss [`IntoBitIndex`].
///
/// Because `BitSet` only stores one bit per item, you can only iterate over a
/// `BitSet<K>` if `K` implements [`FromBitIndex`].
#[derive(Clone)]
pub struct BitSet<K = usize> {
words: Vec<u32>,
phantom: PhantomData<K>,
}
impl<K> BitSet<K> {
pub fn new() -> BitSet<K> {
BitSet {
words: Vec::new(),
phantom: PhantomData,
}
}
fn reserve_words(&mut self, words: usize) {
if self.words.len() < words {
self.words.resize(words, 0);
}
}
pub fn reserve(&mut self, bits: usize) {
self.reserve_words(bits.div_ceil(32));
}
pub fn clear(&mut self) {
for w in self.words.iter_mut() {
*w = 0;
}
}
pub fn is_empty(&self) -> bool {
for w in self.words.iter() {
if *w != 0 {
return false;
}
}
true
}
}
impl<K: IntoBitIndex> BitSet<K> {
pub fn contains(&self, key: K) -> bool {
let idx = BitIndex::from(key);
if idx.word < self.words.len() {
self.words[idx.word] & (1_u32 << idx.bit) != 0
} else {
false
}
}
pub fn insert(&mut self, key: K) -> bool {
let idx = BitIndex::from(key);
self.reserve_words(idx.word + 1);
let exists = self.words[idx.word] & (1_u32 << idx.bit) != 0;
self.words[idx.word] |= 1_u32 << idx.bit;
!exists
}
pub fn remove(&mut self, key: K) -> bool {
let idx = BitIndex::from(key);
if idx.word < self.words.len() {
let exists = self.words[idx.word] & (1_u32 << idx.bit) != 0;
self.words[idx.word] &= !(1_u32 << idx.bit);
exists
} else {
false
}
}
}
impl<K: FromBitIndex> BitSet<K> {
pub fn iter(&self) -> impl '_ + Iterator<Item = K> {
BitSetIter::new(&self.words)
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(K) -> bool,
{
let mut cur = BitIndex::ZERO;
loop {
let word_fn = |w| self.words.get(w).cloned();
let Some(set) = find_next_set(word_fn, cur) else {
return;
};
if !f(K::from_bit_index(set.into())) {
self.words[set.word] &= !(1_u32 << set.bit);
}
cur = set + 1;
}
}
}
impl BitSet<usize> {
/// Returns true if any bits in the given range are set
pub fn any_set_in_range(&self, mut range: Range<usize>) -> bool {
range.end = range.end.min(self.words.len() * 32);
any_set_in_range(&self.words, range.start.into(), range.end.into())
}
/// Returns true if all the bits in the given range are set.
/// Returns true for empty ranges.
pub fn all_set_in_range(&self, range: Range<usize>) -> bool {
if range.is_empty() {
true
} else if range.end > self.words.len() * 32 {
false
} else {
all_set_in_range(&self.words, range.start.into(), range.end.into())
}
}
/// Returns true if any bits in the given range are unset.
pub fn any_unset_in_range(&self, range: Range<usize>) -> bool {
!self.all_set_in_range(range)
}
/// Returns true if all the bits in the given range are unset.
/// Returns true for empty ranges.
pub fn all_unset_in_range(&self, range: Range<usize>) -> bool {
!self.any_set_in_range(range)
}
/// Returns the number of bits set in the given range.
pub fn count_set_in_range(&self, mut range: Range<usize>) -> usize {
range.end = range.end.min(self.words.len() * 32);
count_set_in_range(&self.words, range.start.into(), range.end.into())
}
pub fn set_range(&mut self, range: Range<usize>) {
if !range.is_empty() {
let end_m1 = BitIndex::from(range.end - 1);
self.reserve_words(end_m1.word + 1);
set_range(&mut self.words, range.start.into(), range.end.into());
}
}
pub fn unset_range(&mut self, mut range: Range<usize>) {
range.end = range.end.min(self.words.len() * 32);
unset_range(&mut self.words, range.start.into(), range.end.into());
}
pub fn next_set(&self, start: usize) -> Option<usize> {
let word_fn = |w| self.words.get(w).cloned();
find_next_set(word_fn, start.into()).map(BitIndex::into)
}
pub fn next_unset(&self, start: usize) -> usize {
let word_fn = |w| {
// NOT the result to turn find_next_set() into find_next_unset().
// Letting it run past the end and returning Some(!0) ensures that
// we will always find an unset bit
Some(!self.words.get(w).cloned().unwrap_or(0))
};
find_next_set(word_fn, start.into()).unwrap().into()
}
/// Search for a set of `count` consecutive elements that in the set. The
/// found set must obey the alignment requirements specified by
/// align_offset and align_mul. All elements in the found set will be >=
/// start. Returns the least element of the found set.
///
/// align_mul must be a power of two <= 16
pub fn find_aligned_set_range(
&self,
start: usize,
count: usize,
align_mul: usize,
align_offset: usize,
) -> Option<usize> {
let word_fn = |w| self.words.get(w).cloned();
find_aligned_set_range(
word_fn,
start.into(),
count,
align_mul,
align_offset,
)
.map(BitIndex::into)
}
/// Search for a set of `count` consecutive elements that are not present in
/// the set. The found set must obey the alignment requirements specified by
/// align_offset and align_mul. All elements in the found set will be >=
/// start. Returns the least element of the found set.
///
/// align_mul must be a power of two <= 16
pub fn find_aligned_unset_range(
&self,
start: usize,
count: usize,
align_mul: usize,
align_offset: usize,
) -> usize {
let word_fn = |w| {
// NOT the result to turn find_aligned_set_range() into
// find_aligned_unset_range(). Letting it run past the end and
// returning Some(!0) ensures that we will always find a unset bit
Some(!self.words.get(w).cloned().unwrap_or(0))
};
find_aligned_set_range(
word_fn,
start.into(),
count,
align_mul,
align_offset,
)
.unwrap()
.into()
}
}
impl<K> BitSet<K> {
/// Evaluate an expression and store its value in self
pub fn assign<B>(&mut self, value: BitSetStream<B, K>)
where
B: BitSetStreamTrait,
{
let mut value = value.0;
let len = value.len();
self.words.clear();
self.words.resize_with(len, || value.next());
for _ in 0..16 {
debug_assert_eq!(value.next(), 0);
}
}
/// Calculate the union of self and an expression, and store the result in
/// self.
///
/// Returns true if the value of self changes, or false otherwise. If you
/// don't need the return value of this function, consider using the `|=`
/// operator instead.
pub fn union_with<B>(&mut self, other: BitSetStream<B, K>) -> bool
where
B: BitSetStreamTrait,
{
let mut other = other.0;
let mut added_bits = false;
let other_len = other.len();
self.reserve_words(other_len);
for w in 0..other_len {
let uw = self.words[w] | other.next();
if uw != self.words[w] {
added_bits = true;
self.words[w] = uw;
}
}
added_bits
}
pub fn s(
&self,
_: RangeFull,
) -> BitSetStream<impl '_ + BitSetStreamTrait, K> {
BitSetStream(
BitSetStreamFromBitSet {
iter: self.words.iter().copied(),
},
PhantomData,
)
}
}
impl<K> Default for BitSet<K> {
fn default() -> BitSet<K> {
BitSet::new()
}
}
impl FromIterator<usize> for BitSet {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = usize>,
{
let mut res = BitSet::new();
for i in iter {
res.insert(i);
}
res
}
}
impl<K> PartialEq<BitSet<K>> for BitSet<K> {
fn eq(&self, other: &BitSet<K>) -> bool {
if self.words.len() <= other.words.len() {
for i in 0..self.words.len() {
if self.words[i] != other.words[i] {
return false;
}
}
for i in self.words.len()..other.words.len() {
if other.words[i] != 0 {
return false;
}
}
} else {
for i in 0..other.words.len() {
if self.words[i] != other.words[i] {
return false;
}
}
for i in other.words.len()..self.words.len() {
if self.words[i] != 0 {
return false;
}
}
}
true
}
}
impl<K> Eq for BitSet<K> {}
#[expect(clippy::len_without_is_empty)]
pub trait BitSetStreamTrait {
/// Get the next word
///
/// Guaranteed to return 0 after len() elements
fn next(&mut self) -> u32;
/// Get the number of output words
fn len(&self) -> usize;
}
struct BitSetStreamFromBitSet<T>
where
T: ExactSizeIterator<Item = u32>,
{
iter: T,
}
impl<T> BitSetStreamTrait for BitSetStreamFromBitSet<T>
where
T: ExactSizeIterator<Item = u32>,
{
fn next(&mut self) -> u32 {
self.iter.next().unwrap_or(0)
}
fn len(&self) -> usize {
self.iter.len()
}
}
pub struct BitSetStream<T, K>(T, PhantomData<K>)
where
T: BitSetStreamTrait;
impl<T, K> From<BitSetStream<T, K>> for BitSet<K>
where
T: BitSetStreamTrait,
{
fn from(value: BitSetStream<T, K>) -> Self {
let mut out = BitSet::new();
out.assign(value);
out
}
}
macro_rules! binop {
(
$BinOp:ident,
$bin_op:ident,
$AssignBinOp:ident,
$assign_bin_op:ident,
$Struct:ident,
|$a:ident, $b:ident| $next_impl:expr,
|$a_len: ident, $b_len: ident| $len_impl:expr,
) => {
pub struct $Struct<A, B>
where
A: BitSetStreamTrait,
B: BitSetStreamTrait,
{
a: A,
b: B,
}
impl<A, B> BitSetStreamTrait for $Struct<A, B>
where
A: BitSetStreamTrait,
B: BitSetStreamTrait,
{
fn next(&mut self) -> u32 {
let $a = self.a.next();
let $b = self.b.next();
$next_impl
}
fn len(&self) -> usize {
let $a_len = self.a.len();
let $b_len = self.b.len();
let new_len = $len_impl;
new_len
}
}
impl<A, B, K> $BinOp<BitSetStream<B, K>> for BitSetStream<A, K>
where
A: BitSetStreamTrait,
B: BitSetStreamTrait,
{
type Output = BitSetStream<$Struct<A, B>, K>;
fn $bin_op(self, rhs: BitSetStream<B, K>) -> Self::Output {
BitSetStream(
$Struct {
a: self.0,
b: rhs.0,
},
PhantomData,
)
}
}
impl<B, K> $AssignBinOp<BitSetStream<B, K>> for BitSet<K>
where
B: BitSetStreamTrait,
{
fn $assign_bin_op(&mut self, rhs: BitSetStream<B, K>) {
let mut rhs = rhs.0;
let $a_len = self.words.len();
let $b_len = rhs.len();
let expected_word_len = $len_impl;
self.words.resize(expected_word_len, 0);
for lhs in &mut self.words {
let $a = *lhs;
let $b = rhs.next();
*lhs = $next_impl;
}
for _ in 0..16 {
debug_assert_eq!(
{
let $a = 0;
let $b = rhs.next();
$next_impl
},
0
);
}
}
}
};
}
binop!(
BitAnd,
bitand,
BitAndAssign,
bitand_assign,
BitSetStreamAnd,
|a, b| a & b,
|a, b| min(a, b),
);
binop!(
BitOr,
bitor,
BitOrAssign,
bitor_assign,
BitSetStreamOr,
|a, b| a | b,
|a, b| max(a, b),
);
binop!(
BitXor,
bitxor,
BitXorAssign,
bitxor_assign,
BitSetStreamXor,
|a, b| a ^ b,
|a, b| max(a, b),
);
binop!(
Sub,
sub,
SubAssign,
sub_assign,
BitSetStreamSub,
|a, b| a & !b,
|a, _b| a,
);
struct BitSetIter<'a, K> {
words: &'a [u32],
idx: BitIndex,
phantom: PhantomData<K>,
}
impl<'a, K> BitSetIter<'a, K> {
fn new(words: &'a [u32]) -> Self {
Self {
words,
idx: BitIndex::ZERO,
phantom: PhantomData,
}
}
}
impl<'a, K: FromBitIndex> Iterator for BitSetIter<'a, K> {
type Item = K;
fn next(&mut self) -> Option<K> {
let word_fn = |w| self.words.get(w).cloned();
if let Some(idx) = find_next_set(word_fn, self.idx) {
self.idx = idx + 1;
Some(K::from_bit_index(idx.into()))
} else {
self.idx = BitIndex::from_word(self.words.len());
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn to_vec(set: &BitSet) -> Vec<usize> {
set.iter().collect()
}
#[test]
fn test_basic() {
let mut set = BitSet::new();
assert_eq!(to_vec(&set), &[]);
assert!(set.is_empty());
set.insert(0);
assert_eq!(to_vec(&set), &[0]);
set.insert(73);
set.insert(1);
assert_eq!(to_vec(&set), &[0, 1, 73]);
assert!(!set.is_empty());
assert!(set.contains(73));
assert!(!set.contains(197));
assert!(set.remove(1));
assert!(!set.remove(7));
let mut set2 = set.clone();
assert_eq!(to_vec(&set), &[0, 73]);
assert!(!set.is_empty());
assert!(set.remove(0));
assert!(set.remove(73));
assert!(set.is_empty());
set.clear();
assert!(set.is_empty());
set2.clear();
assert!(set2.is_empty());
}
#[test]
fn test_any_set_in_range() {
let set: BitSet<usize> = Default::default();
assert!(!set.any_set_in_range(0..64));
let set: BitSet<usize> = [15, 31, 64].into_iter().collect();
assert!(!set.any_set_in_range(0..14));
assert!(!set.any_set_in_range(16..31));
assert!(!set.any_set_in_range(32..64));
assert!(!set.any_set_in_range(72..128));
assert!(set.any_set_in_range(5..16));
assert!(set.any_set_in_range(5..20));
assert!(set.any_set_in_range(15..20));
assert!(set.any_set_in_range(0..32));
assert!(set.any_set_in_range(31..33));
assert!(set.any_set_in_range(60..65));
}
#[test]
fn test_all_set_in_range() {
let mut set: BitSet<usize> = Default::default();
set.set_range(15..45);
assert!(!set.all_set_in_range(0..32));
assert!(set.all_set_in_range(16..24));
assert!(!set.all_set_in_range(30..50));
// Empty ranges return true for all_*
assert!(set.all_set_in_range(50..50));
}
#[test]
fn test_any_unnset_in_range() {
let set: BitSet<usize> = Default::default();
assert!(set.any_unset_in_range(0..64));
let mut set: BitSet<usize> = Default::default();
set.set_range(0..65);
for i in [15, 31, 64] {
set.remove(i);
}
assert!(!set.any_unset_in_range(0..14));
assert!(!set.any_unset_in_range(16..31));
assert!(!set.any_unset_in_range(32..64));
assert!(set.any_unset_in_range(5..16));
assert!(set.any_unset_in_range(5..20));
assert!(set.any_unset_in_range(15..20));
assert!(set.any_unset_in_range(0..32));
assert!(set.any_unset_in_range(31..33));
assert!(set.any_unset_in_range(60..65));
// Test past the end
assert!(set.any_unset_in_range(100..120));
}
#[test]
fn test_all_unset_in_range() {
let set: BitSet<usize> = [15, 31, 64].into_iter().collect();
assert!(set.all_unset_in_range(0..15));
assert!(set.all_unset_in_range(16..31));
assert!(set.all_unset_in_range(32..64));
assert!(!set.all_unset_in_range(0..30));
assert!(!set.all_unset_in_range(30..42));
// Empty ranges return true for all_*
assert!(set.all_unset_in_range(50..50));
// Test past the end
assert!(set.all_unset_in_range(100..120));
}
#[test]
fn test_count_set_in_range() {
let set: BitSet<usize> = [15, 16, 31, 64].into_iter().collect();
assert_eq!(set.count_set_in_range(0..15), 0);
assert_eq!(set.count_set_in_range(17..31), 0);
assert_eq!(set.count_set_in_range(32..64), 0);
assert_eq!(set.count_set_in_range(0..30), 2);
assert_eq!(set.count_set_in_range(30..42), 1);
assert_eq!(set.count_set_in_range(0..65), 4);
// Empty ranges return 0
assert_eq!(set.count_set_in_range(50..50), 0);
// Test past the end
assert_eq!(set.count_set_in_range(100..120), 0);
}
#[test]
fn test_set_range() {
for range in [0..4, 17..35, 32..35, 65..7] {
let mut set: BitSet<usize> = Default::default();
set.set_range(range.clone());
for i in 0..96 {
assert_eq!(set.contains(i), range.contains(&i));
}
}
}
#[test]
fn test_unset_range() {
for range in [0..4, 17..35, 32..35, 65..7] {
let mut set: BitSet<usize> = Default::default();
set.set_range(0..96);
set.unset_range(range.clone());
for i in 0..96 {
assert_eq!(set.contains(i), !range.contains(&i));
}
}
}
#[test]
fn test_iter() {
let bits = [0, 3, 11, 12, 13, 24, 30, 31, 32, 63, 65];
let mut set: BitSet<usize> = Default::default();
for i in &bits {
set.insert(*i);
}
let mut iter = set.iter();
for i in &bits {
assert_eq!(iter.next(), Some(*i));
}
assert_eq!(iter.next(), None);
}
#[test]
fn test_next_unset() {
for test_range in
&[0..0, 42..1337, 1337..1337, 31..32, 32..33, 63..64, 64..65]
{
let mut set = BitSet::new();
for i in test_range.clone() {
set.insert(i);
}
for extra_bit in [17, 34, 39] {
assert!(test_range.end != extra_bit);
set.insert(extra_bit);
}
assert_eq!(set.next_unset(test_range.start), test_range.end);
}
}
#[test]
fn test_eq() {
let a: BitSet<usize> = [15, 31, 64].into_iter().collect();
let mut b: BitSet<usize> = Default::default();
assert!(a != b);
b.insert(15);
b.insert(31);
assert!(a != b);
b.insert(64);
assert!(a == b);
b.insert(206);
assert!(a != b);
b.remove(206);
assert!(a == b);
}
#[test]
fn test_from_iter() {
let vec = vec![0, 1, 99];
let set: BitSet = vec.clone().into_iter().collect();
assert_eq!(to_vec(&set), vec);
}
#[test]
fn test_or() {
let a: BitSet = vec![9, 23, 18, 72].into_iter().collect();
let b: BitSet = vec![7, 23, 1337].into_iter().collect();
let expected = [7, 9, 18, 23, 72, 1337];
assert_eq!(to_vec(&(a.s(..) | b.s(..)).into()), &expected[..]);
assert_eq!(to_vec(&(b.s(..) | a.s(..)).into()), &expected[..]);
let mut actual_1 = a.clone();
actual_1 |= b.s(..);
assert_eq!(to_vec(&actual_1), &expected[..]);
let mut actual_2 = b.clone();
actual_2 |= a.s(..);
assert_eq!(to_vec(&actual_2), &expected[..]);
let mut actual_3 = a.clone();
assert!(!actual_3.union_with(a.s(..)));
assert!(actual_3.union_with(b.s(..)));
assert_eq!(to_vec(&actual_3), &expected[..]);
let mut actual_4 = b.clone();
assert!(!actual_4.union_with(b.s(..)));
assert!(actual_4.union_with(a.s(..)));
assert_eq!(to_vec(&actual_4), &expected[..]);
}
#[test]
fn test_and() {
let a: BitSet = vec![1337, 42, 7, 1].into_iter().collect();
let b: BitSet = vec![42, 783, 2, 7].into_iter().collect();
let expected = [7, 42];
assert_eq!(to_vec(&(a.s(..) & b.s(..)).into()), &expected[..]);
assert_eq!(to_vec(&(b.s(..) & a.s(..)).into()), &expected[..]);
let mut actual_1 = a.clone();
actual_1 &= b.s(..);
assert_eq!(to_vec(&actual_1), &expected[..]);
let mut actual_2 = b.clone();
actual_2 &= a.s(..);
assert_eq!(to_vec(&actual_2), &expected[..]);
}
#[test]
fn test_xor() {
let a: BitSet = vec![1337, 42, 7, 1].into_iter().collect();
let b: BitSet = vec![42, 127, 2, 7].into_iter().collect();
let expected = [1, 2, 127, 1337];
assert_eq!(to_vec(&(a.s(..) ^ b.s(..)).into()), &expected[..]);
assert_eq!(to_vec(&(b.s(..) ^ a.s(..)).into()), &expected[..]);
let mut actual_1 = a.clone();
actual_1 ^= b.s(..);
assert_eq!(to_vec(&actual_1), &expected[..]);
let mut actual_2 = b.clone();
actual_2 ^= a.s(..);
assert_eq!(to_vec(&actual_2), &expected[..]);
}
#[test]
fn test_sub() {
let a: BitSet = vec![1337, 42, 7, 1].into_iter().collect();
let b: BitSet = vec![42, 127, 2, 7].into_iter().collect();
let expected_1 = [1, 1337];
let expected_2 = [2, 127];
assert_eq!(to_vec(&(a.s(..) - b.s(..)).into()), &expected_1[..]);
assert_eq!(to_vec(&(b.s(..) - a.s(..)).into()), &expected_2[..]);
let mut actual_1 = a.clone();
actual_1 -= b.s(..);
assert_eq!(to_vec(&actual_1), &expected_1[..]);
let mut actual_2 = b.clone();
actual_2 -= a.s(..);
assert_eq!(to_vec(&actual_2), &expected_2[..]);
}
#[test]
fn test_compund() {
let a: BitSet = vec![1337, 42, 7, 1].into_iter().collect();
let b: BitSet = vec![42, 127, 2, 7].into_iter().collect();
let mut c = BitSet::new();
c &= a.s(..) | b.s(..);
assert!(c.is_empty());
}
fn every_nth_bit_naive(n: usize) -> u32 {
assert!(n <= 32);
assert!(n.is_power_of_two());
let mut x = 0;
for i in 0..32 {
if i % n == 0 {
x |= 1 << i;
}
}
x
}
#[test]
fn test_every_nth_bit() {
for i in 1_usize..=16 {
if i.is_power_of_two() {
assert_eq!(every_nth_bit(i), every_nth_bit_naive(i));
}
}
}
fn slow_find_aligned_unset_range(
bitset: &BitSet<usize>,
start: usize,
count: usize,
align_mul: usize,
align_offset: usize,
) -> usize {
assert!(align_mul.is_power_of_two());
assert!(align_offset < align_mul);
let mut cur = ((start / align_mul) * align_mul) + align_offset;
if cur < start {
cur += align_mul
}
loop {
if bitset.all_unset_in_range(cur..(cur + count)) {
return cur;
}
cur += align_mul
}
}
#[test]
fn test_find_aligned_unset_range() {
let a: BitSet = [0, 4, 5, 6, 7, 61, 128, 129, 130, 250]
.into_iter()
.collect();
for am in [1, 2, 4, 8, 16, 32, 64] {
for ao in [0, 1, 2, 3, 7, 15, 29, 47] {
if ao >= am {
continue;
}
let rem = am - ao;
for c in [1, 2, 5, 9, 17, 32, 37, rem, am, am * 2] {
let mut s = 0;
while s < 300 {
let i = a.find_aligned_unset_range(s, c, am, ao);
let j = slow_find_aligned_unset_range(&a, s, c, am, ao);
assert_eq!(i, j);
s = i + 1;
}
}
}
}
}
}