• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16992335779

15 Aug 2025 02:38PM UTC coverage: 87.202% (-0.5%) from 87.72%
16992335779

Pull #2456

github

web-flow
Merge 39c262e2c into 4a23f65b3
Pull Request #2456: feat: basic BoolBuffer / BoolBufferMut

476 of 1231 new or added lines in 107 files covered. (38.67%)

74 existing lines in 19 files now uncovered.

56525 of 64821 relevant lines covered (87.2%)

623742.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/vortex-buffer/src/bit/buf_mut.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use std::ops::Range;
5

6
use bitvec::prelude::Lsb0;
7
use bitvec::view::BitView;
8
use vortex_error::VortexExpect;
9

10
use crate::{BitBuffer, BufferMut, ByteBuffer, ByteBufferMut, buffer_mut, get_bit};
11

12
/// A mutable bitset buffer that allows random access to individual bits for set and get.
13
///
14
///
15
/// # Example
16
/// ```
17
/// use vortex_buffer::BitBufferMut;
18
///
19
/// let mut bools = BitBufferMut::new_unset(10);
20
/// bools.set_to(9, true);
21
/// for i in 0..9 {
22
///    assert!(!bools.value(i));
23
/// }
24
/// assert!(bools.value(9));
25
///
26
/// // Freeze into a new bools vector.
27
/// let bools = bools.freeze();
28
/// ```
29
///
30
/// See also: [`crate::BitBuffer`].
31
pub struct BitBufferMut {
32
    buffer: ByteBufferMut,
33
    len: usize,
34
}
35

36
impl BitBufferMut {
37
    /// Create new bit buffer from given byte buffer and logical bit length
NEW
38
    pub fn from_buffer(buffer: ByteBufferMut, len: usize) -> Self {
×
NEW
39
        assert!(
×
NEW
40
            len <= buffer.len() * 8,
×
NEW
41
            "Buffer len {} is too short for the given length {len}",
×
NEW
42
            buffer.len()
×
43
        );
NEW
44
        Self { buffer, len }
×
NEW
45
    }
×
46

47
    /// Create a new empty mutable bit buffer with requested capacity (in bits).
NEW
48
    pub fn new(capacity: usize) -> Self {
×
NEW
49
        Self {
×
NEW
50
            buffer: BufferMut::with_capacity(capacity.div_ceil(8)),
×
NEW
51
            len: 0,
×
NEW
52
        }
×
NEW
53
    }
×
54

55
    /// Create a new mutable buffer with requested `len` and all bits set to `true`.
NEW
56
    pub fn new_set(len: usize) -> Self {
×
NEW
57
        Self {
×
NEW
58
            buffer: buffer_mut![0xFF; len.div_ceil(8)],
×
NEW
59
            len,
×
NEW
60
        }
×
NEW
61
    }
×
62

63
    /// Create a new mutable buffer with requested `len` and all bits set to `false`.
NEW
64
    pub fn new_unset(len: usize) -> Self {
×
NEW
65
        Self {
×
NEW
66
            buffer: BufferMut::zeroed(len.div_ceil(8)),
×
NEW
67
            len,
×
NEW
68
        }
×
NEW
69
    }
×
70

71
    /// Create a new empty `BitBufferMut`.
NEW
72
    pub fn empty() -> Self {
×
NEW
73
        Self::new(0)
×
NEW
74
    }
×
75

76
    /// Get the current populated length of the buffer.
NEW
77
    pub fn len(&self) -> usize {
×
NEW
78
        self.len
×
NEW
79
    }
×
80

81
    /// True if the buffer has length 0.
NEW
82
    pub fn is_empty(&self) -> bool {
×
NEW
83
        self.len == 0
×
NEW
84
    }
×
85

86
    /// Get the value at the requested index.
NEW
87
    pub fn value(&self, index: usize) -> bool {
×
NEW
88
        get_bit(&self.buffer, index)
×
NEW
89
    }
×
90

91
    /// Get the bit capacity of the buffer.
NEW
92
    pub fn capacity(&self) -> usize {
×
NEW
93
        self.buffer.capacity() * 8
×
NEW
94
    }
×
95

96
    /// Reserve additional bit capacity for the buffer.
NEW
97
    pub fn reserve(&mut self, additional: usize) {
×
NEW
98
        let capacity = self.len + additional;
×
NEW
99
        if capacity > self.capacity() {
×
NEW
100
            // convert differential to bytes
×
NEW
101
            let additional = capacity.div_ceil(8) - self.buffer.len();
×
NEW
102
            self.buffer.reserve(additional);
×
NEW
103
        }
×
NEW
104
    }
×
105

106
    /// Set the bit at `index` to the given boolean value.
107
    ///
108
    /// This operation is checked so if `index` exceeds the buffer length, this will panic.
NEW
109
    pub fn set_to(&mut self, index: usize, value: bool) {
×
NEW
110
        if value {
×
NEW
111
            self.set(index);
×
NEW
112
        } else {
×
NEW
113
            self.unset(index);
×
NEW
114
        }
×
NEW
115
    }
×
116

117
    /// Set a position to `true`.
118
    ///
119
    /// This operation is checked so if `index` exceeds the buffer length, this will panic.
NEW
120
    pub fn set(&mut self, index: usize) {
×
NEW
121
        assert!(index < self.len, "index {index} exceeds len {}", self.len);
×
122

123
        // SAFETY: checked by assertion
NEW
124
        unsafe { self.set_unchecked(index) };
×
NEW
125
    }
×
126

127
    /// Set a position to `false`.
128
    ///
129
    /// This operation is checked so if `index` exceeds the buffer length, this will panic.
NEW
130
    pub fn unset(&mut self, index: usize) {
×
NEW
131
        assert!(index < self.len, "index {index} exceeds len {}", self.len);
×
132

133
        // SAFETY: checked by assertion
NEW
134
        unsafe { self.unset_unchecked(index) };
×
NEW
135
    }
×
136

137
    /// Set the bit at `index` to `true` without checking bounds.
138
    ///
139
    /// # Safety
140
    ///
141
    /// The caller must ensure that `index` does not exceed the largest bit index in the backing buffer.
NEW
142
    pub unsafe fn set_unchecked(&mut self, index: usize) {
×
NEW
143
        let word_index = index / 8;
×
NEW
144
        let bit_index = index % 8;
×
145
        // SAFETY: checked by caller
NEW
146
        unsafe {
×
NEW
147
            let word = self.buffer.as_mut_ptr().add(word_index);
×
NEW
148
            word.write(*word | 1 << bit_index);
×
NEW
149
        }
×
NEW
150
    }
×
151

152
    /// Unset the bit at `index` without checking bounds.
153
    ///
154
    /// # Safety
155
    ///
156
    /// The caller must ensure that `index` does not exceed the largest bit index in the backing buffer.
NEW
157
    pub unsafe fn unset_unchecked(&mut self, index: usize) {
×
NEW
158
        let word_index = index / 8;
×
NEW
159
        let bit_index = index % 8;
×
160

161
        // SAFETY: checked by caller
NEW
162
        unsafe {
×
NEW
163
            let word = self.buffer.as_mut_ptr().add(word_index);
×
NEW
164
            word.write(*word & !(1 << bit_index));
×
NEW
165
        }
×
NEW
166
    }
×
167

168
    /// Truncate the buffer to the given length.
NEW
169
    pub fn truncate(&mut self, len: usize) {
×
NEW
170
        if len > self.len {
×
NEW
171
            return;
×
NEW
172
        }
×
173

NEW
174
        let new_len_bytes = len.div_ceil(8);
×
NEW
175
        self.buffer.truncate(new_len_bytes);
×
NEW
176
        self.len = len;
×
177

NEW
178
        let remainder = self.len % 8;
×
NEW
179
        if remainder != 0 {
×
NEW
180
            let mask = (1u8 << remainder).wrapping_sub(1);
×
NEW
181
            *self.buffer.as_mut().last_mut().vortex_expect("non empty") &= mask;
×
NEW
182
        }
×
NEW
183
    }
×
184

185
    /// Append a new boolean into the bit buffer, incrementing the length.
186
    ///
187
    /// Panics if the buffer is full.
NEW
188
    pub fn append(&mut self, value: bool) {
×
NEW
189
        if value {
×
NEW
190
            self.append_true()
×
191
        } else {
NEW
192
            self.append_false()
×
193
        }
NEW
194
    }
×
195

196
    /// Append a new true value to the buffer.
197
    ///
198
    /// Panics if there is no remaining capacity.
NEW
199
    pub fn append_true(&mut self) {
×
NEW
200
        if self.len % 8 == 0 {
×
NEW
201
            // Push a new word that starts with 1
×
NEW
202
            self.buffer.push(1u8);
×
NEW
203
        } else {
×
NEW
204
            // Push a 1 bit into the current word.
×
NEW
205
            let word = self.buffer.last_mut().vortex_expect("buffer is not empty");
×
NEW
206
            *word |= 1 << (self.len % 8);
×
NEW
207
        }
×
208

NEW
209
        self.len += 1;
×
NEW
210
    }
×
211

212
    /// Append a new false value to the buffer.
213
    ///
214
    /// Panics if there is no remaining capacity.
NEW
215
    pub fn append_false(&mut self) {
×
NEW
216
        if self.len % 8 == 0 {
×
NEW
217
            // push new word that starts with 0
×
NEW
218
            self.buffer.push(0u8);
×
NEW
219
        }
×
220

NEW
221
        self.len += 1;
×
NEW
222
    }
×
223
    /// Append several boolean values into the bit buffer. After this operation,
224
    /// the length will be incremented by `n`.
225
    ///
226
    /// Panics if the buffer does not have `n` slots left.
NEW
227
    pub fn append_n(&mut self, value: bool, n: usize) {
×
NEW
228
        match value {
×
229
            true => {
NEW
230
                let new_len = self.len + n;
×
NEW
231
                let new_len_bytes = new_len.div_ceil(8);
×
NEW
232
                let cur_remainder = self.len % 8;
×
NEW
233
                let new_remainder = new_len % 8;
×
234

NEW
235
                if cur_remainder != 0 {
×
NEW
236
                    // Pad cur_remainder high bits with 1s
×
NEW
237
                    *self
×
NEW
238
                        .buffer
×
NEW
239
                        .as_mut_slice()
×
NEW
240
                        .last_mut()
×
NEW
241
                        .vortex_expect("buffer is not empty") |= !((1 << cur_remainder) - 1);
×
NEW
242
                }
×
243

244
                // Push several full bytes.
NEW
245
                if new_len_bytes > self.buffer.len() {
×
NEW
246
                    // Push full bytes, except for the final byte.
×
NEW
247
                    self.buffer.push_n(0xFF, new_len_bytes - self.buffer.len());
×
NEW
248
                }
×
249

250
                // Patch zeros into remainder of last byte pushed
NEW
251
                if new_remainder > 0 {
×
NEW
252
                    // Set the new_remainder LSB to 1
×
NEW
253
                    *self
×
NEW
254
                        .buffer
×
NEW
255
                        .as_mut_slice()
×
NEW
256
                        .last_mut()
×
NEW
257
                        .vortex_expect("buffer is not empty") &= (1 << new_remainder) - 1;
×
NEW
258
                }
×
259
            }
260
            false => {
NEW
261
                let new_len = self.len + n;
×
NEW
262
                let new_len_bytes = new_len.div_ceil(8);
×
263

264
                // push new 0 bytes.
NEW
265
                if new_len_bytes > self.buffer.len() {
×
NEW
266
                    self.buffer.push_n(0, new_len_bytes - self.buffer.len());
×
NEW
267
                }
×
268
            }
269
        }
270

NEW
271
        self.len += n;
×
NEW
272
    }
×
273

274
    /// Append bits defined by range from values to this buffer
NEW
275
    pub fn append_packed_range(&mut self, range: Range<usize>, values: &ByteBuffer) {
×
NEW
276
        let bit_len = range.end - range.start;
×
NEW
277
        self.buffer.reserve(bit_len.div_ceil(8));
×
278
        // SAFETY: The copy below will populate the values
NEW
279
        unsafe { self.buffer.set_len((self.len + bit_len).div_ceil(8)) };
×
280

NEW
281
        let self_slice = unsafe {
×
NEW
282
            std::slice::from_raw_parts_mut(
×
NEW
283
                self.buffer.as_mut_ptr() as *mut u64,
×
NEW
284
                self.len.div_ceil(size_of::<u64>()),
×
NEW
285
            )
×
286
        }
NEW
287
        .view_bits_mut::<Lsb0>();
×
NEW
288
        let other_slice = unsafe {
×
NEW
289
            std::slice::from_raw_parts(
×
NEW
290
                values.as_ptr() as *const u64,
×
NEW
291
                values.len().div_ceil(size_of::<u64>()),
×
NEW
292
            )
×
293
        }
NEW
294
        .view_bits::<Lsb0>();
×
295

NEW
296
        let other_sliced = &other_slice[range.start..range.end];
×
NEW
297
        let sliced = &mut self_slice[self.len..][..bit_len];
×
NEW
298
        sliced.copy_from_bitslice(other_sliced);
×
NEW
299
        self.len += bit_len;
×
NEW
300
    }
×
301

302
    /// Append a [`BitBuffer`] to this [`BitBufferMut`]
NEW
303
    pub fn append_buffer(&mut self, buffer: &BitBuffer) {
×
NEW
304
        let buffer_range = buffer.offset()..buffer.offset() + buffer.len();
×
NEW
305
        self.append_packed_range(buffer_range, buffer.inner())
×
NEW
306
    }
×
307

308
    /// Freeze the buffer in its current state into an immutable `BoolBuffer`.
NEW
309
    pub fn freeze(self) -> BitBuffer {
×
NEW
310
        BitBuffer::new(self.buffer.freeze().into_byte_buffer(), self.len)
×
NEW
311
    }
×
312

313
    /// Get the underlying bytes as a slice
NEW
314
    pub fn as_slice(&self) -> &[u8] {
×
NEW
315
        self.buffer.as_slice()
×
NEW
316
    }
×
317

318
    /// Get the underlying bytes as a mutable slice
NEW
319
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
×
NEW
320
        self.buffer.as_mut_slice()
×
NEW
321
    }
×
322
}
323

324
impl Default for BitBufferMut {
NEW
325
    fn default() -> Self {
×
NEW
326
        Self::new(0)
×
NEW
327
    }
×
328
}
329

330
#[cfg(test)]
331
mod tests {
332
    use crate::bit::buf_mut::BitBufferMut;
333

334
    #[test]
335
    fn test_bits_mut() {
336
        let mut bools = BitBufferMut::new_unset(10);
337
        bools.set_to(0, true);
338
        bools.set_to(9, true);
339

340
        let bools = bools.freeze();
341
        assert!(bools.value(0));
342
        for i in 1..=8 {
343
            assert!(!bools.value(i));
344
        }
345
        assert!(bools.value(9));
346
    }
347

348
    #[test]
349
    fn test_append_n() {
350
        let mut bools = BitBufferMut::new(10);
351
        assert_eq!(bools.len(), 0);
352
        assert!(bools.is_empty());
353

354
        bools.append(true);
355
        bools.append_n(false, 8);
356
        bools.append_n(true, 1);
357

358
        let bools = bools.freeze();
359

360
        assert_eq!(bools.true_count(), 2);
361
        assert!(bools.value(0));
362
        assert!(bools.value(9));
363
    }
364
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc