From 497d250d8aaf3224ac1d1b63532afd3342d2b718 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Wed, 17 Jun 2026 09:32:12 +0200 Subject: [PATCH] refactor: replace byte-level bit iteration with 64-bit words Refactor `BitIter` to process `u64` chunks using word-aligned shifts instead of byte-level operations. Introduce a dedicated `MemoryBitIter` for `MemoryBitVec`, updating its `iter()` and `IntoIterator` implementations accordingly. Hide `MemoryBitIter` from the public API to narrow the crate's interface, while leveraging explicit alignment guarantees for safer and more efficient bit extraction. --- src/obicompactvec/src/bitvec.rs | 25 ++++++---------------- src/obicompactvec/src/lib.rs | 2 +- src/obicompactvec/src/memoryvec.rs | 34 +++++------------------------- 3 files changed, 13 insertions(+), 48 deletions(-) diff --git a/src/obicompactvec/src/bitvec.rs b/src/obicompactvec/src/bitvec.rs index 9d78e88..1d91b10 100644 --- a/src/obicompactvec/src/bitvec.rs +++ b/src/obicompactvec/src/bitvec.rs @@ -65,12 +65,7 @@ impl PersistentBitVec { (self.mmap[HEADER_SIZE + (slot >> 3)] >> (slot & 7)) & 1 != 0 } - // Used by iter() and get(): exact byte window, no padding. - fn data_bytes(&self) -> &[u8] { - &self.mmap[HEADER_SIZE..HEADER_SIZE + self.n.div_ceil(8)] - } - - // Bulk word view. SAFETY: mmap is page-aligned, HEADER_SIZE=16 is divisible by 8, + // SAFETY: mmap is page-aligned, HEADER_SIZE=16 is divisible by 8, // so &mmap[HEADER_SIZE] is u64-aligned. Slice length is n_words * 8 bytes. fn data_words(&self) -> &[u64] { let nw = n_words(self.n); @@ -79,11 +74,7 @@ impl PersistentBitVec { } pub fn iter(&self) -> BitIter<'_> { - BitIter { - bytes: self.data_bytes(), - slot: 0, - n: self.n, - } + BitIter { words: self.data_words(), slot: 0, n: self.n } } } @@ -96,9 +87,9 @@ impl<'a> IntoIterator for &'a PersistentBitVec { } pub struct BitIter<'a> { - bytes: &'a [u8], - slot: usize, - n: usize, + pub(crate) words: &'a [u64], + pub(crate) slot: usize, + pub(crate) n: usize, } impl ExactSizeIterator for BitIter<'_> {} @@ -107,10 +98,8 @@ impl Iterator for BitIter<'_> { type Item = bool; fn next(&mut self) -> Option { - if self.slot >= self.n { - return None; - } - let v = (self.bytes[self.slot >> 3] >> (self.slot & 7)) & 1 != 0; + if self.slot >= self.n { return None; } + let v = (self.words[self.slot >> 6] >> (self.slot & 63)) & 1 != 0; self.slot += 1; Some(v) } diff --git a/src/obicompactvec/src/lib.rs b/src/obicompactvec/src/lib.rs index ced509b..3a5f1c4 100644 --- a/src/obicompactvec/src/lib.rs +++ b/src/obicompactvec/src/lib.rs @@ -16,7 +16,7 @@ pub use builder::PersistentCompactIntVecBuilder; pub use intmatrix::{PersistentCompactIntMatrix, PersistentCompactIntMatrixBuilder, pack_compact_int_matrix}; pub use layer_meta::LayerMeta; pub use memoryintvec::{MemoryIntIter, MemoryIntVec}; -pub use memoryvec::{MemoryBitIter, MemoryBitVec}; +pub use memoryvec::MemoryBitVec; pub use reader::PersistentCompactIntVec; pub use traits::{BitPartials, BitSlice, BitSliceMut, BitToInt, ColumnWeights, CountPartials, IntSlice, IntSliceMut, IntToBit}; diff --git a/src/obicompactvec/src/memoryvec.rs b/src/obicompactvec/src/memoryvec.rs index 3076325..fef0960 100644 --- a/src/obicompactvec/src/memoryvec.rs +++ b/src/obicompactvec/src/memoryvec.rs @@ -2,7 +2,7 @@ use std::io; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; use std::path::Path; -use crate::bitvec::{PersistentBitVecBuilder, n_words}; +use crate::bitvec::{BitIter, PersistentBitVecBuilder, n_words}; use crate::traits::{BitSlice, BitSliceMut}; // ── MemoryBitVec ────────────────────────────────────────────────────────────── @@ -125,38 +125,14 @@ impl BitXorAssign<&B> for MemoryBitVec { // ── Iterator ────────────────────────────────────────────────────────────────── -pub struct MemoryBitIter<'a> { - words: &'a [u64], - slot: usize, - n: usize, -} - -impl Iterator for MemoryBitIter<'_> { - type Item = bool; - - fn next(&mut self) -> Option { - if self.slot >= self.n { return None; } - let v = (self.words[self.slot >> 6] >> (self.slot & 63)) & 1 != 0; - self.slot += 1; - Some(v) - } - - fn size_hint(&self) -> (usize, Option) { - let rem = self.n - self.slot; - (rem, Some(rem)) - } -} - -impl ExactSizeIterator for MemoryBitIter<'_> {} - impl MemoryBitVec { - pub fn iter(&self) -> MemoryBitIter<'_> { - MemoryBitIter { words: &self.words, slot: 0, n: self.n } + pub fn iter(&self) -> BitIter<'_> { + BitIter { words: &self.words, slot: 0, n: self.n } } } impl<'a> IntoIterator for &'a MemoryBitVec { type Item = bool; - type IntoIter = MemoryBitIter<'a>; - fn into_iter(self) -> MemoryBitIter<'a> { self.iter() } + type IntoIter = BitIter<'a>; + fn into_iter(self) -> BitIter<'a> { self.iter() } }