pub struct PassingReadTracker {
bits: Vec<u64>,
count: usize,
}
impl PassingReadTracker {
pub fn with_capacity(num_reads: usize) -> Self {
let words = (num_reads + 63) / 64;
Self {
bits: vec![0u64; words],
count: 0,
}
}
pub fn mark(&mut self, global_index: usize) {
let word = global_index / 64;
let bit = global_index % 64;
if word >= self.bits.len() {
self.bits.resize(word + 1, 0);
}
let mask = 1u64 << bit;
if self.bits[word] & mask == 0 {
self.count += 1;
}
self.bits[word] |= mask;
}
pub fn is_passing(&self, global_index: usize) -> bool {
let word = global_index / 64;
let bit = global_index % 64;
if word >= self.bits.len() {
return false;
}
self.bits[word] & (1u64 << bit) != 0
}
pub fn count(&self) -> usize {
self.count
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.count == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_tracker() {
let tracker = PassingReadTracker::with_capacity(100);
assert!(tracker.is_empty());
assert_eq!(tracker.count(), 0);
assert!(!tracker.is_passing(0));
assert!(!tracker.is_passing(99));
}
#[test]
fn test_mark_and_check() {
let mut tracker = PassingReadTracker::with_capacity(100);
tracker.mark(5);
tracker.mark(42);
tracker.mark(99);
assert!(tracker.is_passing(5));
assert!(tracker.is_passing(42));
assert!(tracker.is_passing(99));
assert!(!tracker.is_passing(0));
assert!(!tracker.is_passing(6));
assert!(!tracker.is_passing(41));
assert_eq!(tracker.count(), 3);
}
#[test]
fn test_double_mark_no_double_count() {
let mut tracker = PassingReadTracker::with_capacity(100);
tracker.mark(10);
tracker.mark(10);
assert_eq!(tracker.count(), 1);
}
#[test]
fn test_bit_boundaries() {
let mut tracker = PassingReadTracker::with_capacity(200);
tracker.mark(63);
tracker.mark(64);
tracker.mark(127);
tracker.mark(128);
assert!(tracker.is_passing(63));
assert!(tracker.is_passing(64));
assert!(tracker.is_passing(127));
assert!(tracker.is_passing(128));
assert!(!tracker.is_passing(62));
assert!(!tracker.is_passing(65));
assert_eq!(tracker.count(), 4);
}
#[test]
fn test_growth_beyond_capacity() {
let mut tracker = PassingReadTracker::with_capacity(10);
tracker.mark(1000);
assert!(tracker.is_passing(1000));
assert!(!tracker.is_passing(999));
assert_eq!(tracker.count(), 1);
}
#[test]
fn test_is_passing_beyond_capacity() {
let tracker = PassingReadTracker::with_capacity(10);
assert!(!tracker.is_passing(10000));
}
}