Skip to main content

vortex_buffer/bit/
view.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::ops::Bound;
5use std::ops::RangeBounds;
6
7use crate::BitBuffer;
8use crate::BitBufferMeta;
9use crate::BitBufferMut;
10use crate::ByteBuffer;
11use crate::bit::BitChunks;
12use crate::bit::BitIndexIterator;
13use crate::bit::BitIterator;
14use crate::bit::BitSliceIterator;
15use crate::bit::UnalignedBitChunk;
16use crate::bit::buf_mut::fill_bits;
17use crate::bit::count_ones::count_ones;
18use crate::bit::get_bit_unchecked;
19use crate::bit::select::bit_select;
20use crate::bit::set_bit_unchecked;
21use crate::bit::unset_bit_unchecked;
22
23/// Resolve `start..end` bounds against a logical length, panicking on invalid ranges.
24#[inline]
25fn resolve_range(range: impl RangeBounds<usize>, len: usize) -> (usize, usize) {
26    let start = match range.start_bound() {
27        Bound::Included(&s) => s,
28        Bound::Excluded(&s) => s + 1,
29        Bound::Unbounded => 0,
30    };
31    let end = match range.end_bound() {
32        Bound::Included(&e) => e + 1,
33        Bound::Excluded(&e) => e,
34        Bound::Unbounded => len,
35    };
36
37    assert!(start <= end);
38    assert!(start <= len);
39    assert!(end <= len);
40    (start, end)
41}
42
43/// Normalize a byte slice and bit offset so that the returned offset is `< 8`.
44#[inline]
45fn normalize(buffer: &[u8], offset: usize) -> (&[u8], usize) {
46    let byte_offset = offset / 8;
47    (&buffer[byte_offset..], offset % 8)
48}
49
50/// An immutable, borrowed view over a packed bitset.
51///
52/// This is the borrowing analogue of [`BitBuffer`]: it stores a byte slice together with a bit
53/// `offset` (always `< 8`) and a logical bit `len`, without owning or reference-counting the
54/// backing allocation. Use it to read a bitset without cloning the underlying [`ByteBuffer`].
55#[derive(Debug, Clone, Copy)]
56pub struct BitBufferView<'a> {
57    buffer: &'a [u8],
58    offset: usize,
59    len: usize,
60}
61
62impl<'a> BitBufferView<'a> {
63    /// Create a new view over `buffer` with `len` bits, starting at bit zero.
64    ///
65    /// Panics if the buffer is not large enough to hold `len` bits.
66    pub fn new(buffer: &'a [u8], len: usize) -> Self {
67        Self::new_with_offset(buffer, len, 0)
68    }
69
70    /// Create a new view over `buffer` with `len` bits, starting at the given bit `offset`.
71    ///
72    /// Panics if the buffer is not large enough to hold `len` bits after the offset.
73    pub fn new_with_offset(buffer: &'a [u8], len: usize, offset: usize) -> Self {
74        assert!(
75            len.saturating_add(offset) <= buffer.len().saturating_mul(8),
76            "provided slice (len={}) not large enough to back BitBufferView with offset {offset} len {len}",
77            buffer.len()
78        );
79
80        let (buffer, offset) = normalize(buffer, offset);
81        Self {
82            buffer,
83            offset,
84            len,
85        }
86    }
87
88    /// Create a new view over `buffer` described by `meta`.
89    pub fn from_meta(buffer: &'a [u8], meta: BitBufferMeta) -> Self {
90        Self::new_with_offset(buffer, meta.len(), meta.offset())
91    }
92
93    /// Returns the [`BitBufferMeta`] (offset and length) describing this view.
94    pub fn meta(&self) -> BitBufferMeta {
95        BitBufferMeta::new(self.offset, self.len)
96    }
97
98    /// Get the logical length of this view in bits.
99    #[inline]
100    pub fn len(&self) -> usize {
101        self.len
102    }
103
104    /// Returns `true` if the view is empty.
105    #[inline]
106    pub fn is_empty(&self) -> bool {
107        self.len == 0
108    }
109
110    /// Offset of the start of the view in bits. Always `< 8`.
111    #[inline(always)]
112    pub fn offset(&self) -> usize {
113        self.offset
114    }
115
116    /// Get a reference to the underlying byte slice.
117    #[inline(always)]
118    pub fn inner(&self) -> &'a [u8] {
119        self.buffer
120    }
121
122    /// Retrieve the value at the given index.
123    ///
124    /// Panics if the index is out of bounds.
125    #[inline]
126    pub fn value(&self, index: usize) -> bool {
127        assert!(index < self.len);
128        // SAFETY: checked by assertion
129        unsafe { self.value_unchecked(index) }
130    }
131
132    /// Retrieve the value at the given index without bounds checking.
133    ///
134    /// # Safety
135    ///
136    /// Caller must ensure that `index` is within the range of the view.
137    #[inline]
138    pub unsafe fn value_unchecked(&self, index: usize) -> bool {
139        unsafe { get_bit_unchecked(self.buffer.as_ptr(), index + self.offset) }
140    }
141
142    /// Create a new view over the range `[start, end)` of this view.
143    ///
144    /// Panics if the slice would extend beyond the end of the view.
145    pub fn slice(&self, range: impl RangeBounds<usize>) -> BitBufferView<'a> {
146        let (start, end) = resolve_range(range, self.len);
147        BitBufferView::new_with_offset(self.buffer, end - start, self.offset + start)
148    }
149
150    /// Access chunks of the buffer aligned to an 8 byte boundary as
151    /// `[prefix, <full chunks>, suffix]`.
152    pub fn unaligned_chunks(&self) -> UnalignedBitChunk<'a> {
153        UnalignedBitChunk::new(self.buffer, self.offset, self.len)
154    }
155
156    /// Access chunks of the underlying buffer as 8 byte chunks with a final trailer.
157    pub fn chunks(&self) -> BitChunks<'a> {
158        BitChunks::new(self.buffer, self.offset, self.len)
159    }
160
161    /// Get the number of set bits in the view.
162    pub fn true_count(&self) -> usize {
163        count_ones(self.buffer, self.offset, self.len)
164    }
165
166    /// Get the number of unset bits in the view.
167    pub fn false_count(&self) -> usize {
168        self.len - self.true_count()
169    }
170
171    /// Returns the position of the `nth` set bit (0-indexed), or `None` if out of range.
172    pub fn select(&self, nth: usize) -> Option<usize> {
173        bit_select(self.buffer, self.offset, self.len, nth)
174    }
175
176    /// Iterator over bits in the view.
177    pub fn iter(&self) -> BitIterator<'a> {
178        BitIterator::new(self.buffer, self.offset, self.len)
179    }
180
181    /// Iterator over set indices of the underlying buffer.
182    pub fn set_indices(&self) -> BitIndexIterator<'a> {
183        BitIndexIterator::new(self.buffer, self.offset, self.len)
184    }
185
186    /// Iterator over set slices of the underlying buffer.
187    pub fn set_slices(&self) -> BitSliceIterator<'a> {
188        BitSliceIterator::new(self.buffer, self.offset, self.len)
189    }
190
191    /// Copy this view into an owned [`BitBuffer`].
192    pub fn to_bit_buffer(&self) -> BitBuffer {
193        let bytes = (self.offset + self.len).div_ceil(8);
194        BitBuffer::new_with_offset(
195            ByteBuffer::copy_from(&self.buffer[..bytes]),
196            self.len,
197            self.offset,
198        )
199    }
200}
201
202impl<'a> IntoIterator for BitBufferView<'a> {
203    type Item = bool;
204    type IntoIter = BitIterator<'a>;
205
206    fn into_iter(self) -> Self::IntoIter {
207        self.iter()
208    }
209}
210
211impl PartialEq for BitBufferView<'_> {
212    fn eq(&self, other: &Self) -> bool {
213        if self.len != other.len {
214            return false;
215        }
216
217        self.chunks()
218            .iter_padded()
219            .zip(other.chunks().iter_padded())
220            .all(|(a, b)| a == b)
221    }
222}
223
224impl Eq for BitBufferView<'_> {}
225
226/// A mutable, borrowed view over a packed bitset.
227///
228/// This is the borrowing analogue of [`BitBufferMut`]: it stores a mutable byte slice together
229/// with a bit `offset` (always `< 8`) and a logical bit `len`. Unlike [`BitBufferMut`] it cannot
230/// grow or reallocate, so it only supports in-place reads and writes (such as
231/// [`set`](Self::set), [`unset`](Self::unset), and [`fill_range`](Self::fill_range)).
232#[derive(Debug)]
233pub struct BitBufferMutView<'a> {
234    buffer: &'a mut [u8],
235    offset: usize,
236    len: usize,
237}
238
239impl<'a> BitBufferMutView<'a> {
240    /// Create a new mutable view over `buffer` with `len` bits, starting at bit zero.
241    ///
242    /// Panics if the buffer is not large enough to hold `len` bits.
243    pub fn new(buffer: &'a mut [u8], len: usize) -> Self {
244        Self::new_with_offset(buffer, len, 0)
245    }
246
247    /// Create a new mutable view over `buffer` with `len` bits, starting at bit `offset`.
248    ///
249    /// Panics if the buffer is not large enough to hold `len` bits after the offset.
250    pub fn new_with_offset(buffer: &'a mut [u8], len: usize, offset: usize) -> Self {
251        assert!(
252            len.saturating_add(offset) <= buffer.len().saturating_mul(8),
253            "provided slice (len={}) not large enough to back BitBufferMutView with offset {offset} len {len}",
254            buffer.len()
255        );
256
257        let byte_offset = offset / 8;
258        let offset = offset % 8;
259        Self {
260            buffer: &mut buffer[byte_offset..],
261            offset,
262            len,
263        }
264    }
265
266    /// Borrow this mutable view as an immutable [`BitBufferView`].
267    #[inline]
268    pub fn as_view(&self) -> BitBufferView<'_> {
269        BitBufferView {
270            buffer: self.buffer,
271            offset: self.offset,
272            len: self.len,
273        }
274    }
275
276    /// Get the logical length of this view in bits.
277    #[inline]
278    pub fn len(&self) -> usize {
279        self.len
280    }
281
282    /// Returns `true` if the view is empty.
283    #[inline]
284    pub fn is_empty(&self) -> bool {
285        self.len == 0
286    }
287
288    /// Offset of the start of the view in bits. Always `< 8`.
289    #[inline(always)]
290    pub fn offset(&self) -> usize {
291        self.offset
292    }
293
294    /// Get the underlying bytes as a slice.
295    #[inline]
296    pub fn as_slice(&self) -> &[u8] {
297        self.buffer
298    }
299
300    /// Get the underlying bytes as a mutable slice.
301    #[inline]
302    pub fn as_mut_slice(&mut self) -> &mut [u8] {
303        self.buffer
304    }
305
306    /// Retrieve the value at the given index.
307    ///
308    /// Panics if the index is out of bounds.
309    #[inline]
310    pub fn value(&self, index: usize) -> bool {
311        assert!(index < self.len);
312        // SAFETY: checked by assertion
313        unsafe { self.value_unchecked(index) }
314    }
315
316    /// Retrieve the value at the given index without bounds checking.
317    ///
318    /// # Safety
319    ///
320    /// Caller must ensure that `index` is within the range of the view.
321    #[inline]
322    pub unsafe fn value_unchecked(&self, index: usize) -> bool {
323        unsafe { get_bit_unchecked(self.buffer.as_ptr(), index + self.offset) }
324    }
325
326    /// Get the number of set bits in the view.
327    pub fn true_count(&self) -> usize {
328        self.as_view().true_count()
329    }
330
331    /// Get the number of unset bits in the view.
332    pub fn false_count(&self) -> usize {
333        self.as_view().false_count()
334    }
335
336    /// Iterator over bits in the view.
337    pub fn iter(&self) -> BitIterator<'_> {
338        self.as_view().iter()
339    }
340
341    /// Set the bit at `index` to the given boolean value.
342    ///
343    /// Panics if `index` exceeds the view length.
344    pub fn set_to(&mut self, index: usize, value: bool) {
345        if value {
346            self.set(index);
347        } else {
348            self.unset(index);
349        }
350    }
351
352    /// Set the bit at `index` to the given boolean value without bounds checking.
353    ///
354    /// # Safety
355    ///
356    /// Caller must ensure that `index` is within the range of the view.
357    pub unsafe fn set_to_unchecked(&mut self, index: usize, value: bool) {
358        if value {
359            // SAFETY: checked by caller
360            unsafe { self.set_unchecked(index) }
361        } else {
362            // SAFETY: checked by caller
363            unsafe { self.unset_unchecked(index) }
364        }
365    }
366
367    /// Set the bit at `index` to `true`.
368    ///
369    /// Panics if `index` exceeds the view length.
370    pub fn set(&mut self, index: usize) {
371        assert!(index < self.len, "index {index} exceeds len {}", self.len);
372        // SAFETY: checked by assertion
373        unsafe { self.set_unchecked(index) };
374    }
375
376    /// Set the bit at `index` to `false`.
377    ///
378    /// Panics if `index` exceeds the view length.
379    pub fn unset(&mut self, index: usize) {
380        assert!(index < self.len, "index {index} exceeds len {}", self.len);
381        // SAFETY: checked by assertion
382        unsafe { self.unset_unchecked(index) };
383    }
384
385    /// Set the bit at `index` to `true` without bounds checking.
386    ///
387    /// # Safety
388    ///
389    /// Caller must ensure that `index` is within the range of the view.
390    #[inline]
391    pub unsafe fn set_unchecked(&mut self, index: usize) {
392        // SAFETY: checked by caller
393        unsafe { set_bit_unchecked(self.buffer.as_mut_ptr(), self.offset + index) }
394    }
395
396    /// Set the bit at `index` to `false` without bounds checking.
397    ///
398    /// # Safety
399    ///
400    /// Caller must ensure that `index` is within the range of the view.
401    #[inline]
402    pub unsafe fn unset_unchecked(&mut self, index: usize) {
403        // SAFETY: checked by caller
404        unsafe { unset_bit_unchecked(self.buffer.as_mut_ptr(), self.offset + index) }
405    }
406
407    /// Sets all bits in the range `[start, end)` to `value`.
408    ///
409    /// Panics if `end > self.len()` or `start > end`.
410    #[inline(always)]
411    pub fn fill_range(&mut self, start: usize, end: usize, value: bool) {
412        assert!(end <= self.len, "end {end} exceeds len {}", self.len);
413        assert!(start <= end, "start {start} exceeds end {end}");
414        // SAFETY: assertions guarantee start <= end <= self.len.
415        unsafe { self.fill_range_unchecked(start, end, value) }
416    }
417
418    /// Sets all bits in the range `[start, end)` to `value` without bounds checking.
419    ///
420    /// # Safety
421    ///
422    /// Caller must ensure that `start <= end <= self.len()`.
423    #[inline(always)]
424    pub unsafe fn fill_range_unchecked(&mut self, start: usize, end: usize, value: bool) {
425        fill_bits(self.buffer, self.offset + start, self.offset + end, value);
426    }
427
428    /// Copy this view into an owned [`BitBuffer`].
429    pub fn to_bit_buffer(&self) -> BitBuffer {
430        self.as_view().to_bit_buffer()
431    }
432}
433
434impl BitBuffer {
435    /// Borrow this buffer as a [`BitBufferView`] without cloning the backing allocation.
436    #[inline]
437    pub fn as_view(&self) -> BitBufferView<'_> {
438        BitBufferView {
439            buffer: self.inner().as_slice(),
440            offset: self.offset(),
441            len: self.len(),
442        }
443    }
444}
445
446impl BitBufferMut {
447    /// Borrow this buffer as an immutable [`BitBufferView`].
448    #[inline]
449    pub fn as_view(&self) -> BitBufferView<'_> {
450        BitBufferView {
451            buffer: self.as_slice(),
452            offset: self.offset(),
453            len: self.len(),
454        }
455    }
456
457    /// Borrow this buffer as a [`BitBufferMutView`].
458    #[inline]
459    pub fn as_mut_view(&mut self) -> BitBufferMutView<'_> {
460        let offset = self.offset();
461        let len = self.len();
462        BitBufferMutView {
463            buffer: self.as_mut_slice(),
464            offset,
465            len,
466        }
467    }
468}
469
470#[cfg(test)]
471mod tests {
472    use crate::BitBuffer;
473    use crate::BitBufferMut;
474    use crate::bitbuffer;
475
476    #[test]
477    fn view_reads_match_buffer() {
478        let buffer = bitbuffer![true, false, true, true, false, true, false, false];
479        let view = buffer.as_view();
480
481        assert_eq!(view.len(), buffer.len());
482        assert_eq!(view.true_count(), buffer.true_count());
483        assert_eq!(view.false_count(), buffer.false_count());
484        for i in 0..buffer.len() {
485            assert_eq!(view.value(i), buffer.value(i));
486        }
487        assert_eq!(
488            view.iter().collect::<Vec<_>>(),
489            buffer.iter().collect::<Vec<_>>()
490        );
491    }
492
493    #[test]
494    fn view_slice_preserves_offset() {
495        let buffer = BitBuffer::new_set(20);
496        let sliced = buffer.slice(5..17);
497        let view = buffer.as_view().slice(5..17);
498
499        assert_eq!(view.len(), sliced.len());
500        assert_eq!(view.true_count(), sliced.true_count());
501        assert_eq!(view.to_bit_buffer(), sliced);
502    }
503
504    #[test]
505    fn view_offset_buffer() {
506        let buffer = BitBuffer::new_set(64).slice(3..40);
507        let view = buffer.as_view();
508        assert_eq!(view.offset(), buffer.offset());
509        assert_eq!(view.len(), buffer.len());
510        assert_eq!(view.to_bit_buffer(), buffer);
511    }
512
513    #[test]
514    fn mut_view_set_unset() {
515        let mut buffer = BitBufferMut::new_unset(16);
516        {
517            let mut view = buffer.as_mut_view();
518            view.set(0);
519            view.set(15);
520            view.set_to(7, true);
521            view.fill_range(2, 5, true);
522            assert!(view.value(0));
523            assert_eq!(view.true_count(), 6);
524            view.unset(0);
525        }
526        let frozen = buffer.freeze();
527        assert!(!frozen.value(0));
528        assert!(frozen.value(2));
529        assert!(frozen.value(4));
530        assert!(frozen.value(7));
531        assert!(frozen.value(15));
532        assert_eq!(frozen.true_count(), 5);
533    }
534
535    #[test]
536    fn mut_view_with_offset() {
537        let mut buffer = BitBufferMut::from_buffer(crate::buffer_mut![0u8; 4], 3, 20);
538        {
539            let mut view = buffer.as_mut_view();
540            assert_eq!(view.offset(), 3);
541            view.fill_range(0, 20, true);
542        }
543        let frozen = buffer.freeze();
544        assert_eq!(frozen.true_count(), 20);
545    }
546}