@@ -585,6 +585,57 @@ impl<T: Debug + PrimInt> Vob<T> {
585585 }
586586 }
587587
588+ /// Counts the number of set bits.
589+ /// This method assumes the range is processed with process_range()
590+ fn count_set_bits ( & self , range : Range < usize > ) -> usize {
591+ // Early return for empty ranges
592+ if range. start >= range. end {
593+ return 0 ;
594+ }
595+ let start_word = block_offset :: < T > ( range. start ) ;
596+ if start_word >= self . len {
597+ return 0 ;
598+ }
599+ // this -1 is safe since we already tested for range.start & range.end equality
600+ let end_word = blocks_required :: < T > ( range. end ) - 1 ;
601+
602+ if start_word == end_word {
603+ // Range entirely within one word
604+ let word = self . vec [ start_word] ;
605+ let start_bit = range. start % bits_per_block :: < T > ( ) ;
606+ let end_bit = range. end % bits_per_block :: < T > ( ) ;
607+
608+ // Remove bits before start_bit and bits after end_bit
609+ return count_ones_usize ( if end_bit == 0 {
610+ // end_bit = 0 means we want everything from start_bit to end of word
611+ // After the right shift, we have what we want
612+ word >> start_bit
613+ } else {
614+ // We want bits from start_bit to end_bit
615+ // After right shift, we need to remove the high bits
616+ ( word >> start_bit) << ( start_bit + bits_per_block :: < T > ( ) - end_bit)
617+ } ) ;
618+ }
619+
620+ // First word: shift out bits before start_bit
621+ let start_bit = range. start % bits_per_block :: < T > ( ) ;
622+ let mut count = count_ones_usize ( self . vec [ start_word] >> start_bit) ;
623+
624+ // Middle words
625+ for word_idx in ( start_word + 1 ) ..end_word {
626+ count += count_ones_usize ( self . vec [ word_idx] ) ;
627+ }
628+
629+ // Last word: shift out bits after end_bit
630+ let end_bit = range. end % bits_per_block :: < T > ( ) ;
631+ if end_bit == 0 {
632+ // end_bit = 0 means we want to count the entire end_word
633+ count + count_ones_usize ( self . vec [ end_word] )
634+ } else {
635+ count + count_ones_usize ( self . vec [ end_word] << ( bits_per_block :: < T > ( ) - end_bit) )
636+ }
637+ }
638+
588639 /// Returns an iterator which efficiently produces the index of each unset bit in the specified
589640 /// range. Assuming appropriate support from your CPU, this is much more efficient than
590641 /// checking each bit individually.
@@ -1082,6 +1133,10 @@ impl<T: Debug + PrimInt> Iterator for Iter<'_, T> {
10821133 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
10831134 self . range . size_hint ( )
10841135 }
1136+
1137+ fn count ( self ) -> usize {
1138+ self . range . count ( )
1139+ }
10851140}
10861141
10871142impl < T : Debug + PrimInt > DoubleEndedIterator for Iter < ' _ , T > {
@@ -1148,6 +1203,10 @@ impl<T: Debug + PrimInt> Iterator for IterSetBits<'_, T> {
11481203 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
11491204 self . range . size_hint ( )
11501205 }
1206+
1207+ fn count ( self ) -> usize {
1208+ self . vob . count_set_bits ( self . range )
1209+ }
11511210}
11521211
11531212impl < T : Debug + PrimInt > DoubleEndedIterator for IterSetBits < ' _ , T > {
@@ -1228,6 +1287,12 @@ impl<T: Debug + PrimInt> Iterator for IterUnsetBits<'_, T> {
12281287 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
12291288 self . range . size_hint ( )
12301289 }
1290+
1291+ fn count ( self ) -> usize {
1292+ // this math is safe since (self.range.end - self.range.start) is the total number of bits.
1293+ // and self.vob.count_set_bits() always returns less or equal than that.
1294+ ( self . range . end - self . range . start ) - self . vob . count_set_bits ( self . range )
1295+ }
12311296}
12321297
12331298impl < T : Debug + PrimInt > DoubleEndedIterator for IterUnsetBits < ' _ , T > {
@@ -1300,6 +1365,10 @@ impl<T: Debug + PrimInt> Iterator for StorageIter<'_, T> {
13001365 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
13011366 self . iter . size_hint ( )
13021367 }
1368+
1369+ fn count ( self ) -> usize {
1370+ self . iter . count ( )
1371+ }
13031372}
13041373
13051374#[ inline( always) ]
@@ -1327,6 +1396,16 @@ fn blocks_required<T>(num_bits: usize) -> usize {
13271396 num_bits / bits_per_block :: < T > ( ) + usize:: from ( num_bits % bits_per_block :: < T > ( ) != 0 )
13281397}
13291398
1399+ /// Convenience function that calls T::count_ones() and converts the result to usize
1400+ /// (The conversion is always safe even if T is u128 and usize is u16)
1401+ #[ inline( always) ]
1402+ fn count_ones_usize < T : PrimInt > ( value : T ) -> usize {
1403+ use std:: convert:: TryFrom ;
1404+ // this could safely use unwrap_unchecked() or ever ’as usize', because the result of
1405+ // count_ones() will always fit inside an usize. Even if T==u128 and usize == u8.
1406+ usize:: try_from ( value. count_ones ( ) ) . unwrap ( )
1407+ }
1408+
13301409#[ macro_export]
13311410/// Create a `Vob` from a list of boolean values.
13321411///
@@ -1974,6 +2053,27 @@ mod tests {
19742053 for _ in 0 ..len {
19752054 vob. push ( rng. random ( ) ) ;
19762055 }
2056+ // these tests can later be dialed down, as they noticeable slow down every random vob test.
2057+ assert_eq ! (
2058+ vob. iter_set_bits( ..) . count( ) ,
2059+ vob. iter_set_bits( ..) . filter( |_| true ) . count( )
2060+ ) ;
2061+ assert_eq ! (
2062+ vob. iter_unset_bits( ..) . count( ) ,
2063+ vob. iter_unset_bits( ..) . filter( |_| true ) . count( )
2064+ ) ;
2065+ if len > 2 {
2066+ // trigger the edge cases of _count_set_bits()
2067+ let range = 1 ..len - 1 ;
2068+ assert_eq ! (
2069+ vob. iter_set_bits( range. clone( ) ) . count( ) ,
2070+ vob. iter_set_bits( range. clone( ) ) . filter( |_| true ) . count( )
2071+ ) ;
2072+ assert_eq ! (
2073+ vob. iter_unset_bits( range. clone( ) ) . count( ) ,
2074+ vob. iter_unset_bits( range. clone( ) ) . filter( |_| true ) . count( )
2075+ ) ;
2076+ }
19772077 vob
19782078 }
19792079
@@ -2047,4 +2147,28 @@ mod tests {
20472147 v. push ( true ) ;
20482148 assert_eq ! ( v. vec. len( ) , 1 ) ;
20492149 }
2150+
2151+ #[ test]
2152+ fn test_count ( ) {
2153+ let mut rng = rand:: rng ( ) ;
2154+
2155+ for test_len in 1 ..128 {
2156+ let vob = random_vob ( test_len) ;
2157+ for i in 1 ..test_len - 1 {
2158+ let from = rng. random_range ( 0 ..i) ;
2159+ if from == i {
2160+ continue ;
2161+ }
2162+ let to = rng. random_range ( from..i) ;
2163+ assert_eq ! (
2164+ vob. iter_set_bits( from..to) . count( ) ,
2165+ vob. iter_set_bits( from..to) . filter( |_| true ) . count( )
2166+ ) ;
2167+ assert_eq ! (
2168+ vob. iter_unset_bits( from..to) . count( ) ,
2169+ vob. iter_unset_bits( from..to) . filter( |_| true ) . count( )
2170+ ) ;
2171+ }
2172+ }
2173+ }
20502174}
0 commit comments