use arrow_array::{BooleanArray, UInt32Array};
use roaring::RoaringBitmap;
use crate::permutation::PermutationIndex;
#[derive(Debug, Clone)]
pub struct FilterIndex {
mask: RoaringBitmap,
}
impl FilterIndex {
pub fn from_ids(ids: impl IntoIterator<Item = u32>) -> Self {
Self {
mask: ids.into_iter().collect(),
}
}
pub fn from_boolean_array(arr: &BooleanArray) -> Self {
let mask: RoaringBitmap = arr
.iter()
.enumerate()
.filter_map(|(i, v)| {
#[allow(clippy::cast_possible_truncation)]
v.unwrap_or(false).then_some(i as u32)
})
.collect();
Self { mask }
}
pub fn len(&self) -> u64 {
self.mask.len()
}
pub fn is_empty(&self) -> bool {
self.mask.is_empty()
}
pub fn contains(&self, id: u32) -> bool {
self.mask.contains(id)
}
#[allow(clippy::cast_possible_truncation)] pub fn apply_to_permutation(&self, permutation: &PermutationIndex) -> PermutationIndex {
const CHUNK: usize = 65_536;
let len = permutation.len() as usize;
let mut values = Vec::new();
let mut offset = 0;
while offset < len {
let end = (offset + CHUNK).min(len);
let chunk = permutation.read_range(offset, end);
for &id in &chunk {
if self.mask.contains(id) {
values.push(id);
}
}
offset = end;
}
PermutationIndex::from_array(UInt32Array::from(values))
}
#[must_use]
pub fn intersection(&self, other: &FilterIndex) -> FilterIndex {
FilterIndex {
mask: &self.mask & &other.mask,
}
}
#[must_use]
pub fn union(&self, other: &FilterIndex) -> FilterIndex {
FilterIndex {
mask: &self.mask | &other.mask,
}
}
#[must_use]
pub fn negate(&self, total_rows: u32) -> FilterIndex {
let mut universe = RoaringBitmap::new();
universe.insert_range(0..total_rows);
FilterIndex {
mask: universe - &self.mask,
}
}
#[must_use]
pub fn difference(&self, other: &FilterIndex) -> FilterIndex {
FilterIndex {
mask: &self.mask - &other.mask,
}
}
pub fn into_boolean_array(&self, total_rows: u32) -> BooleanArray {
let values: Vec<bool> = (0..total_rows).map(|i| self.mask.contains(i)).collect();
BooleanArray::from(values)
}
pub fn iter(&self) -> impl Iterator<Item = u32> + '_ {
self.mask.iter()
}
#[allow(dead_code)] pub(crate) fn bitmap(&self) -> &RoaringBitmap {
&self.mask
}
#[allow(dead_code)] pub(crate) fn from_bitmap(mask: RoaringBitmap) -> Self {
Self { mask }
}
#[allow(dead_code)] pub(crate) fn from_bitmap_ref(bitmap: &RoaringBitmap) -> Self {
Self {
mask: bitmap.clone(),
}
}
}