Skip to content

Commit e70112c

Browse files
committed
Add DenseBitSet::union_not
This is similar to the existing `union`, except that bits in the RHS are negated before being incorporated into the LHS. Currently only `DenseBitSet` is supported. Supporting other bitset types is possible, but non-trivial, and currently isn't needed.
1 parent 1a23a6f commit e70112c

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

compiler/rustc_index/src/bit_set.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,24 @@ impl<T: Idx> DenseBitSet<T> {
281281
}
282282

283283
bit_relations_inherent_impls! {}
284+
285+
/// Sets `self = self | !other`.
286+
///
287+
/// FIXME: Incorporate this into [`BitRelations`] and fill out
288+
/// implementations for other bitset types, if needed.
289+
pub fn union_not(&mut self, other: &DenseBitSet<T>) {
290+
assert_eq!(self.domain_size, other.domain_size);
291+
292+
// FIXME(Zalathar): If we were to forcibly _set_ all excess bits before
293+
// the bitwise update, and then clear them again afterwards, we could
294+
// quickly and accurately detect whether the update changed anything.
295+
// But that's only worth doing if there's an actual use-case.
296+
297+
bitwise(&mut self.words, &other.words, |a, b| a | !b);
298+
// The bitwise update `a | !b` can result in the last word containing
299+
// out-of-domain bits, so we need to clear them.
300+
self.clear_excess_bits();
301+
}
284302
}
285303

286304
// dense REL dense
@@ -1087,6 +1105,18 @@ impl<T: Idx> fmt::Debug for ChunkedBitSet<T> {
10871105
}
10881106
}
10891107

1108+
/// Sets `out_vec[i] = op(out_vec[i], in_vec[i])` for each index `i` in both
1109+
/// slices. The slices must have the same length.
1110+
///
1111+
/// Returns true if at least one bit in `out_vec` was changed.
1112+
///
1113+
/// ## Warning
1114+
/// Some bitwise operations (e.g. union-not, xor) can set output bits that were
1115+
/// unset in in both inputs. If this happens in the last word/chunk of a bitset,
1116+
/// it can cause the bitset to contain out-of-domain values, which need to
1117+
/// be cleared with `clear_excess_bits_in_final_word`. This also makes the
1118+
/// "changed" return value unreliable, because the change might have only
1119+
/// affected excess bits.
10901120
#[inline]
10911121
fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
10921122
where

compiler/rustc_index/src/bit_set/tests.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,32 @@ fn union_two_sets() {
7575
assert!(set1.contains(64));
7676
}
7777

78+
#[test]
79+
fn union_not() {
80+
let mut a = DenseBitSet::<usize>::new_empty(100);
81+
let mut b = DenseBitSet::<usize>::new_empty(100);
82+
83+
a.insert(3);
84+
a.insert(5);
85+
a.insert(80);
86+
a.insert(81);
87+
88+
b.insert(5); // Already in `a`.
89+
b.insert(7);
90+
b.insert(63);
91+
b.insert(81); // Already in `a`.
92+
b.insert(90);
93+
94+
a.union_not(&b);
95+
96+
// After union-not, `a` should contain all values in the domain, except for
97+
// the ones that are in `b` and were _not_ already in `a`.
98+
assert_eq!(
99+
a.iter().collect::<Vec<_>>(),
100+
(0usize..100).filter(|&x| !matches!(x, 7 | 63 | 90)).collect::<Vec<_>>(),
101+
);
102+
}
103+
78104
#[test]
79105
fn chunked_bitset() {
80106
let mut b0 = ChunkedBitSet::<usize>::new_empty(0);

0 commit comments

Comments
 (0)