BitSet
perf improvements
This commit makes two changes: 1. Changes `MaybeLiveLocals` to use `ChunkedBitSet` 2. Overrides the `fold` method for the iterator for `ChunkedBitSet`
This commit is contained in:
parent
02916c4c75
commit
bc7cd2f351
5 changed files with 141 additions and 23 deletions
|
@ -681,6 +681,48 @@ impl<T: Idx> BitRelations<HybridBitSet<T>> for ChunkedBitSet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Idx> BitRelations<ChunkedBitSet<T>> for BitSet<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 {
|
||||
Chunk::Zeros(..) => {
|
||||
for word in words {
|
||||
if *word != 0 {
|
||||
changed = true;
|
||||
*word = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Chunk::Ones(..) => (),
|
||||
Chunk::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 {
|
||||
|
@ -743,6 +785,41 @@ impl<'a, T: Idx> Iterator for ChunkedBitIter<'a, T> {
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn fold<B, F>(mut self, mut init: B, mut f: F) -> B
|
||||
where
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
// If `next` has already been called, we may not be at the start of a chunk, so we first
|
||||
// advance the iterator to the start of the next chunk, before proceeding in chunk sized
|
||||
// steps.
|
||||
while self.index % CHUNK_BITS != 0 {
|
||||
let Some(item) = self.next() else {
|
||||
return init
|
||||
};
|
||||
init = f(init, item);
|
||||
}
|
||||
let start_chunk = self.index / CHUNK_BITS;
|
||||
let chunks = &self.bitset.chunks[start_chunk..];
|
||||
for (i, chunk) in chunks.iter().enumerate() {
|
||||
let base = (start_chunk + i) * CHUNK_BITS;
|
||||
match chunk {
|
||||
Chunk::Zeros(_) => (),
|
||||
Chunk::Ones(limit) => {
|
||||
for j in 0..(*limit as usize) {
|
||||
init = f(init, T::new(base + j));
|
||||
}
|
||||
}
|
||||
Chunk::Mixed(_, _, words) => {
|
||||
init = BitIter::new(&**words).fold(init, |val, mut item: T| {
|
||||
item.increment_by(base);
|
||||
f(val, item)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
init
|
||||
}
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
|
@ -799,11 +876,7 @@ fn sequential_update<T: Idx>(
|
|||
mut self_update: impl FnMut(T) -> bool,
|
||||
it: impl Iterator<Item = T>,
|
||||
) -> bool {
|
||||
let mut changed = false;
|
||||
for elem in it {
|
||||
changed |= self_update(elem);
|
||||
}
|
||||
changed
|
||||
it.fold(false, |changed, elem| self_update(elem) | changed)
|
||||
}
|
||||
|
||||
// Optimization of intersection for SparseBitSet that's generic
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue