@@ -585,6 +585,66 @@ 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+ use std:: convert:: TryFrom ;
592+
593+ // Early return for empty ranges
594+ if range. is_empty ( ) {
595+ return 0 ;
596+ }
597+ let start_off = block_offset :: < T > ( range. start ) ;
598+ debug_assert ! (
599+ start_off < self . len( ) ,
600+ "start_off {} >= self.len {}" ,
601+ start_off,
602+ self . len( )
603+ ) ;
604+
605+ // this -1 arithmetic is safe since we already tested for range.start & range.end equality
606+ let end_off = blocks_required :: < T > ( range. end ) - 1 ;
607+
608+ if start_off == end_off {
609+ // Range entirely within one word
610+ let b = self . vec [ start_off] ;
611+ let start_bit = range. start % bits_per_block :: < T > ( ) ;
612+ let end_bit = range. end % bits_per_block :: < T > ( ) ;
613+
614+ // Remove bits before start_bit and bits after end_bit
615+ let count = if end_bit == 0 {
616+ // end_bit = 0 means we want everything from start_bit to end of word
617+ // After the right shift, we have what we want
618+ b >> start_bit
619+ } else {
620+ // We want bits from start_bit to end_bit
621+ // After right shift, we need to remove the high bits
622+ ( b >> start_bit) << ( start_bit + bits_per_block :: < T > ( ) - end_bit)
623+ }
624+ . count_ones ( ) ;
625+ return usize:: try_from ( count) . unwrap ( ) ;
626+ }
627+
628+ // First word: shift out bits before start_bit
629+ let start_bit = range. start % bits_per_block :: < T > ( ) ;
630+ let mut count = usize:: try_from ( ( self . vec [ start_off] >> start_bit) . count_ones ( ) ) . unwrap ( ) ;
631+
632+ // Middle words
633+ for word_idx in ( start_off + 1 ) ..end_off {
634+ count += usize:: try_from ( self . vec [ word_idx] . count_ones ( ) ) . unwrap ( ) ;
635+ }
636+
637+ // Last word: shift out bits after end_bit
638+ let end_bit = range. end % bits_per_block :: < T > ( ) ;
639+ let count_ones = if end_bit == 0 {
640+ // end_bit = 0 means we want to count the entire end_off word
641+ self . vec [ end_off] . count_ones ( )
642+ } else {
643+ ( self . vec [ end_off] << ( bits_per_block :: < T > ( ) - end_bit) ) . count_ones ( )
644+ } ;
645+ count + usize:: try_from ( count_ones) . unwrap ( )
646+ }
647+
588648 /// Returns an iterator which efficiently produces the index of each unset bit in the specified
589649 /// range. Assuming appropriate support from your CPU, this is much more efficient than
590650 /// checking each bit individually.
@@ -1082,6 +1142,10 @@ impl<T: Debug + PrimInt> Iterator for Iter<'_, T> {
10821142 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
10831143 self . range . size_hint ( )
10841144 }
1145+
1146+ fn count ( self ) -> usize {
1147+ self . range . count ( )
1148+ }
10851149}
10861150
10871151impl < T : Debug + PrimInt > DoubleEndedIterator for Iter < ' _ , T > {
@@ -1148,6 +1212,10 @@ impl<T: Debug + PrimInt> Iterator for IterSetBits<'_, T> {
11481212 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
11491213 self . range . size_hint ( )
11501214 }
1215+
1216+ fn count ( self ) -> usize {
1217+ self . vob . count_set_bits ( self . range )
1218+ }
11511219}
11521220
11531221impl < T : Debug + PrimInt > DoubleEndedIterator for IterSetBits < ' _ , T > {
@@ -1228,6 +1296,12 @@ impl<T: Debug + PrimInt> Iterator for IterUnsetBits<'_, T> {
12281296 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
12291297 self . range . size_hint ( )
12301298 }
1299+
1300+ fn count ( self ) -> usize {
1301+ // This arithmetic is safe because (self.range.end - self.range.start) is the total number of bits,
1302+ // and self.vob.count_set_bits() always returns a value less than or equal to that.
1303+ ( self . range . end - self . range . start ) - self . vob . count_set_bits ( self . range )
1304+ }
12311305}
12321306
12331307impl < T : Debug + PrimInt > DoubleEndedIterator for IterUnsetBits < ' _ , T > {
@@ -1300,6 +1374,10 @@ impl<T: Debug + PrimInt> Iterator for StorageIter<'_, T> {
13001374 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
13011375 self . iter . size_hint ( )
13021376 }
1377+
1378+ fn count ( self ) -> usize {
1379+ self . iter . count ( )
1380+ }
13031381}
13041382
13051383#[ inline( always) ]
@@ -1974,6 +2052,27 @@ mod tests {
19742052 for _ in 0 ..len {
19752053 vob. push ( rng. random ( ) ) ;
19762054 }
2055+ // these tests can later be dialed down, as they noticeable slow down every random vob test.
2056+ assert_eq ! (
2057+ vob. iter_set_bits( ..) . count( ) ,
2058+ vob. iter_set_bits( ..) . filter( |_| true ) . count( )
2059+ ) ;
2060+ assert_eq ! (
2061+ vob. iter_unset_bits( ..) . count( ) ,
2062+ vob. iter_unset_bits( ..) . filter( |_| true ) . count( )
2063+ ) ;
2064+ if len > 2 {
2065+ // trigger the edge cases of count_set_bits()
2066+ let range = 1 ..len - 1 ;
2067+ assert_eq ! (
2068+ vob. iter_set_bits( range. clone( ) ) . count( ) ,
2069+ vob. iter_set_bits( range. clone( ) ) . filter( |_| true ) . count( )
2070+ ) ;
2071+ assert_eq ! (
2072+ vob. iter_unset_bits( range. clone( ) ) . count( ) ,
2073+ vob. iter_unset_bits( range. clone( ) ) . filter( |_| true ) . count( )
2074+ ) ;
2075+ }
19772076 vob
19782077 }
19792078
@@ -2047,4 +2146,40 @@ mod tests {
20472146 v. push ( true ) ;
20482147 assert_eq ! ( v. vec. len( ) , 1 ) ;
20492148 }
2149+
2150+ #[ test]
2151+ fn test_count ( ) {
2152+ let mut rng = rand:: rng ( ) ;
2153+
2154+ for test_len in 1 ..128 {
2155+ let vob = random_vob ( test_len) ;
2156+ assert_eq ! (
2157+ vob. iter_storage( ) . count( ) ,
2158+ vob. iter_storage( ) . filter( |_| true ) . count( )
2159+ ) ;
2160+ assert_eq ! ( vob. iter( ) . count( ) , vob. iter( ) . filter( |_| true ) . count( ) ) ;
2161+ for i in 1 ..test_len - 1 {
2162+ let from = rng. random_range ( 0 ..i) ;
2163+ if from == i {
2164+ continue ;
2165+ }
2166+ let to = rng. random_range ( from..i) ;
2167+ assert_eq ! (
2168+ vob. iter_set_bits( from..to) . count( ) ,
2169+ vob. iter_set_bits( from..to) . filter( |_| true ) . count( )
2170+ ) ;
2171+ assert_eq ! (
2172+ vob. iter_unset_bits( from..to) . count( ) ,
2173+ vob. iter_unset_bits( from..to) . filter( |_| true ) . count( )
2174+ ) ;
2175+ }
2176+ }
2177+ }
2178+
2179+ #[ test]
2180+ fn test_collect_capacity ( ) {
2181+ // a test to make sure that iter_set_bits().collect() does not always allocate .len() elements
2182+ let vec: Vec < usize > = Vob :: from_elem ( false , 100 ) . iter_set_bits ( ..) . collect ( ) ;
2183+ assert_eq ! ( vec. capacity( ) , 0 ) ;
2184+ }
20502185}
0 commit comments