rgwml 2.0.0

Typed, local-first tabular data library with columnar in-memory storage.
Documentation
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Bitmap {
    words: Vec<u64>,
    len: u32,
}

impl Bitmap {
    pub fn zeroed(len: u32) -> Self {
        Self {
            words: vec![0; Self::words_for_len(len)],
            len,
        }
    }

    pub fn set_all(len: u32) -> Self {
        let mut bitmap = Self {
            words: vec![u64::MAX; Self::words_for_len(len)],
            len,
        };
        bitmap.clear_trailing_bits();
        bitmap
    }

    pub fn len(&self) -> u32 {
        self.len
    }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub fn is_set(&self, index: u32) -> bool {
        if index >= self.len {
            return false;
        }

        let word_index = index as usize / 64;
        let bit_index = index as usize % 64;
        self.words
            .get(word_index)
            .map(|word| ((word >> bit_index) & 1) == 1)
            .unwrap_or(false)
    }

    pub fn set(&mut self, index: u32, value: bool) {
        if index >= self.len {
            return;
        }

        let word_index = index as usize / 64;
        let bit_index = index as usize % 64;
        if value {
            self.words[word_index] |= 1_u64 << bit_index;
        } else {
            self.words[word_index] &= !(1_u64 << bit_index);
        }
    }

    pub fn count_ones(&self) -> u32 {
        self.words.iter().map(|word| word.count_ones()).sum()
    }

    pub fn from_bools(values: &[bool]) -> Self {
        let mut bitmap = Self::zeroed(values.len() as u32);
        for (index, value) in values.iter().copied().enumerate() {
            bitmap.set(index as u32, value);
        }
        bitmap
    }

    fn words_for_len(len: u32) -> usize {
        if len == 0 {
            0
        } else {
            ((len - 1) / 64 + 1) as usize
        }
    }

    fn clear_trailing_bits(&mut self) {
        let remainder = self.len % 64;
        if remainder == 0 || self.words.is_empty() {
            return;
        }

        let mask = (1_u64 << remainder) - 1;
        if let Some(last) = self.words.last_mut() {
            *last &= mask;
        }
    }
}