1use std::convert::Infallible;
5use std::fmt::Display;
6use std::fmt::Formatter;
7use std::fmt::Result as FmtResult;
8use std::ops::BitAnd;
9use std::ops::BitOr;
10use std::ops::BitXor;
11use std::ops::Not;
12use std::ops::RangeBounds;
13
14use crate::Alignment;
15use crate::BitBufferMeta;
16use crate::BitBufferMut;
17use crate::Buffer;
18use crate::BufferMut;
19use crate::ByteBuffer;
20use crate::bit::BitChunks;
21use crate::bit::BitIndexIterator;
22use crate::bit::BitIterator;
23use crate::bit::BitSliceIterator;
24use crate::bit::UnalignedBitChunk;
25use crate::bit::collect_bool_word;
26use crate::bit::count_ones::count_ones;
27use crate::bit::get_bit_unchecked;
28use crate::bit::ops::bitwise_binary_op;
29use crate::bit::ops::bitwise_binary_op_lhs_owned;
30use crate::bit::ops::bitwise_unary_op;
31use crate::bit::ops::bitwise_unary_op_copy;
32use crate::bit::select::bit_select;
33use crate::buffer;
34
35#[derive(Debug, Clone, Eq)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38pub struct BitBuffer {
39 buffer: ByteBuffer,
40 offset: usize,
44 len: usize,
45}
46
47const LIMIT_LEN: usize = 16;
48impl Display for BitBuffer {
49 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
50 let limit = f.precision().unwrap_or(LIMIT_LEN);
51 let buf: Vec<bool> = self.into_iter().take(limit).collect();
52 f.debug_struct("BitBuffer")
53 .field("len", &self.len)
54 .field("buffer", &buf)
55 .finish()
56 }
57}
58
59impl PartialEq for BitBuffer {
60 fn eq(&self, other: &Self) -> bool {
61 if self.len != other.len {
62 return false;
63 }
64
65 if self.len == 0 {
66 return true;
67 }
68
69 if self.offset == 0 && other.offset == 0 {
71 let full_bytes = self.len / 8;
72 let self_bytes = &self.buffer.as_slice()[..full_bytes];
73 let other_bytes = &other.buffer.as_slice()[..full_bytes];
74 if self_bytes != other_bytes {
75 return false;
76 }
77 let rem = self.len % 8;
79 if rem != 0 {
80 let mask = (1u8 << rem) - 1;
81 let a = self.buffer.as_slice()[full_bytes] & mask;
82 let b = other.buffer.as_slice()[full_bytes] & mask;
83 return a == b;
84 }
85 return true;
86 }
87
88 self.chunks()
89 .iter_padded()
90 .zip(other.chunks().iter_padded())
91 .all(|(a, b)| a == b)
92 }
93}
94
95impl BitBuffer {
96 #[inline]
100 pub fn new(buffer: ByteBuffer, len: usize) -> Self {
101 assert!(
102 buffer.len() * 8 >= len,
103 "provided ByteBuffer not large enough to back BoolBuffer with len {len}"
104 );
105
106 let buffer = buffer.aligned(Alignment::none());
108
109 Self {
110 buffer,
111 len,
112 offset: 0,
113 }
114 }
115
116 #[inline]
121 pub fn new_with_offset(buffer: ByteBuffer, len: usize, offset: usize) -> Self {
122 assert!(
123 len.saturating_add(offset) <= buffer.len().saturating_mul(8),
124 "provided ByteBuffer (len={}) not large enough to back BoolBuffer with offset {offset} len {len}",
125 buffer.len()
126 );
127
128 let buffer = buffer.aligned(Alignment::none());
130
131 let byte_offset = offset / 8;
133 let offset = offset % 8;
134 let buffer = if byte_offset != 0 {
135 buffer.slice(byte_offset..)
136 } else {
137 buffer
138 };
139
140 Self {
141 buffer,
142 offset,
143 len,
144 }
145 }
146
147 #[inline]
149 pub fn new_set(len: usize) -> Self {
150 let words = len.div_ceil(8);
151 let buffer = buffer![0xFF; words];
152
153 Self {
154 buffer,
155 len,
156 offset: 0,
157 }
158 }
159
160 #[inline]
162 pub fn new_unset(len: usize) -> Self {
163 let words = len.div_ceil(8);
164 let buffer = Buffer::zeroed(words);
165
166 Self {
167 buffer,
168 len,
169 offset: 0,
170 }
171 }
172
173 pub fn from_indices(len: usize, indices: impl IntoIterator<Item = usize>) -> BitBuffer {
175 BitBufferMut::from_indices(len, indices).freeze()
176 }
177
178 #[inline]
180 pub fn empty() -> Self {
181 Self::new_set(0)
182 }
183
184 #[inline]
186 pub fn full(value: bool, len: usize) -> Self {
187 if value {
188 Self::new_set(len)
189 } else {
190 Self::new_unset(len)
191 }
192 }
193
194 #[inline]
212 pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
213 BitBufferMut::collect_bool(len, f).freeze()
214 }
215
216 #[inline]
228 pub fn collect_bool_multiversioned<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
229 BitBufferMut::collect_bool_multiversioned(len, f).freeze()
230 }
231
232 pub fn map_cmp<F>(&self, mut f: F) -> Self
237 where
238 F: FnMut(usize, bool) -> bool,
239 {
240 let len = self.len;
241 let mut buffer: BufferMut<u64> = BufferMut::with_capacity(len.div_ceil(64));
242
243 let chunks_count = len / 64;
244 let remainder = len % 64;
245 let chunks = self.chunks();
246
247 for (chunk_idx, src_chunk) in chunks.iter().enumerate() {
248 let packed = collect_bool_word(64, |bit_idx| {
249 let i = bit_idx + chunk_idx * 64;
250 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
251 f(i, bit_value)
252 });
253
254 unsafe { buffer.push_unchecked(packed) }
256 }
257
258 if remainder != 0 {
259 let src_chunk = chunks.remainder_bits();
260 let packed = collect_bool_word(remainder, |bit_idx| {
261 let i = bit_idx + chunks_count * 64;
262 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
263 f(i, bit_value)
264 });
265
266 unsafe { buffer.push_unchecked(packed) }
268 }
269
270 let mut bytes = buffer.into_byte_buffer();
271 bytes.truncate(len.div_ceil(8));
272
273 Self {
274 buffer: bytes.freeze(),
275 offset: 0,
276 len,
277 }
278 }
279
280 #[inline]
282 pub fn clear(&mut self) {
283 self.buffer.clear();
284 self.len = 0;
285 self.offset = 0;
286 }
287
288 #[inline]
293 pub fn len(&self) -> usize {
294 self.len
295 }
296
297 #[inline]
299 pub fn is_empty(&self) -> bool {
300 self.len() == 0
301 }
302
303 #[inline(always)]
305 pub fn offset(&self) -> usize {
306 self.offset
307 }
308
309 #[inline(always)]
311 pub fn inner(&self) -> &ByteBuffer {
312 &self.buffer
313 }
314
315 #[inline]
321 pub fn byte_aligned_bytes(&self) -> Option<&[u8]> {
322 if !self.offset.is_multiple_of(8) {
323 return None;
324 }
325
326 let n_bytes = self.len.div_ceil(8);
327 let start = self.offset / 8;
328 let end = start + n_bytes;
329 Some(&self.buffer.as_slice()[start..end])
330 }
331
332 #[inline]
338 pub fn value(&self, index: usize) -> bool {
339 assert!(index < self.len);
340 unsafe { self.value_unchecked(index) }
341 }
342
343 #[inline]
348 pub unsafe fn value_unchecked(&self, index: usize) -> bool {
349 unsafe { get_bit_unchecked(self.buffer.as_ptr(), index + self.offset) }
350 }
351
352 #[inline]
357 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
358 let (byte_offset, meta) = BitBufferMeta::new(self.offset, self.len).slice(range);
359
360 let buffer = if byte_offset != 0 {
363 self.buffer.slice_unaligned(byte_offset..)
364 } else {
365 self.buffer.clone().aligned(Alignment::none())
366 };
367
368 Self {
369 buffer,
370 offset: meta.offset(),
371 len: meta.len(),
372 }
373 }
374
375 pub fn shrink_offset(self) -> Self {
377 let word_start = self.offset / 8;
378 let word_end = (self.offset + self.len).div_ceil(8);
379
380 let buffer = self.buffer.slice(word_start..word_end);
381
382 let bit_offset = self.offset % 8;
383 let len = self.len;
384 BitBuffer::new_with_offset(buffer, len, bit_offset)
385 }
386
387 #[inline]
389 pub fn unaligned_chunks(&self) -> UnalignedBitChunk<'_> {
390 UnalignedBitChunk::new(self.buffer.as_slice(), self.offset, self.len)
391 }
392
393 #[inline]
397 pub fn chunks(&self) -> BitChunks<'_> {
398 BitChunks::new(self.buffer.as_slice(), self.offset, self.len)
399 }
400
401 #[inline]
403 pub fn true_count(&self) -> usize {
404 count_ones(self.buffer.as_slice(), self.offset, self.len)
405 }
406
407 #[inline]
415 pub fn count_range(&self, start: usize, end: usize) -> usize {
416 assert!(start <= end, "start {start} exceeds end {end}");
417 assert!(end <= self.len, "end {end} exceeds len {}", self.len);
418 count_ones(self.buffer.as_slice(), self.offset + start, end - start)
419 }
420
421 #[inline]
428 pub fn select(&self, nth: usize) -> Option<usize> {
429 bit_select(self.buffer.as_slice(), self.offset, self.len, nth)
430 }
431
432 #[inline]
434 pub fn false_count(&self) -> usize {
435 self.len - self.true_count()
436 }
437
438 #[inline]
440 pub fn iter(&self) -> BitIterator<'_> {
441 BitIterator::new(self.buffer.as_slice(), self.offset, self.len)
442 }
443
444 #[inline]
446 pub fn set_indices(&self) -> BitIndexIterator<'_> {
447 BitIndexIterator::new(self.buffer.as_slice(), self.offset, self.len)
448 }
449
450 #[inline]
452 pub fn set_slices(&self) -> BitSliceIterator<'_> {
453 BitSliceIterator::new(self.buffer.as_slice(), self.offset, self.len)
454 }
455
456 #[inline]
465 pub fn for_each_set_index<F: FnMut(usize)>(&self, mut f: F) {
466 let Ok(()) = self.try_for_each_set_index(|index| {
467 f(index);
468 Ok::<_, Infallible>(())
469 });
470 }
471
472 #[inline]
476 pub fn try_for_each_set_index<E, F>(&self, mut f: F) -> Result<(), E>
477 where
478 F: FnMut(usize) -> Result<(), E>,
479 {
480 let mut base = 0usize;
481 for word in self.chunks().iter_padded() {
482 if word == u64::MAX {
483 for k in 0..64 {
484 f(base + k)?;
485 }
486 } else {
487 let mut w = word;
488 while w != 0 {
489 f(base + w.trailing_zeros() as usize)?;
490 w &= w - 1;
491 }
492 }
493 base += 64;
494 }
495
496 Ok(())
497 }
498
499 pub fn sliced(&self) -> Self {
501 if self.offset.is_multiple_of(8) {
502 return Self::new(
503 self.buffer
504 .slice(self.offset / 8..(self.offset + self.len).div_ceil(8)),
505 self.len,
506 );
507 }
508
509 bitwise_unary_op_copy(self, |a| a)
511 }
512}
513
514impl BitBuffer {
517 #[inline]
519 pub fn into_inner(self) -> (usize, usize, ByteBuffer) {
520 (self.offset, self.len, self.buffer)
521 }
522
523 #[inline]
525 pub fn try_into_mut(self) -> Result<BitBufferMut, Self> {
526 match self.buffer.try_into_mut() {
527 Ok(buffer) => Ok(BitBufferMut::from_buffer(buffer, self.offset, self.len)),
528 Err(buffer) => Err(BitBuffer::new_with_offset(buffer, self.len, self.offset)),
529 }
530 }
531}
532
533impl From<&[bool]> for BitBuffer {
534 fn from(value: &[bool]) -> Self {
535 BitBufferMut::from(value).freeze()
536 }
537}
538
539impl From<Vec<bool>> for BitBuffer {
540 fn from(value: Vec<bool>) -> Self {
541 BitBufferMut::from(value).freeze()
542 }
543}
544
545impl FromIterator<bool> for BitBuffer {
546 #[inline]
547 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
548 BitBufferMut::from_iter(iter).freeze()
549 }
550}
551
552impl BitOr for BitBuffer {
553 type Output = Self;
554
555 #[inline]
556 fn bitor(self, rhs: Self) -> Self::Output {
557 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a | b)
558 }
559}
560
561impl BitOr for &BitBuffer {
562 type Output = BitBuffer;
563
564 #[inline]
565 fn bitor(self, rhs: Self) -> Self::Output {
566 bitwise_binary_op(self, rhs, |a, b| a | b)
567 }
568}
569
570impl BitOr<&BitBuffer> for BitBuffer {
571 type Output = BitBuffer;
572
573 #[inline]
574 fn bitor(self, rhs: &BitBuffer) -> Self::Output {
575 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a | b)
576 }
577}
578
579impl BitAnd for &BitBuffer {
580 type Output = BitBuffer;
581
582 #[inline]
583 fn bitand(self, rhs: Self) -> Self::Output {
584 bitwise_binary_op(self, rhs, |a, b| a & b)
585 }
586}
587
588impl BitAnd<BitBuffer> for &BitBuffer {
589 type Output = BitBuffer;
590
591 #[inline]
592 fn bitand(self, rhs: BitBuffer) -> Self::Output {
593 self.bitand(&rhs)
594 }
595}
596
597impl BitAnd<&BitBuffer> for BitBuffer {
598 type Output = BitBuffer;
599
600 #[inline]
601 fn bitand(self, rhs: &BitBuffer) -> Self::Output {
602 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & b)
603 }
604}
605
606impl BitAnd<BitBuffer> for BitBuffer {
607 type Output = BitBuffer;
608
609 #[inline]
610 fn bitand(self, rhs: BitBuffer) -> Self::Output {
611 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a & b)
612 }
613}
614
615impl Not for &BitBuffer {
616 type Output = BitBuffer;
617
618 #[inline]
619 fn not(self) -> Self::Output {
620 bitwise_unary_op_copy(self, |a| !a)
623 }
624}
625
626impl Not for BitBuffer {
627 type Output = BitBuffer;
628
629 #[inline]
630 fn not(self) -> Self::Output {
631 bitwise_unary_op(self, |a| !a)
632 }
633}
634
635impl BitXor for &BitBuffer {
636 type Output = BitBuffer;
637
638 #[inline]
639 fn bitxor(self, rhs: Self) -> Self::Output {
640 bitwise_binary_op(self, rhs, |a, b| a ^ b)
641 }
642}
643
644impl BitXor<&BitBuffer> for BitBuffer {
645 type Output = BitBuffer;
646
647 #[inline]
648 fn bitxor(self, rhs: &BitBuffer) -> Self::Output {
649 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a ^ b)
650 }
651}
652
653impl BitBuffer {
654 pub fn bitand_not(&self, rhs: &BitBuffer) -> BitBuffer {
659 bitwise_binary_op(self, rhs, |a, b| a & !b)
660 }
661
662 pub fn into_bitand_not(self, rhs: &BitBuffer) -> BitBuffer {
664 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & !b)
665 }
666
667 #[inline]
677 pub fn iter_bits<F>(&self, mut f: F)
678 where
679 F: FnMut(usize, bool),
680 {
681 let total_bits = self.len;
682 if total_bits == 0 {
683 return;
684 }
685
686 let chunks = self.chunks();
688 let chunks_count = total_bits / 64;
689 let remainder = total_bits % 64;
690
691 for (chunk_idx, chunk) in chunks.iter().enumerate() {
692 let base = chunk_idx * 64;
693 for bit_idx in 0..64 {
694 f(base + bit_idx, (chunk >> bit_idx) & 1 == 1);
695 }
696 }
697
698 if remainder != 0 {
699 let rem_chunk = chunks.remainder_bits();
700 let base = chunks_count * 64;
701 for bit_idx in 0..remainder {
702 f(base + bit_idx, (rem_chunk >> bit_idx) & 1 == 1);
703 }
704 }
705 }
706}
707
708impl<'a> IntoIterator for &'a BitBuffer {
709 type Item = bool;
710 type IntoIter = BitIterator<'a>;
711
712 fn into_iter(self) -> Self::IntoIter {
713 self.iter()
714 }
715}
716
717#[cfg(test)]
718mod tests {
719 use rstest::rstest;
720
721 use crate::ByteBuffer;
722 use crate::bit::BitBuffer;
723 use crate::buffer;
724
725 #[test]
726 fn test_bool() {
727 let buffer: ByteBuffer = buffer![1 << 7; 1024];
729 let bools = BitBuffer::new(buffer, 1024 * 8);
730
731 assert_eq!(bools.len(), 1024 * 8);
733 assert!(!bools.is_empty());
734 assert_eq!(bools.true_count(), 1024);
735 assert_eq!(bools.false_count(), 1024 * 7);
736
737 for word in 0..1024 {
739 for bit in 0..8 {
740 if bit == 7 {
741 assert!(bools.value(word * 8 + bit));
742 } else {
743 assert!(!bools.value(word * 8 + bit));
744 }
745 }
746 }
747
748 let sliced = bools.slice(64..72);
750
751 assert_eq!(sliced.len(), 8);
753 assert!(!sliced.is_empty());
754 assert_eq!(sliced.true_count(), 1);
755 assert_eq!(sliced.false_count(), 7);
756
757 for bit in 0..8 {
759 if bit == 7 {
760 assert!(sliced.value(bit));
761 } else {
762 assert!(!sliced.value(bit));
763 }
764 }
765 }
766
767 #[test]
768 fn test_padded_equaltiy() {
769 let buf1 = BitBuffer::new_set(64); let buf2 = BitBuffer::collect_bool(64, |x| x < 32); for i in 0..32 {
773 assert_eq!(buf1.value(i), buf2.value(i), "Bit {} should be the same", i);
774 }
775
776 for i in 32..64 {
777 assert_ne!(buf1.value(i), buf2.value(i), "Bit {} should differ", i);
778 }
779
780 assert_eq!(
781 buf1.slice(0..32),
782 buf2.slice(0..32),
783 "Buffer slices with same bits should be equal (`PartialEq` needs `iter_padded()`)"
784 );
785 assert_ne!(
786 buf1.slice(32..64),
787 buf2.slice(32..64),
788 "Buffer slices with different bits should not be equal (`PartialEq` needs `iter_padded()`)"
789 );
790 }
791
792 #[test]
793 fn test_slice_offset_calculation() {
794 let buf = BitBuffer::collect_bool(16, |_| true);
795 let sliced = buf.slice(10..16);
796 assert_eq!(sliced.len(), 6);
797 assert_eq!(sliced.offset(), 2);
799 }
800
801 #[test]
802 fn test_byte_aligned_bytes() {
803 let bytes: ByteBuffer = buffer![0b1010_0101u8, 0b0000_0011];
804 let buf = BitBuffer::new(bytes.clone(), 10);
805 assert_eq!(buf.byte_aligned_bytes(), Some(bytes.as_slice()));
806
807 let byte_sliced = buf.slice(8..10);
808 assert_eq!(byte_sliced.byte_aligned_bytes(), Some(&[0b0000_0011][..]));
809
810 let bit_sliced = buf.slice(1..9);
811 assert!(bit_sliced.byte_aligned_bytes().is_none());
812 }
813
814 #[test]
815 fn test_from_indices_dense_crosses_words() {
816 let len = 130;
817 let indices = (0..len).filter(|idx| idx % 3 != 1);
818 let buf = BitBuffer::from_indices(len, indices);
819
820 assert_eq!(buf.len(), len);
821 for idx in 0..len {
822 assert_eq!(buf.value(idx), idx % 3 != 1, "mismatch at {idx}");
823 }
824 }
825
826 #[test]
827 #[should_panic(expected = "index 5 exceeds len 5")]
828 fn test_from_indices_out_of_bounds() {
829 BitBuffer::from_indices(5, [0, 5]);
830 }
831
832 #[rstest]
833 #[case(5)]
834 #[case(8)]
835 #[case(10)]
836 #[case(13)]
837 #[case(16)]
838 #[case(23)]
839 #[case(100)]
840 fn test_iter_bits(#[case] len: usize) {
841 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
842
843 let mut collected = Vec::new();
844 buf.iter_bits(|idx, is_set| {
845 collected.push((idx, is_set));
846 });
847
848 assert_eq!(collected.len(), len);
849
850 for (idx, is_set) in collected {
851 assert_eq!(is_set, idx % 2 == 0);
852 }
853 }
854
855 #[rstest]
856 #[case(3, 5)]
857 #[case(3, 8)]
858 #[case(5, 10)]
859 #[case(2, 16)]
860 #[case(8, 16)]
861 #[case(9, 16)]
862 #[case(17, 16)]
863 fn test_iter_bits_with_offset(#[case] offset: usize, #[case] len: usize) {
864 let total_bits = offset + len;
865 let buf = BitBuffer::collect_bool(total_bits, |i| i % 2 == 0);
866 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
867
868 let mut collected = Vec::new();
869 buf_with_offset.iter_bits(|idx, is_set| {
870 collected.push((idx, is_set));
871 });
872
873 assert_eq!(collected.len(), len);
874
875 for (idx, is_set) in collected {
876 assert_eq!(is_set, (offset + idx).is_multiple_of(2));
878 }
879 }
880
881 #[rstest]
882 #[case(8, 10)]
883 #[case(9, 7)]
884 #[case(16, 8)]
885 #[case(17, 10)]
886 fn test_iter_bits_catches_wrong_byte_offset(#[case] offset: usize, #[case] len: usize) {
887 let total_bits = offset + len;
888 let buf = BitBuffer::collect_bool(total_bits, |i| (i / 8) % 2 == 0);
890
891 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
892
893 let mut collected = Vec::new();
894 buf_with_offset.iter_bits(|idx, is_set| {
895 collected.push((idx, is_set));
896 });
897
898 assert_eq!(collected.len(), len);
899
900 for (idx, is_set) in collected {
901 let bit_position = offset + idx;
902 let byte_index = bit_position / 8;
903 let expected_is_set = byte_index.is_multiple_of(2);
904
905 assert_eq!(
906 is_set, expected_is_set,
907 "Bit mismatch at index {}: expected {} got {}",
908 bit_position, expected_is_set, is_set
909 );
910 }
911 }
912
913 #[rstest]
914 #[case(5)]
915 #[case(8)]
916 #[case(10)]
917 #[case(64)]
918 #[case(65)]
919 #[case(100)]
920 #[case(128)]
921 fn test_map_cmp_identity(#[case] len: usize) {
922 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
924 let mapped = buf.map_cmp(|_idx, bit| bit);
925
926 assert_eq!(buf.len(), mapped.len());
927 for i in 0..len {
928 assert_eq!(buf.value(i), mapped.value(i), "Mismatch at index {}", i);
929 }
930 }
931
932 #[rstest]
933 #[case(5)]
934 #[case(8)]
935 #[case(64)]
936 #[case(65)]
937 #[case(100)]
938 fn test_map_cmp_negate(#[case] len: usize) {
939 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
941 let mapped = buf.map_cmp(|_idx, bit| !bit);
942
943 assert_eq!(buf.len(), mapped.len());
944 for i in 0..len {
945 assert_eq!(!buf.value(i), mapped.value(i), "Mismatch at index {}", i);
946 }
947 }
948
949 #[rstest]
950 #[case(0, 0)]
951 #[case(0, 64)]
952 #[case(5, 70)]
953 #[case(64, 130)]
954 #[case(0, 200)]
955 fn test_count_range(#[case] start: usize, #[case] end: usize) {
956 let len = 200;
957 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
958 let expected = (start..end).filter(|i| i % 3 == 0).count();
959 assert_eq!(buf.count_range(start, end), expected);
960 assert_eq!(
962 buf.count_range(start, end),
963 buf.slice(start..end).true_count()
964 );
965 }
966
967 #[rstest]
968 #[case(3)]
969 #[case(7)]
970 fn test_count_range_with_offset(#[case] offset: usize) {
971 let len = 150;
972 let buf = BitBuffer::collect_bool(offset + len, |i| i % 2 == 0);
973 let view = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
974 for (start, end) in [(0, len), (10, 100), (1, 2), (63, 129)] {
975 let expected = (offset + start..offset + end)
976 .filter(|i| i % 2 == 0)
977 .count();
978 assert_eq!(view.count_range(start, end), expected, "[{start}, {end})");
979 }
980 }
981
982 #[rstest]
983 #[case(0)]
984 #[case(1)]
985 #[case(63)]
986 #[case(64)]
987 #[case(65)]
988 #[case(200)]
989 #[case(1000)]
990 fn test_set_index_visitors_match_set_indices(#[case] len: usize) {
991 let buf = BitBuffer::collect_bool(len, |i| i % 5 == 0 || i % 7 == 0);
992 let expected: Vec<usize> = buf.set_indices().collect();
993
994 let mut got = Vec::new();
995 buf.for_each_set_index(|i| got.push(i));
996 assert_eq!(got, expected);
997
998 let mut fallible_got = Vec::new();
999 let result = buf.try_for_each_set_index(|i| {
1000 fallible_got.push(i);
1001 Ok::<(), ()>(())
1002 });
1003 assert_eq!(result, Ok(()));
1004 assert_eq!(fallible_got, expected);
1005 }
1006
1007 #[rstest]
1008 #[case(3, 200)]
1009 #[case(7, 130)]
1010 fn test_for_each_set_index_with_offset(#[case] offset: usize, #[case] len: usize) {
1011 let base = BitBuffer::collect_bool(offset + len, |i| i % 3 == 0);
1012 let view = BitBuffer::new_with_offset(base.inner().clone(), len, offset);
1013 let expected: Vec<usize> = view.set_indices().collect();
1014 let mut got = Vec::new();
1015 view.for_each_set_index(|i| got.push(i));
1016 assert_eq!(got, expected);
1017 }
1018
1019 #[test]
1020 fn test_for_each_set_index_all_set() {
1021 let buf = BitBuffer::new_set(130);
1022 let mut got = Vec::new();
1023 buf.for_each_set_index(|i| got.push(i));
1024 assert_eq!(got, (0..130).collect::<Vec<_>>());
1025 }
1026
1027 #[test]
1028 fn test_try_for_each_set_index_stops_on_error() {
1029 for (buffer, stop) in [
1030 (BitBuffer::new_set(130), 65),
1031 (BitBuffer::collect_bool(130, |i| i % 3 == 0), 66),
1032 ] {
1033 let mut visited = Vec::new();
1034 let result = buffer.try_for_each_set_index(|index| {
1035 visited.push(index);
1036 if index == stop {
1037 return Err(index);
1038 }
1039
1040 Ok(())
1041 });
1042
1043 assert_eq!(result, Err(stop));
1044 assert_eq!(
1045 visited,
1046 buffer
1047 .set_indices()
1048 .take_while(|&i| i <= stop)
1049 .collect::<Vec<_>>()
1050 );
1051 }
1052 }
1053
1054 #[test]
1055 fn test_map_cmp_conditional() {
1056 let len = 100;
1058 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
1059
1060 let mapped = buf.map_cmp(|idx, bit| bit && idx % 4 == 0);
1062
1063 for i in 0..len {
1064 let expected = (i % 2 == 0) && (i % 4 == 0);
1065 assert_eq!(mapped.value(i), expected, "Mismatch at index {}", i);
1066 }
1067 }
1068}