MeiliSearch/milli/src/search/new/small_bitmap.rs

357 lines
12 KiB
Rust
Raw Normal View History

2023-03-14 16:37:47 +01:00
use std::marker::PhantomData;
use super::interner::{FixedSizeInterner, Interned};
/// A compact set of [`Interned<T>`]
2023-03-29 08:44:11 +02:00
///
/// This set optimizes storage by storing the set of values in a bitmap, and further optimizes
/// for bitmaps where the highest possible index (describing the limits of the "universe")
/// is smaller than 64 by storing them as a `u64`.
2023-03-14 16:37:47 +01:00
pub struct SmallBitmap<T> {
2023-03-29 08:44:11 +02:00
// internals are not typed as they only represent the indexes that are set
2023-03-14 16:37:47 +01:00
internal: SmallBitmapInternal,
2023-03-29 08:44:11 +02:00
// restores typing with a tag
2023-03-14 16:37:47 +01:00
_phantom: PhantomData<T>,
}
2023-03-29 08:44:11 +02:00
// manual implementation for when `T` is not Clone.
2023-03-14 16:37:47 +01:00
impl<T> Clone for SmallBitmap<T> {
fn clone(&self) -> Self {
Self { internal: self.internal.clone(), _phantom: PhantomData }
}
}
2023-03-29 08:44:11 +02:00
2023-03-14 16:37:47 +01:00
impl<T> SmallBitmap<T> {
2023-03-29 08:44:11 +02:00
/// Constructs a new, **empty**, `SmallBitmap<T>` with an universe large enough to hold all elements
/// from `interner`.
///
/// The constructed bitmap does not refer to any element in the interner, use [`from_iter`] if there should be
/// some interned values in the bitmap after construction.
2023-03-14 16:37:47 +01:00
pub fn for_interned_values_in(interner: &FixedSizeInterner<T>) -> Self {
Self::new(interner.len())
}
2023-03-29 08:44:11 +02:00
/// Constructs a new, **empty**, `SmallBitmap<T>` with an universe at least as large as specified.
///
/// If the passed universe length is not a multiple of 64, it will be rounded up to the next multiple of 64.
2023-03-14 16:37:47 +01:00
pub fn new(universe_length: u16) -> Self {
if universe_length <= 64 {
Self { internal: SmallBitmapInternal::Tiny(0), _phantom: PhantomData }
} else {
Self {
internal: SmallBitmapInternal::Small(
2023-03-19 14:27:58 +01:00
vec![0; 1 + (universe_length - 1) as usize / 64].into_boxed_slice(),
2023-03-14 16:37:47 +01:00
),
_phantom: PhantomData,
}
}
}
2023-03-29 08:44:11 +02:00
/// The highest index that can be set in this bitmap.
///
/// The universe length is always a multiple of 64, and may be higher than the value passed to [`Self::new`].
2023-03-18 15:04:34 +01:00
pub fn universe_length(&self) -> u16 {
match &self.internal {
SmallBitmapInternal::Tiny(_) => 64,
SmallBitmapInternal::Small(xs) => 64 * xs.len() as u16,
}
}
2023-03-29 08:44:11 +02:00
/// Constructs a new `SmallBitmap<T>` with an universe large enough to hold all elements
/// from `from_interner`, and containing all the `Interned<T>` produced by `xs`.
///
/// It is a logic error to pass an iterator producing `Interned<T>`s that don't belong to the passed interner.
///
/// # Panics
///
/// - If `xs` produces an element that doesn't fit the universe length obtained from `for_interner`.
2023-03-14 16:37:47 +01:00
pub fn from_iter(
xs: impl Iterator<Item = Interned<T>>,
for_interner: &FixedSizeInterner<T>,
) -> Self {
Self {
2023-03-16 09:58:59 +01:00
internal: SmallBitmapInternal::from_iter(xs.map(|x| x.into_raw()), for_interner.len()),
2023-03-14 16:37:47 +01:00
_phantom: PhantomData,
}
}
2023-03-29 08:44:11 +02:00
/// Returns `true` if this bitmap does not contain any `Interned<T>`.
2023-03-14 16:37:47 +01:00
pub fn is_empty(&self) -> bool {
self.internal.is_empty()
}
2023-03-29 08:44:11 +02:00
/// Removes all `Interned<T>` from this bitmap, such that it [`is_empty`] returns `true` after this call.
2023-03-14 16:37:47 +01:00
pub fn clear(&mut self) {
self.internal.clear()
}
2023-03-29 08:44:11 +02:00
/// Whether `x` is part of the bitmap.
///
/// It is a logic error to pass an `Interned<T>` from a different interner that the one this bitmap references.
///
/// # Panics
///
/// - if `x` does not fit in [`universe_length`]
2023-03-14 16:37:47 +01:00
pub fn contains(&self, x: Interned<T>) -> bool {
2023-03-16 09:58:59 +01:00
self.internal.contains(x.into_raw())
2023-03-14 16:37:47 +01:00
}
2023-03-29 08:44:11 +02:00
/// Adds `x` to the bitmap, such that [`contains(x)`] returns `true` after this call.
///
/// It is a logic error to pass an `Interned<T>` from a different interner that the one this bitmap references.
///
/// # Panics
///
/// - if `x` does not fit in [`universe_length`]
2023-03-14 16:37:47 +01:00
pub fn insert(&mut self, x: Interned<T>) {
2023-03-16 09:58:59 +01:00
self.internal.insert(x.into_raw())
2023-03-14 16:37:47 +01:00
}
2023-03-29 08:44:11 +02:00
/// Removes `x` from the bitmap, such that [`contains(x)`] returns `false` after this call.
///
/// It is a logic error to pass an `Interned<T>` from a different interner that the one this bitmap references.
///
/// # Panics
///
/// - if `x` does not fit in [`universe_length`]
2023-03-14 16:37:47 +01:00
pub fn remove(&mut self, x: Interned<T>) {
2023-03-16 09:58:59 +01:00
self.internal.remove(x.into_raw())
2023-03-14 16:37:47 +01:00
}
2023-03-29 08:44:11 +02:00
/// Modifies in place this bitmap to retain only the elements that are also present in `other`.
///
/// # Panics
///
/// - if the universe lengths of `self` and `other` differ
2023-03-14 16:37:47 +01:00
pub fn intersection(&mut self, other: &Self) {
self.internal.intersection(&other.internal)
}
2023-03-29 08:44:11 +02:00
/// Modifies in place this bitmap to add the elements that are present in `other`.
///
/// # Panics
///
/// - if the universe lengths of `self` and `other` differ
2023-03-14 16:37:47 +01:00
pub fn union(&mut self, other: &Self) {
self.internal.union(&other.internal)
}
2023-03-29 08:44:11 +02:00
/// Modifies in place this bitmap to remove the elements that are also present in `other`.
///
/// # Panics
///
/// - if the universe lengths of `self` and `other` differ
2023-03-14 16:37:47 +01:00
pub fn subtract(&mut self, other: &Self) {
self.internal.subtract(&other.internal)
}
2023-03-29 08:44:11 +02:00
/// Whether all the elements of `self` are contained in `other`.
///
/// # Panics
///
/// - if the universe lengths of `self` and `other` differ
2023-03-14 16:37:47 +01:00
pub fn is_subset(&self, other: &Self) -> bool {
self.internal.is_subset(&other.internal)
}
2023-03-29 08:44:11 +02:00
/// Whether any element of `self` is contained in `other`.
///
/// # Panics
///
/// - if the universe lengths of `self` and `other` differ
2023-03-14 16:37:47 +01:00
pub fn intersects(&self, other: &Self) -> bool {
self.internal.intersects(&other.internal)
}
2023-03-29 08:44:11 +02:00
/// Returns an iterator of the `Interned<T>` that are present in this bitmap.
2023-03-14 16:37:47 +01:00
pub fn iter(&self) -> impl Iterator<Item = Interned<T>> + '_ {
2023-03-16 09:58:59 +01:00
self.internal.iter().map(|x| Interned::from_raw(x))
2023-03-14 16:37:47 +01:00
}
}
#[derive(Clone)]
enum SmallBitmapInternal {
Tiny(u64),
Small(Box<[u64]>),
}
2023-03-14 16:37:47 +01:00
impl SmallBitmapInternal {
2023-03-16 09:58:59 +01:00
fn new(universe_length: u16) -> Self {
if universe_length <= 64 {
Self::Tiny(0)
} else {
Self::Small(vec![0; 1 + universe_length as usize / 64].into_boxed_slice())
}
}
2023-03-16 09:58:59 +01:00
fn from_iter(xs: impl Iterator<Item = u16>, universe_length: u16) -> Self {
let mut s = Self::new(universe_length);
for x in xs {
s.insert(x);
}
s
}
pub fn is_empty(&self) -> bool {
match self {
2023-03-14 16:37:47 +01:00
SmallBitmapInternal::Tiny(set) => *set == 0,
SmallBitmapInternal::Small(sets) => {
for set in sets.iter() {
if *set != 0 {
return false;
}
}
true
}
}
}
pub fn clear(&mut self) {
match self {
2023-03-14 16:37:47 +01:00
SmallBitmapInternal::Tiny(set) => *set = 0,
SmallBitmapInternal::Small(sets) => {
for set in sets.iter_mut() {
*set = 0;
}
}
}
}
pub fn contains(&self, mut x: u16) -> bool {
let set = match self {
2023-03-14 16:37:47 +01:00
SmallBitmapInternal::Tiny(set) => *set,
SmallBitmapInternal::Small(set) => {
let idx = x / 64;
x %= 64;
set[idx as usize]
}
};
set & 0b1 << x != 0
}
pub fn insert(&mut self, mut x: u16) {
let set = match self {
2023-03-14 16:37:47 +01:00
SmallBitmapInternal::Tiny(set) => set,
SmallBitmapInternal::Small(set) => {
let idx = x / 64;
x %= 64;
&mut set[idx as usize]
}
};
*set |= 0b1 << x;
}
pub fn remove(&mut self, mut x: u16) {
let set = match self {
2023-03-14 16:37:47 +01:00
SmallBitmapInternal::Tiny(set) => set,
SmallBitmapInternal::Small(set) => {
let idx = x / 64;
x %= 64;
&mut set[idx as usize]
}
};
*set &= !(0b1 << x);
}
2023-03-14 16:37:47 +01:00
pub fn intersection(&mut self, other: &SmallBitmapInternal) {
self.apply_op(other, |a, b| *a &= b);
}
2023-03-14 16:37:47 +01:00
pub fn union(&mut self, other: &SmallBitmapInternal) {
self.apply_op(other, |a, b| *a |= b);
}
2023-03-14 16:37:47 +01:00
pub fn subtract(&mut self, other: &SmallBitmapInternal) {
self.apply_op(other, |a, b| *a &= !b);
}
2023-03-14 16:37:47 +01:00
pub fn apply_op(&mut self, other: &SmallBitmapInternal, op: impl Fn(&mut u64, u64)) {
match (self, other) {
2023-03-14 16:37:47 +01:00
(SmallBitmapInternal::Tiny(a), SmallBitmapInternal::Tiny(b)) => op(a, *b),
(SmallBitmapInternal::Small(a), SmallBitmapInternal::Small(b)) => {
assert!(a.len() == b.len(),);
for (a, b) in a.iter_mut().zip(b.iter()) {
op(a, *b);
}
}
_ => {
panic!();
}
}
}
fn all_satisfy_op(&self, other: &SmallBitmapInternal, op: impl Fn(u64, u64) -> bool) -> bool {
match (self, other) {
2023-03-14 16:37:47 +01:00
(SmallBitmapInternal::Tiny(a), SmallBitmapInternal::Tiny(b)) => op(*a, *b),
(SmallBitmapInternal::Small(a), SmallBitmapInternal::Small(b)) => {
assert!(a.len() == b.len());
for (a, b) in a.iter().zip(b.iter()) {
if !op(*a, *b) {
return false;
}
}
true
}
_ => {
panic!();
}
}
}
fn any_satisfy_op(&self, other: &SmallBitmapInternal, op: impl Fn(u64, u64) -> bool) -> bool {
match (self, other) {
2023-03-14 16:37:47 +01:00
(SmallBitmapInternal::Tiny(a), SmallBitmapInternal::Tiny(b)) => op(*a, *b),
(SmallBitmapInternal::Small(a), SmallBitmapInternal::Small(b)) => {
assert!(a.len() == b.len());
for (a, b) in a.iter().zip(b.iter()) {
if op(*a, *b) {
return true;
}
}
false
}
_ => {
panic!();
}
}
}
2023-03-14 16:37:47 +01:00
pub fn is_subset(&self, other: &SmallBitmapInternal) -> bool {
self.all_satisfy_op(other, |a, b| a & !b == 0)
}
2023-03-14 16:37:47 +01:00
pub fn intersects(&self, other: &SmallBitmapInternal) -> bool {
self.any_satisfy_op(other, |a, b| a & b != 0)
}
2023-03-14 16:37:47 +01:00
pub fn iter(&self) -> SmallBitmapInternalIter<'_> {
match self {
2023-03-14 16:37:47 +01:00
SmallBitmapInternal::Tiny(x) => SmallBitmapInternalIter::Tiny(*x),
SmallBitmapInternal::Small(xs) => {
SmallBitmapInternalIter::Small { cur: xs[0], next: &xs[1..], base: 0 }
}
}
}
}
2023-03-14 16:37:47 +01:00
pub enum SmallBitmapInternalIter<'b> {
Tiny(u64),
Small { cur: u64, next: &'b [u64], base: u16 },
}
2023-03-14 16:37:47 +01:00
impl<'b> Iterator for SmallBitmapInternalIter<'b> {
type Item = u16;
fn next(&mut self) -> Option<Self::Item> {
match self {
2023-03-14 16:37:47 +01:00
SmallBitmapInternalIter::Tiny(set) => {
if *set > 0 {
let idx = set.trailing_zeros() as u16;
*set &= *set - 1;
Some(idx)
} else {
None
}
}
2023-03-14 16:37:47 +01:00
SmallBitmapInternalIter::Small { cur, next, base } => {
if *cur > 0 {
let idx = cur.trailing_zeros() as u16;
*cur &= *cur - 1;
Some(idx + *base)
} else if next.is_empty() {
return None;
} else {
*base += 64;
*cur = next[0];
*next = &next[1..];
self.next()
}
}
}
}
}