Skip to content

Commit 8d70278

Browse files
committed
refactor: optimize BitBuffer::from(Vec<bool>) using 64-bit packing
Refactored the `From<&[bool]>` implementation for `BitBufferMut` to use the same optimized packing strategy as `BitBuffer::collect_bool`. ### Performance Improvement **Before**: Element-by-element iteration, setting individual bits one at a time ```rust for (i, &v) in value.iter().enumerate() { if v { unsafe { buf.set_unchecked(i) } } } ``` **After**: Pack 64 booleans at a time into u64 words before writing to memory ```rust for chunk in 0..chunks { let mut packed = 0u64; for bit_idx in 0..64 { packed |= (value[i] as u64) << bit_idx; } unsafe { buffer.push_unchecked(packed) } } ``` This brings the same performance optimization that production code uses via `collect_bool` to all code paths that create `BitBuffer` from `Vec<bool>`. ### Testing - All 50 vortex-buffer tests pass - All 1541 vortex-array tests pass - No clippy warnings
1 parent 4552c10 commit 8d70278

File tree

1 file changed

+30
-6
lines changed

1 file changed

+30
-6
lines changed

vortex-buffer/src/bit/buf_mut.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -541,14 +541,38 @@ impl Not for BitBufferMut {
541541

542542
impl From<&[bool]> for BitBufferMut {
543543
fn from(value: &[bool]) -> Self {
544-
let mut buf = BitBufferMut::new_unset(value.len());
545-
for (i, &v) in value.iter().enumerate() {
546-
if v {
547-
// SAFETY: i is in bounds
548-
unsafe { buf.set_unchecked(i) }
544+
// Use the same optimized approach as BitBuffer::collect_bool
545+
// Pack 64 booleans at a time into u64 words for better performance
546+
let len = value.len();
547+
let mut buffer = BufferMut::with_capacity(len.div_ceil(64) * 8);
548+
549+
let chunks = len / 64;
550+
let remainder = len % 64;
551+
for chunk in 0..chunks {
552+
let mut packed = 0u64;
553+
for bit_idx in 0..64 {
554+
let i = bit_idx + chunk * 64;
555+
packed |= (value[i] as u64) << bit_idx;
549556
}
557+
558+
// SAFETY: Already allocated sufficient capacity
559+
unsafe { buffer.push_unchecked(packed) }
550560
}
551-
buf
561+
562+
if remainder != 0 {
563+
let mut packed = 0u64;
564+
for bit_idx in 0..remainder {
565+
let i = bit_idx + chunks * 64;
566+
packed |= (value[i] as u64) << bit_idx;
567+
}
568+
569+
// SAFETY: Already allocated sufficient capacity
570+
unsafe { buffer.push_unchecked(packed) }
571+
}
572+
573+
buffer.truncate(len.div_ceil(8));
574+
575+
Self::from_buffer(buffer.freeze().into_byte_buffer().into_mut(), 0, len)
552576
}
553577
}
554578

0 commit comments

Comments
 (0)