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