blob: ebb9b4e7d703c85e4493d0b7de039027cc675c8f [file] [log] [blame] [edit]
//! Compound bit sets.
use crate::scalar::{self, ScalarBitSet};
use alloc::boxed::Box;
use core::{cmp, iter, mem};
/// A large bit set backed by dynamically-sized storage.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// // Create a new bitset.
/// let mut bitset = CompoundBitSet::new();
///
/// // Bitsets are initially empty.
/// assert!(bitset.is_empty());
/// assert_eq!(bitset.len(), 0);
///
/// // Insert into the bitset.
/// bitset.insert(444);
/// bitset.insert(555);
/// bitset.insert(666);
///
/// // Now the bitset is not empty.
/// assert_eq!(bitset.len(), 3);
/// assert!(!bitset.is_empty());
/// assert!(bitset.contains(444));
/// assert!(bitset.contains(555));
/// assert!(bitset.contains(666));
///
/// // Remove an element from the bitset.
/// let was_present = bitset.remove(666);
/// assert!(was_present);
/// assert!(!bitset.contains(666));
/// assert_eq!(bitset.len(), 2);
///
/// // Can iterate over the elements in the set.
/// let elems: Vec<_> = bitset.iter().collect();
/// assert_eq!(elems, [444, 555]);
/// ```
#[derive(Clone, Default, PartialEq, Eq)]
#[cfg_attr(
feature = "enable-serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct CompoundBitSet {
elems: Box<[ScalarBitSet<usize>]>,
max: Option<u32>,
}
impl core::fmt::Debug for CompoundBitSet {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "CompoundBitSet ")?;
f.debug_set().entries(self.iter()).finish()
}
}
const BITS_PER_WORD: usize = mem::size_of::<usize>() * 8;
impl CompoundBitSet {
/// Construct a new, empty bit set.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let bitset = CompoundBitSet::new();
///
/// assert!(bitset.is_empty());
/// ```
#[inline]
pub fn new() -> Self {
CompoundBitSet::default()
}
/// Construct a new, empty bit set with space reserved to store any element
/// `x` such that `x < capacity`.
///
/// The actual capacity reserved may be greater than that requested.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let bitset = CompoundBitSet::with_capacity(4096);
///
/// assert!(bitset.is_empty());
/// assert!(bitset.capacity() >= 4096);
/// ```
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let mut bitset = Self::new();
bitset.ensure_capacity(capacity);
bitset
}
/// Get the number of elements in this bitset.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// assert_eq!(bitset.len(), 0);
///
/// bitset.insert(24);
/// bitset.insert(130);
/// bitset.insert(3600);
///
/// assert_eq!(bitset.len(), 3);
/// ```
#[inline]
pub fn len(&self) -> usize {
self.elems.iter().map(|sub| usize::from(sub.len())).sum()
}
/// Get `n + 1` where `n` is the largest value that can be stored inside
/// this set without growing the backing storage.
///
/// That is, this set can store any value `x` such that `x <
/// bitset.capacity()` without growing the backing storage.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// // New bitsets have zero capacity -- they allocate lazily.
/// assert_eq!(bitset.capacity(), 0);
///
/// // Insert into the bitset, growing its capacity.
/// bitset.insert(999);
///
/// // The bitset must now have capacity for at least `999` elements,
/// // perhaps more.
/// assert!(bitset.capacity() >= 999);
///```
pub fn capacity(&self) -> usize {
self.elems.len() * BITS_PER_WORD
}
/// Is this bitset empty?
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// assert!(bitset.is_empty());
///
/// bitset.insert(1234);
///
/// assert!(!bitset.is_empty());
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Convert an element `i` into the `word` that can be used to index into
/// `self.elems` and the `bit` that can be tested in the
/// `ScalarBitSet<usize>` at `self.elems[word]`.
#[inline]
fn word_and_bit(i: usize) -> (usize, u8) {
let word = i / BITS_PER_WORD;
let bit = i % BITS_PER_WORD;
let bit = u8::try_from(bit).unwrap();
(word, bit)
}
/// The opposite of `word_and_bit`: convert the pair of an index into
/// `self.elems` and associated bit index into a set element.
#[inline]
fn elem(word: usize, bit: u8) -> usize {
let bit = usize::from(bit);
debug_assert!(bit < BITS_PER_WORD);
word * BITS_PER_WORD + bit
}
/// Is `i` contained in this bitset?
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// assert!(!bitset.contains(666));
///
/// bitset.insert(666);
///
/// assert!(bitset.contains(666));
/// ```
#[inline]
pub fn contains(&self, i: usize) -> bool {
let (word, bit) = Self::word_and_bit(i);
if word < self.elems.len() {
self.elems[word].contains(bit)
} else {
false
}
}
/// Ensure there is space in this bitset for the values `0..n`, growing the
/// backing storage if necessary.
///
/// After calling `bitset.ensure_capacity(n)`, inserting any element `i`
/// where `i < n` is guaranteed to succeed without growing the bitset's
/// backing storage.
///
/// # Example
///
/// ```
/// # use cranelift_bitset::CompoundBitSet;
/// # let mut bitset = CompoundBitSet::new();
/// // We are going to do a series of inserts where `1000` will be the
/// // maximum value inserted. Make sure that our bitset has capacity for
/// // these elements once up front, to avoid growing the backing storage
/// // multiple times incrementally.
/// bitset.ensure_capacity(1001);
///
/// for i in 0..=1000 {
/// if i % 2 == 0 {
/// // Inserting this value should not require growing the backing
/// // storage.
/// assert!(bitset.capacity() > i);
/// bitset.insert(i);
/// }
/// }
/// ```
#[inline]
pub fn ensure_capacity(&mut self, n: usize) {
let (word, _bit) = Self::word_and_bit(n);
if word >= self.elems.len() {
assert!(word < usize::try_from(isize::MAX).unwrap());
let delta = word - self.elems.len();
let to_grow = delta + 1;
// Amortize the cost of growing.
let to_grow = cmp::max(to_grow, self.elems.len() * 2);
// Don't make ridiculously small allocations.
let to_grow = cmp::max(to_grow, 4);
let new_elems = self
.elems
.iter()
.copied()
.chain(iter::repeat(ScalarBitSet::new()).take(to_grow))
.collect::<Box<[_]>>();
self.elems = new_elems;
}
}
/// Insert `i` into this bitset.
///
/// Returns whether the value was newly inserted. That is:
///
/// * If the set did not previously contain `i` then `true` is returned.
///
/// * If the set already contained `i` then `false` is returned.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// // When an element is inserted that was not already present in the set,
/// // then `true` is returned.
/// let is_new = bitset.insert(1234);
/// assert!(is_new);
///
/// // The element is now present in the set.
/// assert!(bitset.contains(1234));
///
/// // And when the element is already in the set, `false` is returned from
/// // `insert`.
/// let is_new = bitset.insert(1234);
/// assert!(!is_new);
/// ```
#[inline]
pub fn insert(&mut self, i: usize) -> bool {
self.ensure_capacity(i + 1);
let (word, bit) = Self::word_and_bit(i);
let is_new = self.elems[word].insert(bit);
let i = u32::try_from(i).unwrap();
self.max = self.max.map(|max| cmp::max(max, i)).or(Some(i));
is_new
}
/// Remove `i` from this bitset.
///
/// Returns whether `i` was previously in this set or not.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// // Removing an element that was not present in the set returns `false`.
/// let was_present = bitset.remove(456);
/// assert!(!was_present);
///
/// // And when the element was in the set, `true` is returned.
/// bitset.insert(456);
/// let was_present = bitset.remove(456);
/// assert!(was_present);
/// ```
#[inline]
pub fn remove(&mut self, i: usize) -> bool {
let (word, bit) = Self::word_and_bit(i);
if word < self.elems.len() {
let sub = &mut self.elems[word];
let was_present = sub.remove(bit);
if was_present && self.max() == Some(i) {
self.update_max(word);
}
was_present
} else {
false
}
}
/// Update the `self.max` field, based on the old word index of `self.max`.
fn update_max(&mut self, word_of_old_max: usize) {
self.max = self.elems[0..word_of_old_max + 1]
.iter()
.enumerate()
.rev()
.filter_map(|(word, sub)| {
let bit = sub.max()?;
Some(u32::try_from(Self::elem(word, bit)).unwrap())
})
.next();
}
/// Get the largest value in this set, or `None` if this set is empty.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// // Returns `None` if the bitset is empty.
/// assert!(bitset.max().is_none());
///
/// bitset.insert(123);
/// bitset.insert(987);
/// bitset.insert(999);
///
/// // Otherwise, it returns the largest value in the set.
/// assert_eq!(bitset.max(), Some(999));
/// ```
#[inline]
pub fn max(&self) -> Option<usize> {
self.max.map(|m| usize::try_from(m).unwrap())
}
/// Removes and returns the largest value in this set.
///
/// Returns `None` if this set is empty.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// bitset.insert(111);
/// bitset.insert(222);
/// bitset.insert(333);
/// bitset.insert(444);
/// bitset.insert(555);
///
/// assert_eq!(bitset.pop(), Some(555));
/// assert_eq!(bitset.pop(), Some(444));
/// assert_eq!(bitset.pop(), Some(333));
/// assert_eq!(bitset.pop(), Some(222));
/// assert_eq!(bitset.pop(), Some(111));
/// assert_eq!(bitset.pop(), None);
/// ```
#[inline]
pub fn pop(&mut self) -> Option<usize> {
let max = self.max()?;
self.remove(max);
Some(max)
}
/// Remove all elements from this bitset.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// bitset.insert(100);
/// bitset.insert(200);
/// bitset.insert(300);
///
/// bitset.clear();
///
/// assert!(bitset.is_empty());
/// ```
#[inline]
pub fn clear(&mut self) {
let max = match self.max() {
Some(max) => max,
None => return,
};
let (word, _bit) = Self::word_and_bit(max);
debug_assert!(self.elems[word + 1..].iter().all(|sub| sub.is_empty()));
for sub in &mut self.elems[..=word] {
*sub = ScalarBitSet::new();
}
self.max = None;
}
/// Iterate over the elements in this bitset.
///
/// The elements are always yielded in sorted order.
///
/// # Example
///
/// ```
/// use cranelift_bitset::CompoundBitSet;
///
/// let mut bitset = CompoundBitSet::new();
///
/// bitset.insert(0);
/// bitset.insert(4096);
/// bitset.insert(123);
/// bitset.insert(456);
/// bitset.insert(789);
///
/// assert_eq!(
/// bitset.iter().collect::<Vec<_>>(),
/// [0, 123, 456, 789, 4096],
/// );
/// ```
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter {
bitset: self,
word: 0,
sub: None,
}
}
}
impl<'a> IntoIterator for &'a CompoundBitSet {
type Item = usize;
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// An iterator over the elements in a [`CompoundBitSet`].
pub struct Iter<'a> {
bitset: &'a CompoundBitSet,
word: usize,
sub: Option<scalar::Iter<usize>>,
}
impl Iterator for Iter<'_> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
loop {
if let Some(sub) = &mut self.sub {
if let Some(bit) = sub.next() {
return Some(CompoundBitSet::elem(self.word, bit));
} else {
self.word += 1;
}
}
self.sub = Some(self.bitset.elems.get(self.word)?.iter());
}
}
}