Skip to main content

vortex_buffer/bit/
buf_mut.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::ops::Not;
5
6use bitvec::view::BitView;
7
8use crate::BitBuffer;
9use crate::BufferMut;
10use crate::ByteBufferMut;
11use crate::bit::collect_bool_words;
12use crate::bit::get_bit_unchecked;
13use crate::bit::ops;
14use crate::bit::set_bit_unchecked;
15use crate::bit::unset_bit_unchecked;
16use crate::buffer_mut;
17
18/// Sets all bits in the bit-range `[start_bit, end_bit)` of `slice` to `value`.
19#[inline(always)]
20pub(crate) fn fill_bits(slice: &mut [u8], start_bit: usize, end_bit: usize, value: bool) {
21    if start_bit >= end_bit {
22        return;
23    }
24
25    let fill_byte: u8 = if value { 0xFF } else { 0x00 };
26
27    let start_byte = start_bit / 8;
28    let start_rem = start_bit % 8;
29    let end_byte = end_bit / 8;
30    let end_rem = end_bit % 8;
31
32    if start_byte == end_byte {
33        // All bits are in the same byte
34        let mask = ((1u8 << (end_rem - start_rem)) - 1) << start_rem;
35        if value {
36            slice[start_byte] |= mask;
37        } else {
38            slice[start_byte] &= !mask;
39        }
40    } else {
41        // First partial byte
42        if start_rem != 0 {
43            let mask = !((1u8 << start_rem) - 1);
44            if value {
45                slice[start_byte] |= mask;
46            } else {
47                slice[start_byte] &= !mask;
48            }
49        }
50
51        // Middle bytes
52        let fill_start = if start_rem != 0 {
53            start_byte + 1
54        } else {
55            start_byte
56        };
57        if fill_start < end_byte {
58            slice[fill_start..end_byte].fill(fill_byte);
59        }
60
61        // Last partial byte
62        if end_rem != 0 {
63            let mask = (1u8 << end_rem) - 1;
64            if value {
65                slice[end_byte] |= mask;
66            } else {
67                slice[end_byte] &= !mask;
68            }
69        }
70    }
71}
72
73/// A mutable bitset buffer that allows random access to individual bits for set and get.
74///
75///
76/// # Example
77/// ```
78/// use vortex_buffer::BitBufferMut;
79///
80/// let mut bools = BitBufferMut::new_unset(10);
81/// bools.set_to(9, true);
82/// for i in 0..9 {
83///    assert!(!bools.value(i));
84/// }
85/// assert!(bools.value(9));
86///
87/// // Freeze into a new bools vector.
88/// let bools = bools.freeze();
89/// ```
90///
91/// See also: [`BitBuffer`].
92#[derive(Debug, Clone)]
93pub struct BitBufferMut {
94    buffer: ByteBufferMut,
95    /// Represents the offset of the bit buffer into the first byte.
96    ///
97    /// This is always less than 8 (for when the bit buffer is not aligned to a byte).
98    offset: usize,
99    len: usize,
100}
101
102impl BitBufferMut {
103    /// Create new bit buffer from given byte buffer and logical bit length
104    pub fn from_buffer(buffer: ByteBufferMut, offset: usize, len: usize) -> Self {
105        assert!(
106            len <= buffer.len() * 8,
107            "Buffer len {} is too short for the given length {len}",
108            buffer.len()
109        );
110        Self {
111            buffer,
112            offset,
113            len,
114        }
115    }
116
117    /// Creates a `BitBufferMut` from a [`BitBuffer`] by copying all of the data over.
118    pub fn copy_from(bit_buffer: &BitBuffer) -> Self {
119        Self {
120            buffer: ByteBufferMut::copy_from(bit_buffer.inner()),
121            offset: bit_buffer.offset(),
122            len: bit_buffer.len(),
123        }
124    }
125
126    /// Create a new empty mutable bit buffer with requested capacity (in bits).
127    pub fn with_capacity(capacity: usize) -> Self {
128        Self {
129            buffer: BufferMut::with_capacity(capacity.div_ceil(8)),
130            offset: 0,
131            len: 0,
132        }
133    }
134
135    /// Create a new mutable buffer with requested `len` and all bits set to `true`.
136    pub fn new_set(len: usize) -> Self {
137        Self {
138            buffer: buffer_mut![0xFF; len.div_ceil(8)],
139            offset: 0,
140            len,
141        }
142    }
143
144    /// Create a new mutable buffer with requested `len` and all bits set to `false`.
145    pub fn new_unset(len: usize) -> Self {
146        Self {
147            buffer: BufferMut::zeroed(len.div_ceil(8)),
148            offset: 0,
149            len,
150        }
151    }
152
153    /// Create a new empty `BitBufferMut`.
154    #[inline(always)]
155    pub fn empty() -> Self {
156        Self::with_capacity(0)
157    }
158
159    /// Create a new mutable buffer with requested `len` and all bits set to `value`.
160    pub fn full(value: bool, len: usize) -> Self {
161        if value {
162            Self::new_set(len)
163        } else {
164            Self::new_unset(len)
165        }
166    }
167
168    /// Create a bit buffer of `len` with `indices` set as true.
169    pub fn from_indices(len: usize, indices: impl IntoIterator<Item = usize>) -> BitBufferMut {
170        let mut buffer = BufferMut::<u64>::zeroed(len.div_ceil(64));
171        for idx in indices {
172            assert!(idx < len, "index {idx} exceeds len {len}");
173            buffer.as_mut_slice()[idx / 64] |= 1 << (idx % 64);
174        }
175
176        let mut buffer = buffer.into_byte_buffer();
177        buffer.truncate(len.div_ceil(8));
178
179        Self {
180            buffer,
181            offset: 0,
182            len,
183        }
184    }
185
186    /// Invokes `f` with indexes `0..len` collecting the boolean results into a new `BitBufferMut`
187    #[inline]
188    pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
189        let num_words = len.div_ceil(64);
190        let mut buffer: BufferMut<u64> = BufferMut::with_capacity(num_words);
191        // SAFETY: `collect_bool_words` writes every word in `0..num_words` below
192        // before any read; `u64` has no invalid bit patterns and the assignments
193        // inside `collect_bool_words` are pure writes.
194        unsafe { buffer.set_len(num_words) };
195        collect_bool_words(buffer.as_mut_slice(), len, f);
196
197        let mut bytes = buffer.into_byte_buffer();
198        bytes.truncate(len.div_ceil(8));
199
200        Self {
201            buffer: bytes,
202            offset: 0,
203            len,
204        }
205    }
206
207    /// Return the underlying byte buffer.
208    pub fn inner(&self) -> &ByteBufferMut {
209        &self.buffer
210    }
211
212    /// Consumes the buffer and return the underlying byte buffer.
213    pub fn into_inner(self) -> ByteBufferMut {
214        self.buffer
215    }
216
217    /// Get the current populated length of the buffer.
218    #[inline(always)]
219    pub fn len(&self) -> usize {
220        self.len
221    }
222
223    /// True if the buffer has length 0.
224    #[inline(always)]
225    pub fn is_empty(&self) -> bool {
226        self.len == 0
227    }
228
229    /// Get the current bit offset of the buffer.
230    #[inline(always)]
231    pub fn offset(&self) -> usize {
232        self.offset
233    }
234
235    /// Get the value at the requested index.
236    #[inline(always)]
237    pub fn value(&self, index: usize) -> bool {
238        assert!(index < self.len);
239        // SAFETY: checked by assertion
240        unsafe { self.value_unchecked(index) }
241    }
242
243    /// Get the value at the requested index without bounds checking.
244    ///
245    /// # Safety
246    ///
247    /// The caller must ensure that `index` is less than the length of the buffer.
248    #[inline(always)]
249    pub unsafe fn value_unchecked(&self, index: usize) -> bool {
250        unsafe { get_bit_unchecked(self.buffer.as_ptr(), self.offset + index) }
251    }
252
253    /// Get the bit capacity of the buffer.
254    #[inline(always)]
255    pub fn capacity(&self) -> usize {
256        (self.buffer.capacity() * 8) - self.offset
257    }
258
259    /// Reserve additional bit capacity for the buffer.
260    pub fn reserve(&mut self, additional: usize) {
261        let required_bits = self.offset + self.len + additional;
262        let required_bytes = required_bits.div_ceil(8); // Rounds up.
263
264        let additional_bytes = required_bytes.saturating_sub(self.buffer.len());
265        self.buffer.reserve(additional_bytes);
266    }
267
268    /// Clears the bit buffer (but keeps any allocated memory).
269    pub fn clear(&mut self) {
270        // Also clear the byte buffer (not just `len`) so the "bits beyond len are zero"
271        // invariant holds; `append_false` and `append_buffer` rely on it.
272        self.buffer.clear();
273        self.len = 0;
274        self.offset = 0;
275    }
276
277    /// Set the bit at `index` to the given boolean value.
278    ///
279    /// This operation is checked so if `index` exceeds the buffer length, this will panic.
280    #[inline]
281    pub fn set_to(&mut self, index: usize, value: bool) {
282        if value {
283            self.set(index);
284        } else {
285            self.unset(index);
286        }
287    }
288
289    /// Set the bit at `index` to the given boolean value without checking bounds.
290    ///
291    /// # Safety
292    ///
293    /// The caller must ensure that `index` does not exceed the largest bit index in the backing buffer.
294    #[inline]
295    pub unsafe fn set_to_unchecked(&mut self, index: usize, value: bool) {
296        if value {
297            // SAFETY: checked by caller
298            unsafe { self.set_unchecked(index) }
299        } else {
300            // SAFETY: checked by caller
301            unsafe { self.unset_unchecked(index) }
302        }
303    }
304
305    /// Set a position to `true`.
306    ///
307    /// This operation is checked so if `index` exceeds the buffer length, this will panic.
308    #[inline]
309    pub fn set(&mut self, index: usize) {
310        assert!(index < self.len, "index {index} exceeds len {}", self.len);
311
312        // SAFETY: checked by assertion
313        unsafe { self.set_unchecked(index) };
314    }
315
316    /// Set a position to `false`.
317    ///
318    /// This operation is checked so if `index` exceeds the buffer length, this will panic.
319    #[inline]
320    pub fn unset(&mut self, index: usize) {
321        assert!(index < self.len, "index {index} exceeds len {}", self.len);
322
323        // SAFETY: checked by assertion
324        unsafe { self.unset_unchecked(index) };
325    }
326
327    /// Set the bit at `index` to `true` without checking bounds.
328    ///
329    /// Note: Do not call this in a tight loop. Prefer to use [`set_bit_unchecked`].
330    ///
331    /// # Safety
332    ///
333    /// The caller must ensure that `index` does not exceed the largest bit index in the backing buffer.
334    #[inline]
335    pub unsafe fn set_unchecked(&mut self, index: usize) {
336        // SAFETY: checked by caller
337        unsafe { set_bit_unchecked(self.buffer.as_mut_ptr(), self.offset + index) }
338    }
339
340    /// Unset the bit at `index` without checking bounds.
341    ///
342    /// Note: Do not call this in a tight loop. Prefer to use [`unset_bit_unchecked`].
343    ///
344    /// # Safety
345    ///
346    /// The caller must ensure that `index` does not exceed the largest bit index in the backing buffer.
347    #[inline]
348    pub unsafe fn unset_unchecked(&mut self, index: usize) {
349        // SAFETY: checked by caller
350        unsafe { unset_bit_unchecked(self.buffer.as_mut_ptr(), self.offset + index) }
351    }
352
353    /// Foces the length of the `BitBufferMut` to `new_len`.
354    ///
355    /// # Safety
356    ///
357    /// - `new_len` must be less than or equal to [`capacity()`](Self::capacity)
358    /// - The elements at `old_len..new_len` must be initialized
359    #[inline(always)]
360    pub unsafe fn set_len(&mut self, new_len: usize) {
361        debug_assert!(
362            new_len <= self.capacity(),
363            "`set_len` requires that new_len <= capacity()"
364        );
365
366        // Calculate the new byte length required to hold the bits
367        let bytes_len = (self.offset + new_len).div_ceil(8);
368        unsafe { self.buffer.set_len(bytes_len) };
369
370        self.len = new_len;
371    }
372
373    /// Truncate the buffer to the given length.
374    ///
375    /// If the given length is greater than the current length, this is a no-op.
376    pub fn truncate(&mut self, len: usize) {
377        if len > self.len {
378            return;
379        }
380
381        let end_bit = self.offset + len;
382        let new_len_bytes = end_bit.div_ceil(8);
383        self.buffer.truncate(new_len_bytes);
384        self.len = len;
385
386        // Clear stale bits in the final partial byte so the "bits beyond len are zero" invariant
387        // holds. `append_false` (and `append_buffer`) rely on it to avoid a read-modify-write.
388        if !end_bit.is_multiple_of(8) {
389            let keep = (1u8 << (end_bit % 8)) - 1;
390            self.buffer.as_mut_slice()[new_len_bytes - 1] &= keep;
391        }
392    }
393
394    /// Append a new boolean into the bit buffer, incrementing the length.
395    #[inline]
396    pub fn append(&mut self, value: bool) {
397        if value {
398            self.append_true()
399        } else {
400            self.append_false()
401        }
402    }
403
404    /// Append a new true value to the buffer.
405    #[inline]
406    pub fn append_true(&mut self) {
407        let bit_pos = self.offset + self.len;
408        let byte_pos = bit_pos / 8;
409        let bit_in_byte = bit_pos % 8;
410
411        // Ensure buffer has enough bytes
412        if byte_pos >= self.buffer.len() {
413            self.buffer.push(0u8);
414        }
415
416        // Set the bit
417        self.buffer.as_mut_slice()[byte_pos] |= 1 << bit_in_byte;
418        self.len += 1;
419    }
420
421    /// Append a new false value to the buffer.
422    #[inline]
423    pub fn append_false(&mut self) {
424        let bit_pos = self.offset + self.len;
425        let byte_pos = bit_pos / 8;
426
427        // Ensure buffer has enough bytes (pushed as 0x00, so bit is already unset).
428        if byte_pos >= self.buffer.len() {
429            self.buffer.push(0u8);
430        }
431
432        // The bit is guaranteed to be 0: new bytes are zero-initialized, and
433        // existing bytes have this bit unset (it's beyond the current length).
434        self.len += 1;
435    }
436
437    /// Append several boolean values into the bit buffer. After this operation,
438    /// the length will be incremented by `n`.
439    ///
440    /// Panics if the buffer does not have `n` slots left.
441    #[inline]
442    pub fn append_n(&mut self, value: bool, n: usize) {
443        if n == 0 {
444            return;
445        }
446
447        let end_bit_pos = self.offset + self.len + n;
448        let required_bytes = end_bit_pos.div_ceil(8);
449
450        // Ensure buffer has enough bytes
451        if required_bytes > self.buffer.len() {
452            self.buffer.push_n(0x00, required_bytes - self.buffer.len());
453        }
454
455        let start = self.len;
456        self.len += n;
457        self.fill_range(start, self.len, value);
458    }
459
460    /// Sets all bits in the range `[start, end)` to `value`.
461    ///
462    /// This operates on an arbitrary range within the existing length of the buffer.
463    /// Panics if `end > self.len` or `start > end`.
464    #[inline(always)]
465    pub fn fill_range(&mut self, start: usize, end: usize, value: bool) {
466        assert!(end <= self.len, "end {end} exceeds len {}", self.len);
467        assert!(start <= end, "start {start} exceeds end {end}");
468
469        // SAFETY: assertions above guarantee start <= end <= self.len,
470        // so offset + end fits within the buffer.
471        unsafe { self.fill_range_unchecked(start, end, value) }
472    }
473
474    /// Sets all bits in the range `[start, end)` to `value` without bounds checking.
475    ///
476    /// # Safety
477    ///
478    /// The caller must ensure that `start <= end <= self.len`.
479    #[inline(always)]
480    pub unsafe fn fill_range_unchecked(&mut self, start: usize, end: usize, value: bool) {
481        fill_bits(
482            self.buffer.as_mut_slice(),
483            self.offset + start,
484            self.offset + end,
485            value,
486        );
487    }
488
489    /// Append a [`BitBuffer`] to this [`BitBufferMut`]
490    ///
491    /// This efficiently copies all bits from the source buffer to the end of this buffer.
492    pub fn append_buffer(&mut self, buffer: &BitBuffer) {
493        let bit_len = buffer.len();
494        if bit_len == 0 {
495            return;
496        }
497
498        let start_bit_pos = self.offset + self.len;
499        let end_bit_pos = start_bit_pos + bit_len;
500        let required_bytes = end_bit_pos.div_ceil(8);
501
502        // Ensure buffer has enough bytes, zero-initialized for OR-based writes.
503        if required_bytes > self.buffer.len() {
504            self.buffer.push_n(0x00, required_bytes - self.buffer.len());
505        }
506
507        let dst_bit_offset = start_bit_pos % 8;
508        let src_bit_offset = buffer.offset();
509
510        if dst_bit_offset == 0 && src_bit_offset == 0 {
511            // Both byte-aligned: use memcpy for full bytes, then mask the tail.
512            let dst_byte = start_bit_pos / 8;
513            let src_bytes = buffer.inner().as_slice();
514            let full_bytes = bit_len / 8;
515            self.buffer.as_mut_slice()[dst_byte..dst_byte + full_bytes]
516                .copy_from_slice(&src_bytes[..full_bytes]);
517            let rem = bit_len % 8;
518            if rem != 0 {
519                let mask = (1u8 << rem) - 1;
520                self.buffer.as_mut_slice()[dst_byte + full_bytes] |= src_bytes[full_bytes] & mask;
521            }
522        } else {
523            // Use bitvec for unaligned bit copying.
524            let self_slice = self
525                .buffer
526                .as_mut_slice()
527                .view_bits_mut::<bitvec::prelude::Lsb0>();
528            let other_slice = buffer
529                .inner()
530                .as_slice()
531                .view_bits::<bitvec::prelude::Lsb0>();
532            let source_range = src_bit_offset..src_bit_offset + bit_len;
533            self_slice[start_bit_pos..end_bit_pos].copy_from_bitslice(&other_slice[source_range]);
534        }
535
536        self.len += bit_len;
537    }
538
539    /// Absorbs a mutable buffer that was previously split off.
540    ///
541    /// If the two buffers were previously contiguous and not mutated in a way that causes
542    /// re-allocation i.e., if other was created by calling split_off on this buffer, then this is
543    /// an O(1) operation that just decreases a reference count and sets a few indices.
544    ///
545    /// Otherwise, this method degenerates to self.append_buffer(&other).
546    pub fn unsplit(&mut self, other: Self) {
547        if (self.offset + self.len).is_multiple_of(8) && other.offset == 0 {
548            // We are aligned and can just append the buffers
549            self.buffer.unsplit(other.buffer);
550            self.len += other.len;
551            return;
552        }
553
554        // Otherwise, we need to append the bits one by one
555        self.append_buffer(&other.freeze())
556    }
557
558    /// Freeze the buffer in its current state into an immutable `BoolBuffer`.
559    pub fn freeze(self) -> BitBuffer {
560        BitBuffer::new_with_offset(self.buffer.freeze(), self.len, self.offset)
561    }
562
563    /// Get the underlying bytes as a slice
564    pub fn as_slice(&self) -> &[u8] {
565        self.buffer.as_slice()
566    }
567
568    /// Get the underlying bytes as a mutable slice
569    pub fn as_mut_slice(&mut self) -> &mut [u8] {
570        self.buffer.as_mut_slice()
571    }
572}
573
574impl Default for BitBufferMut {
575    fn default() -> Self {
576        Self::with_capacity(0)
577    }
578}
579
580// Mutate-in-place implementation of bitwise NOT.
581impl Not for BitBufferMut {
582    type Output = BitBufferMut;
583
584    #[inline]
585    fn not(mut self) -> Self::Output {
586        ops::bitwise_unary_op_mut(&mut self, |b| !b);
587        self
588    }
589}
590
591impl From<&[bool]> for BitBufferMut {
592    fn from(value: &[bool]) -> Self {
593        BitBufferMut::collect_bool(value.len(), |i| value[i])
594    }
595}
596
597// allow building a buffer from a set of truthy byte values.
598impl From<&[u8]> for BitBufferMut {
599    fn from(value: &[u8]) -> Self {
600        BitBufferMut::collect_bool(value.len(), |i| value[i] > 0)
601    }
602}
603
604impl From<Vec<bool>> for BitBufferMut {
605    fn from(value: Vec<bool>) -> Self {
606        value.as_slice().into()
607    }
608}
609
610impl FromIterator<bool> for BitBufferMut {
611    #[inline]
612    fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
613        let mut iter = iter.into_iter();
614
615        // Since we do not know the length of the iterator, we can only guess how much memory we
616        // need to reserve. Note that these hints may be inaccurate.
617        let (lower_bound, _) = iter.size_hint();
618
619        // We choose not to use the optional upper bound size hint to match the standard library.
620
621        // Initialize all bits to 0 with the given length. By doing this, we only need to set bits
622        // that are true (and this is faster from benchmarks).
623        let mut buf = BitBufferMut::new_unset(lower_bound);
624        assert_eq!(buf.offset, 0);
625
626        // Directly write within our known capacity.
627        let ptr = buf.buffer.as_mut_ptr();
628        for i in 0..lower_bound {
629            let Some(v) = iter.next() else {
630                // SAFETY: We are definitely under the capacity and all values are already
631                // initialized from `new_unset`.
632                unsafe { buf.set_len(i) };
633                return buf;
634            };
635
636            if v {
637                // SAFETY: We have ensured that we are within the capacity.
638                unsafe { set_bit_unchecked(ptr, i) }
639            }
640        }
641
642        // Append any remaining items one at a time, as we do not know how many more there are.
643        // (`append` is already a single branch + bit set, see `append_true`/`append_false`.)
644        for v in iter {
645            buf.append(v);
646        }
647
648        buf
649    }
650}
651
652#[cfg(test)]
653mod tests {
654    use rstest::rstest;
655
656    use crate::BufferMut;
657    use crate::bit::buf_mut::BitBufferMut;
658    use crate::bitbuffer;
659    use crate::bitbuffer_mut;
660    use crate::buffer_mut;
661
662    #[test]
663    fn test_bits_mut() {
664        let mut bools = bitbuffer_mut![false; 10];
665        bools.set_to(0, true);
666        bools.set_to(9, true);
667
668        let bools = bools.freeze();
669        assert!(bools.value(0));
670        for i in 1..=8 {
671            assert!(!bools.value(i));
672        }
673        assert!(bools.value(9));
674    }
675
676    #[test]
677    fn test_append_n() {
678        let mut bools = BitBufferMut::with_capacity(10);
679        assert_eq!(bools.len(), 0);
680        assert!(bools.is_empty());
681
682        bools.append(true);
683        bools.append_n(false, 8);
684        bools.append_n(true, 1);
685
686        let bools = bools.freeze();
687
688        assert_eq!(bools.true_count(), 2);
689        assert!(bools.value(0));
690        assert!(bools.value(9));
691    }
692
693    #[test]
694    fn append_false_after_truncate_reads_back_false() {
695        // `truncate` leaves stale bits in the final partial byte; a subsequent `append_false`
696        // must still read back as false. Regression test for the `append_false` fast path.
697        let mut bools = BitBufferMut::new_set(16);
698        bools.truncate(12);
699        bools.append_false();
700        bools.append_true();
701
702        let bools = bools.freeze();
703        assert_eq!(bools.len(), 14);
704        assert!(
705            !bools.value(12),
706            "appended false must read back false after truncate"
707        );
708        assert!(bools.value(13));
709    }
710
711    #[test]
712    fn test_reserve_ensures_len_plus_additional() {
713        // This test documents the fix for the bug where reserve was incorrectly
714        // calculating additional bytes from capacity instead of len.
715
716        let mut bits = BitBufferMut::with_capacity(10);
717        assert_eq!(bits.len(), 0);
718
719        bits.reserve(100);
720
721        // Should have capacity for at least len + 100 = 0 + 100 = 100 bits.
722        assert!(bits.capacity() >= 100);
723
724        bits.append_n(true, 50);
725        assert_eq!(bits.len(), 50);
726
727        bits.reserve(100);
728
729        // Should have capacity for at least len + 100 = 50 + 100 = 150 bits.
730        assert!(bits.capacity() >= 150);
731    }
732
733    #[test]
734    fn test_with_offset_zero() {
735        // Test basic operations when offset is 0
736        let buf = BufferMut::zeroed(2);
737        let mut bit_buf = BitBufferMut::from_buffer(buf, 0, 16);
738
739        // Set some bits
740        bit_buf.set(0);
741        bit_buf.set(7);
742        bit_buf.set(8);
743        bit_buf.set(15);
744
745        // Verify values
746        assert!(bit_buf.value(0));
747        assert!(bit_buf.value(7));
748        assert!(bit_buf.value(8));
749        assert!(bit_buf.value(15));
750        assert!(!bit_buf.value(1));
751        assert!(!bit_buf.value(9));
752
753        // Verify underlying bytes
754        assert_eq!(bit_buf.as_slice()[0], 0b10000001);
755        assert_eq!(bit_buf.as_slice()[1], 0b10000001);
756    }
757
758    #[test]
759    fn test_with_offset_within_byte() {
760        // Test operations with offset=3 (within first byte)
761        let buf = buffer_mut![0b11111111, 0b00000000, 0b00000000];
762        let mut bit_buf = BitBufferMut::from_buffer(buf, 3, 10);
763
764        // Initially, bits 3-7 from first byte are set (5 bits)
765        // and bits 0-4 from second byte are unset (5 bits more)
766        assert!(bit_buf.value(0)); // bit 3 of byte 0
767        assert!(bit_buf.value(4)); // bit 7 of byte 0
768        assert!(!bit_buf.value(5)); // bit 0 of byte 1
769
770        // Set a bit in the second byte's range
771        bit_buf.set(7);
772        assert!(bit_buf.value(7));
773
774        // Unset a bit in the first byte's range
775        bit_buf.unset(0);
776        assert!(!bit_buf.value(0));
777    }
778
779    #[test]
780    fn test_with_offset_byte_boundary() {
781        // Test operations with offset=8 (exactly one byte)
782        let buf = buffer_mut![0xFF, 0x00, 0xFF];
783        let mut bit_buf = BitBufferMut::from_buffer(buf, 8, 16);
784
785        // Buffer starts at byte 1, so all bits should be unset initially
786        for i in 0..8 {
787            assert!(!bit_buf.value(i));
788        }
789        // Next byte has all bits set
790        for i in 8..16 {
791            assert!(bit_buf.value(i));
792        }
793
794        // Set some bits
795        bit_buf.set(0);
796        bit_buf.set(3);
797        assert!(bit_buf.value(0));
798        assert!(bit_buf.value(3));
799    }
800
801    #[test]
802    fn test_with_large_offset() {
803        // Test with offset=13 (one byte + 5 bits)
804        let buf = buffer_mut![0xFF, 0xFF, 0xFF, 0xFF];
805        let mut bit_buf = BitBufferMut::from_buffer(buf, 13, 10);
806
807        // All bits should initially be set
808        for i in 0..10 {
809            assert!(bit_buf.value(i));
810        }
811
812        // Unset some bits
813        bit_buf.unset(0);
814        bit_buf.unset(5);
815        bit_buf.unset(9);
816
817        assert!(!bit_buf.value(0));
818        assert!(bit_buf.value(1));
819        assert!(!bit_buf.value(5));
820        assert!(!bit_buf.value(9));
821    }
822
823    #[test]
824    fn test_append_with_offset() {
825        // Create buffer with offset
826        let buf = buffer_mut![0b11100000]; // First 3 bits unset, last 5 set
827        let mut bit_buf = BitBufferMut::from_buffer(buf, 3, 0); // Start at bit 3, len=0
828
829        // Append some bits
830        bit_buf.append(false); // Should use bit 3
831        bit_buf.append(true); // Should use bit 4
832        bit_buf.append(true); // Should use bit 5
833
834        assert_eq!(bit_buf.len(), 3);
835        assert!(!bit_buf.value(0));
836        assert!(bit_buf.value(1));
837        assert!(bit_buf.value(2));
838    }
839
840    #[test]
841    fn test_append_n_with_offset_crossing_boundary() {
842        // Create buffer with offset that will cross byte boundary when appending
843        let buf = BufferMut::zeroed(4);
844        let mut bit_buf = BitBufferMut::from_buffer(buf, 5, 0);
845
846        // Append enough bits to cross into next byte
847        bit_buf.append_n(true, 10); // 5 bits left in first byte, then 5 in second
848
849        assert_eq!(bit_buf.len(), 10);
850        for i in 0..10 {
851            assert!(bit_buf.value(i));
852        }
853
854        // Verify the underlying bytes
855        // Bits 5-7 of byte 0 should be set (3 bits)
856        // Bits 0-6 of byte 1 should be set (7 bits)
857        assert_eq!(bit_buf.as_slice()[0], 0b11100000);
858        assert_eq!(bit_buf.as_slice()[1], 0b01111111);
859    }
860
861    #[test]
862    fn test_truncate_with_offset() {
863        let buf = buffer_mut![0xFF, 0xFF];
864        let mut bit_buf = BitBufferMut::from_buffer(buf, 4, 12);
865
866        assert_eq!(bit_buf.len(), 12);
867
868        // Truncate to 8 bits
869        bit_buf.truncate(8);
870        assert_eq!(bit_buf.len(), 8);
871
872        // Truncate to 3 bits
873        bit_buf.truncate(3);
874        assert_eq!(bit_buf.len(), 3);
875
876        // Truncating to larger length should be no-op
877        bit_buf.truncate(10);
878        assert_eq!(bit_buf.len(), 3);
879    }
880
881    #[test]
882    fn test_capacity_with_offset() {
883        // Use exact buffer size to test capacity calculation
884        let buf = buffer_mut![0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // Exactly 10 bytes = 80 bits
885        let bit_buf = BitBufferMut::from_buffer(buf, 5, 0);
886
887        // Capacity should be at least buffer length minus offset
888        // (may be more due to allocator rounding)
889        assert!(bit_buf.capacity() >= 75);
890        // And should account for offset
891        assert_eq!(bit_buf.capacity() % 8, (80 - 5) % 8);
892    }
893
894    #[test]
895    fn test_reserve_with_offset() {
896        // Use exact buffer to test reserve
897        let buf = buffer_mut![0, 0]; // Exactly 2 bytes = 16 bits
898        let mut bit_buf = BitBufferMut::from_buffer(buf, 3, 0);
899
900        // Current capacity should be at least 13 bits (16 - 3)
901        let initial_capacity = bit_buf.capacity();
902        assert!(initial_capacity >= 13);
903
904        // Reserve 20 more bits (need total of offset 3 + len 0 + additional 20 = 23 bits)
905        bit_buf.reserve(20);
906
907        // Should now have at least 20 bits of capacity
908        assert!(bit_buf.capacity() >= 20);
909    }
910
911    #[test]
912    fn test_freeze_with_offset() {
913        let buf = buffer_mut![0b11110000, 0b00001111];
914        let mut bit_buf = BitBufferMut::from_buffer(buf, 4, 8);
915
916        // Set some bits
917        bit_buf.set(0);
918        bit_buf.set(7);
919
920        // Freeze and verify offset is preserved
921        let frozen = bit_buf.freeze();
922        assert_eq!(frozen.offset(), 4);
923        assert_eq!(frozen.len(), 8);
924
925        // Verify values through frozen buffer
926        assert!(frozen.value(0));
927        assert!(frozen.value(7));
928    }
929
930    #[cfg_attr(miri, ignore)] // bitvec crate uses a ptr cast that Miri doesn't support
931    #[test]
932    fn append_after_clear_reads_back_false() {
933        // `clear` must not leave stale set bits behind: `append_false` and `append_buffer`
934        // rely on bits beyond `len` being zero.
935        let mut bools = BitBufferMut::new_set(16);
936        bools.clear();
937        bools.append_false();
938        bools.append_buffer(&crate::BitBuffer::new_unset(8));
939
940        let bools = bools.freeze();
941        assert_eq!(bools.len(), 9);
942        assert_eq!(bools.true_count(), 0);
943    }
944
945    #[cfg_attr(miri, ignore)] // bitvec crate uses a ptr cast that Miri doesn't support
946    #[test]
947    fn test_append_buffer_after_truncate() {
948        // Truncating leaves stale set bits in the last partial byte; an append after that
949        // must overwrite them rather than OR into them.
950        let mut buf = BitBufferMut::new_set(16);
951        buf.truncate(3);
952        buf.append_buffer(&crate::BitBuffer::new_unset(8));
953
954        let frozen = buf.freeze();
955        assert_eq!(frozen.len(), 11);
956        for i in 0..3 {
957            assert!(frozen.value(i), "bit {i} should be set");
958        }
959        for i in 3..11 {
960            assert!(!frozen.value(i), "bit {i} should be unset");
961        }
962    }
963
964    #[rstest]
965    #[case::both_aligned(0, 0)]
966    #[case::dst_unaligned(3, 0)]
967    #[case::src_unaligned(0, 5)]
968    #[case::mismatched(3, 5)]
969    #[case::equal_nonzero(5, 5)]
970    #[cfg_attr(miri, ignore)] // bitvec crate uses a ptr cast that Miri doesn't support
971    fn test_append_buffer_long(#[case] dst_prefix: usize, #[case] src_start: usize) {
972        // Exercise every alignment combination across many words.
973        let source = crate::BitBuffer::from_iter((0..301).map(|i| i % 3 == 0));
974        let source = source.slice(src_start..301);
975
976        let mut dest = BitBufferMut::with_capacity(512);
977        dest.append_n(true, dst_prefix);
978        dest.append_buffer(&source);
979
980        assert_eq!(dest.len(), dst_prefix + source.len());
981        for i in 0..dst_prefix {
982            assert!(dest.value(i), "prefix bit {i}");
983        }
984        for i in 0..source.len() {
985            assert_eq!(dest.value(dst_prefix + i), source.value(i), "bit {i}");
986        }
987    }
988
989    #[cfg_attr(miri, ignore)] // bitvec crate uses a ptr cast that Miri doesn't support
990    #[test]
991    fn test_append_buffer_with_offsets() {
992        // Create source buffer with offset
993        let source = bitbuffer![false, false, true, true, false, true];
994
995        // Create destination buffer with offset
996        let buf = BufferMut::zeroed(4);
997        let mut dest = BitBufferMut::from_buffer(buf, 3, 0);
998
999        // Append 2 initial bits
1000        dest.append(true);
1001        dest.append(false);
1002
1003        // Append the source buffer
1004        dest.append_buffer(&source);
1005
1006        assert_eq!(dest.len(), 8);
1007        assert!(dest.value(0)); // Our first append
1008        assert!(!dest.value(1)); // Our second append
1009        assert!(!dest.value(2)); // From source[0]
1010        assert!(!dest.value(3)); // From source[1]
1011        assert!(dest.value(4)); // From source[2]
1012        assert!(dest.value(5)); // From source[3]
1013        assert!(!dest.value(6)); // From source[4]
1014        assert!(dest.value(7)); // From source[5]
1015    }
1016
1017    #[test]
1018    fn test_set_unset_unchecked_with_offset() {
1019        let buf = BufferMut::zeroed(3);
1020        let mut bit_buf = BitBufferMut::from_buffer(buf, 7, 10);
1021
1022        unsafe {
1023            bit_buf.set_unchecked(0);
1024            bit_buf.set_unchecked(5);
1025            bit_buf.set_unchecked(9);
1026        }
1027
1028        assert!(bit_buf.value(0));
1029        assert!(bit_buf.value(5));
1030        assert!(bit_buf.value(9));
1031
1032        unsafe {
1033            bit_buf.unset_unchecked(5);
1034        }
1035
1036        assert!(!bit_buf.value(5));
1037    }
1038
1039    #[test]
1040    fn test_value_unchecked_with_offset() {
1041        let buf = buffer_mut![0b11110000, 0b00001111];
1042        let bit_buf = BitBufferMut::from_buffer(buf, 4, 8);
1043
1044        unsafe {
1045            // First 4 bits of logical buffer come from bits 4-7 of first byte (all 1s)
1046            assert!(bit_buf.value_unchecked(0));
1047            assert!(bit_buf.value_unchecked(3));
1048
1049            // Next 4 bits come from bits 0-3 of second byte (all 1s)
1050            assert!(bit_buf.value_unchecked(4));
1051            assert!(bit_buf.value_unchecked(7));
1052        }
1053    }
1054
1055    #[test]
1056    fn test_append_alternating_with_offset() {
1057        let buf = BufferMut::zeroed(4);
1058        let mut bit_buf = BitBufferMut::from_buffer(buf, 2, 0);
1059
1060        // Append alternating pattern across byte boundaries
1061        for i in 0..20 {
1062            bit_buf.append(i % 2 == 0);
1063        }
1064
1065        assert_eq!(bit_buf.len(), 20);
1066        for i in 0..20 {
1067            assert_eq!(bit_buf.value(i), i % 2 == 0);
1068        }
1069    }
1070
1071    #[test]
1072    fn test_new_set_new_unset() {
1073        let set_buf = bitbuffer_mut![true; 10];
1074        let unset_buf = bitbuffer_mut![false; 10];
1075
1076        for i in 0..10 {
1077            assert!(set_buf.value(i));
1078            assert!(!unset_buf.value(i));
1079        }
1080
1081        assert_eq!(set_buf.len(), 10);
1082        assert_eq!(unset_buf.len(), 10);
1083    }
1084
1085    #[test]
1086    fn test_append_n_false_with_offset() {
1087        let buf = BufferMut::zeroed(4);
1088        let mut bit_buf = BitBufferMut::from_buffer(buf, 5, 0);
1089
1090        bit_buf.append_n(false, 15);
1091
1092        assert_eq!(bit_buf.len(), 15);
1093        for i in 0..15 {
1094            assert!(!bit_buf.value(i));
1095        }
1096    }
1097
1098    #[test]
1099    fn test_append_n_true_with_offset() {
1100        let buf = BufferMut::zeroed(4);
1101        let mut bit_buf = BitBufferMut::from_buffer(buf, 5, 0);
1102
1103        bit_buf.append_n(true, 15);
1104
1105        assert_eq!(bit_buf.len(), 15);
1106        for i in 0..15 {
1107            assert!(bit_buf.value(i));
1108        }
1109    }
1110
1111    #[test]
1112    fn test_mixed_operations_with_offset() {
1113        // Complex test combining multiple operations with offset
1114        let buf = BufferMut::zeroed(5);
1115        let mut bit_buf = BitBufferMut::from_buffer(buf, 3, 0);
1116
1117        // Append some bits
1118        bit_buf.append_n(true, 5);
1119        bit_buf.append_n(false, 3);
1120        bit_buf.append(true);
1121
1122        assert_eq!(bit_buf.len(), 9);
1123
1124        // Set and unset
1125        bit_buf.set(6); // Was false, now true
1126        bit_buf.unset(2); // Was true, now false
1127
1128        // Verify
1129        assert!(bit_buf.value(0));
1130        assert!(bit_buf.value(1));
1131        assert!(!bit_buf.value(2)); // Unset
1132        assert!(bit_buf.value(3));
1133        assert!(bit_buf.value(4));
1134        assert!(!bit_buf.value(5));
1135        assert!(bit_buf.value(6)); // Set
1136        assert!(!bit_buf.value(7));
1137        assert!(bit_buf.value(8));
1138
1139        // Truncate
1140        bit_buf.truncate(6);
1141        assert_eq!(bit_buf.len(), 6);
1142
1143        // Freeze and verify offset preserved
1144        let frozen = bit_buf.freeze();
1145        assert_eq!(frozen.offset(), 3);
1146        assert_eq!(frozen.len(), 6);
1147    }
1148
1149    #[test]
1150    fn test_from_iterator_with_incorrect_size_hint() {
1151        // This test catches a bug where FromIterator assumed the upper bound
1152        // from size_hint was accurate. The iterator contract allows the actual
1153        // count to exceed the upper bound, which could cause UB if we used
1154        // append_unchecked beyond the allocated capacity.
1155
1156        // Custom iterator that lies about its size hint.
1157        struct LyingIterator {
1158            values: Vec<bool>,
1159            index: usize,
1160        }
1161
1162        impl Iterator for LyingIterator {
1163            type Item = bool;
1164
1165            fn next(&mut self) -> Option<Self::Item> {
1166                (self.index < self.values.len()).then(|| {
1167                    let val = self.values[self.index];
1168                    self.index += 1;
1169                    val
1170                })
1171            }
1172
1173            fn size_hint(&self) -> (usize, Option<usize>) {
1174                // Deliberately return an incorrect upper bound that's smaller
1175                // than the actual number of elements we'll yield.
1176                let remaining = self.values.len() - self.index;
1177                let lower = remaining.min(5); // Correct lower bound (but capped).
1178                let upper = Some(5); // Incorrect upper bound - we actually have more!
1179                (lower, upper)
1180            }
1181        }
1182
1183        // Create an iterator that claims to have at most 5 elements but actually has 10.
1184        let lying_iter = LyingIterator {
1185            values: vec![
1186                true, false, true, false, true, false, true, false, true, false,
1187            ],
1188            index: 0,
1189        };
1190
1191        // Collect the iterator. This would cause UB in the old implementation
1192        // if it trusted the upper bound and used append_unchecked beyond capacity.
1193        let bit_buf: BitBufferMut = lying_iter.collect();
1194
1195        // Verify all 10 elements were collected correctly.
1196        assert_eq!(bit_buf.len(), 10);
1197        for i in 0..10 {
1198            assert_eq!(bit_buf.value(i), i % 2 == 0);
1199        }
1200    }
1201}