Skip to main content

commonware_utils/bitmap/
mod.rs

1//! Bitmap implementation
2//!
3//! The bitmap is a compact representation of a sequence of bits, using chunks of bytes for a
4//! more-efficient memory layout than doing [`Vec<bool>`].
5
6#[cfg(not(feature = "std"))]
7use alloc::{collections::VecDeque, vec::Vec};
8use bytes::{Buf, BufMut};
9use commonware_codec::{EncodeSize, Error as CodecError, Read, ReadExt, Write, util::at_least};
10use core::{
11    fmt::{self, Formatter, Write as _},
12    iter,
13    ops::{BitAnd, BitOr, BitXor, Index, Range},
14};
15#[cfg(feature = "std")]
16use std::collections::VecDeque;
17
18#[cfg(feature = "std")]
19mod atomic;
20#[cfg(feature = "std")]
21pub use atomic::Atomic;
22mod prunable;
23pub use prunable::Prunable;
24
25pub mod historical;
26commonware_macros::stability_mod!(ALPHA, pub mod roaring);
27
28/// The default [BitMap] chunk size in bytes.
29pub const DEFAULT_CHUNK_SIZE: usize = 8;
30
31/// A bitmap that stores data in chunks of N bytes.
32///
33/// # Panics
34///
35/// Operations panic if `bit / CHUNK_SIZE_BITS > usize::MAX`. On 32-bit systems
36/// with N=32, this occurs at bit >= 1,099,511,627,776.
37#[derive(Clone, PartialEq, Eq, Hash)]
38pub struct BitMap<const N: usize = DEFAULT_CHUNK_SIZE> {
39    /// The bitmap itself, in chunks of size N bytes. Within each byte, lowest order bits are
40    /// treated as coming before higher order bits in the bit ordering.
41    ///
42    /// Invariant: `chunks.len() == len.div_ceil(CHUNK_SIZE_BITS)`
43    /// Invariant: All bits at index `i` where `i >= len` must be 0.
44    chunks: VecDeque<[u8; N]>,
45
46    /// The total number of bits stored in the bitmap.
47    len: u64,
48}
49
50impl<const N: usize> BitMap<N> {
51    const _CHUNK_SIZE_NON_ZERO_ASSERT: () = assert!(N > 0, "chunk size must be > 0");
52
53    /// The size of a chunk in bits.
54    pub const CHUNK_SIZE_BITS: u64 = (N * 8) as u64;
55
56    /// A chunk of all 0s.
57    pub const EMPTY_CHUNK: [u8; N] = [0u8; N];
58
59    /// A chunk of all 1s.
60    pub const FULL_CHUNK: [u8; N] = [u8::MAX; N];
61
62    /* Constructors */
63
64    /// Create a new empty bitmap.
65    pub const fn new() -> Self {
66        #[allow(path_statements)]
67        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
68
69        Self {
70            chunks: VecDeque::new(),
71            len: 0,
72        }
73    }
74
75    // Create a new empty bitmap with the capacity to hold `size` bits without reallocating.
76    pub fn with_capacity(size: u64) -> Self {
77        #[allow(path_statements)]
78        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
79
80        Self {
81            chunks: VecDeque::with_capacity(size.div_ceil(Self::CHUNK_SIZE_BITS) as usize),
82            len: 0,
83        }
84    }
85
86    /// Create a new bitmap with `size` bits, with all bits set to 0.
87    pub fn zeroes(size: u64) -> Self {
88        #[allow(path_statements)]
89        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
90
91        let num_chunks = size.div_ceil(Self::CHUNK_SIZE_BITS) as usize;
92        let mut chunks = VecDeque::with_capacity(num_chunks);
93        for _ in 0..num_chunks {
94            chunks.push_back(Self::EMPTY_CHUNK);
95        }
96        Self { chunks, len: size }
97    }
98
99    /// Create a new bitmap with `size` bits, with all bits set to 1.
100    pub fn ones(size: u64) -> Self {
101        #[allow(path_statements)]
102        Self::_CHUNK_SIZE_NON_ZERO_ASSERT; // Prevent compilation for N == 0
103
104        let num_chunks = size.div_ceil(Self::CHUNK_SIZE_BITS) as usize;
105        let mut chunks = VecDeque::with_capacity(num_chunks);
106        for _ in 0..num_chunks {
107            chunks.push_back(Self::FULL_CHUNK);
108        }
109        let mut result = Self { chunks, len: size };
110        // Clear trailing bits to maintain invariant
111        result.clear_trailing_bits();
112        result
113    }
114
115    /// Create a bitmap of `len` bits directly from its chunk representation.
116    ///
117    /// # Panics
118    ///
119    /// Panics if the chunk count does not match `len` or a bit at index >= `len` is set.
120    #[cfg(feature = "std")]
121    fn from_chunks(chunks: VecDeque<[u8; N]>, len: u64) -> Self {
122        assert_eq!(
123            chunks.len() as u64,
124            len.div_ceil(Self::CHUNK_SIZE_BITS),
125            "chunk count does not match len"
126        );
127        let mut bitmap = Self { chunks, len };
128        assert!(!bitmap.clear_trailing_bits(), "bit past len set");
129        bitmap
130    }
131
132    /* Length */
133
134    /// Return the number of bits currently stored in the bitmap.
135    #[inline]
136    pub const fn len(&self) -> u64 {
137        self.len
138    }
139
140    /// Returns true if the bitmap is empty.
141    #[inline]
142    pub const fn is_empty(&self) -> bool {
143        self.len() == 0
144    }
145
146    /// Returns true if the bitmap length is aligned to a chunk boundary.
147    #[inline]
148    pub const fn is_chunk_aligned(&self) -> bool {
149        self.len.is_multiple_of(Self::CHUNK_SIZE_BITS)
150    }
151
152    // Get the number of chunks currently in the bitmap.
153    fn chunks_len(&self) -> usize {
154        self.chunks.len()
155    }
156
157    /* Getters */
158
159    /// Get the value of the bit at the given index.
160    ///
161    /// # Warning
162    ///
163    /// Panics if the bit doesn't exist.
164    #[inline]
165    pub fn get(&self, bit: u64) -> bool {
166        let chunk = self.get_chunk_containing(bit);
167        Self::get_bit_from_chunk(chunk, bit)
168    }
169
170    /// Returns the bitmap chunk containing the given bit.
171    ///
172    /// # Warning
173    ///
174    /// Panics if the bit doesn't exist.
175    #[inline]
176    fn get_chunk_containing(&self, bit: u64) -> &[u8; N] {
177        assert!(
178            bit < self.len(),
179            "bit {} out of bounds (len: {})",
180            bit,
181            self.len()
182        );
183        &self.chunks[Self::to_chunk_index(bit)]
184    }
185
186    /// Get a reference to a chunk by its index in the current bitmap.
187    /// Note this is an index into the chunks, not a bit.
188    ///
189    /// # Warning
190    ///
191    /// Panics if the `chunk` is out of bounds.
192    #[inline]
193    pub(super) fn get_chunk(&self, chunk: usize) -> &[u8; N] {
194        assert!(
195            chunk < self.chunks.len(),
196            "chunk {} out of bounds (chunks: {})",
197            chunk,
198            self.chunks.len()
199        );
200        &self.chunks[chunk]
201    }
202
203    /// Get the value at the given `bit` from the `chunk`.
204    /// `bit` is an index into the entire bitmap, not just the chunk.
205    #[inline]
206    pub const fn get_bit_from_chunk(chunk: &[u8; N], bit: u64) -> bool {
207        let byte = Self::chunk_byte_offset(bit);
208        let byte = chunk[byte];
209        let mask = Self::chunk_byte_bitmask(bit);
210        (byte & mask) != 0
211    }
212
213    /// Return the last chunk of the bitmap and its size in bits.
214    ///
215    /// # Panics
216    ///
217    /// Panics if bitmap is empty.
218    #[inline]
219    fn last_chunk(&self) -> (&[u8; N], u64) {
220        let rem = self.len % Self::CHUNK_SIZE_BITS;
221        let bits_in_last_chunk = if rem == 0 { Self::CHUNK_SIZE_BITS } else { rem };
222        (self.chunks.back().unwrap(), bits_in_last_chunk)
223    }
224
225    /* Setters */
226
227    /// Extend the bitmap to `new_len` bits, filling new positions with zero.
228    /// No-op if `new_len <= self.len`.
229    pub fn extend_to(&mut self, new_len: u64) {
230        if new_len <= self.len {
231            return;
232        }
233        // Allocate any needed new chunks (all zeroed).
234        let new_chunks_needed = new_len.div_ceil(Self::CHUNK_SIZE_BITS) as usize;
235        let current_chunks = self.chunks.len();
236        for _ in current_chunks..new_chunks_needed {
237            self.chunks.push_back(Self::EMPTY_CHUNK);
238        }
239        self.len = new_len;
240    }
241
242    /// Add a single bit to the bitmap.
243    pub fn push(&mut self, bit: bool) {
244        // Check if we need a new chunk
245        if self.is_chunk_aligned() {
246            self.chunks.push_back(Self::EMPTY_CHUNK);
247        }
248
249        // Append to the last chunk
250        if bit {
251            let last_chunk = self.chunks.back_mut().unwrap();
252            let chunk_byte = Self::chunk_byte_offset(self.len);
253            last_chunk[chunk_byte] |= Self::chunk_byte_bitmask(self.len);
254        }
255        // If bit is false, just advance len -- the bit is already 0
256        self.len += 1;
257    }
258
259    /// Remove and return the last bit from the bitmap.
260    ///
261    /// # Warning
262    ///
263    /// Panics if the bitmap is empty.
264    pub fn pop(&mut self) -> bool {
265        assert!(!self.is_empty(), "Cannot pop from empty bitmap");
266
267        // Get the bit value at the last position
268        let last_bit_pos = self.len - 1;
269        let bit = Self::get_bit_from_chunk(self.chunks.back().unwrap(), last_bit_pos);
270
271        // Decrement length
272        self.len -= 1;
273
274        // Clear the bit we just popped to maintain invariant (if it was 1)
275        if bit {
276            let chunk_byte = Self::chunk_byte_offset(last_bit_pos);
277            let mask = Self::chunk_byte_bitmask(last_bit_pos);
278            self.chunks.back_mut().unwrap()[chunk_byte] &= !mask;
279        }
280
281        // Remove the last chunk if it's now empty
282        if self.is_chunk_aligned() {
283            self.chunks.pop_back();
284        }
285
286        bit
287    }
288
289    /// Shrink the bitmap to `new_len` bits, discarding trailing bits.
290    ///
291    /// # Panics
292    ///
293    /// Panics if `new_len > self.len()`.
294    pub fn truncate(&mut self, new_len: u64) {
295        assert!(new_len <= self.len(), "cannot truncate to a larger size");
296
297        // Pop single bits until we can remove full chunks.
298        while self.len > new_len && !self.is_chunk_aligned() {
299            self.pop();
300        }
301
302        // Pop full chunks from the back.
303        while self.len - new_len >= Self::CHUNK_SIZE_BITS {
304            self.pop_chunk();
305        }
306
307        // Pop remaining individual bits.
308        while self.len > new_len {
309            self.pop();
310        }
311    }
312
313    /// Remove and return the last complete chunk from the bitmap.
314    ///
315    /// # Warning
316    ///
317    /// Panics if the bitmap has fewer than `CHUNK_SIZE_BITS` bits or if not chunk-aligned.
318    pub(super) fn pop_chunk(&mut self) -> [u8; N] {
319        assert!(
320            self.len() >= Self::CHUNK_SIZE_BITS,
321            "cannot pop chunk: bitmap has fewer than CHUNK_SIZE_BITS bits"
322        );
323        assert!(
324            self.is_chunk_aligned(),
325            "cannot pop chunk when not chunk aligned"
326        );
327
328        // Remove and return the last data chunk
329        let chunk = self.chunks.pop_back().expect("chunk must exist");
330        self.len -= Self::CHUNK_SIZE_BITS;
331        chunk
332    }
333
334    /// Flips the given bit.
335    ///
336    /// # Panics
337    ///
338    /// Panics if `bit` is out of bounds.
339    #[inline]
340    pub fn flip(&mut self, bit: u64) {
341        self.assert_bit(bit);
342        let chunk = Self::to_chunk_index(bit);
343        let byte = Self::chunk_byte_offset(bit);
344        let mask = Self::chunk_byte_bitmask(bit);
345        self.chunks[chunk][byte] ^= mask;
346    }
347
348    /// Flips all bits (1s become 0s and vice versa).
349    pub fn flip_all(&mut self) {
350        for chunk in &mut self.chunks {
351            for byte in chunk {
352                *byte = !*byte;
353            }
354        }
355        // Clear trailing bits to maintain invariant
356        self.clear_trailing_bits();
357    }
358
359    /// Set the value of the referenced bit.
360    ///
361    /// # Warning
362    ///
363    /// Panics if the bit doesn't exist.
364    pub fn set(&mut self, bit: u64, value: bool) {
365        assert!(
366            bit < self.len(),
367            "bit {} out of bounds (len: {})",
368            bit,
369            self.len()
370        );
371
372        let chunk = &mut self.chunks[Self::to_chunk_index(bit)];
373        let byte = Self::chunk_byte_offset(bit);
374        let mask = Self::chunk_byte_bitmask(bit);
375        if value {
376            chunk[byte] |= mask;
377        } else {
378            chunk[byte] &= !mask;
379        }
380    }
381
382    /// Sets all bits to the specified value.
383    #[inline]
384    pub fn set_all(&mut self, bit: bool) {
385        let value = if bit { u8::MAX } else { 0 };
386        for chunk in &mut self.chunks {
387            chunk.fill(value);
388        }
389        // Clear trailing bits to maintain invariant
390        if bit {
391            self.clear_trailing_bits();
392        }
393    }
394
395    // Add a byte's worth of bits to the bitmap.
396    //
397    // # Warning
398    //
399    // Panics if self.len is not byte aligned.
400    fn push_byte(&mut self, byte: u8) {
401        assert!(
402            self.len.is_multiple_of(8),
403            "cannot add byte when not byte aligned"
404        );
405
406        // Check if we need a new chunk
407        if self.is_chunk_aligned() {
408            self.chunks.push_back(Self::EMPTY_CHUNK);
409        }
410
411        let chunk_byte = Self::chunk_byte_offset(self.len);
412        self.chunks.back_mut().unwrap()[chunk_byte] = byte;
413        self.len += 8;
414    }
415
416    /// Add a chunk of bits to the bitmap.
417    ///
418    /// # Warning
419    ///
420    /// Panics if self.len is not chunk aligned.
421    pub fn push_chunk(&mut self, chunk: &[u8; N]) {
422        assert!(
423            self.is_chunk_aligned(),
424            "cannot add chunk when not chunk aligned"
425        );
426        self.chunks.push_back(*chunk);
427        self.len += Self::CHUNK_SIZE_BITS;
428    }
429
430    /* Invariant Maintenance */
431
432    /// Clear all bits in the last chunk that are >= self.len to maintain the invariant.
433    /// Returns true if any bits were flipped from 1 to 0.
434    fn clear_trailing_bits(&mut self) -> bool {
435        if self.chunks.is_empty() {
436            return false;
437        }
438
439        let pos_in_chunk = self.len % Self::CHUNK_SIZE_BITS;
440        if pos_in_chunk == 0 {
441            // Chunk is full -- there are no trailing bits to clear.
442            return false;
443        }
444
445        let mut flipped_any = false;
446        let last_chunk = self.chunks.back_mut().unwrap();
447
448        // Clear whole bytes after the last valid bit
449        let last_byte_index = ((pos_in_chunk - 1) / 8) as usize;
450        for byte in last_chunk.iter_mut().skip(last_byte_index + 1) {
451            if *byte != 0 {
452                flipped_any = true;
453                *byte = 0;
454            }
455        }
456
457        // Clear the trailing bits in the last partial byte
458        let bits_in_last_byte = pos_in_chunk % 8;
459        if bits_in_last_byte != 0 {
460            let mask = (1u8 << bits_in_last_byte) - 1;
461            let old_byte = last_chunk[last_byte_index];
462            let new_byte = old_byte & mask;
463            if old_byte != new_byte {
464                flipped_any = true;
465                last_chunk[last_byte_index] = new_byte;
466            }
467        }
468
469        flipped_any
470    }
471
472    /* Pruning */
473
474    /// Remove the first `chunks` chunks from the bitmap.
475    ///
476    /// # Warning
477    ///
478    /// Panics if trying to prune more chunks than exist.
479    fn prune_chunks(&mut self, chunks: usize) {
480        assert!(
481            chunks <= self.chunks.len(),
482            "cannot prune {chunks} chunks, only {} available",
483            self.chunks.len()
484        );
485        self.chunks.drain(..chunks);
486        // Update len to reflect the removed chunks
487        let bits_removed = (chunks as u64) * Self::CHUNK_SIZE_BITS;
488        self.len = self.len.saturating_sub(bits_removed);
489    }
490
491    /// Prepend a chunk to the beginning of the bitmap.
492    pub(super) fn prepend_chunk(&mut self, chunk: &[u8; N]) {
493        self.chunks.push_front(*chunk);
494        self.len += Self::CHUNK_SIZE_BITS;
495    }
496
497    /// Overwrite a chunk's data at the given index.
498    ///
499    /// Replaces the entire chunk data, including any bits beyond `len()` in the last chunk.
500    /// The caller is responsible for ensuring `chunk_data` has the correct bit pattern
501    /// (e.g., zeros beyond the valid length if this is a partial last chunk).
502    ///
503    /// # Panics
504    ///
505    /// Panics if chunk_index is out of bounds.
506    pub(super) fn set_chunk_by_index(&mut self, chunk_index: usize, chunk_data: &[u8; N]) {
507        assert!(
508            chunk_index < self.chunks.len(),
509            "chunk index {chunk_index} out of bounds (chunks_len: {})",
510            self.chunks.len()
511        );
512        self.chunks[chunk_index].copy_from_slice(chunk_data);
513    }
514
515    /* Counting */
516
517    /// Returns the number of bits set to 1.
518    #[inline]
519    pub fn count_ones(&self) -> u64 {
520        // Thanks to the invariant that trailing bits are always 0,
521        // we can simply count all set bits in all chunks.
522        // Iterate over both contiguous deque segments and count 64-bit words first.
523        let (front, back) = self.chunks.as_slices();
524        Self::count_ones_in_chunk_slice(front) + Self::count_ones_in_chunk_slice(back)
525    }
526
527    #[inline]
528    fn count_ones_in_chunk_slice(chunks: &[[u8; N]]) -> u64 {
529        let mut total = 0u64;
530        let (words, remainder) = chunks.as_flattened().as_chunks::<8>();
531        for word in words {
532            total += u64::from_le_bytes(*word).count_ones() as u64;
533        }
534        for byte in remainder {
535            total += byte.count_ones() as u64;
536        }
537        total
538    }
539
540    /// Returns the number of bits set to 0.
541    #[inline]
542    pub fn count_zeros(&self) -> u64 {
543        self.len() - self.count_ones()
544    }
545
546    /* Indexing Helpers */
547
548    /// Convert a bit offset into a bitmask for the byte containing that bit.
549    #[inline]
550    pub(super) const fn chunk_byte_bitmask(bit: u64) -> u8 {
551        1 << (bit % 8)
552    }
553
554    /// Convert a bit into the index of the byte within a chunk containing the bit.
555    #[inline]
556    pub(super) const fn chunk_byte_offset(bit: u64) -> usize {
557        ((bit / 8) % N as u64) as usize
558    }
559
560    /// Convert a bit into the index of the chunk it belongs to.
561    ///
562    /// # Panics
563    ///
564    /// Panics if the chunk index overflows `usize`.
565    #[inline]
566    pub(super) fn to_chunk_index(bit: u64) -> usize {
567        let chunk = bit / Self::CHUNK_SIZE_BITS;
568        assert!(
569            chunk <= usize::MAX as u64,
570            "chunk overflow: {chunk} exceeds usize::MAX",
571        );
572        chunk as usize
573    }
574
575    /* Iterator */
576
577    /// Creates an iterator over the bits.
578    pub const fn iter(&self) -> Iterator<'_, N> {
579        Iterator {
580            bitmap: self,
581            pos: 0,
582        }
583    }
584
585    /// Returns an iterator over the indices of set bits.
586    pub fn ones_iter(&self) -> OnesIter<'_, Self, N> {
587        Readable::ones_iter_from(self, 0)
588    }
589
590    /* Bitwise Operations */
591
592    /// Helper for binary operations
593    #[inline]
594    fn binary_op<F: Fn(u8, u8) -> u8>(&mut self, other: &Self, op: F) {
595        self.assert_eq_len(other);
596        for (a_chunk, b_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
597            for (a_byte, b_byte) in a_chunk.iter_mut().zip(b_chunk.iter()) {
598                *a_byte = op(*a_byte, *b_byte);
599            }
600        }
601        // Clear trailing bits to maintain invariant
602        self.clear_trailing_bits();
603    }
604
605    /// Performs a bitwise AND with another BitMap.
606    ///
607    /// # Panics
608    ///
609    /// Panics if the lengths don't match.
610    pub fn and(&mut self, other: &Self) {
611        self.binary_op(other, |a, b| a & b);
612    }
613
614    /// Performs a bitwise OR with another BitMap.
615    ///
616    /// # Panics
617    ///
618    /// Panics if the lengths don't match.
619    pub fn or(&mut self, other: &Self) {
620        self.binary_op(other, |a, b| a | b);
621    }
622
623    /// Performs a bitwise XOR with another BitMap.
624    ///
625    /// # Panics
626    ///
627    /// Panics if the lengths don't match.
628    pub fn xor(&mut self, other: &Self) {
629        self.binary_op(other, |a, b| a ^ b);
630    }
631
632    /* Assertions */
633
634    /// Asserts that the bit is within bounds.
635    #[inline(always)]
636    fn assert_bit(&self, bit: u64) {
637        assert!(
638            bit < self.len(),
639            "bit {} out of bounds (len: {})",
640            bit,
641            self.len()
642        );
643    }
644
645    /// Asserts that the lengths of two [BitMap]s match.
646    #[inline(always)]
647    fn assert_eq_len(&self, other: &Self) {
648        assert_eq!(
649            self.len(),
650            other.len(),
651            "BitMap lengths don't match: {} vs {}",
652            self.len(),
653            other.len()
654        );
655    }
656
657    /// Check if all the bits in a given range are 0.
658    ///
659    /// Returns `true` if every index in the range is unset (i.e.
660    /// [`Self::get`] returns `false`). Returns `true` if the range
661    /// is empty.
662    ///
663    /// # Panics
664    ///
665    /// Panics if `range.end` exceeds the length of the bitmap.
666    ///
667    /// # Examples
668    ///
669    /// ```
670    /// use commonware_utils::bitmap::BitMap;
671    ///
672    /// let mut bitmap = BitMap::<8>::zeroes(128);
673    /// assert!(bitmap.is_unset(0..128));
674    ///
675    /// bitmap.set(64, true);
676    /// assert!(bitmap.is_unset(0..64));
677    /// assert!(!bitmap.is_unset(0..65));
678    /// ```
679    pub fn is_unset(&self, range: Range<u64>) -> bool {
680        assert!(
681            range.end <= self.len(),
682            "range end {} out of bounds (len: {})",
683            range.end,
684            self.len()
685        );
686        if range.start >= range.end {
687            return true;
688        }
689        let start = range.start;
690        let end = range.end;
691
692        // We know this can't underflow, because start < end.
693        //
694        // We now want "end" to represent the last bit we want to consider.
695        let end = end - 1;
696
697        // Get the chunks containing the start and end bits.
698        let first_chunk = Self::to_chunk_index(start);
699        let last_chunk = Self::to_chunk_index(end);
700
701        // All of these chunks require all of their bits to be checked.
702        // If first_chunk == last_chunk, we skip the loop.
703        for full_chunk in (first_chunk + 1)..last_chunk {
704            if self.chunks[full_chunk] != Self::EMPTY_CHUNK {
705                return false;
706            }
707        }
708
709        // Check first chunk tail (or whole range if first_chunk == last_chunk).
710        let start_byte = Self::chunk_byte_offset(start);
711        let end_byte = Self::chunk_byte_offset(end);
712        let start_mask = (0xFFu16 << ((start & 0b111) as u32)) as u8;
713        let end_mask = (0xFFu16 >> (7 - ((end & 0b111) as u32))) as u8;
714        let first = &self.chunks[first_chunk];
715        let first_end_byte = if first_chunk == last_chunk {
716            end_byte
717        } else {
718            N - 1
719        };
720        for (i, &byte) in first
721            .iter()
722            .enumerate()
723            .take(first_end_byte + 1)
724            .skip(start_byte)
725        {
726            let mut mask = 0xFFu8;
727            if i == start_byte {
728                mask &= start_mask;
729            }
730            if first_chunk == last_chunk && i == end_byte {
731                mask &= end_mask;
732            }
733            if (byte & mask) != 0 {
734                return false;
735            }
736        }
737        if first_chunk == last_chunk {
738            return true;
739        }
740
741        // Check last chunk head.
742        let last = &self.chunks[last_chunk];
743        for (i, &byte) in last.iter().enumerate().take(end_byte + 1) {
744            let mask = if i == end_byte { end_mask } else { 0xFF };
745            if (byte & mask) != 0 {
746                return false;
747            }
748        }
749
750        true
751    }
752}
753
754impl<const N: usize> Default for BitMap<N> {
755    fn default() -> Self {
756        Self::new()
757    }
758}
759
760impl<T: AsRef<[bool]>, const N: usize> From<T> for BitMap<N> {
761    fn from(t: T) -> Self {
762        let bools = t.as_ref();
763        let mut bv = Self::with_capacity(bools.len() as u64);
764        for &b in bools {
765            bv.push(b);
766        }
767        bv
768    }
769}
770
771impl<const N: usize> From<BitMap<N>> for Vec<bool> {
772    fn from(bv: BitMap<N>) -> Self {
773        bv.iter().collect()
774    }
775}
776
777impl<const N: usize> fmt::Debug for BitMap<N> {
778    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
779        // For very large BitMaps, only show a preview
780        const MAX_DISPLAY: u64 = 64;
781        const HALF_DISPLAY: u64 = MAX_DISPLAY / 2;
782
783        // Closure for writing a bit
784        let write_bit = |formatter: &mut Formatter<'_>, bit: u64| -> core::fmt::Result {
785            formatter.write_char(if self.get(bit) { '1' } else { '0' })
786        };
787
788        f.write_str("BitMap[")?;
789        let len = self.len();
790        if len <= MAX_DISPLAY {
791            // Show all bits
792            for i in 0..len {
793                write_bit(f, i)?;
794            }
795        } else {
796            // Show first and last bits with ellipsis
797            for i in 0..HALF_DISPLAY {
798                write_bit(f, i)?;
799            }
800
801            f.write_str("...")?;
802
803            for i in (len - HALF_DISPLAY)..len {
804                write_bit(f, i)?;
805            }
806        }
807        f.write_str("]")
808    }
809}
810
811impl<const N: usize> Index<u64> for BitMap<N> {
812    type Output = bool;
813
814    /// Allows accessing bits using the `[]` operator.
815    ///
816    /// Panics if out of bounds.
817    #[inline]
818    fn index(&self, bit: u64) -> &Self::Output {
819        self.assert_bit(bit);
820        let value = self.get(bit);
821        if value { &true } else { &false }
822    }
823}
824
825impl<const N: usize> BitAnd for &BitMap<N> {
826    type Output = BitMap<N>;
827
828    fn bitand(self, rhs: Self) -> Self::Output {
829        self.assert_eq_len(rhs);
830        let mut result = self.clone();
831        result.and(rhs);
832        result
833    }
834}
835
836impl<const N: usize> BitOr for &BitMap<N> {
837    type Output = BitMap<N>;
838
839    fn bitor(self, rhs: Self) -> Self::Output {
840        self.assert_eq_len(rhs);
841        let mut result = self.clone();
842        result.or(rhs);
843        result
844    }
845}
846
847impl<const N: usize> BitXor for &BitMap<N> {
848    type Output = BitMap<N>;
849
850    fn bitxor(self, rhs: Self) -> Self::Output {
851        self.assert_eq_len(rhs);
852        let mut result = self.clone();
853        result.xor(rhs);
854        result
855    }
856}
857
858impl<const N: usize> Write for BitMap<N> {
859    fn write(&self, buf: &mut impl BufMut) {
860        // Prefix with the number of bits
861        self.len().write(buf);
862
863        // Write all chunks
864        let (front, back) = self.chunks.as_slices();
865        buf.put_slice(front.as_flattened());
866        buf.put_slice(back.as_flattened());
867    }
868}
869
870impl<const N: usize> Read for BitMap<N> {
871    type Cfg = u64; // Max bitmap length
872
873    fn read_cfg(buf: &mut impl Buf, max_len: &Self::Cfg) -> Result<Self, CodecError> {
874        // Parse length in bits
875        let len = u64::read(buf)?;
876        if len > *max_len {
877            return Err(CodecError::InvalidLength(len as usize));
878        }
879
880        // Calculate how many chunks we need to read
881        let num_chunks = len.div_ceil(Self::CHUNK_SIZE_BITS) as usize;
882
883        // Parse chunks
884        let mut chunks = VecDeque::with_capacity(num_chunks);
885        for _ in 0..num_chunks {
886            at_least(buf, N)?;
887            let mut chunk = [0u8; N];
888            buf.copy_to_slice(&mut chunk);
889            chunks.push_back(chunk);
890        }
891
892        let mut result = Self { chunks, len };
893
894        // Verify trailing bits are zero (maintain invariant)
895        if result.clear_trailing_bits() {
896            return Err(CodecError::Invalid(
897                "BitMap",
898                "Invalid trailing bits in encoded data",
899            ));
900        }
901
902        Ok(result)
903    }
904}
905
906impl<const N: usize> EncodeSize for BitMap<N> {
907    fn encode_size(&self) -> usize {
908        // Size of length prefix + all chunks
909        self.len().encode_size() + (self.chunks.len() * N)
910    }
911}
912
913/// Iterator over bits in a [BitMap].
914pub struct Iterator<'a, const N: usize> {
915    /// Reference to the BitMap being iterated over
916    bitmap: &'a BitMap<N>,
917
918    /// Current index in the BitMap
919    pos: u64,
920}
921
922impl<const N: usize> iter::Iterator for Iterator<'_, N> {
923    type Item = bool;
924
925    fn next(&mut self) -> Option<Self::Item> {
926        if self.pos >= self.bitmap.len() {
927            return None;
928        }
929
930        let bit = self.bitmap.get(self.pos);
931        self.pos += 1;
932        Some(bit)
933    }
934
935    fn size_hint(&self) -> (usize, Option<usize>) {
936        let remaining = self.bitmap.len().saturating_sub(self.pos);
937        let capped = remaining.min(usize::MAX as u64) as usize;
938        (capped, Some(capped))
939    }
940}
941
942impl<const N: usize> ExactSizeIterator for Iterator<'_, N> {}
943
944/// Read-only access to a bitmap's chunks and metadata.
945pub trait Readable<const N: usize> {
946    /// Return the number of complete (fully filled) chunks.
947    fn complete_chunks(&self) -> usize;
948
949    /// Return the chunk data at the given absolute chunk index.
950    fn get_chunk(&self, chunk: usize) -> [u8; N];
951
952    /// Return the last chunk and its size in bits.
953    fn last_chunk(&self) -> ([u8; N], u64);
954
955    /// Return the number of pruned chunks.
956    fn pruned_chunks(&self) -> usize;
957
958    /// Return the total number of bits.
959    fn len(&self) -> u64;
960
961    /// Returns true if the bitmap is empty.
962    fn is_empty(&self) -> bool {
963        self.len() == 0
964    }
965
966    /// Return the number of pruned bits (i.e. pruned chunks * bits per chunk).
967    fn pruned_bits(&self) -> u64 {
968        (self.pruned_chunks() as u64) * BitMap::<N>::CHUNK_SIZE_BITS
969    }
970
971    /// Return the value of a single bit.
972    fn get_bit(&self, bit: u64) -> bool {
973        let chunk = self.get_chunk(BitMap::<N>::to_chunk_index(bit));
974        BitMap::<N>::get_bit_from_chunk(&chunk, bit % BitMap::<N>::CHUNK_SIZE_BITS)
975    }
976
977    /// Returns an iterator over the indices of set bits starting from `pos`.
978    ///
979    /// If `pos` falls within a pruned region, iteration starts at the first
980    /// unpruned bit instead.
981    fn ones_iter_from(&self, pos: u64) -> OnesIter<'_, Self, N>
982    where
983        Self: Sized,
984    {
985        let len = self.len();
986        let pruned_start = self.pruned_bits();
987        let pos = pos.max(pruned_start);
988        let mut iter = OnesIter {
989            bitmap: self,
990            len,
991            base: len,
992            word: 0,
993            chunk: [0; N],
994        };
995        if pos < len {
996            let chunk_idx = BitMap::<N>::to_chunk_index(pos);
997            let chunk_start = chunk_idx as u64 * BitMap::<N>::CHUNK_SIZE_BITS;
998            iter.chunk = self.get_chunk(chunk_idx);
999            iter.base = chunk_start + (pos - chunk_start) / 64 * 64;
1000            iter.word = iter.load_word() & (u64::MAX << (pos - iter.base));
1001        }
1002        iter
1003    }
1004}
1005
1006impl<const N: usize> Readable<N> for BitMap<N> {
1007    fn complete_chunks(&self) -> usize {
1008        self.chunks_len()
1009            .saturating_sub(if self.is_chunk_aligned() { 0 } else { 1 })
1010    }
1011
1012    fn get_chunk(&self, chunk: usize) -> [u8; N] {
1013        *Self::get_chunk(self, chunk)
1014    }
1015
1016    fn last_chunk(&self) -> ([u8; N], u64) {
1017        let (c, n) = Self::last_chunk(self);
1018        (*c, n)
1019    }
1020
1021    fn pruned_chunks(&self) -> usize {
1022        0
1023    }
1024
1025    fn len(&self) -> u64 {
1026        self.len
1027    }
1028}
1029
1030/// Iterator over the indices of set (1) bits in a bitmap.
1031///
1032/// If the starting position falls within a pruned region, iteration
1033/// begins at the first unpruned bit.
1034///
1035/// `len` and the current chunk are read from the bitmap once and reused (the chunk until
1036/// iteration crosses into the next one), so the bitmap's contents must not change for the
1037/// iterator's lifetime. Owned bitmaps (`BitMap`, `Prunable`) guarantee this through the
1038/// immutable borrow. A `Readable` whose reads go through interior mutability (e.g. a
1039/// lock-guarded shared bitmap) instead requires the caller to prevent concurrent mutation
1040/// across the whole iteration, for example by constructing the iterator from a held read
1041/// guard rather than a bare shared reference.
1042pub struct OnesIter<'a, B, const N: usize> {
1043    bitmap: &'a B,
1044    /// Cached `bitmap.len()` at iterator construction. For layered bitmaps, `len()`
1045    /// walks the layer chain, so caching this avoids that walk on every `next`.
1046    len: u64,
1047    /// Bit index of bit 0 of `word`. Always a 64-bit word boundary relative to the start
1048    /// of its chunk, except when the iterator is constructed exhausted (then `len`).
1049    base: u64,
1050    /// Set bits of the bitmap word at `base` that have not been yielded yet.
1051    word: u64,
1052    /// The chunk containing `base`. Retaining it serves every word of a multi-word chunk
1053    /// with one fetch (and, for layered bitmaps, one layer resolution) rather than one
1054    /// fetch per yielded bit.
1055    chunk: [u8; N],
1056}
1057
1058impl<B: Readable<N>, const N: usize> OnesIter<'_, B, N> {
1059    /// Load the word at `base` from `chunk`, masking off bits at or beyond `len`.
1060    ///
1061    /// Requires `base < len` and that `chunk` is the chunk containing `base`. Chunks
1062    /// shorter than a word (`N < 8`) and trailing sub-word regions (`N % 8 != 0`) are
1063    /// zero-padded.
1064    fn load_word(&self) -> u64 {
1065        let off = ((self.base % BitMap::<N>::CHUNK_SIZE_BITS) / 8) as usize;
1066        let take = (N - off).min(8);
1067        let mut buf = [0u8; 8];
1068        buf[..take].copy_from_slice(&self.chunk[off..off + take]);
1069        let mut word = u64::from_le_bytes(buf);
1070        let rem = self.len - self.base;
1071        if rem < 64 {
1072            word &= (1 << rem) - 1;
1073        }
1074        word
1075    }
1076}
1077
1078impl<B: Readable<N>, const N: usize> iter::Iterator for OnesIter<'_, B, N> {
1079    type Item = u64;
1080
1081    fn next(&mut self) -> Option<u64> {
1082        let chunk_bits = BitMap::<N>::CHUNK_SIZE_BITS;
1083        while self.word == 0 {
1084            // Advance to the next word: either the next 64-bit stride of the current
1085            // chunk or the first word of the next chunk. Checked, because a heavily
1086            // pruned bitmap can end within one stride of u64::MAX.
1087            let rel = self.base % chunk_bits;
1088            let same_chunk = rel + 64 < chunk_bits;
1089            let stride = if same_chunk { 64 } else { chunk_bits - rel };
1090            let next = self.base.checked_add(stride)?;
1091            if next >= self.len {
1092                return None;
1093            }
1094            self.base = next;
1095            if !same_chunk {
1096                self.chunk = self.bitmap.get_chunk(BitMap::<N>::to_chunk_index(next));
1097            }
1098            self.word = self.load_word();
1099        }
1100        let bit = self.word.trailing_zeros() as u64;
1101        self.word &= self.word - 1;
1102        Some(self.base + bit)
1103    }
1104}
1105
1106#[cfg(feature = "arbitrary")]
1107impl<const N: usize> arbitrary::Arbitrary<'_> for BitMap<N> {
1108    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
1109        let size = u.int_in_range(0..=1024)?;
1110        let mut bits = Self::with_capacity(size);
1111        for _ in 0..size {
1112            bits.push(u.arbitrary::<bool>()?);
1113        }
1114        Ok(bits)
1115    }
1116}
1117
1118#[cfg(test)]
1119mod tests {
1120    use super::*;
1121    use crate::test_rng;
1122    use bytes::BytesMut;
1123    use commonware_codec::{Decode, Encode};
1124    use commonware_formatting::hex;
1125    use rand::RngExt as _;
1126
1127    #[test]
1128    fn test_constructors() {
1129        // Test new()
1130        let bv: BitMap<4> = BitMap::new();
1131        assert_eq!(bv.len(), 0);
1132        assert!(bv.is_empty());
1133
1134        // Test default()
1135        let bv: BitMap<4> = Default::default();
1136        assert_eq!(bv.len(), 0);
1137        assert!(bv.is_empty());
1138
1139        // Test with_capacity()
1140        let bv: BitMap<4> = BitMap::with_capacity(0);
1141        assert_eq!(bv.len(), 0);
1142        assert!(bv.is_empty());
1143
1144        let bv: BitMap<4> = BitMap::with_capacity(10);
1145        assert_eq!(bv.len(), 0);
1146        assert!(bv.is_empty());
1147    }
1148
1149    #[test]
1150    fn test_zeroes() {
1151        let bv: BitMap<1> = BitMap::zeroes(0);
1152        assert_eq!(bv.len(), 0);
1153        assert!(bv.is_empty());
1154        assert_eq!(bv.count_ones(), 0);
1155        assert_eq!(bv.count_zeros(), 0);
1156
1157        let bv: BitMap<1> = BitMap::zeroes(1);
1158        assert_eq!(bv.len(), 1);
1159        assert!(!bv.is_empty());
1160        assert_eq!(bv.len(), 1);
1161        assert!(!bv.get(0));
1162        assert_eq!(bv.count_ones(), 0);
1163        assert_eq!(bv.count_zeros(), 1);
1164
1165        let bv: BitMap<1> = BitMap::zeroes(10);
1166        assert_eq!(bv.len(), 10);
1167        assert!(!bv.is_empty());
1168        assert_eq!(bv.len(), 10);
1169        for i in 0..10 {
1170            assert!(!bv.get(i as u64));
1171        }
1172        assert_eq!(bv.count_ones(), 0);
1173        assert_eq!(bv.count_zeros(), 10);
1174    }
1175
1176    #[test]
1177    fn test_ones() {
1178        let bv: BitMap<1> = BitMap::ones(0);
1179        assert_eq!(bv.len(), 0);
1180        assert!(bv.is_empty());
1181        assert_eq!(bv.count_ones(), 0);
1182        assert_eq!(bv.count_zeros(), 0);
1183
1184        let bv: BitMap<1> = BitMap::ones(1);
1185        assert_eq!(bv.len(), 1);
1186        assert!(!bv.is_empty());
1187        assert_eq!(bv.len(), 1);
1188        assert!(bv.get(0));
1189        assert_eq!(bv.count_ones(), 1);
1190        assert_eq!(bv.count_zeros(), 0);
1191
1192        let bv: BitMap<1> = BitMap::ones(10);
1193        assert_eq!(bv.len(), 10);
1194        assert!(!bv.is_empty());
1195        assert_eq!(bv.len(), 10);
1196        for i in 0..10 {
1197            assert!(bv.get(i as u64));
1198        }
1199        assert_eq!(bv.count_ones(), 10);
1200        assert_eq!(bv.count_zeros(), 0);
1201    }
1202
1203    #[test]
1204    fn test_invariant_trailing_bits_are_zero() {
1205        // Helper function to check the invariant
1206        fn check_trailing_bits_zero<const N: usize>(bitmap: &BitMap<N>) {
1207            let (last_chunk, next_bit) = bitmap.last_chunk();
1208
1209            // Check that all bits >= next_bit in the last chunk are 0
1210            for bit_idx in next_bit..((N * 8) as u64) {
1211                let byte_idx = (bit_idx / 8) as usize;
1212                let bit_in_byte = bit_idx % 8;
1213                let mask = 1u8 << bit_in_byte;
1214                assert_eq!(last_chunk[byte_idx] & mask, 0);
1215            }
1216        }
1217
1218        // Test ones() constructor
1219        let bv: BitMap<4> = BitMap::ones(15);
1220        check_trailing_bits_zero(&bv);
1221
1222        let bv: BitMap<4> = BitMap::ones(33);
1223        check_trailing_bits_zero(&bv);
1224
1225        // Test after push operations
1226        let mut bv: BitMap<4> = BitMap::new();
1227        for i in 0..37 {
1228            bv.push(i % 2 == 0);
1229            check_trailing_bits_zero(&bv);
1230        }
1231
1232        // Test after pop operations
1233        let mut bv: BitMap<4> = BitMap::ones(40);
1234        check_trailing_bits_zero(&bv);
1235        for _ in 0..15 {
1236            bv.pop();
1237            check_trailing_bits_zero(&bv);
1238        }
1239
1240        // Test after flip_all
1241        let mut bv: BitMap<4> = BitMap::ones(25);
1242        bv.flip_all();
1243        check_trailing_bits_zero(&bv);
1244
1245        // Test after binary operations
1246        let bv1: BitMap<4> = BitMap::ones(20);
1247        let bv2: BitMap<4> = BitMap::zeroes(20);
1248
1249        let mut bv_and = bv1.clone();
1250        bv_and.and(&bv2);
1251        check_trailing_bits_zero(&bv_and);
1252
1253        let mut bv_or = bv1.clone();
1254        bv_or.or(&bv2);
1255        check_trailing_bits_zero(&bv_or);
1256
1257        let mut bv_xor = bv1;
1258        bv_xor.xor(&bv2);
1259        check_trailing_bits_zero(&bv_xor);
1260
1261        // Test after deserialization
1262        let original: BitMap<4> = BitMap::ones(27);
1263        let encoded = original.encode();
1264        let decoded: BitMap<4> =
1265            BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
1266        check_trailing_bits_zero(&decoded);
1267
1268        // Test clear_trailing_bits return value
1269        let mut bv_clean: BitMap<4> = BitMap::ones(20);
1270        // Should return false since ones() already clears trailing bits
1271        assert!(!bv_clean.clear_trailing_bits());
1272
1273        // Create a bitmap with invalid trailing bits by manually setting them
1274        let mut bv_dirty: BitMap<4> = BitMap::ones(20);
1275        // Manually corrupt the last chunk to have trailing bits set
1276        let last_chunk = bv_dirty.chunks.back_mut().unwrap();
1277        last_chunk[3] |= 0xF0; // Set some high bits in the last byte
1278        // Should return true since we had invalid trailing bits
1279        assert!(bv_dirty.clear_trailing_bits());
1280        // After clearing, should return false
1281        assert!(!bv_dirty.clear_trailing_bits());
1282        check_trailing_bits_zero(&bv_dirty);
1283    }
1284
1285    #[test]
1286    fn test_get_set() {
1287        let mut bv: BitMap<4> = BitMap::new();
1288
1289        // Test initial state
1290        assert_eq!(bv.len(), 0);
1291        assert!(bv.is_empty());
1292
1293        // Test push
1294        bv.push(true);
1295        bv.push(false);
1296        bv.push(true);
1297        assert_eq!(bv.len(), 3);
1298        assert!(!bv.is_empty());
1299
1300        // Test get
1301        assert!(bv.get(0));
1302        assert!(!bv.get(1));
1303        assert!(bv.get(2));
1304
1305        bv.set(1, true);
1306        assert!(bv.get(1));
1307        bv.set(2, false);
1308        assert!(!bv.get(2));
1309
1310        // Test flip
1311        bv.flip(0); // true -> false
1312        assert!(!bv.get(0));
1313        bv.flip(0); // false -> true
1314        assert!(bv.get(0));
1315    }
1316
1317    #[test]
1318    fn test_chunk_operations() {
1319        let mut bv: BitMap<4> = BitMap::new();
1320        let test_chunk = hex!("0xABCDEF12");
1321
1322        // Test push_chunk
1323        bv.push_chunk(&test_chunk);
1324        assert_eq!(bv.len(), 32); // 4 bytes * 8 bits
1325
1326        // Test get_chunk
1327        let chunk = bv.get_chunk(0);
1328        assert_eq!(chunk, &test_chunk);
1329
1330        // Test get_chunk_containing
1331        let chunk = bv.get_chunk_containing(0);
1332        assert_eq!(chunk, &test_chunk);
1333
1334        // Test last_chunk
1335        let (last_chunk, next_bit) = bv.last_chunk();
1336        assert_eq!(next_bit, BitMap::<4>::CHUNK_SIZE_BITS); // Should be at chunk boundary
1337        assert_eq!(last_chunk, &test_chunk); // The chunk we just pushed
1338    }
1339
1340    #[test]
1341    fn test_pop() {
1342        let mut bv: BitMap<3> = BitMap::new();
1343        bv.push(true);
1344        assert!(bv.pop());
1345        assert_eq!(bv.len(), 0);
1346
1347        bv.push(false);
1348        assert!(!bv.pop());
1349        assert_eq!(bv.len(), 0);
1350
1351        bv.push(true);
1352        bv.push(false);
1353        bv.push(true);
1354        assert!(bv.pop());
1355        assert_eq!(bv.len(), 2);
1356        assert!(!bv.pop());
1357        assert_eq!(bv.len(), 1);
1358        assert!(bv.pop());
1359        assert_eq!(bv.len(), 0);
1360
1361        for i in 0..100 {
1362            bv.push(i % 2 == 0);
1363        }
1364        assert_eq!(bv.len(), 100);
1365        for i in (0..100).rev() {
1366            assert_eq!(bv.pop(), i % 2 == 0);
1367        }
1368        assert_eq!(bv.len(), 0);
1369        assert!(bv.is_empty());
1370    }
1371
1372    #[test]
1373    fn test_truncate() {
1374        let mut bv: BitMap<4> = BitMap::new();
1375        let expected: Vec<bool> = (0..70).map(|i| i % 3 == 0).collect();
1376        for &bit in &expected {
1377            bv.push(bit);
1378        }
1379
1380        bv.truncate(65);
1381        assert_eq!(bv.len(), 65);
1382        for i in 0..65 {
1383            assert_eq!(bv.get(i), expected[i as usize]);
1384        }
1385
1386        bv.truncate(32);
1387        assert_eq!(bv.len(), 32);
1388        for i in 0..32 {
1389            assert_eq!(bv.get(i), expected[i as usize]);
1390        }
1391
1392        bv.truncate(0);
1393        assert_eq!(bv.len(), 0);
1394        assert!(bv.is_empty());
1395    }
1396
1397    #[test]
1398    #[should_panic(expected = "cannot truncate to a larger size")]
1399    fn test_truncate_larger_size_panics() {
1400        let mut bv: BitMap<4> = BitMap::new();
1401        bv.push(true);
1402        bv.truncate(2);
1403    }
1404
1405    #[test]
1406    fn test_pop_chunk() {
1407        let mut bv: BitMap<3> = BitMap::new();
1408        const CHUNK_SIZE: u64 = BitMap::<3>::CHUNK_SIZE_BITS;
1409
1410        // Test 1: Pop a single chunk and verify it returns the correct data
1411        let chunk1 = hex!("0xAABBCC");
1412        bv.push_chunk(&chunk1);
1413        assert_eq!(bv.len(), CHUNK_SIZE);
1414        let popped = bv.pop_chunk();
1415        assert_eq!(popped, chunk1);
1416        assert_eq!(bv.len(), 0);
1417        assert!(bv.is_empty());
1418
1419        // Test 2: Pop multiple chunks in reverse order
1420        let chunk2 = hex!("0x112233");
1421        let chunk3 = hex!("0x445566");
1422        let chunk4 = hex!("0x778899");
1423
1424        bv.push_chunk(&chunk2);
1425        bv.push_chunk(&chunk3);
1426        bv.push_chunk(&chunk4);
1427        assert_eq!(bv.len(), CHUNK_SIZE * 3);
1428
1429        assert_eq!(bv.pop_chunk(), chunk4);
1430        assert_eq!(bv.len(), CHUNK_SIZE * 2);
1431
1432        assert_eq!(bv.pop_chunk(), chunk3);
1433        assert_eq!(bv.len(), CHUNK_SIZE);
1434
1435        assert_eq!(bv.pop_chunk(), chunk2);
1436        assert_eq!(bv.len(), 0);
1437
1438        // Test 3: Verify data integrity when popping chunks
1439        let first_chunk = hex!("0xAABBCC");
1440        let second_chunk = hex!("0x112233");
1441        bv.push_chunk(&first_chunk);
1442        bv.push_chunk(&second_chunk);
1443
1444        // Pop the second chunk, verify it and that first chunk is intact
1445        assert_eq!(bv.pop_chunk(), second_chunk);
1446        assert_eq!(bv.len(), CHUNK_SIZE);
1447
1448        for i in 0..CHUNK_SIZE {
1449            let byte_idx = (i / 8) as usize;
1450            let bit_idx = i % 8;
1451            let expected = (first_chunk[byte_idx] >> bit_idx) & 1 == 1;
1452            assert_eq!(bv.get(i), expected);
1453        }
1454
1455        assert_eq!(bv.pop_chunk(), first_chunk);
1456        assert_eq!(bv.len(), 0);
1457    }
1458
1459    #[test]
1460    #[should_panic(expected = "cannot pop chunk when not chunk aligned")]
1461    fn test_pop_chunk_not_aligned() {
1462        let mut bv: BitMap<3> = BitMap::new();
1463
1464        // Push a full chunk plus one bit
1465        bv.push_chunk(&[0xFF; 3]);
1466        bv.push(true);
1467
1468        // Should panic because not chunk-aligned
1469        bv.pop_chunk();
1470    }
1471
1472    #[test]
1473    #[should_panic(expected = "cannot pop chunk: bitmap has fewer than CHUNK_SIZE_BITS bits")]
1474    fn test_pop_chunk_insufficient_bits() {
1475        let mut bv: BitMap<3> = BitMap::new();
1476
1477        // Push only a few bits (less than a full chunk)
1478        bv.push(true);
1479        bv.push(false);
1480
1481        // Should panic because we don't have a full chunk to pop
1482        bv.pop_chunk();
1483    }
1484
1485    #[test]
1486    fn test_byte_operations() {
1487        let mut bv: BitMap<4> = BitMap::new();
1488
1489        // Test push_byte
1490        bv.push_byte(0xFF);
1491        assert_eq!(bv.len(), 8);
1492
1493        // All bits in the byte should be set
1494        for i in 0..8 {
1495            assert!(bv.get(i as u64));
1496        }
1497
1498        bv.push_byte(0x00);
1499        assert_eq!(bv.len(), 16);
1500
1501        // All bits in the second byte should be clear
1502        for i in 8..16 {
1503            assert!(!bv.get(i as u64));
1504        }
1505    }
1506
1507    #[test]
1508    fn test_count_operations() {
1509        let mut bv: BitMap<4> = BitMap::new();
1510
1511        // Empty bitmap
1512        assert_eq!(bv.count_ones(), 0);
1513        assert_eq!(bv.count_zeros(), 0);
1514
1515        // Add some bits
1516        bv.push(true);
1517        bv.push(false);
1518        bv.push(true);
1519        bv.push(true);
1520        bv.push(false);
1521
1522        assert_eq!(bv.count_ones(), 3);
1523        assert_eq!(bv.count_zeros(), 2);
1524        assert_eq!(bv.len(), 5);
1525
1526        // Test with full bytes
1527        let mut bv2: BitMap<4> = BitMap::new();
1528        bv2.push_byte(0xFF); // 8 ones
1529        bv2.push_byte(0x00); // 8 zeros
1530        bv2.push_byte(0xAA); // 4 ones, 4 zeros (10101010)
1531
1532        assert_eq!(bv2.count_ones(), 12);
1533        assert_eq!(bv2.count_zeros(), 12);
1534        assert_eq!(bv2.len(), 24);
1535    }
1536
1537    #[test]
1538    fn test_set_all() {
1539        let mut bv: BitMap<1> = BitMap::new();
1540
1541        // Add some bits
1542        bv.push(true);
1543        bv.push(false);
1544        bv.push(true);
1545        bv.push(false);
1546        bv.push(true);
1547        bv.push(false);
1548        bv.push(true);
1549        bv.push(false);
1550        bv.push(true);
1551        bv.push(false);
1552
1553        assert_eq!(bv.len(), 10);
1554        assert_eq!(bv.count_ones(), 5);
1555        assert_eq!(bv.count_zeros(), 5);
1556
1557        // Test set_all(true)
1558        bv.set_all(true);
1559        assert_eq!(bv.len(), 10);
1560        assert_eq!(bv.count_ones(), 10);
1561        assert_eq!(bv.count_zeros(), 0);
1562
1563        // Test set_all(false)
1564        bv.set_all(false);
1565        assert_eq!(bv.len(), 10);
1566        assert_eq!(bv.count_ones(), 0);
1567        assert_eq!(bv.count_zeros(), 10);
1568    }
1569
1570    #[test]
1571    fn test_flip_all() {
1572        let mut bv: BitMap<4> = BitMap::new();
1573
1574        bv.push(true);
1575        bv.push(false);
1576        bv.push(true);
1577        bv.push(false);
1578        bv.push(true);
1579
1580        let original_ones = bv.count_ones();
1581        let original_zeros = bv.count_zeros();
1582        let original_len = bv.len();
1583
1584        bv.flip_all();
1585
1586        // Length should not change
1587        assert_eq!(bv.len(), original_len);
1588
1589        // Ones and zeros should be swapped
1590        assert_eq!(bv.count_ones(), original_zeros);
1591        assert_eq!(bv.count_zeros(), original_ones);
1592
1593        // Check bits
1594        assert!(!bv.get(0));
1595        assert!(bv.get(1));
1596        assert!(!bv.get(2));
1597        assert!(bv.get(3));
1598        assert!(!bv.get(4));
1599    }
1600
1601    #[test]
1602    fn test_bitwise_and() {
1603        let mut bv1: BitMap<4> = BitMap::new();
1604        let mut bv2: BitMap<4> = BitMap::new();
1605
1606        // Create test patterns: 10110 & 11010 = 10010
1607        let pattern1 = [true, false, true, true, false];
1608        let pattern2 = [true, true, false, true, false];
1609        let expected = [true, false, false, true, false];
1610
1611        for &bit in &pattern1 {
1612            bv1.push(bit);
1613        }
1614        for &bit in &pattern2 {
1615            bv2.push(bit);
1616        }
1617
1618        bv1.and(&bv2);
1619
1620        assert_eq!(bv1.len(), 5);
1621        for (i, &expected_bit) in expected.iter().enumerate() {
1622            assert_eq!(bv1.get(i as u64), expected_bit);
1623        }
1624    }
1625
1626    #[test]
1627    fn test_bitwise_or() {
1628        let mut bv1: BitMap<4> = BitMap::new();
1629        let mut bv2: BitMap<4> = BitMap::new();
1630
1631        // Create test patterns: 10110 | 11010 = 11110
1632        let pattern1 = [true, false, true, true, false];
1633        let pattern2 = [true, true, false, true, false];
1634        let expected = [true, true, true, true, false];
1635
1636        for &bit in &pattern1 {
1637            bv1.push(bit);
1638        }
1639        for &bit in &pattern2 {
1640            bv2.push(bit);
1641        }
1642
1643        bv1.or(&bv2);
1644
1645        assert_eq!(bv1.len(), 5);
1646        for (i, &expected_bit) in expected.iter().enumerate() {
1647            assert_eq!(bv1.get(i as u64), expected_bit);
1648        }
1649    }
1650
1651    #[test]
1652    fn test_bitwise_xor() {
1653        let mut bv1: BitMap<4> = BitMap::new();
1654        let mut bv2: BitMap<4> = BitMap::new();
1655
1656        // Create test patterns: 10110 ^ 11010 = 01100
1657        let pattern1 = [true, false, true, true, false];
1658        let pattern2 = [true, true, false, true, false];
1659        let expected = [false, true, true, false, false];
1660
1661        for &bit in &pattern1 {
1662            bv1.push(bit);
1663        }
1664        for &bit in &pattern2 {
1665            bv2.push(bit);
1666        }
1667
1668        bv1.xor(&bv2);
1669
1670        assert_eq!(bv1.len(), 5);
1671        for (i, &expected_bit) in expected.iter().enumerate() {
1672            assert_eq!(bv1.get(i as u64), expected_bit);
1673        }
1674    }
1675
1676    #[test]
1677    fn test_multi_chunk_operations() {
1678        let mut bv1: BitMap<4> = BitMap::new();
1679        let mut bv2: BitMap<4> = BitMap::new();
1680
1681        // Fill multiple chunks
1682        let chunk1 = hex!("0xAABBCCDD"); // 10101010 10111011 11001100 11011101
1683        let chunk2 = hex!("0x55667788"); // 01010101 01100110 01110111 10001000
1684
1685        bv1.push_chunk(&chunk1);
1686        bv1.push_chunk(&chunk1);
1687        bv2.push_chunk(&chunk2);
1688        bv2.push_chunk(&chunk2);
1689
1690        assert_eq!(bv1.len(), 64);
1691        assert_eq!(bv2.len(), 64);
1692
1693        // Test AND operation
1694        let mut bv_and = bv1.clone();
1695        bv_and.and(&bv2);
1696
1697        // Test OR operation
1698        let mut bv_or = bv1.clone();
1699        bv_or.or(&bv2);
1700
1701        // Test XOR operation
1702        let mut bv_xor = bv1.clone();
1703        bv_xor.xor(&bv2);
1704
1705        // Verify results make sense
1706        assert_eq!(bv_and.len(), 64);
1707        assert_eq!(bv_or.len(), 64);
1708        assert_eq!(bv_xor.len(), 64);
1709
1710        // AND should have fewer or equal ones than either operand
1711        assert!(bv_and.count_ones() <= bv1.count_ones());
1712        assert!(bv_and.count_ones() <= bv2.count_ones());
1713
1714        // OR should have more or equal ones than either operand
1715        assert!(bv_or.count_ones() >= bv1.count_ones());
1716        assert!(bv_or.count_ones() >= bv2.count_ones());
1717    }
1718
1719    #[test]
1720    fn test_partial_chunk_operations() {
1721        let mut bv1: BitMap<4> = BitMap::new();
1722        let mut bv2: BitMap<4> = BitMap::new();
1723
1724        // Add partial chunks (not aligned to chunk boundaries)
1725        for i in 0..35 {
1726            // 35 bits = 4 bytes + 3 bits
1727            bv1.push(i % 2 == 0);
1728            bv2.push(i % 3 == 0);
1729        }
1730
1731        assert_eq!(bv1.len(), 35);
1732        assert_eq!(bv2.len(), 35);
1733
1734        // Test operations with partial chunks
1735        let mut bv_and = bv1.clone();
1736        bv_and.and(&bv2);
1737
1738        let mut bv_or = bv1.clone();
1739        bv_or.or(&bv2);
1740
1741        let mut bv_xor = bv1.clone();
1742        bv_xor.xor(&bv2);
1743
1744        // All should maintain the same length
1745        assert_eq!(bv_and.len(), 35);
1746        assert_eq!(bv_or.len(), 35);
1747        assert_eq!(bv_xor.len(), 35);
1748
1749        // Test flip_all with partial chunk
1750        let mut bv_inv = bv1.clone();
1751        let original_ones = bv_inv.count_ones();
1752        let original_zeros = bv_inv.count_zeros();
1753        bv_inv.flip_all();
1754        assert_eq!(bv_inv.count_ones(), original_zeros);
1755        assert_eq!(bv_inv.count_zeros(), original_ones);
1756    }
1757
1758    #[test]
1759    #[should_panic(expected = "bit 1 out of bounds (len: 1)")]
1760    fn test_flip_out_of_bounds() {
1761        let mut bv: BitMap<4> = BitMap::new();
1762        bv.push(true);
1763        bv.flip(1); // Only bit 0 exists
1764    }
1765
1766    #[test]
1767    #[should_panic(expected = "BitMap lengths don't match: 2 vs 1")]
1768    fn test_and_length_mismatch() {
1769        let mut bv1: BitMap<4> = BitMap::new();
1770        let mut bv2: BitMap<4> = BitMap::new();
1771
1772        bv1.push(true);
1773        bv1.push(false);
1774        bv2.push(true); // Different length
1775
1776        bv1.and(&bv2);
1777    }
1778
1779    #[test]
1780    #[should_panic(expected = "BitMap lengths don't match: 1 vs 2")]
1781    fn test_or_length_mismatch() {
1782        let mut bv1: BitMap<4> = BitMap::new();
1783        let mut bv2: BitMap<4> = BitMap::new();
1784
1785        bv1.push(true);
1786        bv2.push(true);
1787        bv2.push(false); // Different length
1788
1789        bv1.or(&bv2);
1790    }
1791
1792    #[test]
1793    #[should_panic(expected = "BitMap lengths don't match: 3 vs 2")]
1794    fn test_xor_length_mismatch() {
1795        let mut bv1: BitMap<4> = BitMap::new();
1796        let mut bv2: BitMap<4> = BitMap::new();
1797
1798        bv1.push(true);
1799        bv1.push(false);
1800        bv1.push(true);
1801        bv2.push(true);
1802        bv2.push(false); // Different length
1803
1804        bv1.xor(&bv2);
1805    }
1806
1807    #[test]
1808    fn test_equality() {
1809        // Test empty bitmaps
1810        assert_eq!(BitMap::<4>::new(), BitMap::<4>::new());
1811        assert_eq!(BitMap::<8>::new(), BitMap::<8>::new());
1812
1813        // Test non-empty bitmaps from constructors
1814        let pattern = [true, false, true, true, false, false, true, false, true];
1815        let bv4: BitMap<4> = pattern.as_ref().into();
1816        assert_eq!(bv4, BitMap::<4>::from(pattern.as_ref()));
1817        let bv8: BitMap<8> = pattern.as_ref().into();
1818        assert_eq!(bv8, BitMap::<8>::from(pattern.as_ref()));
1819
1820        // Test non-empty bitmaps from push operations
1821        let mut bv1: BitMap<4> = BitMap::new();
1822        let mut bv2: BitMap<4> = BitMap::new();
1823        for i in 0..33 {
1824            let bit = i % 3 == 0;
1825            bv1.push(bit);
1826            bv2.push(bit);
1827        }
1828        assert_eq!(bv1, bv2);
1829
1830        // Test inequality: different lengths
1831        bv1.push(true);
1832        assert_ne!(bv1, bv2);
1833        bv1.pop(); // Restore equality
1834        assert_eq!(bv1, bv2);
1835
1836        // Test inequality: different content
1837        bv1.flip(15);
1838        assert_ne!(bv1, bv2);
1839        bv1.flip(15); // Restore equality
1840        assert_eq!(bv1, bv2);
1841
1842        // Test equality after operations
1843        let mut bv_ops1 = BitMap::<16>::ones(25);
1844        let mut bv_ops2 = BitMap::<16>::ones(25);
1845        bv_ops1.flip_all();
1846        bv_ops2.flip_all();
1847        assert_eq!(bv_ops1, bv_ops2);
1848
1849        let mask_bits: Vec<bool> = (0..33).map(|i| i % 3 == 0).collect();
1850        let mask = BitMap::<4>::from(mask_bits);
1851        bv1.and(&mask);
1852        bv2.and(&mask);
1853        assert_eq!(bv1, bv2);
1854    }
1855
1856    #[test]
1857    fn test_different_chunk_sizes() {
1858        // Test with different chunk sizes
1859        let mut bv8: BitMap<8> = BitMap::new();
1860        let mut bv16: BitMap<16> = BitMap::new();
1861        let mut bv32: BitMap<32> = BitMap::new();
1862
1863        // Test chunk operations first (must be chunk-aligned)
1864        let chunk8 = [0xFF; 8];
1865        let chunk16 = [0xAA; 16];
1866        let chunk32 = [0x55; 32];
1867
1868        bv8.push_chunk(&chunk8);
1869        bv16.push_chunk(&chunk16);
1870        bv32.push_chunk(&chunk32);
1871
1872        // Test basic operations work with different sizes
1873        bv8.push(true);
1874        bv8.push(false);
1875        assert_eq!(bv8.len(), 64 + 2);
1876        assert_eq!(bv8.count_ones(), 64 + 1); // chunk8 is all 0xFF + 1 true bit
1877        assert_eq!(bv8.count_zeros(), 1);
1878
1879        bv16.push(true);
1880        bv16.push(false);
1881        assert_eq!(bv16.len(), 128 + 2);
1882        assert_eq!(bv16.count_ones(), 64 + 1); // chunk16 is 0xAA pattern + 1 true bit
1883        assert_eq!(bv16.count_zeros(), 64 + 1);
1884
1885        bv32.push(true);
1886        bv32.push(false);
1887        assert_eq!(bv32.len(), 256 + 2);
1888        assert_eq!(bv32.count_ones(), 128 + 1); // chunk32 is 0x55 pattern + 1 true bit
1889        assert_eq!(bv32.count_zeros(), 128 + 1);
1890    }
1891
1892    #[test]
1893    fn test_iterator() {
1894        // Test empty iterator
1895        let bv: BitMap<4> = BitMap::new();
1896        let mut iter = bv.iter();
1897        assert_eq!(iter.next(), None);
1898        assert_eq!(iter.size_hint(), (0, Some(0)));
1899
1900        // Test iterator with some bits
1901        let pattern = [true, false, true, false, true];
1902        let bv: BitMap<4> = pattern.as_ref().into();
1903
1904        // Collect all bits via iterator
1905        let collected: Vec<bool> = bv.iter().collect();
1906        assert_eq!(collected, pattern);
1907
1908        // Test size_hint
1909        let mut iter = bv.iter();
1910        assert_eq!(iter.size_hint(), (5, Some(5)));
1911
1912        // Consume one element and check size_hint again
1913        assert_eq!(iter.next(), Some(true));
1914        assert_eq!(iter.size_hint(), (4, Some(4)));
1915
1916        // Test ExactSizeIterator
1917        let iter = bv.iter();
1918        assert_eq!(iter.len(), 5);
1919
1920        // Test iterator with larger bitmap
1921        let mut large_bv: BitMap<8> = BitMap::new();
1922        for i in 0..100 {
1923            large_bv.push(i % 3 == 0);
1924        }
1925
1926        let collected: Vec<bool> = large_bv.iter().collect();
1927        assert_eq!(collected.len(), 100);
1928        for (i, &bit) in collected.iter().enumerate() {
1929            assert_eq!(bit, i % 3 == 0);
1930        }
1931    }
1932
1933    #[test]
1934    fn test_iterator_edge_cases() {
1935        // Test iterator with single bit
1936        let mut bv: BitMap<4> = BitMap::new();
1937        bv.push(true);
1938
1939        let collected: Vec<bool> = bv.iter().collect();
1940        assert_eq!(collected, vec![true]);
1941
1942        // Test iterator across chunk boundaries
1943        let mut bv: BitMap<4> = BitMap::new();
1944        // Fill exactly one chunk (32 bits)
1945        for i in 0..32 {
1946            bv.push(i % 2 == 0);
1947        }
1948        // Add a few more bits in the next chunk
1949        bv.push(true);
1950        bv.push(false);
1951        bv.push(true);
1952
1953        let collected: Vec<bool> = bv.iter().collect();
1954        assert_eq!(collected.len(), 35);
1955
1956        // Verify the pattern
1957        for (i, &bit) in collected.iter().enumerate().take(32) {
1958            assert_eq!(bit, i % 2 == 0);
1959        }
1960        assert!(collected[32]);
1961        assert!(!collected[33]);
1962        assert!(collected[34]);
1963    }
1964
1965    #[test]
1966    fn test_ones_iter_empty() {
1967        let bv: BitMap<4> = BitMap::new();
1968        let ones: Vec<u64> = bv.ones_iter().collect();
1969        assert!(ones.is_empty());
1970    }
1971
1972    #[test]
1973    fn test_ones_iter_all_zeros() {
1974        let bv = BitMap::<4>::zeroes(100);
1975        let ones: Vec<u64> = bv.ones_iter().collect();
1976        assert!(ones.is_empty());
1977    }
1978
1979    #[test]
1980    fn test_ones_iter_all_ones() {
1981        let bv = BitMap::<4>::ones(100);
1982        let ones: Vec<u64> = bv.ones_iter().collect();
1983        let expected: Vec<u64> = (0..100).collect();
1984        assert_eq!(ones, expected);
1985    }
1986
1987    #[test]
1988    fn test_ones_iter_sparse() {
1989        let mut bv = BitMap::<4>::zeroes(64);
1990        bv.set(0, true);
1991        bv.set(31, true);
1992        bv.set(32, true);
1993        bv.set(63, true);
1994
1995        let ones: Vec<u64> = bv.ones_iter().collect();
1996        assert_eq!(ones, vec![0, 31, 32, 63]);
1997    }
1998
1999    #[test]
2000    fn test_ones_iter_single_bit() {
2001        let mut bv: BitMap<4> = BitMap::new();
2002        bv.push(true);
2003        assert_eq!(bv.ones_iter().collect::<Vec<_>>(), vec![0]);
2004
2005        let mut bv: BitMap<4> = BitMap::new();
2006        bv.push(false);
2007        assert!(bv.ones_iter().collect::<Vec<_>>().is_empty());
2008    }
2009
2010    #[test]
2011    fn test_ones_iter_multi_chunk() {
2012        // Use small chunks (4 bytes = 32 bits) to ensure multi-chunk coverage.
2013        let mut bv = BitMap::<4>::zeroes(96);
2014        // Set one bit per chunk.
2015        bv.set(7, true); // chunk 0
2016        bv.set(40, true); // chunk 1
2017        bv.set(95, true); // chunk 2
2018
2019        let ones: Vec<u64> = bv.ones_iter().collect();
2020        assert_eq!(ones, vec![7, 40, 95]);
2021    }
2022
2023    #[test]
2024    fn test_ones_iter_partial_chunk() {
2025        // 35 bits = 1 full chunk (32 bits) + 3 bits in a partial chunk.
2026        let mut bv = BitMap::<4>::zeroes(35);
2027        bv.set(31, true); // last bit of full chunk
2028        bv.set(32, true); // first bit of partial chunk
2029        bv.set(34, true); // last bit
2030
2031        let ones: Vec<u64> = bv.ones_iter().collect();
2032        assert_eq!(ones, vec![31, 32, 34]);
2033    }
2034
2035    #[test]
2036    fn test_ones_iter_from_midway() {
2037        let mut bv = BitMap::<4>::zeroes(64);
2038        bv.set(5, true);
2039        bv.set(20, true);
2040        bv.set(40, true);
2041        bv.set(60, true);
2042
2043        // Start from position 20 -- should skip bit 5.
2044        let ones: Vec<u64> = Readable::ones_iter_from(&bv, 20).collect();
2045        assert_eq!(ones, vec![20, 40, 60]);
2046
2047        // Start from position 21 -- should skip bits 5 and 20.
2048        let ones: Vec<u64> = Readable::ones_iter_from(&bv, 21).collect();
2049        assert_eq!(ones, vec![40, 60]);
2050
2051        // Start past all set bits.
2052        let ones: Vec<u64> = Readable::ones_iter_from(&bv, 61).collect();
2053        assert!(ones.is_empty());
2054    }
2055
2056    #[test]
2057    fn test_ones_iter_matches_count_ones() {
2058        let mut bv: BitMap<8> = BitMap::new();
2059        for i in 0..200 {
2060            bv.push(i % 7 == 0);
2061        }
2062        assert_eq!(bv.ones_iter().count() as u64, bv.count_ones());
2063    }
2064
2065    #[test]
2066    fn test_ones_iter_different_chunk_sizes() {
2067        let pattern: Vec<bool> = (0..100).map(|i| i % 5 == 0).collect();
2068        let expected: Vec<u64> = (0..100).filter(|i| i % 5 == 0).collect();
2069
2070        let bv4: BitMap<4> = pattern.as_slice().into();
2071        let bv8: BitMap<8> = pattern.as_slice().into();
2072        let bv16: BitMap<16> = pattern.as_slice().into();
2073
2074        assert_eq!(bv4.ones_iter().collect::<Vec<_>>(), expected);
2075        assert_eq!(bv8.ones_iter().collect::<Vec<_>>(), expected);
2076        assert_eq!(bv16.ones_iter().collect::<Vec<_>>(), expected);
2077    }
2078
2079    #[test]
2080    fn test_ones_iter_multi_word_chunk() {
2081        // 32-byte chunks hold four 64-bit words. Set bits adjacent to every word
2082        // boundary within a chunk and to the chunk boundary itself.
2083        let expected = vec![0, 63, 64, 127, 128, 255, 256, 511, 512, 599];
2084        let mut bv = BitMap::<32>::zeroes(600);
2085        for &bit in &expected {
2086            bv.set(bit, true);
2087        }
2088        assert_eq!(bv.ones_iter().collect::<Vec<_>>(), expected);
2089    }
2090
2091    #[test]
2092    fn test_ones_iter_from_mid_word() {
2093        // Starting positions inside every word of a multi-word chunk mask out exactly
2094        // the bits below the start.
2095        let bv = BitMap::<32>::ones(300);
2096        for pos in [0, 1, 63, 64, 65, 191, 192, 255, 256, 299] {
2097            let ones: Vec<u64> = Readable::ones_iter_from(&bv, pos).collect();
2098            let expected: Vec<u64> = (pos..300).collect();
2099            assert_eq!(ones, expected);
2100        }
2101    }
2102
2103    #[test]
2104    fn test_ones_iter_word_aligned_len() {
2105        // A length exactly at a word boundary must not mask off the final bit.
2106        let bv = BitMap::<8>::ones(64);
2107        assert_eq!(
2108            bv.ones_iter().collect::<Vec<_>>(),
2109            (0..64).collect::<Vec<_>>()
2110        );
2111        let bv = BitMap::<32>::ones(256);
2112        assert_eq!(
2113            bv.ones_iter().collect::<Vec<_>>(),
2114            (0..256).collect::<Vec<_>>()
2115        );
2116    }
2117
2118    #[test]
2119    fn test_ones_iter_matches_get_bit() {
2120        // Pseudo-random pattern over every chunk shape: sub-word (1, 3, 4), exactly one
2121        // word (8), multi-word (16, 32), and multi-word with a partial tail word (12,
2122        // 23). Check the full iteration and every possible starting position against
2123        // get_bit.
2124        fn check<const N: usize>() {
2125            let mut rng = test_rng();
2126            let mut bv: BitMap<N> = BitMap::new();
2127            let len = 5 * BitMap::<N>::CHUNK_SIZE_BITS + 7;
2128            for _ in 0..len {
2129                bv.push(rng.random_bool(0.375));
2130            }
2131            let expected: Vec<u64> = (0..len).filter(|&i| bv.get_bit(i)).collect();
2132            assert_eq!(bv.ones_iter().collect::<Vec<_>>(), expected);
2133            for pos in 0..=len {
2134                let tail: Vec<u64> = expected.iter().copied().filter(|&b| b >= pos).collect();
2135                assert_eq!(Readable::ones_iter_from(&bv, pos).collect::<Vec<_>>(), tail);
2136            }
2137        }
2138        check::<1>();
2139        check::<3>();
2140        check::<4>();
2141        check::<8>();
2142        check::<12>();
2143        check::<16>();
2144        check::<23>();
2145        check::<32>();
2146    }
2147
2148    #[test]
2149    fn test_codec_roundtrip() {
2150        // Test empty bitmap
2151        let original: BitMap<4> = BitMap::new();
2152        let encoded = original.encode();
2153        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
2154        assert_eq!(original, decoded);
2155
2156        // Test small bitmap
2157        let pattern = [true, false, true, false, true];
2158        let original: BitMap<4> = pattern.as_ref().into();
2159        let encoded = original.encode();
2160        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
2161        assert_eq!(original, decoded);
2162
2163        // Verify the decoded bitmap has the same bits
2164        for (i, &expected) in pattern.iter().enumerate() {
2165            assert_eq!(decoded.get(i as u64), expected);
2166        }
2167
2168        // Test larger bitmap across multiple chunks
2169        let mut large_original: BitMap<8> = BitMap::new();
2170        for i in 0..100 {
2171            large_original.push(i % 7 == 0);
2172        }
2173
2174        let encoded = large_original.encode();
2175        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
2176        assert_eq!(large_original, decoded);
2177
2178        // Verify all bits match
2179        assert_eq!(decoded.len(), 100);
2180        for i in 0..100 {
2181            assert_eq!(decoded.get(i as u64), i % 7 == 0);
2182        }
2183    }
2184
2185    #[test]
2186    fn test_codec_different_chunk_sizes() {
2187        let pattern = [true, false, true, true, false, false, true];
2188
2189        // Test with different chunk sizes
2190        let bv4: BitMap<4> = pattern.as_ref().into();
2191        let bv8: BitMap<8> = pattern.as_ref().into();
2192        let bv16: BitMap<16> = pattern.as_ref().into();
2193
2194        // Encode and decode each
2195        let encoded4 = bv4.encode();
2196        let decoded4 = BitMap::decode_cfg(&mut encoded4.as_ref(), &(usize::MAX as u64)).unwrap();
2197        assert_eq!(bv4, decoded4);
2198
2199        let encoded8 = bv8.encode();
2200        let decoded8 = BitMap::decode_cfg(&mut encoded8.as_ref(), &(usize::MAX as u64)).unwrap();
2201        assert_eq!(bv8, decoded8);
2202
2203        let encoded16 = bv16.encode();
2204        let decoded16 = BitMap::decode_cfg(&mut encoded16.as_ref(), &(usize::MAX as u64)).unwrap();
2205        assert_eq!(bv16, decoded16);
2206
2207        // All should have the same logical content
2208        for (i, &expected) in pattern.iter().enumerate() {
2209            let i = i as u64;
2210            assert_eq!(decoded4.get(i), expected);
2211            assert_eq!(decoded8.get(i), expected);
2212            assert_eq!(decoded16.get(i), expected);
2213        }
2214    }
2215
2216    #[test]
2217    fn test_codec_edge_cases() {
2218        // Test bitmap with exactly one chunk filled
2219        let mut bv: BitMap<4> = BitMap::new();
2220        for i in 0..32 {
2221            bv.push(i % 2 == 0);
2222        }
2223
2224        let encoded = bv.encode();
2225        let decoded = BitMap::decode_cfg(&mut encoded.as_ref(), &(usize::MAX as u64)).unwrap();
2226        assert_eq!(bv, decoded);
2227        assert_eq!(decoded.len(), 32);
2228
2229        // Test bitmap with partial chunk
2230        let mut bv2: BitMap<4> = BitMap::new();
2231        for i in 0..35 {
2232            // 32 + 3 bits
2233            bv2.push(i % 3 == 0);
2234        }
2235
2236        let encoded2 = bv2.encode();
2237        let decoded2 = BitMap::decode_cfg(&mut encoded2.as_ref(), &(usize::MAX as u64)).unwrap();
2238        assert_eq!(bv2, decoded2);
2239        assert_eq!(decoded2.len(), 35);
2240    }
2241
2242    #[test]
2243    fn test_encode_size() {
2244        // Test encode size calculation
2245        let bv: BitMap<4> = BitMap::new();
2246        let encoded = bv.encode();
2247        assert_eq!(bv.encode_size(), encoded.len());
2248
2249        // Test with some data
2250        let pattern = [true, false, true, false, true];
2251        let bv: BitMap<4> = pattern.as_ref().into();
2252        let encoded = bv.encode();
2253        assert_eq!(bv.encode_size(), encoded.len());
2254
2255        // Test with larger data
2256        let mut large_bv: BitMap<8> = BitMap::new();
2257        for i in 0..100 {
2258            large_bv.push(i % 2 == 0);
2259        }
2260        let encoded = large_bv.encode();
2261        assert_eq!(large_bv.encode_size(), encoded.len());
2262    }
2263
2264    #[test]
2265    fn test_codec_empty_chunk_optimization() {
2266        // Test that empty last chunks are not serialized
2267
2268        // Case 1: Empty bitmap (omits the only empty chunk)
2269        let bv_empty: BitMap<4> = BitMap::new();
2270        let encoded_empty = bv_empty.encode();
2271        let decoded_empty: BitMap<4> =
2272            BitMap::decode_cfg(&mut encoded_empty.as_ref(), &(usize::MAX as u64)).unwrap();
2273        assert_eq!(bv_empty, decoded_empty);
2274        assert_eq!(bv_empty.len(), decoded_empty.len());
2275        // Should only encode the length, no chunks
2276        assert_eq!(encoded_empty.len(), bv_empty.len().encode_size());
2277
2278        // Case 2: Bitmap ending exactly at chunk boundary (omits empty last chunk)
2279        let mut bv_exact: BitMap<4> = BitMap::new();
2280        for _ in 0..32 {
2281            bv_exact.push(true);
2282        }
2283        let encoded_exact = bv_exact.encode();
2284        let decoded_exact: BitMap<4> =
2285            BitMap::decode_cfg(&mut encoded_exact.as_ref(), &(usize::MAX as u64)).unwrap();
2286        assert_eq!(bv_exact, decoded_exact);
2287
2288        // Case 3: Bitmap with partial last chunk (includes last chunk)
2289        let mut bv_partial: BitMap<4> = BitMap::new();
2290        for _ in 0..35 {
2291            bv_partial.push(true);
2292        }
2293        let encoded_partial = bv_partial.encode();
2294        let decoded_partial: BitMap<4> =
2295            BitMap::decode_cfg(&mut encoded_partial.as_ref(), &(usize::MAX as u64)).unwrap();
2296        assert_eq!(bv_partial, decoded_partial);
2297        assert_eq!(bv_partial.len(), decoded_partial.len());
2298
2299        // Verify optimization works correctly
2300        assert!(encoded_exact.len() < encoded_partial.len());
2301        assert_eq!(encoded_exact.len(), bv_exact.len().encode_size() + 4); // length + 1 chunk
2302        assert_eq!(encoded_partial.len(), bv_partial.len().encode_size() + 8); // length + 2 chunks
2303    }
2304
2305    #[test]
2306    fn test_codec_error_cases() {
2307        // Test invalid length with range check
2308        let mut buf = BytesMut::new();
2309        100u64.write(&mut buf); // bits length
2310
2311        // 100 bits requires 4 chunks (3 full + partially filled)
2312        for _ in 0..4 {
2313            [0u8; 4].write(&mut buf);
2314        }
2315
2316        // Test with a restricted range that excludes 100
2317        let result = BitMap::<4>::decode_cfg(&mut buf, &99);
2318        assert!(matches!(result, Err(CodecError::InvalidLength(100))));
2319
2320        // Test truncated buffer (not enough chunks)
2321        let mut buf = BytesMut::new();
2322        100u64.write(&mut buf); // bits length requiring 4 chunks (3 full + partially filled)
2323        // Only write 3 chunks
2324        [0u8; 4].write(&mut buf);
2325        [0u8; 4].write(&mut buf);
2326        [0u8; 4].write(&mut buf);
2327
2328        let result = BitMap::<4>::decode_cfg(&mut buf, &(usize::MAX as u64));
2329        // Should fail when trying to read missing chunks
2330        assert!(result.is_err());
2331
2332        // Test invalid trailing bits
2333
2334        // Create a valid bitmap and encode it
2335        let original: BitMap<4> = BitMap::ones(20);
2336        let mut buf = BytesMut::new();
2337        original.write(&mut buf);
2338
2339        // Manually corrupt the encoded data by setting trailing bits
2340        let corrupted_data = buf.freeze();
2341        let mut corrupted_bytes = corrupted_data.to_vec();
2342
2343        // The last byte should have some trailing bits set to 1
2344        // For 20 bits with 4-byte chunks: 20 bits = 2.5 bytes, so last byte should have 4 valid bits
2345        // Set the high 4 bits of the last byte to 1 (these should be 0)
2346        let last_byte_idx = corrupted_bytes.len() - 1;
2347        corrupted_bytes[last_byte_idx] |= 0xF0;
2348
2349        // Read should fail
2350        let result = BitMap::<4>::read_cfg(&mut corrupted_bytes.as_slice(), &(usize::MAX as u64));
2351        assert!(matches!(
2352            result,
2353            Err(CodecError::Invalid(
2354                "BitMap",
2355                "Invalid trailing bits in encoded data"
2356            ))
2357        ));
2358    }
2359
2360    #[test]
2361    fn test_codec_range_config() {
2362        // Test RangeCfg validation in read_cfg
2363
2364        // Create a bitmap with 100 bits
2365        let mut original: BitMap<4> = BitMap::new();
2366        for i in 0..100 {
2367            original.push(i % 3 == 0);
2368        }
2369
2370        // Write to a buffer
2371        let mut buf = BytesMut::new();
2372        original.write(&mut buf);
2373
2374        // Test with max length < actual size (should fail)
2375        let result = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &50);
2376        assert!(matches!(result, Err(CodecError::InvalidLength(100))));
2377
2378        // Test with max length == actual size (should succeed)
2379        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &100).unwrap();
2380        assert_eq!(decoded.len(), 100);
2381        assert_eq!(decoded, original);
2382
2383        // Test with max length > actual size (should succeed)
2384        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &101).unwrap();
2385        assert_eq!(decoded.len(), 100);
2386        assert_eq!(decoded, original);
2387
2388        // Test empty bitmap
2389        let empty = BitMap::<4>::new();
2390        let mut buf = BytesMut::new();
2391        empty.write(&mut buf);
2392
2393        // Empty bitmap should work with max length 0
2394        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &0).unwrap();
2395        assert_eq!(decoded.len(), 0);
2396        assert!(decoded.is_empty());
2397
2398        // Empty bitmap should work with max length > 0
2399        let decoded = BitMap::<4>::decode_cfg(&mut buf.as_ref(), &1).unwrap();
2400        assert_eq!(decoded.len(), 0);
2401        assert!(decoded.is_empty());
2402    }
2403
2404    #[test]
2405    fn test_from() {
2406        // Test From trait with different input types
2407
2408        // Test with Vec<bool>
2409        let vec_bool = vec![true, false, true, false, true];
2410        let bv: BitMap<4> = vec_bool.into();
2411        assert_eq!(bv.len(), 5);
2412        assert_eq!(bv.count_ones(), 3);
2413        assert_eq!(bv.count_zeros(), 2);
2414        for (i, &expected) in [true, false, true, false, true].iter().enumerate() {
2415            assert_eq!(bv.get(i as u64), expected);
2416        }
2417
2418        // Test with array slice
2419        let array = [false, true, true, false];
2420        let bv: BitMap<4> = (&array).into();
2421        assert_eq!(bv.len(), 4);
2422        assert_eq!(bv.count_ones(), 2);
2423        assert_eq!(bv.count_zeros(), 2);
2424        for (i, &expected) in array.iter().enumerate() {
2425            assert_eq!(bv.get(i as u64), expected);
2426        }
2427
2428        // Test with empty slice
2429        let empty: Vec<bool> = vec![];
2430        let bv: BitMap<4> = empty.into();
2431        assert_eq!(bv.len(), 0);
2432        assert!(bv.is_empty());
2433
2434        // Test with large slice
2435        let large: Vec<bool> = (0..100).map(|i| i % 3 == 0).collect();
2436        let bv: BitMap<8> = large.clone().into();
2437        assert_eq!(bv.len(), 100);
2438        for (i, &expected) in large.iter().enumerate() {
2439            assert_eq!(bv.get(i as u64), expected);
2440        }
2441    }
2442
2443    #[test]
2444    fn test_debug_formatting() {
2445        // Test Debug formatting for different sizes
2446
2447        // Test empty bitmap
2448        let bv: BitMap<4> = BitMap::new();
2449        let debug_str = format!("{bv:?}");
2450        assert_eq!(debug_str, "BitMap[]");
2451
2452        // Test small bitmap (should show all bits)
2453        let bv: BitMap<4> = [true, false, true, false, true].as_ref().into();
2454        let debug_str = format!("{bv:?}");
2455        assert_eq!(debug_str, "BitMap[10101]");
2456
2457        // Test bitmap at the display limit (64 bits)
2458        let pattern: Vec<bool> = (0..64).map(|i| i % 2 == 0).collect();
2459        let bv: BitMap<8> = pattern.into();
2460        let debug_str = format!("{bv:?}");
2461        let expected_pattern = "1010".repeat(16); // 64 bits alternating
2462        assert_eq!(debug_str, format!("BitMap[{expected_pattern}]"));
2463
2464        // Test large bitmap (should show ellipsis)
2465        let large_pattern: Vec<bool> = (0..100).map(|i| i % 2 == 0).collect();
2466        let bv: BitMap<16> = large_pattern.into();
2467        let debug_str = format!("{bv:?}");
2468
2469        // Should show first 32 bits + "..." + last 32 bits
2470        let first_32 = "10".repeat(16); // First 32 bits: 1010...
2471        let last_32 = "10".repeat(16); // Last 32 bits: ...1010
2472        let expected = format!("BitMap[{first_32}...{last_32}]");
2473        assert_eq!(debug_str, expected);
2474
2475        // Test single bit
2476        let bv: BitMap<4> = [true].as_ref().into();
2477        assert_eq!(format!("{bv:?}"), "BitMap[1]");
2478
2479        let bv: BitMap<4> = [false].as_ref().into();
2480        assert_eq!(format!("{bv:?}"), "BitMap[0]");
2481
2482        // Test exactly at boundary (65 bits - should show ellipsis)
2483        let pattern: Vec<bool> = (0..65).map(|i| i == 0 || i == 64).collect(); // First and last bits are true
2484        let bv: BitMap<16> = pattern.into();
2485        let debug_str = format!("{bv:?}");
2486
2487        // Should show first 32 bits (100000...) + "..." + last 32 bits (...000001)
2488        let first_32 = "1".to_string() + &"0".repeat(31);
2489        let last_32 = "0".repeat(31) + "1";
2490        let expected = format!("BitMap[{first_32}...{last_32}]");
2491        assert_eq!(debug_str, expected);
2492    }
2493
2494    #[test]
2495    fn test_from_different_chunk_sizes() {
2496        // Test From trait works with different chunk sizes
2497        let pattern = [true, false, true, true, false, false, true];
2498
2499        let bv4: BitMap<4> = pattern.as_ref().into();
2500        let bv8: BitMap<8> = pattern.as_ref().into();
2501        let bv16: BitMap<16> = pattern.as_ref().into();
2502
2503        // All should have the same content regardless of chunk size
2504        // Test each bitmap separately since they have different types
2505        for bv in [&bv4] {
2506            assert_eq!(bv.len(), 7);
2507            assert_eq!(bv.count_ones(), 4);
2508            assert_eq!(bv.count_zeros(), 3);
2509            for (i, &expected) in pattern.iter().enumerate() {
2510                assert_eq!(bv.get(i as u64), expected);
2511            }
2512        }
2513
2514        assert_eq!(bv8.len(), 7);
2515        assert_eq!(bv8.count_ones(), 4);
2516        assert_eq!(bv8.count_zeros(), 3);
2517        for (i, &expected) in pattern.iter().enumerate() {
2518            assert_eq!(bv8.get(i as u64), expected);
2519        }
2520
2521        assert_eq!(bv16.len(), 7);
2522        assert_eq!(bv16.count_ones(), 4);
2523        assert_eq!(bv16.count_zeros(), 3);
2524        for (i, &expected) in pattern.iter().enumerate() {
2525            assert_eq!(bv16.get(i as u64), expected);
2526        }
2527    }
2528
2529    #[test]
2530    fn test_prune_chunks() {
2531        let mut bv: BitMap<4> = BitMap::new();
2532        bv.push_chunk(&[1, 2, 3, 4]);
2533        bv.push_chunk(&[5, 6, 7, 8]);
2534        bv.push_chunk(&[9, 10, 11, 12]);
2535
2536        assert_eq!(bv.len(), 96);
2537        assert_eq!(bv.get_chunk(0), &[1, 2, 3, 4]);
2538
2539        // Prune first chunk
2540        bv.prune_chunks(1);
2541        assert_eq!(bv.len(), 64);
2542        assert_eq!(bv.get_chunk(0), &[5, 6, 7, 8]);
2543        assert_eq!(bv.get_chunk(1), &[9, 10, 11, 12]);
2544
2545        // Prune another chunk
2546        bv.prune_chunks(1);
2547        assert_eq!(bv.len(), 32);
2548        assert_eq!(bv.get_chunk(0), &[9, 10, 11, 12]);
2549    }
2550
2551    #[test]
2552    #[should_panic(expected = "cannot prune")]
2553    fn test_prune_too_many_chunks() {
2554        let mut bv: BitMap<4> = BitMap::new();
2555        bv.push_chunk(&[1, 2, 3, 4]);
2556        bv.push_chunk(&[5, 6, 7, 8]);
2557        bv.push(true);
2558
2559        // Try to prune 4 chunks when only 3 are available
2560        bv.prune_chunks(4);
2561    }
2562
2563    #[test]
2564    fn test_prune_with_partial_last_chunk() {
2565        let mut bv: BitMap<4> = BitMap::new();
2566        bv.push_chunk(&[1, 2, 3, 4]);
2567        bv.push_chunk(&[5, 6, 7, 8]);
2568        bv.push(true);
2569        bv.push(false);
2570
2571        assert_eq!(bv.len(), 66);
2572
2573        // Can prune first chunk
2574        bv.prune_chunks(1);
2575        assert_eq!(bv.len(), 34);
2576        assert_eq!(bv.get_chunk(0), &[5, 6, 7, 8]);
2577
2578        // Last partial chunk still has the appended bits
2579        assert!(bv.get(32));
2580        assert!(!bv.get(33));
2581    }
2582
2583    #[test]
2584    fn test_prune_all_chunks_resets_next_bit() {
2585        let mut bv: BitMap<4> = BitMap::new();
2586        bv.push_chunk(&[1, 2, 3, 4]);
2587        bv.push_chunk(&[5, 6, 7, 8]);
2588        bv.push(true);
2589        bv.push(false);
2590        bv.push(true);
2591
2592        // Bitmap has 2 full chunks + 3 bits in partial chunk
2593        assert_eq!(bv.len(), 67);
2594
2595        // Prune all chunks (this leaves chunks empty, triggering the reset path)
2596        bv.prune_chunks(3);
2597
2598        // Regression test: len() should be 0, not the old next_bit value (3)
2599        assert_eq!(bv.len(), 0);
2600        assert!(bv.is_empty());
2601
2602        // Bitmap should behave as freshly created
2603        bv.push(true);
2604        assert_eq!(bv.len(), 1);
2605        assert!(bv.get(0));
2606    }
2607
2608    #[test]
2609    fn test_is_chunk_aligned() {
2610        // Empty bitmap is chunk aligned
2611        let bv: BitMap<4> = BitMap::new();
2612        assert!(bv.is_chunk_aligned());
2613
2614        // Test with various chunk sizes
2615        let mut bv4: BitMap<4> = BitMap::new();
2616        assert!(bv4.is_chunk_aligned());
2617
2618        // Add bits one at a time and check alignment
2619        for i in 1..=32 {
2620            bv4.push(i % 2 == 0);
2621            if i == 32 {
2622                assert!(bv4.is_chunk_aligned()); // Exactly one chunk
2623            } else {
2624                assert!(!bv4.is_chunk_aligned()); // Partial chunk
2625            }
2626        }
2627
2628        // Add more bits
2629        for i in 33..=64 {
2630            bv4.push(i % 2 == 0);
2631            if i == 64 {
2632                assert!(bv4.is_chunk_aligned()); // Exactly two chunks
2633            } else {
2634                assert!(!bv4.is_chunk_aligned()); // Partial chunk
2635            }
2636        }
2637
2638        // Test with push_chunk
2639        let mut bv: BitMap<8> = BitMap::new();
2640        assert!(bv.is_chunk_aligned());
2641        bv.push_chunk(&[0xFF; 8]);
2642        assert!(bv.is_chunk_aligned()); // 64 bits = 1 chunk for N=8
2643        bv.push_chunk(&[0xAA; 8]);
2644        assert!(bv.is_chunk_aligned()); // 128 bits = 2 chunks
2645        bv.push(true);
2646        assert!(!bv.is_chunk_aligned()); // 129 bits = partial chunk
2647
2648        // Test with push_byte
2649        let mut bv: BitMap<4> = BitMap::new();
2650        for _ in 0..4 {
2651            bv.push_byte(0xFF);
2652        }
2653        assert!(bv.is_chunk_aligned()); // 32 bits = 1 chunk for N=4
2654
2655        // Test after pop
2656        bv.pop();
2657        assert!(!bv.is_chunk_aligned()); // 31 bits = partial chunk
2658
2659        // Test with zeroes and ones constructors
2660        let bv_zeroes: BitMap<4> = BitMap::zeroes(64);
2661        assert!(bv_zeroes.is_chunk_aligned());
2662
2663        let bv_ones: BitMap<4> = BitMap::ones(96);
2664        assert!(bv_ones.is_chunk_aligned());
2665
2666        let bv_partial: BitMap<4> = BitMap::zeroes(65);
2667        assert!(!bv_partial.is_chunk_aligned());
2668    }
2669
2670    #[test]
2671    fn test_unprune_restores_length() {
2672        let mut prunable: Prunable<4> = Prunable::new_with_pruned_chunks(1).unwrap();
2673        assert_eq!(prunable.len(), Prunable::<4>::CHUNK_SIZE_BITS);
2674        assert_eq!(prunable.pruned_chunks(), 1);
2675        let chunk = [0xDE, 0xAD, 0xBE, 0xEF];
2676
2677        prunable.unprune_chunks(&[chunk]);
2678
2679        assert_eq!(prunable.pruned_chunks(), 0);
2680        assert_eq!(prunable.len(), Prunable::<4>::CHUNK_SIZE_BITS);
2681        assert_eq!(prunable.get_chunk_containing(0), &chunk);
2682    }
2683
2684    mod proptests {
2685        use super::*;
2686        use proptest::prelude::*;
2687
2688        proptest! {
2689            #[test]
2690            fn is_unset_matches_naive(
2691                bits in prop::collection::vec(any::<bool>(), 1..=512usize),
2692                start in 0u64..=512,
2693                end in 0u64..=512,
2694            ) {
2695                let bitmap: BitMap = BitMap::from(bits.as_slice());
2696                let len = bitmap.len();
2697                let start = start.min(len);
2698                let end = end.max(start).min(len);
2699                let range = start..end;
2700
2701                let expected = range.clone().all(|i| !bitmap.get(i));
2702
2703                prop_assert_eq!(bitmap.is_unset(range), expected);
2704            }
2705        }
2706    }
2707
2708    #[test]
2709    fn is_unset_all_zeros() {
2710        let bitmap = BitMap::<8>::zeroes(256);
2711        assert!(bitmap.is_unset(0..256));
2712    }
2713
2714    #[test]
2715    fn is_unset_all_ones() {
2716        let bitmap = BitMap::<8>::ones(256);
2717        assert!(!bitmap.is_unset(0..256));
2718    }
2719
2720    #[test]
2721    fn is_unset_single_bit() {
2722        let mut bitmap = BitMap::<8>::zeroes(64);
2723        bitmap.set(31, true);
2724        assert!(bitmap.is_unset(0..31));
2725        assert!(!bitmap.is_unset(0..32));
2726        assert!(!bitmap.is_unset(31..32));
2727        assert!(bitmap.is_unset(32..64));
2728    }
2729
2730    #[test]
2731    fn is_unset_empty_range() {
2732        let bitmap = BitMap::<8>::ones(64);
2733        assert!(bitmap.is_unset(0..0));
2734        assert!(bitmap.is_unset(32..32));
2735        assert!(bitmap.is_unset(64..64));
2736    }
2737
2738    #[test]
2739    fn is_unset_chunk_boundaries() {
2740        // N=1 means 8 bits per chunk, so boundaries are more frequent
2741        let mut bitmap = BitMap::<1>::zeroes(32);
2742        bitmap.set(7, true);
2743        assert!(bitmap.is_unset(0..7));
2744        assert!(!bitmap.is_unset(0..8));
2745        assert!(bitmap.is_unset(8..32));
2746    }
2747
2748    #[test]
2749    fn is_unset_small_chunk_multi_span() {
2750        // N=4 means 32 bits per chunk, test spanning 3 chunks
2751        let mut bitmap = BitMap::<4>::zeroes(128);
2752        bitmap.set(96, true);
2753        assert!(bitmap.is_unset(0..96));
2754        assert!(!bitmap.is_unset(0..97));
2755        assert!(bitmap.is_unset(97..128));
2756    }
2757
2758    #[test]
2759    #[should_panic(expected = "out of bounds")]
2760    fn is_unset_out_of_bounds() {
2761        let bitmap = BitMap::<8>::zeroes(64);
2762        bitmap.is_unset(0..65);
2763    }
2764
2765    #[cfg(feature = "arbitrary")]
2766    mod conformance {
2767        use super::*;
2768        use commonware_codec::conformance::CodecConformance;
2769
2770        commonware_conformance::conformance_tests! {
2771            CodecConformance<BitMap>
2772        }
2773    }
2774}