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]
189 pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
190 BitBufferMut::collect_bool(len, f).freeze()
191 }
192
193 pub fn map_cmp<F>(&self, mut f: F) -> Self
198 where
199 F: FnMut(usize, bool) -> bool,
200 {
201 let len = self.len;
202 let mut buffer: BufferMut<u64> = BufferMut::with_capacity(len.div_ceil(64));
203
204 let chunks_count = len / 64;
205 let remainder = len % 64;
206 let chunks = self.chunks();
207
208 for (chunk_idx, src_chunk) in chunks.iter().enumerate() {
209 let packed = collect_bool_word(64, |bit_idx| {
210 let i = bit_idx + chunk_idx * 64;
211 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
212 f(i, bit_value)
213 });
214
215 unsafe { buffer.push_unchecked(packed) }
217 }
218
219 if remainder != 0 {
220 let src_chunk = chunks.remainder_bits();
221 let packed = collect_bool_word(remainder, |bit_idx| {
222 let i = bit_idx + chunks_count * 64;
223 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
224 f(i, bit_value)
225 });
226
227 unsafe { buffer.push_unchecked(packed) }
229 }
230
231 let mut bytes = buffer.into_byte_buffer();
232 bytes.truncate(len.div_ceil(8));
233
234 Self {
235 buffer: bytes.freeze(),
236 offset: 0,
237 len,
238 }
239 }
240
241 pub fn clear(&mut self) {
243 self.buffer.clear();
244 self.len = 0;
245 self.offset = 0;
246 }
247
248 #[inline]
253 pub fn len(&self) -> usize {
254 self.len
255 }
256
257 #[inline]
259 pub fn is_empty(&self) -> bool {
260 self.len() == 0
261 }
262
263 #[inline(always)]
265 pub fn offset(&self) -> usize {
266 self.offset
267 }
268
269 #[inline(always)]
271 pub fn inner(&self) -> &ByteBuffer {
272 &self.buffer
273 }
274
275 #[inline]
281 pub fn byte_aligned_bytes(&self) -> Option<&[u8]> {
282 if !self.offset.is_multiple_of(8) {
283 return None;
284 }
285
286 let n_bytes = self.len.div_ceil(8);
287 let start = self.offset / 8;
288 let end = start + n_bytes;
289 Some(&self.buffer.as_slice()[start..end])
290 }
291
292 #[inline]
298 pub fn value(&self, index: usize) -> bool {
299 assert!(index < self.len);
300 unsafe { self.value_unchecked(index) }
301 }
302
303 #[inline]
308 pub unsafe fn value_unchecked(&self, index: usize) -> bool {
309 unsafe { get_bit_unchecked(self.buffer.as_ptr(), index + self.offset) }
310 }
311
312 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
317 let start = match range.start_bound() {
318 Bound::Included(&s) => s,
319 Bound::Excluded(&s) => s + 1,
320 Bound::Unbounded => 0,
321 };
322 let end = match range.end_bound() {
323 Bound::Included(&e) => e + 1,
324 Bound::Excluded(&e) => e,
325 Bound::Unbounded => self.len,
326 };
327
328 assert!(start <= end);
329 assert!(start <= self.len);
330 assert!(end <= self.len);
331 let len = end - start;
332
333 let offset = self.offset + start;
334 let byte_offset = offset / 8;
335 let bit_offset = offset % 8;
336
337 let buffer = if byte_offset != 0 {
340 self.buffer.slice_unaligned(byte_offset..)
341 } else {
342 self.buffer.clone().aligned(Alignment::none())
343 };
344
345 Self {
346 buffer,
347 offset: bit_offset,
348 len,
349 }
350 }
351
352 pub fn shrink_offset(self) -> Self {
354 let word_start = self.offset / 8;
355 let word_end = (self.offset + self.len).div_ceil(8);
356
357 let buffer = self.buffer.slice(word_start..word_end);
358
359 let bit_offset = self.offset % 8;
360 let len = self.len;
361 BitBuffer::new_with_offset(buffer, len, bit_offset)
362 }
363
364 pub fn unaligned_chunks(&self) -> UnalignedBitChunk<'_> {
366 UnalignedBitChunk::new(self.buffer.as_slice(), self.offset, self.len)
367 }
368
369 pub fn chunks(&self) -> BitChunks<'_> {
373 BitChunks::new(self.buffer.as_slice(), self.offset, self.len)
374 }
375
376 #[inline]
378 pub fn true_count(&self) -> usize {
379 count_ones(self.buffer.as_slice(), self.offset, self.len)
380 }
381
382 #[inline]
390 pub fn count_range(&self, start: usize, end: usize) -> usize {
391 assert!(start <= end, "start {start} exceeds end {end}");
392 assert!(end <= self.len, "end {end} exceeds len {}", self.len);
393 count_ones(self.buffer.as_slice(), self.offset + start, end - start)
394 }
395
396 pub fn select(&self, nth: usize) -> Option<usize> {
403 bit_select(self.buffer.as_slice(), self.offset, self.len, nth)
404 }
405
406 #[inline]
408 pub fn false_count(&self) -> usize {
409 self.len - self.true_count()
410 }
411
412 pub fn iter(&self) -> BitIterator<'_> {
414 BitIterator::new(self.buffer.as_slice(), self.offset, self.len)
415 }
416
417 pub fn set_indices(&self) -> BitIndexIterator<'_> {
419 BitIndexIterator::new(self.buffer.as_slice(), self.offset, self.len)
420 }
421
422 pub fn set_slices(&self) -> BitSliceIterator<'_> {
424 BitSliceIterator::new(self.buffer.as_slice(), self.offset, self.len)
425 }
426
427 #[inline]
436 pub fn for_each_set_index<F: FnMut(usize)>(&self, mut f: F) {
437 let mut base = 0usize;
438 for word in self.chunks().iter_padded() {
439 if word == u64::MAX {
440 for k in 0..64 {
441 f(base + k);
442 }
443 } else {
444 let mut w = word;
445 while w != 0 {
446 f(base + w.trailing_zeros() as usize);
447 w &= w - 1;
448 }
449 }
450 base += 64;
451 }
452 }
453
454 pub fn sliced(&self) -> Self {
456 if self.offset.is_multiple_of(8) {
457 return Self::new(
458 self.buffer
459 .slice(self.offset / 8..(self.offset + self.len).div_ceil(8)),
460 self.len,
461 );
462 }
463
464 bitwise_unary_op_copy(self, |a| a)
466 }
467}
468
469impl BitBuffer {
472 pub fn into_inner(self) -> (usize, usize, ByteBuffer) {
474 (self.offset, self.len, self.buffer)
475 }
476
477 pub fn try_into_mut(self) -> Result<BitBufferMut, Self> {
479 match self.buffer.try_into_mut() {
480 Ok(buffer) => Ok(BitBufferMut::from_buffer(buffer, self.offset, self.len)),
481 Err(buffer) => Err(BitBuffer::new_with_offset(buffer, self.len, self.offset)),
482 }
483 }
484}
485
486impl From<&[bool]> for BitBuffer {
487 fn from(value: &[bool]) -> Self {
488 BitBufferMut::from(value).freeze()
489 }
490}
491
492impl From<Vec<bool>> for BitBuffer {
493 fn from(value: Vec<bool>) -> Self {
494 BitBufferMut::from(value).freeze()
495 }
496}
497
498impl FromIterator<bool> for BitBuffer {
499 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
500 BitBufferMut::from_iter(iter).freeze()
501 }
502}
503
504impl BitOr for BitBuffer {
505 type Output = Self;
506
507 #[inline]
508 fn bitor(self, rhs: Self) -> Self::Output {
509 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a | b)
510 }
511}
512
513impl BitOr for &BitBuffer {
514 type Output = BitBuffer;
515
516 #[inline]
517 fn bitor(self, rhs: Self) -> Self::Output {
518 bitwise_binary_op(self, rhs, |a, b| a | b)
519 }
520}
521
522impl BitOr<&BitBuffer> for BitBuffer {
523 type Output = BitBuffer;
524
525 #[inline]
526 fn bitor(self, rhs: &BitBuffer) -> Self::Output {
527 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a | b)
528 }
529}
530
531impl BitAnd for &BitBuffer {
532 type Output = BitBuffer;
533
534 #[inline]
535 fn bitand(self, rhs: Self) -> Self::Output {
536 bitwise_binary_op(self, rhs, |a, b| a & b)
537 }
538}
539
540impl BitAnd<BitBuffer> for &BitBuffer {
541 type Output = BitBuffer;
542
543 #[inline]
544 fn bitand(self, rhs: BitBuffer) -> Self::Output {
545 self.bitand(&rhs)
546 }
547}
548
549impl BitAnd<&BitBuffer> for BitBuffer {
550 type Output = BitBuffer;
551
552 #[inline]
553 fn bitand(self, rhs: &BitBuffer) -> Self::Output {
554 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & b)
555 }
556}
557
558impl BitAnd<BitBuffer> for BitBuffer {
559 type Output = BitBuffer;
560
561 #[inline]
562 fn bitand(self, rhs: BitBuffer) -> Self::Output {
563 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a & b)
564 }
565}
566
567impl Not for &BitBuffer {
568 type Output = BitBuffer;
569
570 #[inline]
571 fn not(self) -> Self::Output {
572 bitwise_unary_op_copy(self, |a| !a)
575 }
576}
577
578impl Not for BitBuffer {
579 type Output = BitBuffer;
580
581 #[inline]
582 fn not(self) -> Self::Output {
583 bitwise_unary_op(self, |a| !a)
584 }
585}
586
587impl BitXor for &BitBuffer {
588 type Output = BitBuffer;
589
590 #[inline]
591 fn bitxor(self, rhs: Self) -> Self::Output {
592 bitwise_binary_op(self, rhs, |a, b| a ^ b)
593 }
594}
595
596impl BitXor<&BitBuffer> for BitBuffer {
597 type Output = BitBuffer;
598
599 #[inline]
600 fn bitxor(self, rhs: &BitBuffer) -> Self::Output {
601 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a ^ b)
602 }
603}
604
605impl BitBuffer {
606 pub fn bitand_not(&self, rhs: &BitBuffer) -> BitBuffer {
611 bitwise_binary_op(self, rhs, |a, b| a & !b)
612 }
613
614 pub fn into_bitand_not(self, rhs: &BitBuffer) -> BitBuffer {
616 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & !b)
617 }
618
619 #[inline]
629 pub fn iter_bits<F>(&self, mut f: F)
630 where
631 F: FnMut(usize, bool),
632 {
633 let total_bits = self.len;
634 if total_bits == 0 {
635 return;
636 }
637
638 let chunks = self.chunks();
640 let chunks_count = total_bits / 64;
641 let remainder = total_bits % 64;
642
643 for (chunk_idx, chunk) in chunks.iter().enumerate() {
644 let base = chunk_idx * 64;
645 for bit_idx in 0..64 {
646 f(base + bit_idx, (chunk >> bit_idx) & 1 == 1);
647 }
648 }
649
650 if remainder != 0 {
651 let rem_chunk = chunks.remainder_bits();
652 let base = chunks_count * 64;
653 for bit_idx in 0..remainder {
654 f(base + bit_idx, (rem_chunk >> bit_idx) & 1 == 1);
655 }
656 }
657 }
658}
659
660impl<'a> IntoIterator for &'a BitBuffer {
661 type Item = bool;
662 type IntoIter = BitIterator<'a>;
663
664 fn into_iter(self) -> Self::IntoIter {
665 self.iter()
666 }
667}
668
669#[cfg(test)]
670mod tests {
671 use rstest::rstest;
672
673 use crate::ByteBuffer;
674 use crate::bit::BitBuffer;
675 use crate::buffer;
676
677 #[test]
678 fn test_bool() {
679 let buffer: ByteBuffer = buffer![1 << 7; 1024];
681 let bools = BitBuffer::new(buffer, 1024 * 8);
682
683 assert_eq!(bools.len(), 1024 * 8);
685 assert!(!bools.is_empty());
686 assert_eq!(bools.true_count(), 1024);
687 assert_eq!(bools.false_count(), 1024 * 7);
688
689 for word in 0..1024 {
691 for bit in 0..8 {
692 if bit == 7 {
693 assert!(bools.value(word * 8 + bit));
694 } else {
695 assert!(!bools.value(word * 8 + bit));
696 }
697 }
698 }
699
700 let sliced = bools.slice(64..72);
702
703 assert_eq!(sliced.len(), 8);
705 assert!(!sliced.is_empty());
706 assert_eq!(sliced.true_count(), 1);
707 assert_eq!(sliced.false_count(), 7);
708
709 for bit in 0..8 {
711 if bit == 7 {
712 assert!(sliced.value(bit));
713 } else {
714 assert!(!sliced.value(bit));
715 }
716 }
717 }
718
719 #[test]
720 fn test_padded_equaltiy() {
721 let buf1 = BitBuffer::new_set(64); let buf2 = BitBuffer::collect_bool(64, |x| x < 32); for i in 0..32 {
725 assert_eq!(buf1.value(i), buf2.value(i), "Bit {} should be the same", i);
726 }
727
728 for i in 32..64 {
729 assert_ne!(buf1.value(i), buf2.value(i), "Bit {} should differ", i);
730 }
731
732 assert_eq!(
733 buf1.slice(0..32),
734 buf2.slice(0..32),
735 "Buffer slices with same bits should be equal (`PartialEq` needs `iter_padded()`)"
736 );
737 assert_ne!(
738 buf1.slice(32..64),
739 buf2.slice(32..64),
740 "Buffer slices with different bits should not be equal (`PartialEq` needs `iter_padded()`)"
741 );
742 }
743
744 #[test]
745 fn test_slice_offset_calculation() {
746 let buf = BitBuffer::collect_bool(16, |_| true);
747 let sliced = buf.slice(10..16);
748 assert_eq!(sliced.len(), 6);
749 assert_eq!(sliced.offset(), 2);
751 }
752
753 #[test]
754 fn test_byte_aligned_bytes() {
755 let bytes: ByteBuffer = buffer![0b1010_0101u8, 0b0000_0011];
756 let buf = BitBuffer::new(bytes.clone(), 10);
757 assert_eq!(buf.byte_aligned_bytes(), Some(bytes.as_slice()));
758
759 let byte_sliced = buf.slice(8..10);
760 assert_eq!(byte_sliced.byte_aligned_bytes(), Some(&[0b0000_0011][..]));
761
762 let bit_sliced = buf.slice(1..9);
763 assert!(bit_sliced.byte_aligned_bytes().is_none());
764 }
765
766 #[test]
767 fn test_from_indices_dense_crosses_words() {
768 let len = 130;
769 let indices = (0..len).filter(|idx| idx % 3 != 1);
770 let buf = BitBuffer::from_indices(len, indices);
771
772 assert_eq!(buf.len(), len);
773 for idx in 0..len {
774 assert_eq!(buf.value(idx), idx % 3 != 1, "mismatch at {idx}");
775 }
776 }
777
778 #[test]
779 #[should_panic(expected = "index 5 exceeds len 5")]
780 fn test_from_indices_out_of_bounds() {
781 BitBuffer::from_indices(5, [0, 5]);
782 }
783
784 #[rstest]
785 #[case(5)]
786 #[case(8)]
787 #[case(10)]
788 #[case(13)]
789 #[case(16)]
790 #[case(23)]
791 #[case(100)]
792 fn test_iter_bits(#[case] len: usize) {
793 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
794
795 let mut collected = Vec::new();
796 buf.iter_bits(|idx, is_set| {
797 collected.push((idx, is_set));
798 });
799
800 assert_eq!(collected.len(), len);
801
802 for (idx, is_set) in collected {
803 assert_eq!(is_set, idx % 2 == 0);
804 }
805 }
806
807 #[rstest]
808 #[case(3, 5)]
809 #[case(3, 8)]
810 #[case(5, 10)]
811 #[case(2, 16)]
812 #[case(8, 16)]
813 #[case(9, 16)]
814 #[case(17, 16)]
815 fn test_iter_bits_with_offset(#[case] offset: usize, #[case] len: usize) {
816 let total_bits = offset + len;
817 let buf = BitBuffer::collect_bool(total_bits, |i| i % 2 == 0);
818 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
819
820 let mut collected = Vec::new();
821 buf_with_offset.iter_bits(|idx, is_set| {
822 collected.push((idx, is_set));
823 });
824
825 assert_eq!(collected.len(), len);
826
827 for (idx, is_set) in collected {
828 assert_eq!(is_set, (offset + idx).is_multiple_of(2));
830 }
831 }
832
833 #[rstest]
834 #[case(8, 10)]
835 #[case(9, 7)]
836 #[case(16, 8)]
837 #[case(17, 10)]
838 fn test_iter_bits_catches_wrong_byte_offset(#[case] offset: usize, #[case] len: usize) {
839 let total_bits = offset + len;
840 let buf = BitBuffer::collect_bool(total_bits, |i| (i / 8) % 2 == 0);
842
843 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
844
845 let mut collected = Vec::new();
846 buf_with_offset.iter_bits(|idx, is_set| {
847 collected.push((idx, is_set));
848 });
849
850 assert_eq!(collected.len(), len);
851
852 for (idx, is_set) in collected {
853 let bit_position = offset + idx;
854 let byte_index = bit_position / 8;
855 let expected_is_set = byte_index.is_multiple_of(2);
856
857 assert_eq!(
858 is_set, expected_is_set,
859 "Bit mismatch at index {}: expected {} got {}",
860 bit_position, expected_is_set, is_set
861 );
862 }
863 }
864
865 #[rstest]
866 #[case(5)]
867 #[case(8)]
868 #[case(10)]
869 #[case(64)]
870 #[case(65)]
871 #[case(100)]
872 #[case(128)]
873 fn test_map_cmp_identity(#[case] len: usize) {
874 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
876 let mapped = buf.map_cmp(|_idx, bit| bit);
877
878 assert_eq!(buf.len(), mapped.len());
879 for i in 0..len {
880 assert_eq!(buf.value(i), mapped.value(i), "Mismatch at index {}", i);
881 }
882 }
883
884 #[rstest]
885 #[case(5)]
886 #[case(8)]
887 #[case(64)]
888 #[case(65)]
889 #[case(100)]
890 fn test_map_cmp_negate(#[case] len: usize) {
891 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
893 let mapped = buf.map_cmp(|_idx, bit| !bit);
894
895 assert_eq!(buf.len(), mapped.len());
896 for i in 0..len {
897 assert_eq!(!buf.value(i), mapped.value(i), "Mismatch at index {}", i);
898 }
899 }
900
901 #[rstest]
902 #[case(0, 0)]
903 #[case(0, 64)]
904 #[case(5, 70)]
905 #[case(64, 130)]
906 #[case(0, 200)]
907 fn test_count_range(#[case] start: usize, #[case] end: usize) {
908 let len = 200;
909 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
910 let expected = (start..end).filter(|i| i % 3 == 0).count();
911 assert_eq!(buf.count_range(start, end), expected);
912 assert_eq!(
914 buf.count_range(start, end),
915 buf.slice(start..end).true_count()
916 );
917 }
918
919 #[rstest]
920 #[case(3)]
921 #[case(7)]
922 fn test_count_range_with_offset(#[case] offset: usize) {
923 let len = 150;
924 let buf = BitBuffer::collect_bool(offset + len, |i| i % 2 == 0);
925 let view = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
926 for (start, end) in [(0, len), (10, 100), (1, 2), (63, 129)] {
927 let expected = (offset + start..offset + end)
928 .filter(|i| i % 2 == 0)
929 .count();
930 assert_eq!(view.count_range(start, end), expected, "[{start}, {end})");
931 }
932 }
933
934 #[rstest]
935 #[case(0)]
936 #[case(1)]
937 #[case(63)]
938 #[case(64)]
939 #[case(65)]
940 #[case(200)]
941 #[case(1000)]
942 fn test_for_each_set_index_matches_set_indices(#[case] len: usize) {
943 let buf = BitBuffer::collect_bool(len, |i| i % 5 == 0 || i % 7 == 0);
944 let expected: Vec<usize> = buf.set_indices().collect();
945 let mut got = Vec::new();
946 buf.for_each_set_index(|i| got.push(i));
947 assert_eq!(got, expected);
948 }
949
950 #[rstest]
951 #[case(3, 200)]
952 #[case(7, 130)]
953 fn test_for_each_set_index_with_offset(#[case] offset: usize, #[case] len: usize) {
954 let base = BitBuffer::collect_bool(offset + len, |i| i % 3 == 0);
955 let view = BitBuffer::new_with_offset(base.inner().clone(), len, offset);
956 let expected: Vec<usize> = view.set_indices().collect();
957 let mut got = Vec::new();
958 view.for_each_set_index(|i| got.push(i));
959 assert_eq!(got, expected);
960 }
961
962 #[test]
963 fn test_for_each_set_index_all_set() {
964 let buf = BitBuffer::new_set(130);
965 let mut got = Vec::new();
966 buf.for_each_set_index(|i| got.push(i));
967 assert_eq!(got, (0..130).collect::<Vec<_>>());
968 }
969
970 #[test]
971 fn test_map_cmp_conditional() {
972 let len = 100;
974 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
975
976 let mapped = buf.map_cmp(|idx, bit| bit && idx % 4 == 0);
978
979 for i in 0..len {
980 let expected = (i % 2 == 0) && (i % 4 == 0);
981 assert_eq!(mapped.value(i), expected, "Mismatch at index {}", i);
982 }
983 }
984}