@@ -181,6 +181,45 @@ impl<T: Idx> BitSet<T> {
181181 // Note: we currently don't bother trying to make a Sparse set.
182182 HybridBitSet :: Dense ( self . to_owned ( ) )
183183 }
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+ }
184223}
185224
186225/// This is implemented by all the bitsets so that BitSet::union() can be
@@ -518,10 +557,12 @@ impl<T: Idx> HybridBitSet<T> {
518557 changed
519558 }
520559 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) ;
525566 * self = HybridBitSet :: Dense ( new_dense) ;
526567 changed
527568 }
0 commit comments