@@ -651,24 +651,174 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
651
651
652
652
impl < T : Idx > BitRelations < HybridBitSet < T > > for ChunkedBitSet < T > {
653
653
fn union ( & mut self , other : & HybridBitSet < T > ) -> bool {
654
- // FIXME: this is slow if `other` is dense, and could easily be
655
- // improved, but it hasn't been a problem in practice so far.
656
654
assert_eq ! ( self . domain_size, other. domain_size( ) ) ;
657
- sequential_update ( |elem| self . insert ( elem) , other. iter ( ) )
655
+
656
+ match other {
657
+ HybridBitSet :: Sparse ( _) => sequential_update ( |elem| self . insert ( elem) , other. iter ( ) ) ,
658
+ HybridBitSet :: Dense ( dense) => self . union ( dense) ,
659
+ }
658
660
}
659
661
660
662
fn subtract ( & mut self , other : & HybridBitSet < T > ) -> bool {
661
- // FIXME: this is slow if `other` is dense, and could easily be
662
- // improved, but it hasn't been a problem in practice so far.
663
663
assert_eq ! ( self . domain_size, other. domain_size( ) ) ;
664
- sequential_update ( |elem| self . remove ( elem) , other. iter ( ) )
664
+
665
+ match other {
666
+ HybridBitSet :: Sparse ( _) => sequential_update ( |elem| self . remove ( elem) , other. iter ( ) ) ,
667
+ HybridBitSet :: Dense ( dense) => self . subtract ( dense) ,
668
+ }
665
669
}
666
670
667
671
fn intersect ( & mut self , _other : & HybridBitSet < T > ) -> bool {
668
672
unimplemented ! ( "implement if/when necessary" ) ;
669
673
}
670
674
}
671
675
676
+ impl < T : Idx > BitRelations < BitSet < T > > for ChunkedBitSet < T > {
677
+ fn union ( & mut self , other : & BitSet < T > ) -> bool {
678
+ assert_eq ! ( self . domain_size, other. domain_size( ) ) ;
679
+
680
+ let mut changed = false ;
681
+ for ( chunk, other_words) in self . chunks . iter_mut ( ) . zip ( other. words ( ) . chunks ( CHUNK_WORDS ) ) {
682
+ match chunk {
683
+ Zeros ( chunk_domain_size) => {
684
+ if let Some ( first_nonzero_index) = first_nonzero ( other_words) {
685
+ let other_count =
686
+ bit_count ( & other_words[ first_nonzero_index..] ) as ChunkSize ;
687
+ debug_assert ! ( other_count <= * chunk_domain_size) ;
688
+ if other_count == * chunk_domain_size {
689
+ * chunk = Ones ( * chunk_domain_size) ;
690
+ changed = true ;
691
+ } else if other_count != 0 {
692
+ // We take some effort to avoid copying the words.
693
+ let words = Rc :: < [ Word ; CHUNK_WORDS ] > :: new_zeroed ( ) ;
694
+ // SAFETY: `words` can safely be all zeroes.
695
+ let mut words = unsafe { words. assume_init ( ) } ;
696
+ let words_ref = Rc :: get_mut ( & mut words) . unwrap ( ) ;
697
+
698
+ debug_assert_eq ! (
699
+ num_words( * chunk_domain_size as usize ) ,
700
+ other_words. len( )
701
+ ) ;
702
+ words_ref[ first_nonzero_index..other_words. len ( ) ]
703
+ . copy_from_slice ( & other_words[ first_nonzero_index..] ) ;
704
+
705
+ * chunk = Mixed ( * chunk_domain_size, other_count, words) ;
706
+ changed = true ;
707
+ }
708
+ }
709
+ }
710
+ Ones ( _) => { }
711
+ Mixed ( chunk_domain_size, chunk_count, chunk_words) => {
712
+ if let Some ( first_nonzero_index) = first_nonzero ( other_words) {
713
+ debug_assert_eq ! ( num_words( * chunk_domain_size as usize ) , other_words. len( ) ) ;
714
+ let op = |a, b| a | b;
715
+ if bitwise_changes (
716
+ & chunk_words[ first_nonzero_index..other_words. len ( ) ] ,
717
+ & other_words[ first_nonzero_index..] ,
718
+ op,
719
+ ) {
720
+ let chunk_words = Rc :: make_mut ( chunk_words) ;
721
+ let has_changed = bitwise (
722
+ & mut chunk_words[ first_nonzero_index..other_words. len ( ) ] ,
723
+ & other_words[ first_nonzero_index..] ,
724
+ op,
725
+ ) ;
726
+ debug_assert ! ( has_changed) ;
727
+
728
+ * chunk_count = bit_count ( chunk_words) as ChunkSize ;
729
+ debug_assert ! ( * chunk_count > 0 ) ;
730
+ if * chunk_count == * chunk_domain_size {
731
+ * chunk = Ones ( * chunk_domain_size) ;
732
+ }
733
+ changed = true
734
+ }
735
+ }
736
+ }
737
+ }
738
+ }
739
+ changed
740
+ }
741
+
742
+ fn subtract ( & mut self , other : & BitSet < T > ) -> bool {
743
+ assert_eq ! ( self . domain_size, other. domain_size( ) ) ;
744
+
745
+ let mut changed = false ;
746
+ for ( chunk, other_words) in self . chunks . iter_mut ( ) . zip ( other. words ( ) . chunks ( CHUNK_WORDS ) ) {
747
+ match chunk {
748
+ Zeros ( _) => { }
749
+ Ones ( chunk_domain_size) => {
750
+ if let Some ( first_nonzero_index) = first_nonzero ( other_words) {
751
+ let other_count =
752
+ bit_count ( & other_words[ first_nonzero_index..] ) as ChunkSize ;
753
+ debug_assert ! ( other_count <= * chunk_domain_size) ;
754
+ if other_count == * chunk_domain_size {
755
+ * chunk = Zeros ( * chunk_domain_size) ;
756
+ changed = true ;
757
+ } else {
758
+ // We take some effort to avoid copying the words.
759
+ let words = Rc :: < [ Word ; CHUNK_WORDS ] > :: new_zeroed ( ) ;
760
+ // SAFETY: `words` can safely be all zeroes.
761
+ let mut words = unsafe { words. assume_init ( ) } ;
762
+ let words_ref = Rc :: get_mut ( & mut words) . unwrap ( ) ;
763
+
764
+ debug_assert_eq ! (
765
+ num_words( * chunk_domain_size as usize ) ,
766
+ other_words. len( )
767
+ ) ;
768
+ for ( word, other) in words_ref[ first_nonzero_index..]
769
+ . iter_mut ( )
770
+ . zip ( other_words[ first_nonzero_index..] . iter ( ) )
771
+ {
772
+ * word = !other;
773
+ }
774
+
775
+ clear_excess_bits_in_final_word (
776
+ * chunk_domain_size as usize ,
777
+ & mut words_ref[ ..other_words. len ( ) ] ,
778
+ ) ;
779
+
780
+ * chunk =
781
+ Mixed ( * chunk_domain_size, * chunk_domain_size - other_count, words) ;
782
+ changed = true ;
783
+ }
784
+ }
785
+ }
786
+ Mixed ( chunk_domain_size, chunk_count, chunk_words) => {
787
+ if let Some ( first_nonzero_index) = first_nonzero ( other_words) {
788
+ debug_assert_eq ! ( num_words( * chunk_domain_size as usize ) , other_words. len( ) ) ;
789
+ let op = |a, b : Word | a & !b;
790
+ if bitwise_changes (
791
+ & chunk_words[ first_nonzero_index..other_words. len ( ) ] ,
792
+ & other_words[ first_nonzero_index..] ,
793
+ op,
794
+ ) {
795
+ let chunk_words = Rc :: make_mut ( chunk_words) ;
796
+ let has_changed = bitwise (
797
+ & mut chunk_words[ first_nonzero_index..other_words. len ( ) ] ,
798
+ & other_words[ first_nonzero_index..] ,
799
+ op,
800
+ ) ;
801
+ debug_assert ! ( has_changed) ;
802
+
803
+ * chunk_count = bit_count ( chunk_words) as ChunkSize ;
804
+ debug_assert ! ( chunk_count < chunk_domain_size) ;
805
+ if * chunk_count == 0 {
806
+ * chunk = Zeros ( * chunk_domain_size) ;
807
+ }
808
+ changed = true
809
+ }
810
+ }
811
+ }
812
+ }
813
+ }
814
+ changed
815
+ }
816
+
817
+ fn intersect ( & mut self , _other : & BitSet < T > ) -> bool {
818
+ unimplemented ! ( "implement if/when necessary" ) ;
819
+ }
820
+ }
821
+
672
822
impl < T > Clone for ChunkedBitSet < T > {
673
823
fn clone ( & self ) -> Self {
674
824
ChunkedBitSet {
@@ -1771,6 +1921,11 @@ fn chunk_word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
1771
1921
word_index_and_mask ( chunk_elem)
1772
1922
}
1773
1923
1924
+ #[ inline]
1925
+ fn first_nonzero ( words : & [ Word ] ) -> Option < usize > {
1926
+ words. iter ( ) . position ( |w| * w != 0 )
1927
+ }
1928
+
1774
1929
fn clear_excess_bits_in_final_word ( domain_size : usize , words : & mut [ Word ] ) {
1775
1930
let num_bits_in_final_word = domain_size % WORD_BITS ;
1776
1931
if num_bits_in_final_word > 0 {
0 commit comments