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;
34use crate::bit::select::bit_select_unset;
35
36#[derive(Debug, Clone, Eq)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub struct BitBuffer {
40 buffer: ByteBuffer,
41 offset: usize,
45 len: usize,
46}
47
48const LIMIT_LEN: usize = 16;
49impl Display for BitBuffer {
50 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
51 let limit = f.precision().unwrap_or(LIMIT_LEN);
52 let buf: Vec<bool> = self.into_iter().take(limit).collect();
53 f.debug_struct("BitBuffer")
54 .field("len", &self.len)
55 .field("buffer", &buf)
56 .finish()
57 }
58}
59
60impl PartialEq for BitBuffer {
61 fn eq(&self, other: &Self) -> bool {
62 if self.len != other.len {
63 return false;
64 }
65
66 if self.len == 0 {
67 return true;
68 }
69
70 if self.offset == 0 && other.offset == 0 {
72 let full_bytes = self.len / 8;
73 let self_bytes = &self.buffer.as_slice()[..full_bytes];
74 let other_bytes = &other.buffer.as_slice()[..full_bytes];
75 if self_bytes != other_bytes {
76 return false;
77 }
78 let rem = self.len % 8;
80 if rem != 0 {
81 let mask = (1u8 << rem) - 1;
82 let a = self.buffer.as_slice()[full_bytes] & mask;
83 let b = other.buffer.as_slice()[full_bytes] & mask;
84 return a == b;
85 }
86 return true;
87 }
88
89 self.chunks()
90 .iter_padded()
91 .zip(other.chunks().iter_padded())
92 .all(|(a, b)| a == b)
93 }
94}
95
96impl BitBuffer {
97 #[inline]
101 pub fn new(buffer: ByteBuffer, len: usize) -> Self {
102 assert!(
103 buffer.len() * 8 >= len,
104 "provided ByteBuffer not large enough to back BoolBuffer with len {len}"
105 );
106
107 let buffer = buffer.aligned(Alignment::none());
109
110 Self {
111 buffer,
112 len,
113 offset: 0,
114 }
115 }
116
117 #[inline]
122 pub fn new_with_offset(buffer: ByteBuffer, len: usize, offset: usize) -> Self {
123 assert!(
124 len.saturating_add(offset) <= buffer.len().saturating_mul(8),
125 "provided ByteBuffer (len={}) not large enough to back BoolBuffer with offset {offset} len {len}",
126 buffer.len()
127 );
128
129 let buffer = buffer.aligned(Alignment::none());
131
132 let byte_offset = offset / 8;
134 let offset = offset % 8;
135 let buffer = if byte_offset != 0 {
136 buffer.slice(byte_offset..)
137 } else {
138 buffer
139 };
140
141 Self {
142 buffer,
143 offset,
144 len,
145 }
146 }
147
148 #[inline]
150 pub fn new_set(len: usize) -> Self {
151 Self::new_set_in(len, BufferAllocatorRef::statically_allocated())
152 }
153
154 #[inline]
156 pub fn new_set_in(len: usize, allocator: BufferAllocatorRef) -> Self {
157 let words = len.div_ceil(8);
158 let buffer = Buffer::full_in(0xFF, words, allocator);
159
160 Self {
161 buffer,
162 len,
163 offset: 0,
164 }
165 }
166
167 #[inline]
169 pub fn new_unset(len: usize) -> Self {
170 Self::new_unset_in(len, BufferAllocatorRef::statically_allocated())
171 }
172
173 #[inline]
175 pub fn new_unset_in(len: usize, allocator: BufferAllocatorRef) -> Self {
176 let words = len.div_ceil(8);
177 let buffer = Buffer::zeroed_in(words, allocator);
178
179 Self {
180 buffer,
181 len,
182 offset: 0,
183 }
184 }
185
186 pub fn from_indices(len: usize, indices: impl IntoIterator<Item = usize>) -> BitBuffer {
188 BitBufferMut::from_indices(len, indices).freeze()
189 }
190
191 #[inline]
193 pub fn empty() -> Self {
194 Self::new_set(0)
195 }
196
197 #[inline]
199 pub fn full(value: bool, len: usize) -> Self {
200 Self::full_in(value, len, BufferAllocatorRef::statically_allocated())
201 }
202
203 #[inline]
205 pub fn full_in(value: bool, len: usize, allocator: BufferAllocatorRef) -> Self {
206 if value {
207 Self::new_set_in(len, allocator)
208 } else {
209 Self::new_unset_in(len, allocator)
210 }
211 }
212
213 #[inline]
239 pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
240 BitBufferMut::collect_bool(len, f).freeze()
241 }
242
243 #[inline]
245 pub fn collect_bool_in<F: FnMut(usize) -> bool>(
246 len: usize,
247 f: F,
248 allocator: BufferAllocatorRef,
249 ) -> Self {
250 BitBufferMut::collect_bool_in(len, f, allocator).freeze()
251 }
252
253 #[inline]
264 pub fn collect_bool_multiversioned<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
265 Self::collect_bool_multiversioned_in(len, f, BufferAllocatorRef::statically_allocated())
266 }
267
268 #[inline]
270 pub fn collect_bool_multiversioned_in<F: FnMut(usize) -> bool>(
271 len: usize,
272 f: F,
273 allocator: BufferAllocatorRef,
274 ) -> Self {
275 BitBufferMut::collect_bool_multiversioned_in(len, f, allocator).freeze()
276 }
277
278 pub fn map_cmp<F>(&self, mut f: F) -> Self
283 where
284 F: FnMut(usize, bool) -> bool,
285 {
286 let len = self.len;
287 let mut buffer: BufferMut<u64> = BufferMut::with_capacity(len.div_ceil(64));
288
289 let chunks_count = len / 64;
290 let remainder = len % 64;
291 let chunks = self.chunks();
292
293 for (chunk_idx, src_chunk) in chunks.iter().enumerate() {
294 let packed = collect_bool_word(64, |bit_idx| {
295 let i = bit_idx + chunk_idx * 64;
296 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
297 f(i, bit_value)
298 });
299
300 unsafe { buffer.push_unchecked(packed) }
302 }
303
304 if remainder != 0 {
305 let src_chunk = chunks.remainder_bits();
306 let packed = collect_bool_word(remainder, |bit_idx| {
307 let i = bit_idx + chunks_count * 64;
308 let bit_value = (src_chunk >> bit_idx) & 1 == 1;
309 f(i, bit_value)
310 });
311
312 unsafe { buffer.push_unchecked(packed) }
314 }
315
316 let mut bytes = buffer.into_byte_buffer();
317 bytes.truncate(len.div_ceil(8));
318
319 Self {
320 buffer: bytes.freeze(),
321 offset: 0,
322 len,
323 }
324 }
325
326 #[inline]
328 pub fn clear(&mut self) {
329 self.buffer.clear();
330 self.len = 0;
331 self.offset = 0;
332 }
333
334 #[inline]
339 pub fn len(&self) -> usize {
340 self.len
341 }
342
343 #[inline]
345 pub fn is_empty(&self) -> bool {
346 self.len() == 0
347 }
348
349 #[allow(clippy::inline_always)]
351 #[inline(always)]
352 pub fn offset(&self) -> usize {
353 self.offset
354 }
355
356 #[allow(clippy::inline_always)]
358 #[inline(always)]
359 pub fn inner(&self) -> &ByteBuffer {
360 &self.buffer
361 }
362
363 #[inline]
369 pub fn byte_aligned_bytes(&self) -> Option<&[u8]> {
370 if !self.offset.is_multiple_of(8) {
371 return None;
372 }
373
374 let n_bytes = self.len.div_ceil(8);
375 let start = self.offset / 8;
376 let end = start + n_bytes;
377 Some(&self.buffer.as_slice()[start..end])
378 }
379
380 #[inline]
386 pub fn value(&self, index: usize) -> bool {
387 assert!(index < self.len);
388 unsafe { self.value_unchecked(index) }
389 }
390
391 #[inline]
396 pub unsafe fn value_unchecked(&self, index: usize) -> bool {
397 unsafe { get_bit_unchecked(self.buffer.as_ptr(), index + self.offset) }
398 }
399
400 #[inline]
405 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
406 let (byte_offset, meta) = BitBufferMeta::new(self.offset, self.len).slice(range);
407
408 let buffer = if byte_offset != 0 {
411 self.buffer.slice_unaligned(byte_offset..)
412 } else {
413 self.buffer.clone().aligned(Alignment::none())
414 };
415
416 Self {
417 buffer,
418 offset: meta.offset(),
419 len: meta.len(),
420 }
421 }
422
423 pub fn shrink_offset(self) -> Self {
425 let word_start = self.offset / 8;
426 let word_end = (self.offset + self.len).div_ceil(8);
427
428 let buffer = self.buffer.slice(word_start..word_end);
429
430 let bit_offset = self.offset % 8;
431 let len = self.len;
432 BitBuffer::new_with_offset(buffer, len, bit_offset)
433 }
434
435 #[inline]
437 pub fn unaligned_chunks(&self) -> UnalignedBitChunk<'_> {
438 UnalignedBitChunk::new(self.buffer.as_slice(), self.offset, self.len)
439 }
440
441 #[inline]
445 pub fn chunks(&self) -> BitChunks<'_> {
446 BitChunks::new(self.buffer.as_slice(), self.offset, self.len)
447 }
448
449 #[inline]
451 pub fn true_count(&self) -> usize {
452 count_ones(self.buffer.as_slice(), self.offset, self.len)
453 }
454
455 #[inline]
463 pub fn count_range(&self, start: usize, end: usize) -> usize {
464 assert!(start <= end, "start {start} exceeds end {end}");
465 assert!(end <= self.len, "end {end} exceeds len {}", self.len);
466 count_ones(self.buffer.as_slice(), self.offset + start, end - start)
467 }
468
469 #[inline]
476 pub fn select(&self, nth: usize) -> Option<usize> {
477 bit_select(self.buffer.as_slice(), self.offset, self.len, nth)
478 }
479
480 #[inline]
487 pub fn select_unset(&self, nth: usize) -> Option<usize> {
488 bit_select_unset(self.buffer.as_slice(), self.offset, self.len, nth)
489 }
490
491 #[inline]
496 pub fn last_set_index(&self) -> Option<usize> {
497 let chunks = self.unaligned_chunks();
498 let lead = chunks.lead_padding();
499 let prefix_words = usize::from(chunks.prefix().is_some());
500
501 if let Some(word) = chunks.suffix()
502 && word != 0
503 {
504 let word_index = prefix_words + chunks.chunks().len();
505 return Some(word_index * 64 + 63 - word.leading_zeros() as usize - lead);
506 }
507
508 for (index, &word) in chunks.chunks().iter().enumerate().rev() {
509 if word != 0 {
510 let word_index = prefix_words + index;
511 return Some(word_index * 64 + 63 - word.leading_zeros() as usize - lead);
512 }
513 }
514
515 chunks.prefix().filter(|word| *word != 0).map(|word| {
516 debug_assert!(word.trailing_zeros() as usize >= lead);
517 63 - word.leading_zeros() as usize - lead
518 })
519 }
520
521 #[inline]
523 pub fn false_count(&self) -> usize {
524 self.len - self.true_count()
525 }
526
527 #[inline]
529 pub fn iter(&self) -> BitIterator<'_> {
530 BitIterator::new(self.buffer.as_slice(), self.offset, self.len)
531 }
532
533 #[inline]
535 pub fn set_indices(&self) -> BitIndexIterator<'_> {
536 BitIndexIterator::new(self.buffer.as_slice(), self.offset, self.len)
537 }
538
539 #[inline]
541 pub fn set_slices(&self) -> BitSliceIterator<'_> {
542 BitSliceIterator::new(self.buffer.as_slice(), self.offset, self.len)
543 }
544
545 #[inline]
554 pub fn for_each_set_index<F: FnMut(usize)>(&self, mut f: F) {
555 let Ok(()) = self.try_for_each_set_index(|index| {
556 f(index);
557 Ok::<_, Infallible>(())
558 });
559 }
560
561 #[inline]
565 pub fn try_for_each_set_index<E, F>(&self, mut f: F) -> Result<(), E>
566 where
567 F: FnMut(usize) -> Result<(), E>,
568 {
569 let mut base = 0usize;
570 for word in self.chunks().iter_padded() {
571 if word == u64::MAX {
572 for k in 0..64 {
573 f(base + k)?;
574 }
575 } else {
576 let mut w = word;
577 while w != 0 {
578 f(base + w.trailing_zeros() as usize)?;
579 w &= w - 1;
580 }
581 }
582 base += 64;
583 }
584
585 Ok(())
586 }
587
588 pub fn sliced(&self) -> Self {
590 if self.offset.is_multiple_of(8) {
591 return Self::new(
592 self.buffer
593 .slice(self.offset / 8..(self.offset + self.len).div_ceil(8)),
594 self.len,
595 );
596 }
597
598 bitwise_unary_op_copy(self, |a| a)
600 }
601}
602
603impl BitBuffer {
606 #[inline]
608 pub fn into_inner(self) -> (usize, usize, ByteBuffer) {
609 (self.offset, self.len, self.buffer)
610 }
611
612 #[inline]
614 pub fn try_into_mut(self) -> Result<BitBufferMut, Self> {
615 match self.buffer.try_into_mut() {
616 Ok(buffer) => Ok(BitBufferMut::from_buffer(buffer, self.offset, self.len)),
617 Err(buffer) => Err(BitBuffer::new_with_offset(buffer, self.len, self.offset)),
618 }
619 }
620}
621
622impl From<&[bool]> for BitBuffer {
623 fn from(value: &[bool]) -> Self {
624 BitBufferMut::from(value).freeze()
625 }
626}
627
628impl From<Vec<bool>> for BitBuffer {
629 fn from(value: Vec<bool>) -> Self {
630 BitBufferMut::from(value).freeze()
631 }
632}
633
634impl FromIterator<bool> for BitBuffer {
635 #[inline]
636 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
637 BitBufferMut::from_iter(iter).freeze()
638 }
639}
640
641impl BitOr for BitBuffer {
642 type Output = Self;
643
644 #[inline]
645 fn bitor(self, rhs: Self) -> Self::Output {
646 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a | b)
647 }
648}
649
650impl BitOr for &BitBuffer {
651 type Output = BitBuffer;
652
653 #[inline]
654 fn bitor(self, rhs: Self) -> Self::Output {
655 bitwise_binary_op(self, rhs, |a, b| a | b)
656 }
657}
658
659impl BitOr<&BitBuffer> for BitBuffer {
660 type Output = BitBuffer;
661
662 #[inline]
663 fn bitor(self, rhs: &BitBuffer) -> Self::Output {
664 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a | b)
665 }
666}
667
668impl BitAnd for &BitBuffer {
669 type Output = BitBuffer;
670
671 #[inline]
672 fn bitand(self, rhs: Self) -> Self::Output {
673 bitwise_binary_op(self, rhs, |a, b| a & b)
674 }
675}
676
677impl BitAnd<BitBuffer> for &BitBuffer {
678 type Output = BitBuffer;
679
680 #[inline]
681 fn bitand(self, rhs: BitBuffer) -> Self::Output {
682 self.bitand(&rhs)
683 }
684}
685
686impl BitAnd<&BitBuffer> for BitBuffer {
687 type Output = BitBuffer;
688
689 #[inline]
690 fn bitand(self, rhs: &BitBuffer) -> Self::Output {
691 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & b)
692 }
693}
694
695impl BitAnd<BitBuffer> for BitBuffer {
696 type Output = BitBuffer;
697
698 #[inline]
699 fn bitand(self, rhs: BitBuffer) -> Self::Output {
700 bitwise_binary_op_lhs_owned(self, &rhs, |a, b| a & b)
701 }
702}
703
704impl Not for &BitBuffer {
705 type Output = BitBuffer;
706
707 #[inline]
708 fn not(self) -> Self::Output {
709 bitwise_unary_op_copy(self, |a| !a)
712 }
713}
714
715impl Not for BitBuffer {
716 type Output = BitBuffer;
717
718 #[inline]
719 fn not(self) -> Self::Output {
720 bitwise_unary_op(self, |a| !a)
721 }
722}
723
724impl BitXor for &BitBuffer {
725 type Output = BitBuffer;
726
727 #[inline]
728 fn bitxor(self, rhs: Self) -> Self::Output {
729 bitwise_binary_op(self, rhs, |a, b| a ^ b)
730 }
731}
732
733impl BitXor<&BitBuffer> for BitBuffer {
734 type Output = BitBuffer;
735
736 #[inline]
737 fn bitxor(self, rhs: &BitBuffer) -> Self::Output {
738 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a ^ b)
739 }
740}
741
742impl BitBuffer {
743 pub fn bitand_not(&self, rhs: &BitBuffer) -> BitBuffer {
748 bitwise_binary_op(self, rhs, |a, b| a & !b)
749 }
750
751 pub fn into_bitand_not(self, rhs: &BitBuffer) -> BitBuffer {
753 bitwise_binary_op_lhs_owned(self, rhs, |a, b| a & !b)
754 }
755
756 #[inline]
766 pub fn iter_bits<F>(&self, mut f: F)
767 where
768 F: FnMut(usize, bool),
769 {
770 let total_bits = self.len;
771 if total_bits == 0 {
772 return;
773 }
774
775 let chunks = self.chunks();
777 let chunks_count = total_bits / 64;
778 let remainder = total_bits % 64;
779
780 for (chunk_idx, chunk) in chunks.iter().enumerate() {
781 let base = chunk_idx * 64;
782 for bit_idx in 0..64 {
783 f(base + bit_idx, (chunk >> bit_idx) & 1 == 1);
784 }
785 }
786
787 if remainder != 0 {
788 let rem_chunk = chunks.remainder_bits();
789 let base = chunks_count * 64;
790 for bit_idx in 0..remainder {
791 f(base + bit_idx, (rem_chunk >> bit_idx) & 1 == 1);
792 }
793 }
794 }
795}
796
797impl<'a> IntoIterator for &'a BitBuffer {
798 type Item = bool;
799 type IntoIter = BitIterator<'a>;
800
801 fn into_iter(self) -> Self::IntoIter {
802 self.iter()
803 }
804}
805
806#[cfg(test)]
807mod tests {
808 use rstest::rstest;
809
810 use crate::ByteBuffer;
811 use crate::bit::BitBuffer;
812 use crate::buffer;
813
814 #[test]
815 fn test_bool() {
816 let buffer: ByteBuffer = buffer![1 << 7; 1024];
818 let bools = BitBuffer::new(buffer, 1024 * 8);
819
820 assert_eq!(bools.len(), 1024 * 8);
822 assert!(!bools.is_empty());
823 assert_eq!(bools.true_count(), 1024);
824 assert_eq!(bools.false_count(), 1024 * 7);
825
826 for word in 0..1024 {
828 for bit in 0..8 {
829 if bit == 7 {
830 assert!(bools.value(word * 8 + bit));
831 } else {
832 assert!(!bools.value(word * 8 + bit));
833 }
834 }
835 }
836
837 let sliced = bools.slice(64..72);
839
840 assert_eq!(sliced.len(), 8);
842 assert!(!sliced.is_empty());
843 assert_eq!(sliced.true_count(), 1);
844 assert_eq!(sliced.false_count(), 7);
845
846 for bit in 0..8 {
848 if bit == 7 {
849 assert!(sliced.value(bit));
850 } else {
851 assert!(!sliced.value(bit));
852 }
853 }
854 }
855
856 #[test]
857 fn test_padded_equaltiy() {
858 let buf1 = BitBuffer::new_set(64); let buf2 = BitBuffer::collect_bool(64, |x| x < 32); for i in 0..32 {
862 assert_eq!(buf1.value(i), buf2.value(i), "Bit {} should be the same", i);
863 }
864
865 for i in 32..64 {
866 assert_ne!(buf1.value(i), buf2.value(i), "Bit {} should differ", i);
867 }
868
869 assert_eq!(
870 buf1.slice(0..32),
871 buf2.slice(0..32),
872 "Buffer slices with same bits should be equal (`PartialEq` needs `iter_padded()`)"
873 );
874 assert_ne!(
875 buf1.slice(32..64),
876 buf2.slice(32..64),
877 "Buffer slices with different bits should not be equal (`PartialEq` needs `iter_padded()`)"
878 );
879 }
880
881 #[test]
882 fn test_slice_offset_calculation() {
883 let buf = BitBuffer::collect_bool(16, |_| true);
884 let sliced = buf.slice(10..16);
885 assert_eq!(sliced.len(), 6);
886 assert_eq!(sliced.offset(), 2);
888 }
889
890 #[test]
891 fn test_byte_aligned_bytes() {
892 let bytes: ByteBuffer = buffer![0b1010_0101u8, 0b0000_0011];
893 let buf = BitBuffer::new(bytes.clone(), 10);
894 assert_eq!(buf.byte_aligned_bytes(), Some(bytes.as_slice()));
895
896 let byte_sliced = buf.slice(8..10);
897 assert_eq!(byte_sliced.byte_aligned_bytes(), Some(&[0b0000_0011][..]));
898
899 let bit_sliced = buf.slice(1..9);
900 assert!(bit_sliced.byte_aligned_bytes().is_none());
901 }
902
903 #[test]
904 fn test_from_indices_dense_crosses_words() {
905 let len = 130;
906 let indices = (0..len).filter(|idx| idx % 3 != 1);
907 let buf = BitBuffer::from_indices(len, indices);
908
909 assert_eq!(buf.len(), len);
910 for idx in 0..len {
911 assert_eq!(buf.value(idx), idx % 3 != 1, "mismatch at {idx}");
912 }
913 }
914
915 #[test]
916 #[should_panic(expected = "index 5 exceeds len 5")]
917 fn test_from_indices_out_of_bounds() {
918 BitBuffer::from_indices(5, [0, 5]);
919 }
920
921 #[rstest]
922 #[case(0, 0, None)]
923 #[case(3, 7, None)]
924 #[case(0, 1, Some(0))]
925 #[case(8, 64, Some(63))]
926 #[case(13, 65, Some(0))]
927 #[case(13, 65, Some(64))]
928 #[case(67, 151, Some(97))]
929 #[case(67, 151, Some(150))]
930 fn last_set_index_handles_offsets_and_padding(
931 #[case] offset: usize,
932 #[case] len: usize,
933 #[case] expected: Option<usize>,
934 ) {
935 let backing = BitBuffer::from_iter(
936 std::iter::repeat_n(true, offset)
937 .chain((0..len).map(|index| Some(index) == expected))
938 .chain(std::iter::repeat_n(true, 7)),
939 );
940 let buffer = BitBuffer::new_with_offset(backing.inner().clone(), len, offset);
941
942 assert_eq!(buffer.last_set_index(), expected);
943 }
944
945 #[rstest]
946 #[case(5)]
947 #[case(8)]
948 #[case(10)]
949 #[case(13)]
950 #[case(16)]
951 #[case(23)]
952 #[case(100)]
953 fn test_iter_bits(#[case] len: usize) {
954 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
955
956 let mut collected = Vec::new();
957 buf.iter_bits(|idx, is_set| {
958 collected.push((idx, is_set));
959 });
960
961 let expected: Vec<_> = (0..len).map(|idx| (idx, idx % 2 == 0)).collect();
962 assert_eq!(collected, expected);
963 }
964
965 #[rstest]
966 #[case(3, 5)]
967 #[case(3, 8)]
968 #[case(5, 10)]
969 #[case(2, 16)]
970 #[case(8, 16)]
971 #[case(9, 16)]
972 #[case(17, 16)]
973 fn test_iter_bits_with_offset(#[case] offset: usize, #[case] len: usize) {
974 let total_bits = offset + len;
975 let buf = BitBuffer::collect_bool(total_bits, |i| i % 2 == 0);
976 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
977
978 let mut collected = Vec::new();
979 buf_with_offset.iter_bits(|idx, is_set| {
980 collected.push((idx, is_set));
981 });
982
983 let expected: Vec<_> = (0..len)
984 .map(|idx| (idx, (offset + idx).is_multiple_of(2)))
985 .collect();
986 assert_eq!(collected, expected);
987 }
988
989 #[rstest]
990 #[case(8, 10)]
991 #[case(9, 7)]
992 #[case(16, 8)]
993 #[case(17, 10)]
994 fn test_iter_bits_catches_wrong_byte_offset(#[case] offset: usize, #[case] len: usize) {
995 let total_bits = offset + len;
996 let buf = BitBuffer::collect_bool(total_bits, |i| (i / 8) % 2 == 0);
998
999 let buf_with_offset = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
1000
1001 let mut collected = Vec::new();
1002 buf_with_offset.iter_bits(|idx, is_set| {
1003 collected.push((idx, is_set));
1004 });
1005
1006 let expected: Vec<_> = (0..len)
1007 .map(|idx| (idx, ((offset + idx) / 8).is_multiple_of(2)))
1008 .collect();
1009 assert_eq!(collected, expected);
1010 }
1011
1012 #[rstest]
1013 #[case(5)]
1014 #[case(8)]
1015 #[case(10)]
1016 #[case(64)]
1017 #[case(65)]
1018 #[case(100)]
1019 #[case(128)]
1020 fn test_map_cmp_identity(#[case] len: usize) {
1021 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
1023 let mapped = buf.map_cmp(|_idx, bit| bit);
1024
1025 assert_eq!(buf.len(), mapped.len());
1026 for i in 0..len {
1027 assert_eq!(buf.value(i), mapped.value(i), "Mismatch at index {}", i);
1028 }
1029 }
1030
1031 #[rstest]
1032 #[case(5)]
1033 #[case(8)]
1034 #[case(64)]
1035 #[case(65)]
1036 #[case(100)]
1037 fn test_map_cmp_negate(#[case] len: usize) {
1038 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
1040 let mapped = buf.map_cmp(|_idx, bit| !bit);
1041
1042 assert_eq!(buf.len(), mapped.len());
1043 for i in 0..len {
1044 assert_eq!(!buf.value(i), mapped.value(i), "Mismatch at index {}", i);
1045 }
1046 }
1047
1048 #[rstest]
1049 #[case(0, 0)]
1050 #[case(0, 64)]
1051 #[case(5, 70)]
1052 #[case(64, 130)]
1053 #[case(0, 200)]
1054 fn test_count_range(#[case] start: usize, #[case] end: usize) {
1055 let len = 200;
1056 let buf = BitBuffer::collect_bool(len, |i| i % 3 == 0);
1057 let expected = (start..end).filter(|i| i % 3 == 0).count();
1058 assert_eq!(buf.count_range(start, end), expected);
1059 assert_eq!(
1061 buf.count_range(start, end),
1062 buf.slice(start..end).true_count()
1063 );
1064 }
1065
1066 #[rstest]
1067 #[case(3)]
1068 #[case(7)]
1069 fn test_count_range_with_offset(#[case] offset: usize) {
1070 let len = 150;
1071 let buf = BitBuffer::collect_bool(offset + len, |i| i % 2 == 0);
1072 let view = BitBuffer::new_with_offset(buf.inner().clone(), len, offset);
1073 for (start, end) in [(0, len), (10, 100), (1, 2), (63, 129)] {
1074 let expected = (offset + start..offset + end)
1075 .filter(|i| i % 2 == 0)
1076 .count();
1077 assert_eq!(view.count_range(start, end), expected, "[{start}, {end})");
1078 }
1079 }
1080
1081 #[rstest]
1082 #[case(0)]
1083 #[case(1)]
1084 #[case(63)]
1085 #[case(64)]
1086 #[case(65)]
1087 #[case(200)]
1088 #[case(1000)]
1089 fn test_set_index_visitors_match_set_indices(#[case] len: usize) {
1090 let buf = BitBuffer::collect_bool(len, |i| i % 5 == 0 || i % 7 == 0);
1091 let expected: Vec<usize> = buf.set_indices().collect();
1092
1093 let mut got = Vec::new();
1094 buf.for_each_set_index(|i| got.push(i));
1095 assert_eq!(got, expected);
1096
1097 let mut fallible_got = Vec::new();
1098 let result = buf.try_for_each_set_index(|i| {
1099 fallible_got.push(i);
1100 Ok::<(), ()>(())
1101 });
1102 assert_eq!(result, Ok(()));
1103 assert_eq!(fallible_got, expected);
1104 }
1105
1106 #[rstest]
1107 #[case(3, 200)]
1108 #[case(7, 130)]
1109 fn test_for_each_set_index_with_offset(#[case] offset: usize, #[case] len: usize) {
1110 let base = BitBuffer::collect_bool(offset + len, |i| i % 3 == 0);
1111 let view = BitBuffer::new_with_offset(base.inner().clone(), len, offset);
1112 let expected: Vec<usize> = view.set_indices().collect();
1113 let mut got = Vec::new();
1114 view.for_each_set_index(|i| got.push(i));
1115 assert_eq!(got, expected);
1116 }
1117
1118 #[test]
1119 fn test_for_each_set_index_all_set() {
1120 let buf = BitBuffer::new_set(130);
1121 let mut got = Vec::new();
1122 buf.for_each_set_index(|i| got.push(i));
1123 assert_eq!(got, (0..130).collect::<Vec<_>>());
1124 }
1125
1126 #[test]
1127 fn test_try_for_each_set_index_stops_on_error() {
1128 for (buffer, stop) in [
1129 (BitBuffer::new_set(130), 65),
1130 (BitBuffer::collect_bool(130, |i| i % 3 == 0), 66),
1131 ] {
1132 let mut visited = Vec::new();
1133 let result = buffer.try_for_each_set_index(|index| {
1134 visited.push(index);
1135 if index == stop {
1136 return Err(index);
1137 }
1138
1139 Ok(())
1140 });
1141
1142 assert_eq!(result, Err(stop));
1143 assert_eq!(
1144 visited,
1145 buffer
1146 .set_indices()
1147 .take_while(|&i| i <= stop)
1148 .collect::<Vec<_>>()
1149 );
1150 }
1151 }
1152
1153 #[test]
1154 fn test_map_cmp_conditional() {
1155 let len = 100;
1157 let buf = BitBuffer::collect_bool(len, |i| i % 2 == 0);
1158
1159 let mapped = buf.map_cmp(|idx, bit| bit && idx % 4 == 0);
1161
1162 for i in 0..len {
1163 let expected = (i % 2 == 0) && (i % 4 == 0);
1164 assert_eq!(mapped.value(i), expected, "Mismatch at index {}", i);
1165 }
1166 }
1167
1168 #[rstest]
1169 #[case(0, 200)]
1170 #[case(3, 197)]
1171 #[case(13, 600)]
1172 fn test_select_unset_sliced(#[case] start: usize, #[case] len: usize) {
1173 let buf = BitBuffer::collect_bool(start + len, |i| i % 3 == 0 || i % 7 == 0);
1174 let sliced = buf.slice(start..start + len);
1175 let expected: Vec<usize> = sliced
1176 .iter()
1177 .enumerate()
1178 .filter_map(|(index, set)| (!set).then_some(index))
1179 .collect();
1180
1181 for (nth, &index) in expected.iter().enumerate() {
1182 assert_eq!(
1183 sliced.select_unset(nth),
1184 Some(index),
1185 "start={start} nth={nth}"
1186 );
1187 }
1188 assert_eq!(sliced.select_unset(expected.len()), None);
1189 }
1190}