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