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

vortex-data / vortex / 16992684502

15 Aug 2025 02:56PM UTC coverage: 87.875% (+0.2%) from 87.72%
16992684502

Pull #2456

github

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

1275 of 1428 new or added lines in 110 files covered. (89.29%)

334 existing lines in 31 files now uncovered.

57169 of 65057 relevant lines covered (87.88%)

658056.52 hits per line

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

83.01
/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 {
66,333✔
49
        Self {
66,333✔
50
            buffer: BufferMut::with_capacity(capacity.div_ceil(8)),
66,333✔
51
            len: 0,
66,333✔
52
        }
66,333✔
53
    }
66,333✔
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 {
159,385✔
65
        Self {
159,385✔
66
            buffer: BufferMut::zeroed(len.div_ceil(8)),
159,385✔
67
            len,
159,385✔
68
        }
159,385✔
69
    }
159,385✔
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 {
85,981✔
78
        self.len
85,981✔
79
    }
85,981✔
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,325,948✔
121
        assert!(index < self.len, "index {index} exceeds len {}", self.len);
1,325,948✔
122

123
        // SAFETY: checked by assertion
124
        unsafe { self.set_unchecked(index) };
1,325,948✔
125
    }
1,325,948✔
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,838,408✔
143
        let word_index = index / 8;
10,838,408✔
144
        let bit_index = index % 8;
10,838,408✔
145
        // SAFETY: checked by caller
146
        unsafe {
10,838,408✔
147
            let word = self.buffer.as_mut_ptr().add(word_index);
10,838,408✔
148
            word.write(*word | 1 << bit_index);
10,838,408✔
149
        }
10,838,408✔
150
    }
10,838,408✔
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) {
83,467✔
228
        match value {
83,467✔
229
            true => {
230
                let new_len = self.len + n;
41,353✔
231
                let new_len_bytes = new_len.div_ceil(8);
41,353✔
232
                let cur_remainder = self.len % 8;
41,353✔
233
                let new_remainder = new_len % 8;
41,353✔
234

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

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

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

264
                // push new 0 bytes.
265
                if new_len_bytes > self.buffer.len() {
42,114✔
266
                    self.buffer.push_n(0, new_len_bytes - self.buffer.len());
32,515✔
267
                }
34,024✔
268
            }
269
        }
270

271
        self.len += n;
83,467✔
272
    }
83,467✔
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 = unsafe {
25,296✔
282
            std::slice::from_raw_parts_mut(
25,296✔
283
                self.buffer.as_mut_ptr() as *mut u64,
25,296✔
284
                self.buffer.len().div_ceil(size_of::<u64>()),
25,296✔
285
            )
25,296✔
286
        }
287
        .view_bits_mut::<Lsb0>();
25,296✔
288
        let other_slice = unsafe {
25,296✔
289
            std::slice::from_raw_parts(
25,296✔
290
                values.as_ptr() as *const u64,
25,296✔
291
                values.len().div_ceil(size_of::<u64>()),
25,296✔
292
            )
25,296✔
293
        }
294
        .view_bits::<Lsb0>();
25,296✔
295

296
        let other_sliced = &other_slice[range.start..range.end];
25,296✔
297
        self_slice[self.len..][..bit_len].copy_from_bitslice(other_sliced);
25,296✔
298
        self.len += bit_len;
25,296✔
299
    }
25,296✔
300

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

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

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

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

323
impl Default for BitBufferMut {
324
    fn default() -> Self {
12,572✔
325
        Self::new(0)
12,572✔
326
    }
12,572✔
327
}
328

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

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

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

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

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

357
        let bools = bools.freeze();
1✔
358

359
        assert_eq!(bools.true_count(), 2);
1✔
360
        assert!(bools.value(0));
1✔
361
        assert!(bools.value(9));
1✔
362
    }
1✔
363
}
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