Rollup merge of #147630 - nnethercote:bitset-cleanups, r=cjgillot,Zalathar

Bitset cleanups

Some minor cleanups I did while working on rust-lang/rust#147619.

r? ```@Zalathar```
This commit is contained in:
Matthias Krüger
2025-10-14 19:47:30 +02:00
committed by GitHub
2 changed files with 18 additions and 110 deletions

View File

@@ -160,7 +160,7 @@ impl<T: Idx> DenseBitSet<T> {
/// Count the number of set bits in the set.
pub fn count(&self) -> usize {
self.words.iter().map(|e| e.count_ones() as usize).sum()
count_ones(&self.words)
}
/// Returns `true` if `self` contains `elem`.
@@ -786,7 +786,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
match (&mut self_chunk, &other_chunk) {
(_, Zeros) | (Ones, _) => {}
(Zeros, Ones) | (Mixed(..), Ones) | (Zeros, Mixed(..)) => {
(Zeros, _) | (Mixed(..), Ones) => {
// `other_chunk` fully overwrites `self_chunk`
*self_chunk = other_chunk.clone();
changed = true;
@@ -814,10 +814,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
op,
);
debug_assert!(has_changed);
*self_chunk_count = self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum();
*self_chunk_count =
count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == chunk_domain_size {
*self_chunk = Ones;
}
@@ -850,7 +848,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
match (&mut self_chunk, &other_chunk) {
(Zeros, _) | (_, Zeros) => {}
(Ones | Mixed(_, _), Ones) => {
(Ones | Mixed(..), Ones) => {
changed = true;
*self_chunk = Zeros;
}
@@ -868,10 +866,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
let self_chunk_count = chunk_domain_size - *other_chunk_count;
debug_assert_eq!(
self_chunk_count,
self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum()
count_ones(&self_chunk_words[0..num_words]) as ChunkSize
);
*self_chunk = Mixed(self_chunk_count, Rc::new(self_chunk_words));
}
@@ -894,10 +889,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
op,
);
debug_assert!(has_changed);
*self_chunk_count = self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum();
*self_chunk_count =
count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == 0 {
*self_chunk = Zeros;
}
@@ -953,10 +946,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
op,
);
debug_assert!(has_changed);
*self_chunk_count = self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum();
*self_chunk_count =
count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == 0 {
*self_chunk = Zeros;
}
@@ -970,48 +961,6 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
}
}
impl<T: Idx> BitRelations<ChunkedBitSet<T>> for DenseBitSet<T> {
fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
sequential_update(|elem| self.insert(elem), other.iter())
}
fn subtract(&mut self, _other: &ChunkedBitSet<T>) -> bool {
unimplemented!("implement if/when necessary");
}
fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
assert_eq!(self.domain_size(), other.domain_size);
let mut changed = false;
for (i, chunk) in other.chunks.iter().enumerate() {
let mut words = &mut self.words[i * CHUNK_WORDS..];
if words.len() > CHUNK_WORDS {
words = &mut words[..CHUNK_WORDS];
}
match chunk {
Zeros => {
for word in words {
if *word != 0 {
changed = true;
*word = 0;
}
}
}
Ones => (),
Mixed(_, data) => {
for (i, word) in words.iter_mut().enumerate() {
let new_val = *word & data[i];
if new_val != *word {
changed = true;
*word = new_val;
}
}
}
}
}
changed
}
}
impl<T> Clone for ChunkedBitSet<T> {
fn clone(&self) -> Self {
ChunkedBitSet {
@@ -1085,21 +1034,12 @@ impl Chunk {
assert!(0 < count && count < chunk_domain_size);
// Check the number of set bits matches `count`.
assert_eq!(
words.iter().map(|w| w.count_ones() as ChunkSize).sum::<ChunkSize>(),
count
);
assert_eq!(count_ones(words.as_slice()) as ChunkSize, count);
// Check the not-in-use words are all zeroed.
let num_words = num_words(chunk_domain_size as usize);
if num_words < CHUNK_WORDS {
assert_eq!(
words[num_words..]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum::<ChunkSize>(),
0
);
assert_eq!(count_ones(&words[num_words..]) as ChunkSize, 0);
}
}
}
@@ -1122,15 +1062,6 @@ enum ChunkIter<'a> {
Finished,
}
// Applies a function to mutate a bitset, and returns true if any
// of the applications return true
fn sequential_update<T: Idx>(
mut self_update: impl FnMut(T) -> bool,
it: impl Iterator<Item = T>,
) -> bool {
it.fold(false, |changed, elem| self_update(elem) | changed)
}
impl<T: Idx> fmt::Debug for ChunkedBitSet<T> {
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
w.debug_list().entries(self.iter()).finish()
@@ -1590,7 +1521,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
/// Returns the number of elements in `row`.
pub fn count(&self, row: R) -> usize {
let (start, end) = self.range(row);
self.words[start..end].iter().map(|e| e.count_ones() as usize).sum()
count_ones(&self.words[start..end])
}
}
@@ -1801,6 +1732,11 @@ fn max_bit(word: Word) -> usize {
WORD_BITS - 1 - word.leading_zeros() as usize
}
#[inline]
fn count_ones(words: &[Word]) -> usize {
words.iter().map(|word| word.count_ones() as usize).sum()
}
/// Integral type used to represent the bit set.
pub trait FiniteBitSetTy:
BitAnd<Output = Self>