@@ -181,6 +181,45 @@ impl<T: Idx> BitSet<T> {
181
181
// Note: we currently don't bother trying to make a Sparse set.
182
182
HybridBitSet :: Dense ( self . to_owned ( ) )
183
183
}
184
+
185
+ /// Set `self = self | other`. In contrast to `union` returns `true` if the set contains at
186
+ /// least one bit that is not in `other` (i.e. `other` is not a superset of `self`).
187
+ ///
188
+ /// This is an optimization for union of a hybrid bitset.
189
+ fn reverse_union_sparse ( & mut self , sparse : & SparseBitSet < T > ) -> bool {
190
+ assert ! ( sparse. domain_size == self . domain_size) ;
191
+ self . clear_excess_bits ( ) ;
192
+
193
+ let mut not_already = false ;
194
+ // Index of the current word not yet merged.
195
+ let mut current_index = 0 ;
196
+ // Mask of bits that came from the sparse set in the current word.
197
+ let mut new_bit_mask = 0 ;
198
+ for ( word_index, mask) in sparse. iter ( ) . map ( |x| word_index_and_mask ( * x) ) {
199
+ // Next bit is in a word not inspected yet.
200
+ if word_index > current_index {
201
+ self . words [ current_index] |= new_bit_mask;
202
+ // Were there any bits in the old word that did not occur in the sparse set?
203
+ not_already |= ( self . words [ current_index] ^ new_bit_mask) != 0 ;
204
+ // Check all words we skipped for any set bit.
205
+ not_already |= self . words [ current_index+1 ..word_index] . iter ( ) . any ( |& x| x != 0 ) ;
206
+ // Update next word.
207
+ current_index = word_index;
208
+ // Reset bit mask, no bits have been merged yet.
209
+ new_bit_mask = 0 ;
210
+ }
211
+ // Add bit and mark it as coming from the sparse set.
212
+ // self.words[word_index] |= mask;
213
+ new_bit_mask |= mask;
214
+ }
215
+ self . words [ current_index] |= new_bit_mask;
216
+ // Any bits in the last inspected word that were not in the sparse set?
217
+ not_already |= ( self . words [ current_index] ^ new_bit_mask) != 0 ;
218
+ // Any bits in the tail? Note `clear_excess_bits` before.
219
+ not_already |= self . words [ current_index+1 ..] . iter ( ) . any ( |& x| x != 0 ) ;
220
+
221
+ not_already
222
+ }
184
223
}
185
224
186
225
/// This is implemented by all the bitsets so that BitSet::union() can be
@@ -518,10 +557,12 @@ impl<T: Idx> HybridBitSet<T> {
518
557
changed
519
558
}
520
559
HybridBitSet :: Dense ( other_dense) => {
521
- // `self` is sparse and `other` is dense. Densify
522
- // `self` and then do the bitwise union.
523
- let mut new_dense = self_sparse. to_dense ( ) ;
524
- let changed = new_dense. union ( other_dense) ;
560
+ // `self` is sparse and `other` is dense. Clone the
561
+ // other set and do the bitwise union with sparse
562
+ // `self`. This avoids traversing the dense
563
+ // representation twice.
564
+ let mut new_dense = other_dense. clone ( ) ;
565
+ let changed = new_dense. reverse_union_sparse ( self_sparse) ;
525
566
* self = HybridBitSet :: Dense ( new_dense) ;
526
567
changed
527
568
}
0 commit comments