pub const WORD_BITS: usize = 64;
pub const WORD_SHIFT: usize = 6;
pub const WORD_MASK: usize = 63;
#[inline]
pub fn word_count(n: usize) -> usize {
(n + WORD_BITS - 1) >> WORD_SHIFT
}
#[inline]
pub fn set_bit(words: &mut [u64], i: usize) {
words[i >> WORD_SHIFT] |= 1u64 << (i & WORD_MASK);
}
#[inline]
pub fn clear_bit(words: &mut [u64], i: usize) {
words[i >> WORD_SHIFT] &= !(1u64 << (i & WORD_MASK));
}
#[inline]
pub fn test_bit(words: &[u64], i: usize) -> bool {
(words[i >> WORD_SHIFT] & (1u64 << (i & WORD_MASK))) != 0
}
#[inline]
pub fn contains_all(snapshot: &[u64], mask: &[u64]) -> bool {
debug_assert_eq!(snapshot.len(), mask.len());
match mask.len() {
0 => true,
1 => (snapshot[0] & mask[0]) == mask[0],
_ => scalar_contains_all(snapshot, mask),
}
}
#[inline]
fn scalar_contains_all(snapshot: &[u64], mask: &[u64]) -> bool {
for i in 0..mask.len() {
if (snapshot[i] & mask[i]) != mask[i] {
return false;
}
}
true
}
#[inline]
pub fn intersects(snapshot: &[u64], mask: &[u64]) -> bool {
debug_assert_eq!(snapshot.len(), mask.len());
match mask.len() {
0 => false,
1 => (snapshot[0] & mask[0]) != 0,
_ => scalar_intersects(snapshot, mask),
}
}
#[inline]
fn scalar_intersects(snapshot: &[u64], mask: &[u64]) -> bool {
for i in 0..mask.len() {
if (snapshot[i] & mask[i]) != 0 {
return true;
}
}
false
}
#[inline]
pub fn for_each_set_bit(words: &[u64], mut f: impl FnMut(usize)) {
for (word_idx, &word) in words.iter().enumerate() {
let base = word_idx << WORD_SHIFT;
let mut w = word;
while w != 0 {
let tz = w.trailing_zeros() as usize;
f(base + tz);
w &= w - 1; }
}
}
#[inline]
pub fn or_into(dst: &mut [u64], src: &[u64]) {
debug_assert_eq!(dst.len(), src.len());
for i in 0..dst.len() {
dst[i] |= src[i];
}
}
#[inline]
pub fn is_empty(words: &[u64]) -> bool {
words.iter().all(|&w| w == 0)
}
#[inline]
pub fn clear_all(words: &mut [u64]) {
for w in words.iter_mut() {
*w = 0;
}
}
#[inline]
pub fn swap(a: &mut [u64], b: &mut [u64]) {
debug_assert_eq!(a.len(), b.len());
for i in 0..a.len() {
std::mem::swap(&mut a[i], &mut b[i]);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn word_count_values() {
assert_eq!(word_count(0), 0);
assert_eq!(word_count(1), 1);
assert_eq!(word_count(64), 1);
assert_eq!(word_count(65), 2);
assert_eq!(word_count(128), 2);
assert_eq!(word_count(129), 3);
}
#[test]
fn set_clear_test_bit() {
let mut bm = vec![0u64; 2];
set_bit(&mut bm, 0);
assert!(test_bit(&bm, 0));
assert!(!test_bit(&bm, 1));
set_bit(&mut bm, 65);
assert!(test_bit(&bm, 65));
clear_bit(&mut bm, 0);
assert!(!test_bit(&bm, 0));
assert!(test_bit(&bm, 65));
}
#[test]
fn contains_all_works() {
let snapshot = vec![0b1111u64];
let mask = vec![0b0101u64];
assert!(contains_all(&snapshot, &mask));
let mask2 = vec![0b10000u64];
assert!(!contains_all(&snapshot, &mask2));
}
#[test]
fn contains_all_empty() {
let empty: Vec<u64> = vec![];
assert!(contains_all(&empty, &empty));
}
#[test]
fn intersects_works() {
let snapshot = vec![0b1010u64];
let mask = vec![0b0010u64];
assert!(intersects(&snapshot, &mask));
let mask2 = vec![0b0101u64];
assert!(!intersects(&snapshot, &mask2));
}
#[test]
fn for_each_set_bit_works() {
let bm = vec![0b1010_0101u64, 0u64];
let mut bits = Vec::new();
for_each_set_bit(&bm, |i| bits.push(i));
assert_eq!(bits, vec![0, 2, 5, 7]);
}
#[test]
fn for_each_set_bit_multi_word() {
let mut bm = vec![0u64; 2];
set_bit(&mut bm, 0);
set_bit(&mut bm, 63);
set_bit(&mut bm, 64);
set_bit(&mut bm, 127);
let mut bits = Vec::new();
for_each_set_bit(&bm, |i| bits.push(i));
assert_eq!(bits, vec![0, 63, 64, 127]);
}
#[test]
fn or_into_works() {
let mut dst = vec![0b1010u64];
let src = vec![0b0101u64];
or_into(&mut dst, &src);
assert_eq!(dst[0], 0b1111);
}
#[test]
fn is_empty_works() {
assert!(is_empty(&[0u64, 0u64]));
assert!(!is_empty(&[0u64, 1u64]));
}
#[test]
fn contains_all_sign_bit() {
let mut snapshot = vec![0u64; 1];
set_bit(&mut snapshot, 63);
let mut mask = vec![0u64; 1];
set_bit(&mut mask, 63);
assert!(contains_all(&snapshot, &mask));
assert!(!contains_all(&[0u64], &mask));
}
#[test]
fn intersects_sign_bit() {
let mut snapshot = vec![0u64; 1];
set_bit(&mut snapshot, 63);
let mut mask = vec![0u64; 1];
set_bit(&mut mask, 63);
assert!(intersects(&snapshot, &mask));
assert!(!intersects(&[0u64], &mask));
}
}