use roaring::RoaringBitmap;
use smallvec::SmallVec;
use std::ops::Range;
#[cfg(test)]
#[path = "selection_tests.rs"]
mod tests;
#[derive(Clone, Debug, Default)]
pub enum AtomSelection {
#[default]
Empty,
All,
Range(Range<u32>),
Ranges(SmallVec<[Range<u32>; 4]>),
Sparse(Vec<u32>),
Roaring(RoaringBitmap),
}
impl AtomSelection {
#[must_use]
pub fn count(&self, table_len: u32) -> u64 {
match self {
Self::Empty => 0,
Self::All => u64::from(table_len),
Self::Range(r) => u64::from(r.end.saturating_sub(r.start)),
Self::Ranges(rs) => rs
.iter()
.map(|r| u64::from(r.end.saturating_sub(r.start)))
.sum(),
Self::Sparse(v) => v.len() as u64,
Self::Roaring(map) => map.len(),
}
}
#[must_use]
pub fn contains(&self, index: u32) -> bool {
match self {
Self::Empty => false,
Self::All => true,
Self::Range(r) => r.contains(&index),
Self::Ranges(rs) => rs.iter().any(|r| r.contains(&index)),
Self::Sparse(v) => v.binary_search(&index).is_ok(),
Self::Roaring(map) => map.contains(index),
}
}
pub fn for_each(&self, table_len: u32, mut visit: impl FnMut(u32)) {
match self {
Self::Empty => {}
Self::All => {
for i in 0..table_len {
visit(i);
}
}
Self::Range(r) => {
for i in r.start..r.end.min(table_len) {
visit(i);
}
}
Self::Ranges(rs) => {
for r in rs {
for i in r.start..r.end.min(table_len) {
visit(i);
}
}
}
Self::Sparse(v) => {
for &i in v {
if i < table_len {
visit(i);
}
}
}
Self::Roaring(map) => {
for i in map {
if i < table_len {
visit(i);
}
}
}
}
}
#[must_use]
pub fn to_bitmap(&self, table_len: u32) -> RoaringBitmap {
match self {
Self::Roaring(map) => map.clone(),
Self::Range(r) => {
let mut map = RoaringBitmap::new();
map.insert_range(r.start..r.end.min(table_len));
map
}
_ => {
let mut map = RoaringBitmap::new();
self.for_each(table_len, |i| {
map.insert(i);
});
map
}
}
}
#[must_use]
pub fn union(&self, other: &Self, table_len: u32) -> Self {
match (self, other) {
(Self::Empty, _) => other.clone(),
(_, Self::Empty) => self.clone(),
(Self::All, _) | (_, Self::All) => Self::All,
_ => Self::Roaring(self.to_bitmap(table_len) | other.to_bitmap(table_len)),
}
}
#[must_use]
pub fn intersect(&self, other: &Self, table_len: u32) -> Self {
match (self, other) {
(Self::Empty, _) | (_, Self::Empty) => Self::Empty,
(Self::All, _) => other.clone(),
(_, Self::All) => self.clone(),
_ => Self::Roaring(self.to_bitmap(table_len) & other.to_bitmap(table_len)),
}
}
#[must_use]
pub fn difference(&self, other: &Self, table_len: u32) -> Self {
match (self, other) {
(Self::Empty, _) | (_, Self::All) => Self::Empty,
(_, Self::Empty) => self.clone(),
_ => Self::Roaring(self.to_bitmap(table_len) - other.to_bitmap(table_len)),
}
}
}