1use std::fmt::Display;
5use std::fmt::Formatter;
6use std::fmt::Result as FmtResult;
7use std::ops::BitAnd;
8use std::ops::BitOr;
9use std::ops::BitXor;
10use std::ops::Bound;
11use std::ops::Not;
12use std::ops::RangeBounds;
13
14use crate::Alignment;
15use crate::BitBufferMut;
16use crate::Buffer;
17use crate::BufferMut;
18use crate::ByteBuffer;
19use crate::bit::BitChunks;
20use crate::bit::BitIndexIterator;
21use crate::bit::BitIterator;
22use crate::bit::BitSliceIterator;
23use crate::bit::UnalignedBitChunk;
24use crate::bit::collect_bool_word;
25use crate::bit::count_ones::count_ones;
26use crate::bit::get_bit_unchecked;
27use crate::bit::ops::bitwise_binary_op;
28use crate::bit::ops::bitwise_binary_op_lhs_owned;
29use crate::bit::ops::bitwise_unary_op;
30use crate::bit::ops::bitwise_unary_op_copy;
31use crate::bit::select::bit_select;
32use crate::buffer;
33
34#[derive(Debug, Clone, Eq)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct BitBuffer {
38 buffer: ByteBuffer,
39 offset: usize,
43 len: usize,
44}
45
46const LIMIT_LEN: usize = 16;
47impl Display for BitBuffer {
48 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
49 let limit = f.precision().unwrap_or(LIMIT_LEN);
50 let buf: Vec<bool> = self.into_iter().take(limit).collect();
51 f.debug_struct("BitBuffer")
52 .field("len", &self.len)
53 .field("buffer", &buf)
54 .finish()
55 }
56}
57
58impl PartialEq for BitBuffer {
59 fn eq(&self, other: &Self) -> bool {
60 if self.len != other.len {
61 return false;
62 }
63
64 if self.len == 0 {
65 return true;
66 }
67
68 if self.offset == 0 && other.offset == 0 {
70 let full_bytes = self.len / 8;
71 let self_bytes = &self.buffer.as_slice()[..full_bytes];
72 let other_bytes = &other.buffer.as_slice()[..full_bytes];
73 if self_bytes != other_bytes {
74 return false;
75 }
76 let rem = self.len % 8;
78 if rem != 0 {
79 let mask = (1u8 << rem) - 1;
80 let a = self.buffer.as_slice()[full_bytes] & mask;
81 let b = other.buffer.as_slice()[full_bytes] & mask;
82 return a == b;
83 }
84 return true;
85 }
86
87 self.chunks()
88 .iter_padded()
89 .zip(other.chunks().iter_padded())
90 .all(|(a, b)| a == b)
91 }
92}
93
94impl BitBuffer {
95 pub fn new(buffer: ByteBuffer, len: usize) -> Self {
99 assert!(
100 buffer.len() * 8 >= len,
101 "provided ByteBuffer not large enough to back BoolBuffer with len {len}"
102 );
103
104 let buffer = buffer.aligned(Alignment::none());
106
107 Self {
108 buffer,
109 len,
110 offset: 0,
111 }
112 }
113
114 pub fn new_with_offset(buffer: ByteBuffer, len: usize, offset: usize) -> Self {
119 assert!(
120 len.saturating_add(offset) <= buffer.len().saturating_mul(8),
121 "provided ByteBuffer (len={}) not large enough to back BoolBuffer with offset {offset} len {len}",
122 buffer.len()
123 );
124
125 let buffer = buffer.aligned(Alignment::none());
127
128 let byte_offset = offset / 8;
130 let offset = offset % 8;
131 let buffer = if byte_offset != 0 {
132 buffer.slice(byte_offset..)
133 } else {
134 buffer
135 };
136
137 Self {
138 buffer,
139 offset,
140 len,
141 }
142 }
143
144 pub fn new_set(len: usize) -> Self {
146 let words = len.div_ceil(8);
147 let buffer = buffer![0xFF; words];
148
149 Self {
150 buffer,
151 len,
152 offset: 0,
153 }
154 }
155
156 pub fn new_unset(len: usize) -> Self {
158 let words = len.div_ceil(8);
159 let buffer = Buffer::zeroed(words);
160
161 Self {
162 buffer,
163 len,
164 offset: 0,
165 }
166 }
167
168 pub fn from_indices(len: usize, indices: impl IntoIterator<Item = usize>) -> BitBuffer {
170 BitBufferMut::from_indices(len, indices).freeze()
171 }
172
173 pub fn empty() -> Self {
175 Self::new_set(0)
176 }
177
178 pub fn full(value: bool, len: usize) -> Self {
180 if value {
181 Self::new_set(len)
182 } else {
183 Self::new_unset(len)
184 }
185 }
186
187 #[inline]
205 pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
206 BitBufferMut::collect_bool(len, f).freeze()
207 }
208
209 #[inline]
221 pub fn collect_bool_multiversioned<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
222 BitBufferMut::collect_bool_multiversioned(len, f).freeze()
223 }
224
225 pub fn map_cmp<F>(&self, mut f: F) -> Self
230 where
231 F: FnMut(usize, bool) -> bool,
232 {
233 let len = self.len;
234 let mut buffer: BufferMut<u64> = BufferMut::with_capacity(len.div_ceil(64));
235
236 let chunks_count = len / 64;
237 let remainder = len % 64;
238 let chunks = self.chunks();
239
240 for (chunk_idx, src_chunk) in chunks.iter().enumerate() {
241 let packed = collect_bool_word(64, |bit_idx| {
242 let i = bit_idx + chunk_idx * 64;
243 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
244 f(i, bit_value)
245 });
246
247 unsafe { buffer.push_unchecked(packed) }
249 }
250
251 if remainder != 0 {
252 let src_chunk = chunks.remainder_bits();
253 let packed = collect_bool_word(remainder, |bit_idx| {
254 let i = bit_idx + chunks_count * 64;
255 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
256 f(i, bit_value)
257 });
258
259 unsafe { buffer.push_unchecked(packed) }
261 }
262
263 let mut bytes = buffer.into_byte_buffer();
264 bytes.truncate(len.div_ceil(8));
265
266 Self {
267 buffer: bytes.freeze(),
268 offset: 0,
269 len,
270 }
271 }
272
273 pub fn clear(&mut self) {
275 self.buffer.clear();
276 self.len = 0;
277 self.offset = 0;
278 }
279
280 #[inline]
285 pub fn len(&self) -> usize {
286 self.len
287 }
288
289 #[inline]
291 pub fn is_empty(&self) -> bool {
292 self.len() == 0
293 }
294
295 #[inline(always)]
297 pub fn offset(&self) -> usize {
298 self.offset
299 }
300
301 #[inline(always)]
303 pub fn inner(&self) -> &ByteBuffer {
304 &self.buffer
305 }
306
307 #[inline]
313 pub fn byte_aligned_bytes(&self) -> Option<&[u8]> {
314 if !self.offset.is_multiple_of(8) {
315 return None;
316 }
317
318 let n_bytes = self.len.div_ceil(8);
319 let start = self.offset / 8;
320 let end = start + n_bytes;
321 Some(&self.buffer.as_slice()[start..end])
322 }
323
324 #[inline]
330 pub fn value(&self, index: usize) -> bool {
331 assert!(index < self.len);
332 unsafe { self.value_unchecked(index) }
333 }
334
335 #[inline]
340 pub unsafe fn value_unchecked(&self, index: usize) -> bool {
341 unsafe { get_bit_unchecked(self.buffer.as_ptr(), index + self.offset) }
342 }
343
344 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
349 let start = match range.start_bound() {
350 Bound::Included(&s) => s,
351 Bound::Excluded(&s) => s + 1,
352 Bound::Unbounded => 0,
353 };
354 let end = match range.end_bound() {
355 Bound::Included(&e) => e + 1,
356 Bound::Excluded(&e) => e,
357 Bound::Unbounded => self.len,
358 };
359
360 assert!(start <= end);
361 assert!(start <= self.len);
362 assert!(end <= self.len);
363 let len = end - start;
364
365 let offset = self.offset + start;
366 let byte_offset = offset / 8;
367 let bit_offset = offset % 8;
368
369 let buffer = if byte_offset != 0 {
372 self.buffer.slice_unaligned(byte_offset..)
373 } else {
374 self.buffer.clone().aligned(Alignment::none())
375 };
376
377 Self {
378 buffer,
379 offset: bit_offset,
380 len,
381 }
382 }
383
384 pub fn shrink_offset(self) -> Self {
386 let word_start = self.offset / 8;
387 let word_end = (self.offset + self.len).div_ceil(8);
388
389 let buffer = self.buffer.slice(word_start..word_end);
390
391 let bit_offset = self.offset % 8;
392 let len = self.len;
393 BitBuffer::new_with_offset(buffer, len, bit_offset)
394 }
395
396 pub fn unaligned_chunks(&self) -> UnalignedBitChunk<'_> {
398 UnalignedBitChunk::new(self.buffer.as_slice(), self.offset, self.len)
399 }
400
401 pub fn chunks(&self) -> BitChunks<'_> {
405 BitChunks::new(self.buffer.as_slice(), self.offset, self.len)
406 }
407
408 #[inline]
410 pub fn true_count(&self) -> usize {
411 count_ones(self.buffer.as_slice(), self.offset, self.len)
412 }
413
414 #[inline]
422 pub fn count_range(&self, start: usize, end: usize) -> usize {
423 assert!(start <= end, "start {start} exceeds end {end}");
424 assert!(end <= self.len, "end {end} exceeds len {}", self.len);
425 count_ones(self.buffer.as_slice(), self.offset + start, end - start)
426 }
427
428 pub fn select(&self, nth: usize) -> Option<usize> {
435 bit_select(self.buffer.as_slice(), self.offset, self.len, nth)
436 }
437
438 #[inline]
440 pub fn false_count(&self) -> usize {
441 self.len - self.true_count()
442 }
443
444 pub fn iter(&self) -> BitIterator<'_> {
446 BitIterator::new(self.buffer.as_slice(), self.offset, self.len)
447 }
448
449 pub fn set_indices(&self) -> BitIndexIterator<'_> {
451 BitIndexIterator::new(self.buffer.as_slice(), self.offset, self.len)
452 }
453
454 pub fn set_slices(&self) -> BitSliceIterator<'_> {
456 BitSliceIterator::new(self.buffer.as_slice(), self.offset, self.len)
457 }
458
459 #[inline]
468 pub fn for_each_set_index<F: FnMut(usize)>(&self, mut f: F) {
469 let mut base = 0usize;
470 for word in self.chunks().iter_padded() {
471 if word == u64::MAX {
472 for k in 0..64 {
473 f(base + k);
474 }
475 } else {
476 let mut w = word;
477 while w != 0 {
478 f(base + w.trailing_zeros() as usize);
479 w &= w - 1;
480 }
481 }
482 base += 64;
483 }
484 }
485
486 pub fn sliced(&self) -> Self {
488 if self.offset.is_multiple_of(8) {
489 return Self::new(
490 self.buffer
491 .slice(self.offset / 8..(self.offset + self.len).div_ceil(8)),
492 self.len,
493 );
494 }
495
496 bitwise_unary_op_copy(self, |a| a)
498 }
499}
500
501impl BitBuffer {
504 pub fn into_inner(self) -> (usize, usize, ByteBuffer) {
506 (self.offset, self.len, self.buffer)
507 }
508
509 pub fn try_into_mut(self) -> Result<BitBufferMut, Self> {
511 match self.buffer.try_into_mut() {
512 Ok(buffer) => Ok(BitBufferMut::from_buffer(buffer, self.offset, self.len)),
513 Err(buffer) => Err(BitBuffer::new_with_offset(buffer, self.len, self.offset)),
514 }
515 }
516}
517
518impl From<&[bool]> for BitBuffer {
519 fn from(value: &[bool]) -> Self {
520 BitBufferMut::from(value).freeze()
521 }
522}
523
524impl From<Vec<bool>> for BitBuffer {
525 fn from(value: Vec<bool>) -> Self {
526 BitBufferMut::from(value).freeze()
527 }
528}
529
530impl FromIterator<bool> for BitBuffer {
531 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
532 BitBufferMut::from_iter(iter).freeze()
533 }
534}
535
536impl BitOr for BitBuffer {
537 type Output = Self;
538
539 #[inline]
540 fn bitor(self, rhs: Self) -> Self::Output {
541 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a | b)
542 }
543}
544
545impl BitOr for &BitBuffer {
546 type Output = BitBuffer;
547
548 #[inline]
549 fn bitor(self, rhs: Self) -> Self::Output {
550 bitwise_binary_op(self, rhs, |a, b| a | b)
551 }
552}
553
554impl BitOr<&BitBuffer> for BitBuffer {
555 type Output = BitBuffer;
556
557 #[inline]
558 fn bitor(self, rhs: &BitBuffer) -> Self::Output {
559 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a | b)
560 }
561}
562
563impl BitAnd for &BitBuffer {
564 type Output = BitBuffer;
565
566 #[inline]
567 fn bitand(self, rhs: Self) -> Self::Output {
568 bitwise_binary_op(self, rhs, |a, b| a & b)
569 }
570}
571
572impl BitAnd<BitBuffer> for &BitBuffer {
573 type Output = BitBuffer;
574
575 #[inline]
576 fn bitand(self, rhs: BitBuffer) -> Self::Output {
577 self.bitand(&rhs)
578 }
579}
580
581impl BitAnd<&BitBuffer> for BitBuffer {
582 type Output = BitBuffer;
583
584 #[inline]
585 fn bitand(self, rhs: &BitBuffer) -> Self::Output {
586 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & b)
587 }
588}
589
590impl BitAnd<BitBuffer> for BitBuffer {
591 type Output = BitBuffer;
592
593 #[inline]
594 fn bitand(self, rhs: BitBuffer) -> Self::Output {
595 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a & b)
596 }
597}
598
599impl Not for &BitBuffer {
600 type Output = BitBuffer;
601
602 #[inline]
603 fn not(self) -> Self::Output {
604 bitwise_unary_op_copy(self, |a| !a)
607 }
608}
609
610impl Not for BitBuffer {
611 type Output = BitBuffer;
612
613 #[inline]
614 fn not(self) -> Self::Output {
615 bitwise_unary_op(self, |a| !a)
616 }
617}
618
619impl BitXor for &BitBuffer {
620 type Output = BitBuffer;
621
622 #[inline]
623 fn bitxor(self, rhs: Self) -> Self::Output {
624 bitwise_binary_op(self, rhs, |a, b| a ^ b)
625 }
626}
627
628impl BitXor<&BitBuffer> for BitBuffer {
629 type Output = BitBuffer;
630
631 #[inline]
632 fn bitxor(self, rhs: &BitBuffer) -> Self::Output {
633 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a ^ b)
634 }
635}
636
637impl BitBuffer {
638 pub fn bitand_not(&self, rhs: &BitBuffer) -> BitBuffer {
643 bitwise_binary_op(self, rhs, |a, b| a & !b)
644 }
645
646 pub fn into_bitand_not(self, rhs: &BitBuffer) -> BitBuffer {
648 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & !b)
649 }
650
651 #[inline]
661 pub fn iter_bits<F>(&self, mut f: F)
662 where
663 F: FnMut(usize, bool),
664 {
665 let total_bits = self.len;
666 if total_bits == 0 {
667 return;
668 }
669
670 let chunks = self.chunks();
672 let chunks_count = total_bits / 64;
673 let remainder = total_bits % 64;
674
675 for (chunk_idx, chunk) in chunks.iter().enumerate() {
676 let base = chunk_idx * 64;
677 for bit_idx in 0..64 {
678 f(base + bit_idx, (chunk >> bit_idx) & 1 == 1);
679 }
680 }
681
682 if remainder != 0 {
683 let rem_chunk = chunks.remainder_bits();
684 let base = chunks_count * 64;
685 for bit_idx in 0..remainder {
686 f(base + bit_idx, (rem_chunk >> bit_idx) & 1 == 1);
687 }
688 }
689 }
690}
691
692impl<'a> IntoIterator for &'a BitBuffer {
693 type Item = bool;
694 type IntoIter = BitIterator<'a>;
695
696 fn into_iter(self) -> Self::IntoIter {
697 self.iter()
698 }
699}
700
701#[cfg(test)]
702mod tests {
703 use rstest::rstest;
704
705 use crate::ByteBuffer;
706 use crate::bit::BitBuffer;
707 use crate::buffer;
708
709 #[test]
710 fn test_bool() {
711 let buffer: ByteBuffer = buffer![1 << 7; 1024];
713 let bools = BitBuffer::new(buffer, 1024 * 8);
714
715 assert_eq!(bools.len(), 1024 * 8);
717 assert!(!bools.is_empty());
718 assert_eq!(bools.true_count(), 1024);
719 assert_eq!(bools.false_count(), 1024 * 7);
720
721 for word in 0..1024 {
723 for bit in 0..8 {
724 if bit == 7 {
725 assert!(bools.value(word * 8 + bit));
726 } else {
727 assert!(!bools.value(word * 8 + bit));
728 }
729 }
730 }
731
732 let sliced = bools.slice(64..72);
734
735 assert_eq!(sliced.len(), 8);
737 assert!(!sliced.is_empty());
738 assert_eq!(sliced.true_count(), 1);
739 assert_eq!(sliced.false_count(), 7);
740
741 for bit in 0..8 {
743 if bit == 7 {
744 assert!(sliced.value(bit));
745 } else {
746 assert!(!sliced.value(bit));
747 }
748 }
749 }
750
751 #[test]
752 fn test_padded_equaltiy() {
753 let buf1 = BitBuffer::new_set(64); let buf2 = BitBuffer::collect_bool(64, |x| x < 32); for i in 0..32 {
757 assert_eq!(buf1.value(i), buf2.value(i), "Bit {} should be the same", i);
758 }
759
760 for i in 32..64 {
761 assert_ne!(buf1.value(i), buf2.value(i), "Bit {} should differ", i);
762 }
763
764 assert_eq!(
765 buf1.slice(0..32),
766 buf2.slice(0..32),
767 "Buffer slices with same bits should be equal (`PartialEq` needs `iter_padded()`)"
768 );
769 assert_ne!(
770 buf1.slice(32..64),
771 buf2.slice(32..64),
772 "Buffer slices with different bits should not be equal (`PartialEq` needs `iter_padded()`)"
773 );
774 }
775
776 #[test]
777 fn test_slice_offset_calculation() {
778 let buf = BitBuffer::collect_bool(16, |_| true);
779 let sliced = buf.slice(10..16);
780 assert_eq!(sliced.len(), 6);
781 assert_eq!(sliced.offset(), 2);
783 }
784
785 #[test]
786 fn test_byte_aligned_bytes() {
787 let bytes: ByteBuffer = buffer![0b1010_0101u8, 0b0000_0011];
788 let buf = BitBuffer::new(bytes.clone(), 10);
789 assert_eq!(buf.byte_aligned_bytes(), Some(bytes.as_slice()));
790
791 let byte_sliced = buf.slice(8..10);
792 assert_eq!(byte_sliced.byte_aligned_bytes(), Some(&[0b0000_0011][..]));
793
794 let bit_sliced = buf.slice(1..9);
795 assert!(bit_sliced.byte_aligned_bytes().is_none());
796 }
797
798 #[test]
799 fn test_from_indices_dense_crosses_words() {
800 let len = 130;
801 let indices = (0..len).filter(|idx| idx % 3 != 1);
802 let buf = BitBuffer::from_indices(len, indices);
803
804 assert_eq!(buf.len(), len);
805 for idx in 0..len {
806 assert_eq!(buf.value(idx), idx % 3 != 1, "mismatch at {idx}");
807 }
808 }
809
810 #[test]
811 #[should_panic(expected = "index 5 exceeds len 5")]
812 fn test_from_indices_out_of_bounds() {
813 BitBuffer::from_indices(5, [0, 5]);
814 }
815
816 #[rstest]
817 #[case(5)]
818 #[case(8)]
819 #[case(10)]
820 #[case(13)]
821 #[case(16)]
822 #[case(23)]
823 #[case(100)]
824 fn test_iter_bits(#[case] len: usize) {
825 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
826
827 let mut collected = Vec::new();
828 buf.iter_bits(|idx, is_set| {
829 collected.push((idx, is_set));
830 });
831
832 assert_eq!(collected.len(), len);
833
834 for (idx, is_set) in collected {
835 assert_eq!(is_set, idx % 2 == 0);
836 }
837 }
838
839 #[rstest]
840 #[case(3, 5)]
841 #[case(3, 8)]
842 #[case(5, 10)]
843 #[case(2, 16)]
844 #[case(8, 16)]
845 #[case(9, 16)]
846 #[case(17, 16)]
847 fn test_iter_bits_with_offset(#[case] offset: usize, #[case] len: usize) {
848 let total_bits = offset + len;
849 let buf = BitBuffer::collect_bool(total_bits, |i| i % 2 == 0);
850 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
851
852 let mut collected = Vec::new();
853 buf_with_offset.iter_bits(|idx, is_set| {
854 collected.push((idx, is_set));
855 });
856
857 assert_eq!(collected.len(), len);
858
859 for (idx, is_set) in collected {
860 assert_eq!(is_set, (offset + idx).is_multiple_of(2));
862 }
863 }
864
865 #[rstest]
866 #[case(8, 10)]
867 #[case(9, 7)]
868 #[case(16, 8)]
869 #[case(17, 10)]
870 fn test_iter_bits_catches_wrong_byte_offset(#[case] offset: usize, #[case] len: usize) {
871 let total_bits = offset + len;
872 let buf = BitBuffer::collect_bool(total_bits, |i| (i / 8) % 2 == 0);
874
875 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
876
877 let mut collected = Vec::new();
878 buf_with_offset.iter_bits(|idx, is_set| {
879 collected.push((idx, is_set));
880 });
881
882 assert_eq!(collected.len(), len);
883
884 for (idx, is_set) in collected {
885 let bit_position = offset + idx;
886 let byte_index = bit_position / 8;
887 let expected_is_set = byte_index.is_multiple_of(2);
888
889 assert_eq!(
890 is_set, expected_is_set,
891 "Bit mismatch at index {}: expected {} got {}",
892 bit_position, expected_is_set, is_set
893 );
894 }
895 }
896
897 #[rstest]
898 #[case(5)]
899 #[case(8)]
900 #[case(10)]
901 #[case(64)]
902 #[case(65)]
903 #[case(100)]
904 #[case(128)]
905 fn test_map_cmp_identity(#[case] len: usize) {
906 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
908 let mapped = buf.map_cmp(|_idx, bit| bit);
909
910 assert_eq!(buf.len(), mapped.len());
911 for i in 0..len {
912 assert_eq!(buf.value(i), mapped.value(i), "Mismatch at index {}", i);
913 }
914 }
915
916 #[rstest]
917 #[case(5)]
918 #[case(8)]
919 #[case(64)]
920 #[case(65)]
921 #[case(100)]
922 fn test_map_cmp_negate(#[case] len: usize) {
923 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
925 let mapped = buf.map_cmp(|_idx, bit| !bit);
926
927 assert_eq!(buf.len(), mapped.len());
928 for i in 0..len {
929 assert_eq!(!buf.value(i), mapped.value(i), "Mismatch at index {}", i);
930 }
931 }
932
933 #[rstest]
934 #[case(0, 0)]
935 #[case(0, 64)]
936 #[case(5, 70)]
937 #[case(64, 130)]
938 #[case(0, 200)]
939 fn test_count_range(#[case] start: usize, #[case] end: usize) {
940 let len = 200;
941 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
942 let expected = (start..end).filter(|i| i % 3 == 0).count();
943 assert_eq!(buf.count_range(start, end), expected);
944 assert_eq!(
946 buf.count_range(start, end),
947 buf.slice(start..end).true_count()
948 );
949 }
950
951 #[rstest]
952 #[case(3)]
953 #[case(7)]
954 fn test_count_range_with_offset(#[case] offset: usize) {
955 let len = 150;
956 let buf = BitBuffer::collect_bool(offset + len, |i| i % 2 == 0);
957 let view = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
958 for (start, end) in [(0, len), (10, 100), (1, 2), (63, 129)] {
959 let expected = (offset + start..offset + end)
960 .filter(|i| i % 2 == 0)
961 .count();
962 assert_eq!(view.count_range(start, end), expected, "[{start}, {end})");
963 }
964 }
965
966 #[rstest]
967 #[case(0)]
968 #[case(1)]
969 #[case(63)]
970 #[case(64)]
971 #[case(65)]
972 #[case(200)]
973 #[case(1000)]
974 fn test_for_each_set_index_matches_set_indices(#[case] len: usize) {
975 let buf = BitBuffer::collect_bool(len, |i| i % 5 == 0 || i % 7 == 0);
976 let expected: Vec<usize> = buf.set_indices().collect();
977 let mut got = Vec::new();
978 buf.for_each_set_index(|i| got.push(i));
979 assert_eq!(got, expected);
980 }
981
982 #[rstest]
983 #[case(3, 200)]
984 #[case(7, 130)]
985 fn test_for_each_set_index_with_offset(#[case] offset: usize, #[case] len: usize) {
986 let base = BitBuffer::collect_bool(offset + len, |i| i % 3 == 0);
987 let view = BitBuffer::new_with_offset(base.inner().clone(), len, offset);
988 let expected: Vec<usize> = view.set_indices().collect();
989 let mut got = Vec::new();
990 view.for_each_set_index(|i| got.push(i));
991 assert_eq!(got, expected);
992 }
993
994 #[test]
995 fn test_for_each_set_index_all_set() {
996 let buf = BitBuffer::new_set(130);
997 let mut got = Vec::new();
998 buf.for_each_set_index(|i| got.push(i));
999 assert_eq!(got, (0..130).collect::<Vec<_>>());
1000 }
1001
1002 #[test]
1003 fn test_map_cmp_conditional() {
1004 let len = 100;
1006 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
1007
1008 let mapped = buf.map_cmp(|idx, bit| bit && idx % 4 == 0);
1010
1011 for i in 0..len {
1012 let expected = (i % 2 == 0) && (i % 4 == 0);
1013 assert_eq!(mapped.value(i), expected, "Mismatch at index {}", i);
1014 }
1015 }
1016}