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::BufferAllocatorRef;
19use crate::BufferMut;
20use crate::ByteBuffer;
21use crate::bit::BitChunks;
22use crate::bit::BitIndexIterator;
23use crate::bit::BitIterator;
24use crate::bit::BitSliceIterator;
25use crate::bit::UnalignedBitChunk;
26use crate::bit::collect_bool_word;
27use crate::bit::count_ones::count_ones;
28use crate::bit::get_bit_unchecked;
29use crate::bit::ops::bitwise_binary_op;
30use crate::bit::ops::bitwise_binary_op_lhs_owned;
31use crate::bit::ops::bitwise_unary_op;
32use crate::bit::ops::bitwise_unary_op_copy;
33use crate::bit::select::bit_select;
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 Self::new_set_in(len, BufferAllocatorRef::statically_allocated())
151 }
152
153 #[inline]
155 pub fn new_set_in(len: usize, allocator: BufferAllocatorRef) -> Self {
156 let words = len.div_ceil(8);
157 let buffer = Buffer::full_in(0xFF, words, allocator);
158
159 Self {
160 buffer,
161 len,
162 offset: 0,
163 }
164 }
165
166 #[inline]
168 pub fn new_unset(len: usize) -> Self {
169 Self::new_unset_in(len, BufferAllocatorRef::statically_allocated())
170 }
171
172 #[inline]
174 pub fn new_unset_in(len: usize, allocator: BufferAllocatorRef) -> Self {
175 let words = len.div_ceil(8);
176 let buffer = Buffer::zeroed_in(words, allocator);
177
178 Self {
179 buffer,
180 len,
181 offset: 0,
182 }
183 }
184
185 pub fn from_indices(len: usize, indices: impl IntoIterator<Item = usize>) -> BitBuffer {
187 BitBufferMut::from_indices(len, indices).freeze()
188 }
189
190 #[inline]
192 pub fn empty() -> Self {
193 Self::new_set(0)
194 }
195
196 #[inline]
198 pub fn full(value: bool, len: usize) -> Self {
199 Self::full_in(value, len, BufferAllocatorRef::statically_allocated())
200 }
201
202 #[inline]
204 pub fn full_in(value: bool, len: usize, allocator: BufferAllocatorRef) -> Self {
205 if value {
206 Self::new_set_in(len, allocator)
207 } else {
208 Self::new_unset_in(len, allocator)
209 }
210 }
211
212 #[inline]
238 pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
239 BitBufferMut::collect_bool(len, f).freeze()
240 }
241
242 #[inline]
244 pub fn collect_bool_in<F: FnMut(usize) -> bool>(
245 len: usize,
246 f: F,
247 allocator: BufferAllocatorRef,
248 ) -> Self {
249 BitBufferMut::collect_bool_in(len, f, allocator).freeze()
250 }
251
252 #[inline]
263 pub fn collect_bool_multiversioned<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
264 Self::collect_bool_multiversioned_in(len, f, BufferAllocatorRef::statically_allocated())
265 }
266
267 #[inline]
269 pub fn collect_bool_multiversioned_in<F: FnMut(usize) -> bool>(
270 len: usize,
271 f: F,
272 allocator: BufferAllocatorRef,
273 ) -> Self {
274 BitBufferMut::collect_bool_multiversioned_in(len, f, allocator).freeze()
275 }
276
277 pub fn map_cmp<F>(&self, mut f: F) -> Self
282 where
283 F: FnMut(usize, bool) -> bool,
284 {
285 let len = self.len;
286 let mut buffer: BufferMut<u64> = BufferMut::with_capacity(len.div_ceil(64));
287
288 let chunks_count = len / 64;
289 let remainder = len % 64;
290 let chunks = self.chunks();
291
292 for (chunk_idx, src_chunk) in chunks.iter().enumerate() {
293 let packed = collect_bool_word(64, |bit_idx| {
294 let i = bit_idx + chunk_idx * 64;
295 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
296 f(i, bit_value)
297 });
298
299 unsafe { buffer.push_unchecked(packed) }
301 }
302
303 if remainder != 0 {
304 let src_chunk = chunks.remainder_bits();
305 let packed = collect_bool_word(remainder, |bit_idx| {
306 let i = bit_idx + chunks_count * 64;
307 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
308 f(i, bit_value)
309 });
310
311 unsafe { buffer.push_unchecked(packed) }
313 }
314
315 let mut bytes = buffer.into_byte_buffer();
316 bytes.truncate(len.div_ceil(8));
317
318 Self {
319 buffer: bytes.freeze(),
320 offset: 0,
321 len,
322 }
323 }
324
325 #[inline]
327 pub fn clear(&mut self) {
328 self.buffer.clear();
329 self.len = 0;
330 self.offset = 0;
331 }
332
333 #[inline]
338 pub fn len(&self) -> usize {
339 self.len
340 }
341
342 #[inline]
344 pub fn is_empty(&self) -> bool {
345 self.len() == 0
346 }
347
348 #[allow(clippy::inline_always)]
350 #[inline(always)]
351 pub fn offset(&self) -> usize {
352 self.offset
353 }
354
355 #[allow(clippy::inline_always)]
357 #[inline(always)]
358 pub fn inner(&self) -> &ByteBuffer {
359 &self.buffer
360 }
361
362 #[inline]
368 pub fn byte_aligned_bytes(&self) -> Option<&[u8]> {
369 if !self.offset.is_multiple_of(8) {
370 return None;
371 }
372
373 let n_bytes = self.len.div_ceil(8);
374 let start = self.offset / 8;
375 let end = start + n_bytes;
376 Some(&self.buffer.as_slice()[start..end])
377 }
378
379 #[inline]
385 pub fn value(&self, index: usize) -> bool {
386 assert!(index < self.len);
387 unsafe { self.value_unchecked(index) }
388 }
389
390 #[inline]
395 pub unsafe fn value_unchecked(&self, index: usize) -> bool {
396 unsafe { get_bit_unchecked(self.buffer.as_ptr(), index + self.offset) }
397 }
398
399 #[inline]
404 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
405 let (byte_offset, meta) = BitBufferMeta::new(self.offset, self.len).slice(range);
406
407 let buffer = if byte_offset != 0 {
410 self.buffer.slice_unaligned(byte_offset..)
411 } else {
412 self.buffer.clone().aligned(Alignment::none())
413 };
414
415 Self {
416 buffer,
417 offset: meta.offset(),
418 len: meta.len(),
419 }
420 }
421
422 pub fn shrink_offset(self) -> Self {
424 let word_start = self.offset / 8;
425 let word_end = (self.offset + self.len).div_ceil(8);
426
427 let buffer = self.buffer.slice(word_start..word_end);
428
429 let bit_offset = self.offset % 8;
430 let len = self.len;
431 BitBuffer::new_with_offset(buffer, len, bit_offset)
432 }
433
434 #[inline]
436 pub fn unaligned_chunks(&self) -> UnalignedBitChunk<'_> {
437 UnalignedBitChunk::new(self.buffer.as_slice(), self.offset, self.len)
438 }
439
440 #[inline]
444 pub fn chunks(&self) -> BitChunks<'_> {
445 BitChunks::new(self.buffer.as_slice(), self.offset, self.len)
446 }
447
448 #[inline]
450 pub fn true_count(&self) -> usize {
451 count_ones(self.buffer.as_slice(), self.offset, self.len)
452 }
453
454 #[inline]
462 pub fn count_range(&self, start: usize, end: usize) -> usize {
463 assert!(start <= end, "start {start} exceeds end {end}");
464 assert!(end <= self.len, "end {end} exceeds len {}", self.len);
465 count_ones(self.buffer.as_slice(), self.offset + start, end - start)
466 }
467
468 #[inline]
475 pub fn select(&self, nth: usize) -> Option<usize> {
476 bit_select(self.buffer.as_slice(), self.offset, self.len, nth)
477 }
478
479 #[inline]
484 pub fn last_set_index(&self) -> Option<usize> {
485 let chunks = self.unaligned_chunks();
486 let lead = chunks.lead_padding();
487 let prefix_words = usize::from(chunks.prefix().is_some());
488
489 if let Some(word) = chunks.suffix()
490 && word != 0
491 {
492 let word_index = prefix_words + chunks.chunks().len();
493 return Some(word_index * 64 + 63 - word.leading_zeros() as usize - lead);
494 }
495
496 for (index, &word) in chunks.chunks().iter().enumerate().rev() {
497 if word != 0 {
498 let word_index = prefix_words + index;
499 return Some(word_index * 64 + 63 - word.leading_zeros() as usize - lead);
500 }
501 }
502
503 chunks.prefix().filter(|word| *word != 0).map(|word| {
504 debug_assert!(word.trailing_zeros() as usize >= lead);
505 63 - word.leading_zeros() as usize - lead
506 })
507 }
508
509 #[inline]
511 pub fn false_count(&self) -> usize {
512 self.len - self.true_count()
513 }
514
515 #[inline]
517 pub fn iter(&self) -> BitIterator<'_> {
518 BitIterator::new(self.buffer.as_slice(), self.offset, self.len)
519 }
520
521 #[inline]
523 pub fn set_indices(&self) -> BitIndexIterator<'_> {
524 BitIndexIterator::new(self.buffer.as_slice(), self.offset, self.len)
525 }
526
527 #[inline]
529 pub fn set_slices(&self) -> BitSliceIterator<'_> {
530 BitSliceIterator::new(self.buffer.as_slice(), self.offset, self.len)
531 }
532
533 #[inline]
542 pub fn for_each_set_index<F: FnMut(usize)>(&self, mut f: F) {
543 let Ok(()) = self.try_for_each_set_index(|index| {
544 f(index);
545 Ok::<_, Infallible>(())
546 });
547 }
548
549 #[inline]
553 pub fn try_for_each_set_index<E, F>(&self, mut f: F) -> Result<(), E>
554 where
555 F: FnMut(usize) -> Result<(), E>,
556 {
557 let mut base = 0usize;
558 for word in self.chunks().iter_padded() {
559 if word == u64::MAX {
560 for k in 0..64 {
561 f(base + k)?;
562 }
563 } else {
564 let mut w = word;
565 while w != 0 {
566 f(base + w.trailing_zeros() as usize)?;
567 w &= w - 1;
568 }
569 }
570 base += 64;
571 }
572
573 Ok(())
574 }
575
576 pub fn sliced(&self) -> Self {
578 if self.offset.is_multiple_of(8) {
579 return Self::new(
580 self.buffer
581 .slice(self.offset / 8..(self.offset + self.len).div_ceil(8)),
582 self.len,
583 );
584 }
585
586 bitwise_unary_op_copy(self, |a| a)
588 }
589}
590
591impl BitBuffer {
594 #[inline]
596 pub fn into_inner(self) -> (usize, usize, ByteBuffer) {
597 (self.offset, self.len, self.buffer)
598 }
599
600 #[inline]
602 pub fn try_into_mut(self) -> Result<BitBufferMut, Self> {
603 match self.buffer.try_into_mut() {
604 Ok(buffer) => Ok(BitBufferMut::from_buffer(buffer, self.offset, self.len)),
605 Err(buffer) => Err(BitBuffer::new_with_offset(buffer, self.len, self.offset)),
606 }
607 }
608}
609
610impl From<&[bool]> for BitBuffer {
611 fn from(value: &[bool]) -> Self {
612 BitBufferMut::from(value).freeze()
613 }
614}
615
616impl From<Vec<bool>> for BitBuffer {
617 fn from(value: Vec<bool>) -> Self {
618 BitBufferMut::from(value).freeze()
619 }
620}
621
622impl FromIterator<bool> for BitBuffer {
623 #[inline]
624 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
625 BitBufferMut::from_iter(iter).freeze()
626 }
627}
628
629impl BitOr for BitBuffer {
630 type Output = Self;
631
632 #[inline]
633 fn bitor(self, rhs: Self) -> Self::Output {
634 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a | b)
635 }
636}
637
638impl BitOr for &BitBuffer {
639 type Output = BitBuffer;
640
641 #[inline]
642 fn bitor(self, rhs: Self) -> Self::Output {
643 bitwise_binary_op(self, rhs, |a, b| a | b)
644 }
645}
646
647impl BitOr<&BitBuffer> for BitBuffer {
648 type Output = BitBuffer;
649
650 #[inline]
651 fn bitor(self, rhs: &BitBuffer) -> Self::Output {
652 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a | b)
653 }
654}
655
656impl BitAnd for &BitBuffer {
657 type Output = BitBuffer;
658
659 #[inline]
660 fn bitand(self, rhs: Self) -> Self::Output {
661 bitwise_binary_op(self, rhs, |a, b| a & b)
662 }
663}
664
665impl BitAnd<BitBuffer> for &BitBuffer {
666 type Output = BitBuffer;
667
668 #[inline]
669 fn bitand(self, rhs: BitBuffer) -> Self::Output {
670 self.bitand(&rhs)
671 }
672}
673
674impl BitAnd<&BitBuffer> for BitBuffer {
675 type Output = BitBuffer;
676
677 #[inline]
678 fn bitand(self, rhs: &BitBuffer) -> Self::Output {
679 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & b)
680 }
681}
682
683impl BitAnd<BitBuffer> for BitBuffer {
684 type Output = BitBuffer;
685
686 #[inline]
687 fn bitand(self, rhs: BitBuffer) -> Self::Output {
688 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a & b)
689 }
690}
691
692impl Not for &BitBuffer {
693 type Output = BitBuffer;
694
695 #[inline]
696 fn not(self) -> Self::Output {
697 bitwise_unary_op_copy(self, |a| !a)
700 }
701}
702
703impl Not for BitBuffer {
704 type Output = BitBuffer;
705
706 #[inline]
707 fn not(self) -> Self::Output {
708 bitwise_unary_op(self, |a| !a)
709 }
710}
711
712impl BitXor for &BitBuffer {
713 type Output = BitBuffer;
714
715 #[inline]
716 fn bitxor(self, rhs: Self) -> Self::Output {
717 bitwise_binary_op(self, rhs, |a, b| a ^ b)
718 }
719}
720
721impl BitXor<&BitBuffer> for BitBuffer {
722 type Output = BitBuffer;
723
724 #[inline]
725 fn bitxor(self, rhs: &BitBuffer) -> Self::Output {
726 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a ^ b)
727 }
728}
729
730impl BitBuffer {
731 pub fn bitand_not(&self, rhs: &BitBuffer) -> BitBuffer {
736 bitwise_binary_op(self, rhs, |a, b| a & !b)
737 }
738
739 pub fn into_bitand_not(self, rhs: &BitBuffer) -> BitBuffer {
741 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & !b)
742 }
743
744 #[inline]
754 pub fn iter_bits<F>(&self, mut f: F)
755 where
756 F: FnMut(usize, bool),
757 {
758 let total_bits = self.len;
759 if total_bits == 0 {
760 return;
761 }
762
763 let chunks = self.chunks();
765 let chunks_count = total_bits / 64;
766 let remainder = total_bits % 64;
767
768 for (chunk_idx, chunk) in chunks.iter().enumerate() {
769 let base = chunk_idx * 64;
770 for bit_idx in 0..64 {
771 f(base + bit_idx, (chunk >> bit_idx) & 1 == 1);
772 }
773 }
774
775 if remainder != 0 {
776 let rem_chunk = chunks.remainder_bits();
777 let base = chunks_count * 64;
778 for bit_idx in 0..remainder {
779 f(base + bit_idx, (rem_chunk >> bit_idx) & 1 == 1);
780 }
781 }
782 }
783}
784
785impl<'a> IntoIterator for &'a BitBuffer {
786 type Item = bool;
787 type IntoIter = BitIterator<'a>;
788
789 fn into_iter(self) -> Self::IntoIter {
790 self.iter()
791 }
792}
793
794#[cfg(test)]
795mod tests {
796 use rstest::rstest;
797
798 use crate::ByteBuffer;
799 use crate::bit::BitBuffer;
800 use crate::buffer;
801
802 #[test]
803 fn test_bool() {
804 let buffer: ByteBuffer = buffer![1 << 7; 1024];
806 let bools = BitBuffer::new(buffer, 1024 * 8);
807
808 assert_eq!(bools.len(), 1024 * 8);
810 assert!(!bools.is_empty());
811 assert_eq!(bools.true_count(), 1024);
812 assert_eq!(bools.false_count(), 1024 * 7);
813
814 for word in 0..1024 {
816 for bit in 0..8 {
817 if bit == 7 {
818 assert!(bools.value(word * 8 + bit));
819 } else {
820 assert!(!bools.value(word * 8 + bit));
821 }
822 }
823 }
824
825 let sliced = bools.slice(64..72);
827
828 assert_eq!(sliced.len(), 8);
830 assert!(!sliced.is_empty());
831 assert_eq!(sliced.true_count(), 1);
832 assert_eq!(sliced.false_count(), 7);
833
834 for bit in 0..8 {
836 if bit == 7 {
837 assert!(sliced.value(bit));
838 } else {
839 assert!(!sliced.value(bit));
840 }
841 }
842 }
843
844 #[test]
845 fn test_padded_equaltiy() {
846 let buf1 = BitBuffer::new_set(64); let buf2 = BitBuffer::collect_bool(64, |x| x < 32); for i in 0..32 {
850 assert_eq!(buf1.value(i), buf2.value(i), "Bit {} should be the same", i);
851 }
852
853 for i in 32..64 {
854 assert_ne!(buf1.value(i), buf2.value(i), "Bit {} should differ", i);
855 }
856
857 assert_eq!(
858 buf1.slice(0..32),
859 buf2.slice(0..32),
860 "Buffer slices with same bits should be equal (`PartialEq` needs `iter_padded()`)"
861 );
862 assert_ne!(
863 buf1.slice(32..64),
864 buf2.slice(32..64),
865 "Buffer slices with different bits should not be equal (`PartialEq` needs `iter_padded()`)"
866 );
867 }
868
869 #[test]
870 fn test_slice_offset_calculation() {
871 let buf = BitBuffer::collect_bool(16, |_| true);
872 let sliced = buf.slice(10..16);
873 assert_eq!(sliced.len(), 6);
874 assert_eq!(sliced.offset(), 2);
876 }
877
878 #[test]
879 fn test_byte_aligned_bytes() {
880 let bytes: ByteBuffer = buffer![0b1010_0101u8, 0b0000_0011];
881 let buf = BitBuffer::new(bytes.clone(), 10);
882 assert_eq!(buf.byte_aligned_bytes(), Some(bytes.as_slice()));
883
884 let byte_sliced = buf.slice(8..10);
885 assert_eq!(byte_sliced.byte_aligned_bytes(), Some(&[0b0000_0011][..]));
886
887 let bit_sliced = buf.slice(1..9);
888 assert!(bit_sliced.byte_aligned_bytes().is_none());
889 }
890
891 #[test]
892 fn test_from_indices_dense_crosses_words() {
893 let len = 130;
894 let indices = (0..len).filter(|idx| idx % 3 != 1);
895 let buf = BitBuffer::from_indices(len, indices);
896
897 assert_eq!(buf.len(), len);
898 for idx in 0..len {
899 assert_eq!(buf.value(idx), idx % 3 != 1, "mismatch at {idx}");
900 }
901 }
902
903 #[test]
904 #[should_panic(expected = "index 5 exceeds len 5")]
905 fn test_from_indices_out_of_bounds() {
906 BitBuffer::from_indices(5, [0, 5]);
907 }
908
909 #[rstest]
910 #[case(0, 0, None)]
911 #[case(3, 7, None)]
912 #[case(0, 1, Some(0))]
913 #[case(8, 64, Some(63))]
914 #[case(13, 65, Some(0))]
915 #[case(13, 65, Some(64))]
916 #[case(67, 151, Some(97))]
917 #[case(67, 151, Some(150))]
918 fn last_set_index_handles_offsets_and_padding(
919 #[case] offset: usize,
920 #[case] len: usize,
921 #[case] expected: Option<usize>,
922 ) {
923 let backing = BitBuffer::from_iter(
924 std::iter::repeat_n(true, offset)
925 .chain((0..len).map(|index| Some(index) == expected))
926 .chain(std::iter::repeat_n(true, 7)),
927 );
928 let buffer = BitBuffer::new_with_offset(backing.inner().clone(), len, offset);
929
930 assert_eq!(buffer.last_set_index(), expected);
931 }
932
933 #[rstest]
934 #[case(5)]
935 #[case(8)]
936 #[case(10)]
937 #[case(13)]
938 #[case(16)]
939 #[case(23)]
940 #[case(100)]
941 fn test_iter_bits(#[case] len: usize) {
942 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
943
944 let mut collected = Vec::new();
945 buf.iter_bits(|idx, is_set| {
946 collected.push((idx, is_set));
947 });
948
949 assert_eq!(collected.len(), len);
950
951 for (idx, is_set) in collected {
952 assert_eq!(is_set, idx % 2 == 0);
953 }
954 }
955
956 #[rstest]
957 #[case(3, 5)]
958 #[case(3, 8)]
959 #[case(5, 10)]
960 #[case(2, 16)]
961 #[case(8, 16)]
962 #[case(9, 16)]
963 #[case(17, 16)]
964 fn test_iter_bits_with_offset(#[case] offset: usize, #[case] len: usize) {
965 let total_bits = offset + len;
966 let buf = BitBuffer::collect_bool(total_bits, |i| i % 2 == 0);
967 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
968
969 let mut collected = Vec::new();
970 buf_with_offset.iter_bits(|idx, is_set| {
971 collected.push((idx, is_set));
972 });
973
974 assert_eq!(collected.len(), len);
975
976 for (idx, is_set) in collected {
977 assert_eq!(is_set, (offset + idx).is_multiple_of(2));
979 }
980 }
981
982 #[rstest]
983 #[case(8, 10)]
984 #[case(9, 7)]
985 #[case(16, 8)]
986 #[case(17, 10)]
987 fn test_iter_bits_catches_wrong_byte_offset(#[case] offset: usize, #[case] len: usize) {
988 let total_bits = offset + len;
989 let buf = BitBuffer::collect_bool(total_bits, |i| (i / 8) % 2 == 0);
991
992 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
993
994 let mut collected = Vec::new();
995 buf_with_offset.iter_bits(|idx, is_set| {
996 collected.push((idx, is_set));
997 });
998
999 assert_eq!(collected.len(), len);
1000
1001 for (idx, is_set) in collected {
1002 let bit_position = offset + idx;
1003 let byte_index = bit_position / 8;
1004 let expected_is_set = byte_index.is_multiple_of(2);
1005
1006 assert_eq!(
1007 is_set, expected_is_set,
1008 "Bit mismatch at index {}: expected {} got {}",
1009 bit_position, expected_is_set, is_set
1010 );
1011 }
1012 }
1013
1014 #[rstest]
1015 #[case(5)]
1016 #[case(8)]
1017 #[case(10)]
1018 #[case(64)]
1019 #[case(65)]
1020 #[case(100)]
1021 #[case(128)]
1022 fn test_map_cmp_identity(#[case] len: usize) {
1023 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
1025 let mapped = buf.map_cmp(|_idx, bit| bit);
1026
1027 assert_eq!(buf.len(), mapped.len());
1028 for i in 0..len {
1029 assert_eq!(buf.value(i), mapped.value(i), "Mismatch at index {}", i);
1030 }
1031 }
1032
1033 #[rstest]
1034 #[case(5)]
1035 #[case(8)]
1036 #[case(64)]
1037 #[case(65)]
1038 #[case(100)]
1039 fn test_map_cmp_negate(#[case] len: usize) {
1040 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
1042 let mapped = buf.map_cmp(|_idx, bit| !bit);
1043
1044 assert_eq!(buf.len(), mapped.len());
1045 for i in 0..len {
1046 assert_eq!(!buf.value(i), mapped.value(i), "Mismatch at index {}", i);
1047 }
1048 }
1049
1050 #[rstest]
1051 #[case(0, 0)]
1052 #[case(0, 64)]
1053 #[case(5, 70)]
1054 #[case(64, 130)]
1055 #[case(0, 200)]
1056 fn test_count_range(#[case] start: usize, #[case] end: usize) {
1057 let len = 200;
1058 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
1059 let expected = (start..end).filter(|i| i % 3 == 0).count();
1060 assert_eq!(buf.count_range(start, end), expected);
1061 assert_eq!(
1063 buf.count_range(start, end),
1064 buf.slice(start..end).true_count()
1065 );
1066 }
1067
1068 #[rstest]
1069 #[case(3)]
1070 #[case(7)]
1071 fn test_count_range_with_offset(#[case] offset: usize) {
1072 let len = 150;
1073 let buf = BitBuffer::collect_bool(offset + len, |i| i % 2 == 0);
1074 let view = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
1075 for (start, end) in [(0, len), (10, 100), (1, 2), (63, 129)] {
1076 let expected = (offset + start..offset + end)
1077 .filter(|i| i % 2 == 0)
1078 .count();
1079 assert_eq!(view.count_range(start, end), expected, "[{start}, {end})");
1080 }
1081 }
1082
1083 #[rstest]
1084 #[case(0)]
1085 #[case(1)]
1086 #[case(63)]
1087 #[case(64)]
1088 #[case(65)]
1089 #[case(200)]
1090 #[case(1000)]
1091 fn test_set_index_visitors_match_set_indices(#[case] len: usize) {
1092 let buf = BitBuffer::collect_bool(len, |i| i % 5 == 0 || i % 7 == 0);
1093 let expected: Vec<usize> = buf.set_indices().collect();
1094
1095 let mut got = Vec::new();
1096 buf.for_each_set_index(|i| got.push(i));
1097 assert_eq!(got, expected);
1098
1099 let mut fallible_got = Vec::new();
1100 let result = buf.try_for_each_set_index(|i| {
1101 fallible_got.push(i);
1102 Ok::<(), ()>(())
1103 });
1104 assert_eq!(result, Ok(()));
1105 assert_eq!(fallible_got, expected);
1106 }
1107
1108 #[rstest]
1109 #[case(3, 200)]
1110 #[case(7, 130)]
1111 fn test_for_each_set_index_with_offset(#[case] offset: usize, #[case] len: usize) {
1112 let base = BitBuffer::collect_bool(offset + len, |i| i % 3 == 0);
1113 let view = BitBuffer::new_with_offset(base.inner().clone(), len, offset);
1114 let expected: Vec<usize> = view.set_indices().collect();
1115 let mut got = Vec::new();
1116 view.for_each_set_index(|i| got.push(i));
1117 assert_eq!(got, expected);
1118 }
1119
1120 #[test]
1121 fn test_for_each_set_index_all_set() {
1122 let buf = BitBuffer::new_set(130);
1123 let mut got = Vec::new();
1124 buf.for_each_set_index(|i| got.push(i));
1125 assert_eq!(got, (0..130).collect::<Vec<_>>());
1126 }
1127
1128 #[test]
1129 fn test_try_for_each_set_index_stops_on_error() {
1130 for (buffer, stop) in [
1131 (BitBuffer::new_set(130), 65),
1132 (BitBuffer::collect_bool(130, |i| i % 3 == 0), 66),
1133 ] {
1134 let mut visited = Vec::new();
1135 let result = buffer.try_for_each_set_index(|index| {
1136 visited.push(index);
1137 if index == stop {
1138 return Err(index);
1139 }
1140
1141 Ok(())
1142 });
1143
1144 assert_eq!(result, Err(stop));
1145 assert_eq!(
1146 visited,
1147 buffer
1148 .set_indices()
1149 .take_while(|&i| i <= stop)
1150 .collect::<Vec<_>>()
1151 );
1152 }
1153 }
1154
1155 #[test]
1156 fn test_map_cmp_conditional() {
1157 let len = 100;
1159 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
1160
1161 let mapped = buf.map_cmp(|idx, bit| bit && idx % 4 == 0);
1163
1164 for i in 0..len {
1165 let expected = (i % 2 == 0) && (i % 4 == 0);
1166 assert_eq!(mapped.value(i), expected, "Mismatch at index {}", i);
1167 }
1168 }
1169}