Skip to main content

scirs2_core/collections/
bit_vec.rs

1//! `BitVec` — a compact bit vector backed by a `Vec<u64>`.
2//!
3//! Each bit is stored in a single machine-word-sized chunk, making storage
4//! roughly 64× more memory-efficient than a `Vec<bool>`.  All bitwise
5//! operations (AND, OR, XOR) operate word-at-a-time for maximum throughput.
6//!
7//! # Example
8//!
9//! ```rust
10//! use scirs2_core::collections::BitVec;
11//!
12//! let mut bv = BitVec::new(8);
13//! bv.set(2, true);
14//! bv.set(5, true);
15//!
16//! assert!(bv.get(2));
17//! assert!(!bv.get(3));
18//! assert_eq!(bv.count_ones(), 2);
19//!
20//! let ones: Vec<usize> = bv.iter_ones().collect();
21//! assert_eq!(ones, vec![2, 5]);
22//! ```
23
24use std::fmt;
25
26// ============================================================================
27// BitVec
28// ============================================================================
29
30/// A compact bit vector.
31///
32/// Bits are stored in `u64` chunks.  The bit at logical index `i` lives in
33/// chunk `i / 64` at bit position `i % 64`.
34#[derive(Clone)]
35pub struct BitVec {
36    /// Number of valid logical bits.
37    n_bits: usize,
38    /// Backing storage; `chunks.len() == ceil(n_bits / 64)`.
39    chunks: Vec<u64>,
40}
41
42impl BitVec {
43    /// Creates a new `BitVec` of `n_bits` bits, all initialised to `false`.
44    pub fn new(n_bits: usize) -> Self {
45        let n_chunks = Self::chunks_for(n_bits);
46        BitVec {
47            n_bits,
48            chunks: vec![0u64; n_chunks],
49        }
50    }
51
52    /// Creates a `BitVec` of `n_bits` bits, all initialised to `true`.
53    pub fn all_ones(n_bits: usize) -> Self {
54        let n_chunks = Self::chunks_for(n_bits);
55        let mut chunks = vec![u64::MAX; n_chunks];
56        // Zero out the padding bits in the last chunk to keep invariants.
57        Self::mask_last_chunk(&mut chunks, n_bits);
58        BitVec { n_bits, chunks }
59    }
60
61    /// Returns the total number of logical bits.
62    pub fn n_bits(&self) -> usize {
63        self.n_bits
64    }
65
66    /// Returns `true` if the bit vector has zero capacity.
67    pub fn is_empty(&self) -> bool {
68        self.n_bits == 0
69    }
70
71    /// Sets bit `i` to `val`.
72    ///
73    /// # Panics
74    ///
75    /// Panics if `i >= self.n_bits()`.
76    pub fn set(&mut self, i: usize, val: bool) {
77        assert!(
78            i < self.n_bits,
79            "BitVec::set: index {} out of range (len={})",
80            i,
81            self.n_bits
82        );
83        let (chunk_idx, bit_idx) = Self::locate(i);
84        if val {
85            self.chunks[chunk_idx] |= 1u64 << bit_idx;
86        } else {
87            self.chunks[chunk_idx] &= !(1u64 << bit_idx);
88        }
89    }
90
91    /// Returns the value of bit `i`.
92    ///
93    /// Returns `false` for out-of-range indices (does not panic).
94    pub fn get(&self, i: usize) -> bool {
95        if i >= self.n_bits {
96            return false;
97        }
98        let (chunk_idx, bit_idx) = Self::locate(i);
99        (self.chunks[chunk_idx] >> bit_idx) & 1 == 1
100    }
101
102    /// Toggles bit `i`.
103    ///
104    /// # Panics
105    ///
106    /// Panics if `i >= self.n_bits()`.
107    pub fn flip(&mut self, i: usize) {
108        assert!(i < self.n_bits, "BitVec::flip: index {} out of range", i);
109        let (chunk_idx, bit_idx) = Self::locate(i);
110        self.chunks[chunk_idx] ^= 1u64 << bit_idx;
111    }
112
113    /// Returns the number of bits set to `1`.
114    pub fn count_ones(&self) -> usize {
115        self.chunks.iter().map(|c| c.count_ones() as usize).sum()
116    }
117
118    /// Returns the number of bits set to `0`.
119    pub fn count_zeros(&self) -> usize {
120        self.n_bits - self.count_ones()
121    }
122
123    /// Returns an iterator over the indices of all `1`-bits in ascending order.
124    pub fn iter_ones(&self) -> IterOnes<'_> {
125        IterOnes {
126            bv: self,
127            chunk_idx: 0,
128            // Start with the first chunk's bits; will advance as needed.
129            remaining: if self.chunks.is_empty() {
130                0u64
131            } else {
132                self.chunks[0]
133            },
134            logical_base: 0,
135        }
136    }
137
138    /// Returns an iterator over the indices of all `0`-bits in ascending order.
139    pub fn iter_zeros(&self) -> impl Iterator<Item = usize> + '_ {
140        (0..self.n_bits).filter(|&i| !self.get(i))
141    }
142
143    /// Clears all bits (sets every bit to `0`).
144    pub fn clear(&mut self) {
145        for c in &mut self.chunks {
146            *c = 0;
147        }
148    }
149
150    /// Sets all bits to `1`.
151    pub fn set_all(&mut self) {
152        for c in &mut self.chunks {
153            *c = u64::MAX;
154        }
155        Self::mask_last_chunk(&mut self.chunks, self.n_bits);
156    }
157
158    // ------------------------------------------------------------------
159    // Bitwise operations (in-place)
160    // ------------------------------------------------------------------
161
162    /// `self &= other`.  Panics if the bit-widths differ.
163    pub fn and_assign(&mut self, other: &BitVec) {
164        self.assert_same_len(other, "and_assign");
165        for (a, b) in self.chunks.iter_mut().zip(other.chunks.iter()) {
166            *a &= *b;
167        }
168    }
169
170    /// `self |= other`.  Panics if the bit-widths differ.
171    pub fn or_assign(&mut self, other: &BitVec) {
172        self.assert_same_len(other, "or_assign");
173        for (a, b) in self.chunks.iter_mut().zip(other.chunks.iter()) {
174            *a |= *b;
175        }
176    }
177
178    /// `self ^= other`.  Panics if the bit-widths differ.
179    pub fn xor_assign(&mut self, other: &BitVec) {
180        self.assert_same_len(other, "xor_assign");
181        for (a, b) in self.chunks.iter_mut().zip(other.chunks.iter()) {
182            *a ^= *b;
183        }
184    }
185
186    // ------------------------------------------------------------------
187    // Bitwise operations (returning new BitVec)
188    // ------------------------------------------------------------------
189
190    /// Returns `self & other`.  Panics if the bit-widths differ.
191    pub fn and(&self, other: &BitVec) -> BitVec {
192        self.assert_same_len(other, "and");
193        let chunks: Vec<u64> = self
194            .chunks
195            .iter()
196            .zip(other.chunks.iter())
197            .map(|(a, b)| a & b)
198            .collect();
199        BitVec {
200            n_bits: self.n_bits,
201            chunks,
202        }
203    }
204
205    /// Returns `self | other`.  Panics if the bit-widths differ.
206    pub fn or(&self, other: &BitVec) -> BitVec {
207        self.assert_same_len(other, "or");
208        let chunks: Vec<u64> = self
209            .chunks
210            .iter()
211            .zip(other.chunks.iter())
212            .map(|(a, b)| a | b)
213            .collect();
214        BitVec {
215            n_bits: self.n_bits,
216            chunks,
217        }
218    }
219
220    /// Returns `self ^ other`.  Panics if the bit-widths differ.
221    pub fn xor(&self, other: &BitVec) -> BitVec {
222        self.assert_same_len(other, "xor");
223        let chunks: Vec<u64> = self
224            .chunks
225            .iter()
226            .zip(other.chunks.iter())
227            .map(|(a, b)| a ^ b)
228            .collect();
229        BitVec {
230            n_bits: self.n_bits,
231            chunks,
232        }
233    }
234
235    /// Returns the bitwise NOT of `self`.
236    pub fn not(&self) -> BitVec {
237        let mut chunks: Vec<u64> = self.chunks.iter().map(|c| !c).collect();
238        Self::mask_last_chunk(&mut chunks, self.n_bits);
239        BitVec {
240            n_bits: self.n_bits,
241            chunks,
242        }
243    }
244
245    // ------------------------------------------------------------------
246    // Private helpers
247    // ------------------------------------------------------------------
248
249    #[inline]
250    fn chunks_for(n_bits: usize) -> usize {
251        (n_bits + 63) / 64
252    }
253
254    #[inline]
255    fn locate(i: usize) -> (usize, usize) {
256        (i / 64, i % 64)
257    }
258
259    /// Zeros out bits beyond `n_bits` in the last chunk.
260    fn mask_last_chunk(chunks: &mut Vec<u64>, n_bits: usize) {
261        if n_bits == 0 || chunks.is_empty() {
262            return;
263        }
264        let tail = n_bits % 64;
265        if tail != 0 {
266            let last = chunks.len() - 1;
267            chunks[last] &= (1u64 << tail) - 1;
268        }
269    }
270
271    fn assert_same_len(&self, other: &BitVec, op: &str) {
272        assert_eq!(
273            self.n_bits, other.n_bits,
274            "BitVec::{}: length mismatch ({} vs {})",
275            op, self.n_bits, other.n_bits
276        );
277    }
278}
279
280// ============================================================================
281// IterOnes
282// ============================================================================
283
284/// Iterator over the indices of set bits, produced by [`BitVec::iter_ones`].
285pub struct IterOnes<'a> {
286    bv: &'a BitVec,
287    /// Index of the *current* chunk we are scanning.
288    chunk_idx: usize,
289    /// The bits still to be processed in the current chunk.
290    remaining: u64,
291    /// Logical bit index of bit 0 in the current chunk.
292    logical_base: usize,
293}
294
295impl<'a> Iterator for IterOnes<'a> {
296    type Item = usize;
297
298    fn next(&mut self) -> Option<usize> {
299        loop {
300            if self.remaining != 0 {
301                // Fast-path: consume the lowest set bit.
302                let bit_pos = self.remaining.trailing_zeros() as usize;
303                // Clear that bit.
304                self.remaining &= self.remaining - 1;
305                let logical = self.logical_base + bit_pos;
306                if logical < self.bv.n_bits {
307                    return Some(logical);
308                }
309                // Bit is a padding bit — skip.
310                continue;
311            }
312            // Move to next chunk.
313            self.chunk_idx += 1;
314            if self.chunk_idx >= self.bv.chunks.len() {
315                return None;
316            }
317            self.logical_base = self.chunk_idx * 64;
318            self.remaining = self.bv.chunks[self.chunk_idx];
319        }
320    }
321}
322
323// ============================================================================
324// Trait implementations
325// ============================================================================
326
327impl PartialEq for BitVec {
328    fn eq(&self, other: &Self) -> bool {
329        self.n_bits == other.n_bits && self.chunks == other.chunks
330    }
331}
332
333impl Eq for BitVec {}
334
335impl fmt::Debug for BitVec {
336    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337        write!(f, "BitVec({} bits: ", self.n_bits)?;
338        for i in 0..self.n_bits {
339            write!(f, "{}", if self.get(i) { '1' } else { '0' })?;
340        }
341        write!(f, ")")
342    }
343}
344
345// ============================================================================
346// Tests
347// ============================================================================
348
349#[cfg(test)]
350mod tests {
351    use super::*;
352
353    #[test]
354    fn test_set_get() {
355        let mut bv = BitVec::new(64);
356        bv.set(0, true);
357        bv.set(63, true);
358        assert!(bv.get(0));
359        assert!(bv.get(63));
360        assert!(!bv.get(32));
361    }
362
363    #[test]
364    fn test_count_ones() {
365        let mut bv = BitVec::new(100);
366        bv.set(0, true);
367        bv.set(50, true);
368        bv.set(99, true);
369        assert_eq!(bv.count_ones(), 3);
370        assert_eq!(bv.count_zeros(), 97);
371    }
372
373    #[test]
374    fn test_iter_ones() {
375        let mut bv = BitVec::new(200);
376        let expected = vec![0usize, 63, 64, 127, 199];
377        for &i in &expected {
378            bv.set(i, true);
379        }
380        let ones: Vec<_> = bv.iter_ones().collect();
381        assert_eq!(ones, expected);
382    }
383
384    #[test]
385    fn test_bitwise_and() {
386        let mut a = BitVec::new(8);
387        let mut b = BitVec::new(8);
388        a.set(1, true);
389        a.set(3, true);
390        b.set(1, true);
391        b.set(5, true);
392        let c = a.and(&b);
393        assert!(c.get(1));
394        assert!(!c.get(3));
395        assert!(!c.get(5));
396    }
397
398    #[test]
399    fn test_bitwise_or() {
400        let mut a = BitVec::new(8);
401        let mut b = BitVec::new(8);
402        a.set(1, true);
403        b.set(5, true);
404        let c = a.or(&b);
405        assert!(c.get(1));
406        assert!(c.get(5));
407    }
408
409    #[test]
410    fn test_bitwise_xor() {
411        let mut a = BitVec::new(8);
412        let mut b = BitVec::new(8);
413        a.set(1, true);
414        a.set(3, true);
415        b.set(1, true);
416        b.set(5, true);
417        let c = a.xor(&b);
418        assert!(!c.get(1), "1 XOR 1 = 0");
419        assert!(c.get(3), "1 XOR 0 = 1");
420        assert!(c.get(5), "0 XOR 1 = 1");
421    }
422
423    #[test]
424    fn test_not() {
425        let mut bv = BitVec::new(8);
426        bv.set(0, true);
427        bv.set(7, true);
428        let n = bv.not();
429        assert!(!n.get(0));
430        assert!(!n.get(7));
431        assert!(n.get(1));
432        assert_eq!(n.count_ones(), 6);
433    }
434
435    #[test]
436    fn test_all_ones() {
437        let bv = BitVec::all_ones(10);
438        assert_eq!(bv.count_ones(), 10);
439        for i in 0..10 {
440            assert!(bv.get(i));
441        }
442    }
443
444    #[test]
445    fn test_flip() {
446        let mut bv = BitVec::new(16);
447        bv.flip(4);
448        assert!(bv.get(4));
449        bv.flip(4);
450        assert!(!bv.get(4));
451    }
452
453    #[test]
454    fn test_large_bitvec() {
455        let n = 10_000;
456        let mut bv = BitVec::new(n);
457        for i in (0..n).step_by(7) {
458            bv.set(i, true);
459        }
460        let expected_count = (0..n).step_by(7).count();
461        assert_eq!(bv.count_ones(), expected_count);
462
463        let ones: Vec<_> = bv.iter_ones().collect();
464        let expected_ones: Vec<_> = (0..n).step_by(7).collect();
465        assert_eq!(ones, expected_ones);
466    }
467
468    #[test]
469    fn test_clear_and_set_all() {
470        let mut bv = BitVec::new(128);
471        bv.set_all();
472        assert_eq!(bv.count_ones(), 128);
473        bv.clear();
474        assert_eq!(bv.count_ones(), 0);
475    }
476
477    #[test]
478    fn test_out_of_range_get() {
479        let bv = BitVec::new(8);
480        assert!(!bv.get(100)); // should not panic, just return false
481    }
482
483    #[test]
484    fn test_clone_eq() {
485        let mut bv = BitVec::new(32);
486        bv.set(5, true);
487        bv.set(15, true);
488        let bv2 = bv.clone();
489        assert_eq!(bv, bv2);
490    }
491}