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