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

vortex-data / vortex / 16980313501

15 Aug 2025 01:01AM UTC coverage: 87.714% (-0.006%) from 87.72%
16980313501

Pull #2456

github

web-flow
Merge 02c3c7f9e into aaf3e36ad
Pull Request #2456: feat: basic BoolBuffer / BoolBufferMut

1267 of 1420 new or added lines in 110 files covered. (89.23%)

4 existing lines in 3 files now uncovered.

56995 of 64978 relevant lines covered (87.71%)

658370.36 hits per line

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

82.23
/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
38
    pub fn from_buffer(buffer: ByteBufferMut, len: usize) -> Self {
4,171✔
39
        assert!(
4,171✔
40
            len <= buffer.len() * 8,
4,171✔
NEW
41
            "Buffer len {} is too short for the given length {len}",
×
NEW
42
            buffer.len()
×
43
        );
44
        Self { buffer, len }
4,171✔
45
    }
4,171✔
46

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

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

63
    /// Create a new mutable buffer with requested `len` and all bits set to `false`.
64
    pub fn new_unset(len: usize) -> Self {
158,355✔
65
        Self {
158,355✔
66
            buffer: BufferMut::zeroed(len.div_ceil(8)),
158,355✔
67
            len,
158,355✔
68
        }
158,355✔
69
    }
158,355✔
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.
77
    pub fn len(&self) -> usize {
91,960✔
78
        self.len
91,960✔
79
    }
91,960✔
80

81
    /// True if the buffer has length 0.
82
    pub fn is_empty(&self) -> bool {
1✔
83
        self.len == 0
1✔
84
    }
1✔
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.
109
    pub fn set_to(&mut self, index: usize, value: bool) {
15,181✔
110
        if value {
15,181✔
111
            self.set(index);
12,558✔
112
        } else {
12,558✔
113
            self.unset(index);
2,623✔
114
        }
2,623✔
115
    }
15,181✔
116

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

123
        // SAFETY: checked by assertion
124
        unsafe { self.set_unchecked(index) };
1,231,985✔
125
    }
1,231,985✔
126

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

133
        // SAFETY: checked by assertion
134
        unsafe { self.unset_unchecked(index) };
3,483✔
135
    }
3,483✔
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.
142
    pub unsafe fn set_unchecked(&mut self, index: usize) {
10,684,976✔
143
        let word_index = index / 8;
10,684,976✔
144
        let bit_index = index % 8;
10,684,976✔
145
        // SAFETY: checked by caller
146
        unsafe {
10,684,976✔
147
            let word = self.buffer.as_mut_ptr().add(word_index);
10,684,976✔
148
            word.write(*word | 1 << bit_index);
10,684,976✔
149
        }
10,684,976✔
150
    }
10,684,976✔
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.
157
    pub unsafe fn unset_unchecked(&mut self, index: usize) {
3,483✔
158
        let word_index = index / 8;
3,483✔
159
        let bit_index = index % 8;
3,483✔
160

161
        // SAFETY: checked by caller
162
        unsafe {
3,483✔
163
            let word = self.buffer.as_mut_ptr().add(word_index);
3,483✔
164
            word.write(*word & !(1 << bit_index));
3,483✔
165
        }
3,483✔
166
    }
3,483✔
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.
188
    pub fn append(&mut self, value: bool) {
468,099✔
189
        if value {
468,099✔
190
            self.append_true()
329,596✔
191
        } else {
192
            self.append_false()
138,503✔
193
        }
194
    }
468,099✔
195

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

209
        self.len += 1;
329,596✔
210
    }
329,596✔
211

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

221
        self.len += 1;
138,503✔
222
    }
138,503✔
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.
227
    pub fn append_n(&mut self, value: bool, n: usize) {
94,069✔
228
        match value {
94,069✔
229
            true => {
230
                let new_len = self.len + n;
45,892✔
231
                let new_len_bytes = new_len.div_ceil(8);
45,892✔
232
                let cur_remainder = self.len % 8;
45,892✔
233
                let new_remainder = new_len % 8;
45,892✔
234

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

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

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

264
                // push new 0 bytes.
265
                if new_len_bytes > self.buffer.len() {
48,177✔
266
                    self.buffer.push_n(0, new_len_bytes - self.buffer.len());
37,030✔
267
                }
38,539✔
268
            }
269
        }
270

271
        self.len += n;
94,069✔
272
    }
94,069✔
273

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

281
        let self_slice = self.buffer.as_mut_slice().view_bits_mut::<Lsb0>();
25,296✔
282
        let other_slice = values.as_slice().view_bits::<Lsb0>();
25,296✔
283

284
        let other_sliced = &other_slice[range.start..range.end];
25,296✔
285
        let sliced = &mut self_slice[self.len..][..bit_len];
25,296✔
286
        sliced.copy_from_bitslice(other_sliced);
25,296✔
287
        self.len += bit_len;
25,296✔
288
    }
25,296✔
289

290
    /// Append a [`BitBuffer`] to this [`BitBufferMut`]
291
    pub fn append_buffer(&mut self, buffer: &BitBuffer) {
24,952✔
292
        let buffer_range = buffer.offset()..buffer.offset() + buffer.len();
24,952✔
293
        self.append_packed_range(buffer_range, buffer.inner())
24,952✔
294
    }
24,952✔
295

296
    /// Freeze the buffer in its current state into an immutable `BoolBuffer`.
297
    pub fn freeze(self) -> BitBuffer {
217,257✔
298
        BitBuffer::new(self.buffer.freeze().into_byte_buffer(), self.len)
217,257✔
299
    }
217,257✔
300

301
    /// Get the underlying bytes as a slice
302
    pub fn as_slice(&self) -> &[u8] {
258✔
303
        self.buffer.as_slice()
258✔
304
    }
258✔
305

306
    /// Get the underlying bytes as a mutable slice
NEW
307
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
×
NEW
308
        self.buffer.as_mut_slice()
×
NEW
309
    }
×
310
}
311

312
impl Default for BitBufferMut {
313
    fn default() -> Self {
12,572✔
314
        Self::new(0)
12,572✔
315
    }
12,572✔
316
}
317

318
#[cfg(test)]
319
mod tests {
320
    use crate::bit::buf_mut::BitBufferMut;
321

322
    #[test]
323
    fn test_bits_mut() {
1✔
324
        let mut bools = BitBufferMut::new_unset(10);
1✔
325
        bools.set_to(0, true);
1✔
326
        bools.set_to(9, true);
1✔
327

328
        let bools = bools.freeze();
1✔
329
        assert!(bools.value(0));
1✔
330
        for i in 1..=8 {
9✔
331
            assert!(!bools.value(i));
8✔
332
        }
333
        assert!(bools.value(9));
1✔
334
    }
1✔
335

336
    #[test]
337
    fn test_append_n() {
1✔
338
        let mut bools = BitBufferMut::new(10);
1✔
339
        assert_eq!(bools.len(), 0);
1✔
340
        assert!(bools.is_empty());
1✔
341

342
        bools.append(true);
1✔
343
        bools.append_n(false, 8);
1✔
344
        bools.append_n(true, 1);
1✔
345

346
        let bools = bools.freeze();
1✔
347

348
        assert_eq!(bools.true_count(), 2);
1✔
349
        assert!(bools.value(0));
1✔
350
        assert!(bools.value(9));
1✔
351
    }
1✔
352
}
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