@@ -509,14 +509,20 @@ enum Chunk {
509509 /// to store the length, which would make this type larger. These excess
510510 /// words are always zero, as are any excess bits in the final in-use word.
511511 ///
512- /// The `ChunkSize` field is the count of 1s set in the chunk, and
513- /// must satisfy `0 < count < chunk_domain_size`.
514- ///
515512 /// The words are within an `Rc` because it's surprisingly common to
516513 /// duplicate an entire chunk, e.g. in `ChunkedBitSet::clone_from()`, or
517514 /// when a `Mixed` chunk is union'd into a `Zeros` chunk. When we do need
518515 /// to modify a chunk we use `Rc::make_mut`.
519- Mixed ( ChunkSize , Rc < [ Word ; CHUNK_WORDS ] > ) ,
516+ Mixed {
517+ /// Count of set bits (1s) in this chunk's words.
518+ ///
519+ /// Invariant: `0 < ones_count < chunk_domain_size`.
520+ ///
521+ /// Tracking this separately allows individual insert/remove calls to
522+ /// know that the chunk has become all-zeroes or all-ones, in O(1) time.
523+ ones_count : ChunkSize ,
524+ words : Rc < [ Word ; CHUNK_WORDS ] > ,
525+ } ,
520526}
521527
522528// This type is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -613,7 +619,7 @@ impl<T: Idx> ChunkedBitSet<T> {
613619 match & chunk {
614620 Zeros => false ,
615621 Ones => true ,
616- Mixed ( _, words) => {
622+ Mixed { ones_count : _, words } => {
617623 let ( word_index, mask) = chunk_word_index_and_mask ( elem) ;
618624 ( words[ word_index] & mask) != 0
619625 }
@@ -644,19 +650,19 @@ impl<T: Idx> ChunkedBitSet<T> {
644650
645651 let ( word_index, mask) = chunk_word_index_and_mask ( elem) ;
646652 words_ref[ word_index] |= mask;
647- * chunk = Mixed ( 1 , words) ;
653+ * chunk = Mixed { ones_count : 1 , words } ;
648654 } else {
649655 * chunk = Ones ;
650656 }
651657 true
652658 }
653659 Ones => false ,
654- Mixed ( ref mut count , ref mut words) => {
660+ Mixed { ref mut ones_count , ref mut words } => {
655661 // We skip all the work if the bit is already set.
656662 let ( word_index, mask) = chunk_word_index_and_mask ( elem) ;
657663 if ( words[ word_index] & mask) == 0 {
658- * count += 1 ;
659- if * count < chunk_domain_size {
664+ * ones_count += 1 ;
665+ if * ones_count < chunk_domain_size {
660666 let words = Rc :: make_mut ( words) ;
661667 words[ word_index] |= mask;
662668 } else {
@@ -702,18 +708,18 @@ impl<T: Idx> ChunkedBitSet<T> {
702708 ) ;
703709 let ( word_index, mask) = chunk_word_index_and_mask ( elem) ;
704710 words_ref[ word_index] &= !mask;
705- * chunk = Mixed ( chunk_domain_size - 1 , words) ;
711+ * chunk = Mixed { ones_count : chunk_domain_size - 1 , words } ;
706712 } else {
707713 * chunk = Zeros ;
708714 }
709715 true
710716 }
711- Mixed ( ref mut count , ref mut words) => {
717+ Mixed { ref mut ones_count , ref mut words } => {
712718 // We skip all the work if the bit is already clear.
713719 let ( word_index, mask) = chunk_word_index_and_mask ( elem) ;
714720 if ( words[ word_index] & mask) != 0 {
715- * count -= 1 ;
716- if * count > 0 {
721+ * ones_count -= 1 ;
722+ if * ones_count > 0 {
717723 let words = Rc :: make_mut ( words) ;
718724 words[ word_index] &= !mask;
719725 } else {
@@ -732,7 +738,7 @@ impl<T: Idx> ChunkedBitSet<T> {
732738 match self . chunks . get ( chunk_index) {
733739 Some ( Zeros ) => ChunkIter :: Zeros ,
734740 Some ( Ones ) => ChunkIter :: Ones ( 0 ..chunk_domain_size as usize ) ,
735- Some ( Mixed ( _, words) ) => {
741+ Some ( Mixed { ones_count : _, words } ) => {
736742 let num_words = num_words ( chunk_domain_size as usize ) ;
737743 ChunkIter :: Mixed ( BitIter :: new ( & words[ 0 ..num_words] ) )
738744 }
@@ -765,14 +771,14 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
765771
766772 match ( & mut self_chunk, & other_chunk) {
767773 ( _, Zeros ) | ( Ones , _) => { }
768- ( Zeros , _) | ( Mixed ( .. ) , Ones ) => {
774+ ( Zeros , _) | ( Mixed { .. } , Ones ) => {
769775 // `other_chunk` fully overwrites `self_chunk`
770776 * self_chunk = other_chunk. clone ( ) ;
771777 changed = true ;
772778 }
773779 (
774- Mixed ( self_chunk_count , self_chunk_words) ,
775- Mixed ( _other_chunk_count , other_chunk_words) ,
780+ Mixed { ones_count : self_chunk_ones , words : self_chunk_words } ,
781+ Mixed { ones_count : _ , words : other_chunk_words } ,
776782 ) => {
777783 // First check if the operation would change
778784 // `self_chunk.words`. If not, we can avoid allocating some
@@ -807,8 +813,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
807813 op,
808814 ) ;
809815 debug_assert ! ( has_changed) ;
810- * self_chunk_count = count_ones ( & self_chunk_words[ 0 ..num_words] ) as ChunkSize ;
811- if * self_chunk_count == chunk_domain_size {
816+ * self_chunk_ones = count_ones ( & self_chunk_words[ 0 ..num_words] ) as ChunkSize ;
817+ if * self_chunk_ones == chunk_domain_size {
812818 * self_chunk = Ones ;
813819 }
814820 changed = true ;
@@ -839,11 +845,11 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
839845
840846 match ( & mut self_chunk, & other_chunk) {
841847 ( Zeros , _) | ( _, Zeros ) => { }
842- ( Ones | Mixed ( .. ) , Ones ) => {
848+ ( Ones | Mixed { .. } , Ones ) => {
843849 changed = true ;
844850 * self_chunk = Zeros ;
845851 }
846- ( Ones , Mixed ( other_chunk_count , other_chunk_words) ) => {
852+ ( Ones , Mixed { ones_count : other_chunk_ones , words : other_chunk_words } ) => {
847853 changed = true ;
848854 let num_words = num_words ( chunk_domain_size as usize ) ;
849855 debug_assert ! ( num_words > 0 && num_words <= CHUNK_WORDS ) ;
@@ -854,16 +860,17 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
854860 * word = !* word & tail_mask;
855861 tail_mask = Word :: MAX ;
856862 }
857- let self_chunk_count = chunk_domain_size - * other_chunk_count ;
863+ let self_chunk_ones = chunk_domain_size - * other_chunk_ones ;
858864 debug_assert_eq ! (
859- self_chunk_count ,
865+ self_chunk_ones ,
860866 count_ones( & self_chunk_words[ 0 ..num_words] ) as ChunkSize
861867 ) ;
862- * self_chunk = Mixed ( self_chunk_count, Rc :: new ( self_chunk_words) ) ;
868+ * self_chunk =
869+ Mixed { ones_count : self_chunk_ones, words : Rc :: new ( self_chunk_words) } ;
863870 }
864871 (
865- Mixed ( self_chunk_count , self_chunk_words) ,
866- Mixed ( _other_chunk_count , other_chunk_words) ,
872+ Mixed { ones_count : self_chunk_ones , words : self_chunk_words } ,
873+ Mixed { ones_count : _ , words : other_chunk_words } ,
867874 ) => {
868875 // See `ChunkedBitSet::union` for details on what is happening here.
869876 let num_words = num_words ( chunk_domain_size as usize ) ;
@@ -883,8 +890,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
883890 op,
884891 ) ;
885892 debug_assert ! ( has_changed) ;
886- * self_chunk_count = count_ones ( & self_chunk_words[ 0 ..num_words] ) as ChunkSize ;
887- if * self_chunk_count == 0 {
893+ * self_chunk_ones = count_ones ( & self_chunk_words[ 0 ..num_words] ) as ChunkSize ;
894+ if * self_chunk_ones == 0 {
888895 * self_chunk = Zeros ;
889896 }
890897 changed = true ;
@@ -915,13 +922,13 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
915922
916923 match ( & mut self_chunk, & other_chunk) {
917924 ( Zeros , _) | ( _, Ones ) => { }
918- ( Ones , Zeros | Mixed ( .. ) ) | ( Mixed ( .. ) , Zeros ) => {
925+ ( Ones , Zeros | Mixed { .. } ) | ( Mixed { .. } , Zeros ) => {
919926 changed = true ;
920927 * self_chunk = other_chunk. clone ( ) ;
921928 }
922929 (
923- Mixed ( self_chunk_count , self_chunk_words) ,
924- Mixed ( _other_chunk_count , other_chunk_words) ,
930+ Mixed { ones_count : self_chunk_ones , words : self_chunk_words } ,
931+ Mixed { ones_count : _ , words : other_chunk_words } ,
925932 ) => {
926933 // See `ChunkedBitSet::union` for details on what is happening here.
927934 let num_words = num_words ( chunk_domain_size as usize ) ;
@@ -941,8 +948,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
941948 op,
942949 ) ;
943950 debug_assert ! ( has_changed) ;
944- * self_chunk_count = count_ones ( & self_chunk_words[ 0 ..num_words] ) as ChunkSize ;
945- if * self_chunk_count == 0 {
951+ * self_chunk_ones = count_ones ( & self_chunk_words[ 0 ..num_words] ) as ChunkSize ;
952+ if * self_chunk_ones == 0 {
946953 * self_chunk = Zeros ;
947954 }
948955 changed = true ;
@@ -1023,11 +1030,11 @@ impl Chunk {
10231030 assert ! ( chunk_domain_size as usize <= CHUNK_BITS ) ;
10241031 match * self {
10251032 Zeros | Ones => { }
1026- Mixed ( count , ref words) => {
1027- assert ! ( 0 < count && count < chunk_domain_size) ;
1033+ Mixed { ones_count , ref words } => {
1034+ assert ! ( 0 < ones_count && ones_count < chunk_domain_size) ;
10281035
10291036 // Check the number of set bits matches `count`.
1030- assert_eq ! ( count_ones( words. as_slice( ) ) as ChunkSize , count ) ;
1037+ assert_eq ! ( count_ones( words. as_slice( ) ) as ChunkSize , ones_count ) ;
10311038
10321039 // Check the not-in-use words are all zeroed.
10331040 let num_words = num_words ( chunk_domain_size as usize ) ;
@@ -1043,7 +1050,7 @@ impl Chunk {
10431050 match * self {
10441051 Zeros => 0 ,
10451052 Ones => chunk_domain_size as usize ,
1046- Mixed ( count , _ ) => count as usize ,
1053+ Mixed { ones_count , words : _ } => usize:: from ( ones_count ) ,
10471054 }
10481055 }
10491056}
0 commit comments