#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Validity {
AllValid,
AllInvalid,
Mask(Bitmap),
}
impl Validity {
#[must_use]
pub fn footprint(&self) -> usize {
match self {
Self::AllValid | Self::AllInvalid => 0,
Self::Mask(mask) => mask.footprint(),
}
}
#[must_use]
pub fn is_valid(&self, index: usize) -> bool {
match self {
Self::AllValid => true,
Self::AllInvalid => false,
Self::Mask(mask) => mask.get(index),
}
}
#[must_use]
pub fn has_nulls(&self, len: usize) -> bool {
match self {
Self::AllValid => false,
Self::AllInvalid => len > 0,
Self::Mask(mask) => mask.count_valid(len) != len,
}
}
#[must_use]
pub fn count_valid(&self, len: usize) -> usize {
match self {
Self::AllValid => len,
Self::AllInvalid => 0,
Self::Mask(mask) => mask.count_valid(len),
}
}
#[must_use]
pub fn normalize(self, len: usize) -> Self {
match self {
Self::Mask(ref mask) => {
let valid = mask.count_valid(len);
if valid == len {
Self::AllValid
} else if valid == 0 {
Self::AllInvalid
} else {
self
}
}
other => other,
}
}
#[must_use]
pub fn with_null(self, index: usize, len: usize) -> Self {
let mut mask = match self {
Self::AllValid => Bitmap::all_valid(len),
Self::AllInvalid => return Self::AllInvalid,
Self::Mask(mask) => mask,
};
mask.set(index, false);
Self::Mask(mask)
}
pub fn from_iter(len: usize, valid: impl Fn(usize) -> bool) -> Self {
let mut mask = Bitmap::all_valid(len);
for index in 0..len {
if !valid(index) {
mask.set(index, false);
}
}
Self::Mask(mask).normalize(len)
}
#[must_use]
pub fn from_run(valid: &[bool]) -> Self {
let len = valid.len();
let mut words = vec![0u64; len.div_ceil(64)];
for (word, run) in words.iter_mut().zip(valid.chunks(64)) {
let mut packed = if run.len() == 64 { 0 } else { u64::MAX << run.len() };
for (bit, &live) in run.iter().enumerate() {
packed |= u64::from(live) << bit;
}
*word = packed;
}
Self::Mask(Bitmap { words }).normalize(len)
}
#[must_use]
pub fn and(&self, other: &Self, len: usize) -> Self {
match (self, other) {
(Self::AllInvalid, _) | (_, Self::AllInvalid) => Self::AllInvalid,
(Self::AllValid, Self::AllValid) => Self::AllValid,
(Self::AllValid, right) => right.clone().normalize(len),
(left, Self::AllValid) => left.clone().normalize(len),
(Self::Mask(left), Self::Mask(right)) => {
let mut result = left.clone();
result.and_with(right);
Self::Mask(result).normalize(len)
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Bitmap {
words: Vec<u64>,
}
impl Bitmap {
#[must_use]
pub fn footprint(&self) -> usize {
self.words.capacity() * size_of::<u64>()
}
#[must_use]
pub fn all_valid(len: usize) -> Self {
Self { words: vec![u64::MAX; len.div_ceil(64)] }
}
#[must_use]
pub fn all_invalid(len: usize) -> Self {
Self { words: vec![0; len.div_ceil(64)] }
}
#[must_use]
pub fn get(&self, index: usize) -> bool {
let word = index / 64;
self.words.get(word).is_some_and(|w| w >> (index % 64) & 1 == 1)
}
pub fn set(&mut self, index: usize, valid: bool) {
let word = index / 64;
if word >= self.words.len() {
self.words.resize(word + 1, 0);
}
let bit = 1u64 << (index % 64);
if valid {
self.words[word] |= bit;
} else {
self.words[word] &= !bit;
}
}
#[must_use]
pub fn count_valid(&self, len: usize) -> usize {
let mut count = 0usize;
let full_words = len / 64;
for word in self.words.iter().take(full_words) {
count += word.count_ones() as usize;
}
let tail = len % 64;
if tail > 0 {
if let Some(word) = self.words.get(full_words) {
let keep = u64::MAX >> (64 - tail);
count += (word & keep).count_ones() as usize;
}
}
count
}
#[must_use]
pub fn word(&self, at: usize) -> u64 {
self.words.get(at).copied().unwrap_or(0)
}
pub fn and_with(&mut self, other: &Self) {
for (index, word) in self.words.iter_mut().enumerate() {
*word &= other.words.get(index).copied().unwrap_or(0);
}
}
}
#[cfg(test)]
mod tests {
use super::{Bitmap, Validity};
#[test]
fn the_three_cases_answer_the_same_question_the_same_way() {
let mut mask = Bitmap::all_valid(8);
assert!(Validity::AllValid.is_valid(3));
assert!(!Validity::AllInvalid.is_valid(3));
assert!(Validity::Mask(mask.clone()).is_valid(3));
mask.set(3, false);
assert!(!Validity::Mask(mask).is_valid(3));
}
#[test]
fn a_uniform_mask_collapses_to_the_flag_it_should_have_been() {
assert_eq!(Validity::Mask(Bitmap::all_valid(64)).normalize(64), Validity::AllValid);
assert_eq!(Validity::Mask(Bitmap::all_invalid(64)).normalize(64), Validity::AllInvalid);
let mut mask = Bitmap::all_valid(64);
mask.set(7, false);
assert!(matches!(Validity::Mask(mask).normalize(64), Validity::Mask(_)));
}
#[test]
fn a_word_of_validity_says_the_same_thing_the_bits_do_one_at_a_time() {
let mut mask = Bitmap::all_valid(200);
mask.set(0, false);
mask.set(63, false);
mask.set(64, false);
mask.set(199, false);
for index in 0..200 {
let from_word = mask.word(index / 64) >> (index % 64) & 1 == 1;
assert_eq!(from_word, mask.get(index), "{index}");
}
assert_eq!(mask.word(9), 0);
assert!(!mask.get(9 * 64));
}
#[test]
fn packing_a_run_of_bytes_says_the_same_thing_as_setting_the_bits() {
for len in [0, 1, 63, 64, 65, 100, 1024] {
let live: Vec<bool> = (0..len).map(|index| index % 7 != 0).collect();
let packed = Validity::from_run(&live);
let set = Validity::from_iter(len, |index| live[index]);
assert_eq!(packed, set, "{len}");
for (index, &want) in live.iter().enumerate() {
assert_eq!(packed.is_valid(index), want, "{len} at {index}");
}
}
assert_eq!(
Validity::from_run(&[true, false, true]),
Validity::from_iter(3, |index| index != 1)
);
assert_eq!(Validity::from_run(&[true; 64]), Validity::AllValid);
assert_eq!(Validity::from_run(&[false; 64]), Validity::AllInvalid);
assert_eq!(Validity::from_run(&[]), Validity::AllValid);
}
#[test]
fn counting_stops_at_the_length_and_not_at_the_word_boundary() {
let mask = Bitmap::all_valid(100);
assert_eq!(mask.count_valid(100), 100);
assert_eq!(mask.count_valid(65), 65);
assert_eq!(mask.count_valid(1), 1);
assert_eq!(mask.count_valid(0), 0);
}
#[test]
fn setting_a_null_on_an_all_valid_vector_materializes_a_mask() {
let validity = Validity::AllValid.with_null(5, 64);
assert!(!validity.is_valid(5));
assert!(validity.is_valid(4));
assert_eq!(validity.count_valid(64), 63);
assert!(validity.has_nulls(64));
}
#[test]
fn setting_a_null_on_an_all_invalid_vector_changes_nothing() {
assert_eq!(Validity::AllInvalid.with_null(5, 64), Validity::AllInvalid);
}
#[test]
fn intersection_short_circuits_on_the_flags() {
let mut left = Bitmap::all_valid(8);
left.set(0, false);
let mut right = Bitmap::all_valid(8);
right.set(1, false);
let both = Validity::Mask(left.clone()).and(&Validity::Mask(right), 8);
assert!(!both.is_valid(0));
assert!(!both.is_valid(1));
assert!(both.is_valid(2));
assert_eq!(both.count_valid(8), 6);
assert_eq!(Validity::AllValid.and(&Validity::AllValid, 8), Validity::AllValid);
assert_eq!(Validity::AllInvalid.and(&Validity::Mask(left), 8), Validity::AllInvalid);
}
#[test]
fn validity_from_a_predicate_normalizes_itself() {
assert_eq!(Validity::from_iter(16, |_| true), Validity::AllValid);
assert_eq!(Validity::from_iter(16, |_| false), Validity::AllInvalid);
let mixed = Validity::from_iter(16, |i| i % 2 == 0);
assert_eq!(mixed.count_valid(16), 8);
}
}