Path: blob/main/cranelift/bitset/src/compound.rs
3054 views
//! Compound bit sets.12use crate::scalar::{self, ScalarBitSet, ScalarBitSetStorage};3use alloc::boxed::Box;4use core::{cmp, iter, mem};5use wasmtime_core::alloc::{TryExtend, Vec};6use wasmtime_core::error::OutOfMemory;78/// A large bit set backed by dynamically-sized storage.9///10/// # Example11///12/// ```13/// use cranelift_bitset::CompoundBitSet;14///15/// // Create a new bitset.16/// let mut bitset = CompoundBitSet::new();17///18/// // Bitsets are initially empty.19/// assert!(bitset.is_empty());20/// assert_eq!(bitset.len(), 0);21///22/// // Insert into the bitset.23/// bitset.insert(444);24/// bitset.insert(555);25/// bitset.insert(666);26///27/// // Now the bitset is not empty.28/// assert_eq!(bitset.len(), 3);29/// assert!(!bitset.is_empty());30/// assert!(bitset.contains(444));31/// assert!(bitset.contains(555));32/// assert!(bitset.contains(666));33///34/// // Remove an element from the bitset.35/// let was_present = bitset.remove(666);36/// assert!(was_present);37/// assert!(!bitset.contains(666));38/// assert_eq!(bitset.len(), 2);39///40/// // Can iterate over the elements in the set.41/// let elems: Vec<_> = bitset.iter().collect();42/// assert_eq!(elems, [444, 555]);43/// ```44#[derive(Clone, Default, PartialEq, Eq)]45#[cfg_attr(46feature = "enable-serde",47derive(serde_derive::Serialize, serde_derive::Deserialize)48)]49pub struct CompoundBitSet<T = usize> {50elems: Box<[ScalarBitSet<T>]>,51max: Option<u32>,52}5354impl core::fmt::Debug for CompoundBitSet {55fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {56write!(f, "CompoundBitSet ")?;57f.debug_set().entries(self.iter()).finish()58}59}6061impl CompoundBitSet {62/// Construct a new, empty bit set.63///64/// # Example65///66/// ```67/// use cranelift_bitset::CompoundBitSet;68///69/// let bitset = CompoundBitSet::new();70///71/// assert!(bitset.is_empty());72/// ```73#[inline]74pub fn new() -> Self {75CompoundBitSet::default()76}77}7879impl<T: ScalarBitSetStorage> CompoundBitSet<T> {80const BITS_PER_SCALAR: usize = mem::size_of::<T>() * 8;8182/// Construct a new, empty bit set with space reserved to store any element83/// `x` such that `x < capacity`.84///85/// The actual capacity reserved may be greater than that requested.86///87/// # Panics88///89/// Panics on allocation failure. Use [`CompoundBitSet::try_with_capacity`]90/// to handle allocation failure.91///92/// # Example93///94/// ```95/// use cranelift_bitset::CompoundBitSet;96///97/// let bitset = CompoundBitSet::<u32>::with_capacity(4096);98///99/// assert!(bitset.is_empty());100/// assert!(bitset.capacity() >= 4096);101/// ```102#[inline]103pub fn with_capacity(capacity: usize) -> Self {104Self::try_with_capacity(capacity).unwrap()105}106107/// Like [`CompoundBitSet::with_capacity`] but returns an error on108/// allocation failure.109#[inline]110pub fn try_with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {111let mut bitset = Self::default();112bitset.try_ensure_capacity(capacity)?;113Ok(bitset)114}115116/// Get the number of elements in this bitset.117///118/// # Example119///120/// ```121/// use cranelift_bitset::CompoundBitSet;122///123/// let mut bitset = CompoundBitSet::new();124///125/// assert_eq!(bitset.len(), 0);126///127/// bitset.insert(24);128/// bitset.insert(130);129/// bitset.insert(3600);130///131/// assert_eq!(bitset.len(), 3);132/// ```133#[inline]134pub fn len(&self) -> usize {135self.elems.iter().map(|sub| usize::from(sub.len())).sum()136}137138/// Get `n + 1` where `n` is the largest value that can be stored inside139/// this set without growing the backing storage.140///141/// That is, this set can store any value `x` such that `x <142/// bitset.capacity()` without growing the backing storage.143///144/// # Example145///146/// ```147/// use cranelift_bitset::CompoundBitSet;148///149/// let mut bitset = CompoundBitSet::new();150///151/// // New bitsets have zero capacity -- they allocate lazily.152/// assert_eq!(bitset.capacity(), 0);153///154/// // Insert into the bitset, growing its capacity.155/// bitset.insert(999);156///157/// // The bitset must now have capacity for at least `999` elements,158/// // perhaps more.159/// assert!(bitset.capacity() >= 999);160///```161pub fn capacity(&self) -> usize {162self.elems.len() * Self::BITS_PER_SCALAR163}164165/// Is this bitset empty?166///167/// # Example168///169/// ```170/// use cranelift_bitset::CompoundBitSet;171///172/// let mut bitset = CompoundBitSet::new();173///174/// assert!(bitset.is_empty());175///176/// bitset.insert(1234);177///178/// assert!(!bitset.is_empty());179/// ```180#[inline]181pub fn is_empty(&self) -> bool {182self.len() == 0183}184185/// Convert an element `i` into the `word` that can be used to index into186/// `self.elems` and the `bit` that can be tested in the187/// `ScalarBitSet<usize>` at `self.elems[word]`.188#[inline]189fn word_and_bit(i: usize) -> (usize, u8) {190let word = i / Self::BITS_PER_SCALAR;191let bit = i % Self::BITS_PER_SCALAR;192let bit = u8::try_from(bit).unwrap();193(word, bit)194}195196/// The opposite of `word_and_bit`: convert the pair of an index into197/// `self.elems` and associated bit index into a set element.198#[inline]199fn elem(word: usize, bit: u8) -> usize {200let bit = usize::from(bit);201debug_assert!(bit < Self::BITS_PER_SCALAR);202word * Self::BITS_PER_SCALAR + bit203}204205/// Is `i` contained in this bitset?206///207/// # Example208///209/// ```210/// use cranelift_bitset::CompoundBitSet;211///212/// let mut bitset = CompoundBitSet::new();213///214/// assert!(!bitset.contains(666));215///216/// bitset.insert(666);217///218/// assert!(bitset.contains(666));219/// ```220#[inline]221pub fn contains(&self, i: usize) -> bool {222let (word, bit) = Self::word_and_bit(i);223if word < self.elems.len() {224self.elems[word].contains(bit)225} else {226false227}228}229230/// Ensure there is space in this bitset for the values `0..n`, growing the231/// backing storage if necessary.232///233/// After calling `bitset.ensure_capacity(n)`, inserting any element `i`234/// where `i < n` is guaranteed to succeed without growing the bitset's235/// backing storage.236///237/// # Panics238///239/// Panics on allocation failure. Use240/// [`CompoundBitSet::try_ensure_capacity`] to handle allocation failure.241///242/// # Example243///244/// ```245/// # use cranelift_bitset::CompoundBitSet;246/// # let mut bitset = CompoundBitSet::new();247/// // We are going to do a series of inserts where `1000` will be the248/// // maximum value inserted. Make sure that our bitset has capacity for249/// // these elements once up front, to avoid growing the backing storage250/// // multiple times incrementally.251/// bitset.ensure_capacity(1001);252///253/// for i in 0..=1000 {254/// if i % 2 == 0 {255/// // Inserting this value should not require growing the backing256/// // storage.257/// assert!(bitset.capacity() > i);258/// bitset.insert(i);259/// }260/// }261/// ```262#[inline]263pub fn ensure_capacity(&mut self, n: usize) {264self.try_ensure_capacity(n).unwrap()265}266267/// Like [`CompoundBitSet::ensure_capacity`] but returns an error on268/// allocation failure.269#[inline]270pub fn try_ensure_capacity(&mut self, n: usize) -> Result<(), OutOfMemory> {271// Subtract one from the capacity to get the maximum bit that we might272// set. If `n` is 0 then nothing need be done as no capacity needs to be273// allocated.274let (word, _bit) = Self::word_and_bit(match n.checked_sub(1) {275None => return Ok(()),276Some(n) => n,277});278279if word < self.elems.len() {280// Already have capacity.281return Ok(());282}283284// Need to allocate additional capacity.285286assert!(word < usize::try_from(isize::MAX).unwrap());287288let delta = word - self.elems.len();289let to_grow = delta + 1;290291// Amortize the cost of growing by at least growing another292// `self.elems.len()`, so the new length is double the old length.293let to_grow = cmp::max(to_grow, self.elems.len());294// Don't make ridiculously small allocations.295let to_grow = cmp::max(to_grow, 4);296297let mut new_elems = Vec::from(mem::take(&mut self.elems));298new_elems.reserve_exact(to_grow)?;299new_elems.try_extend(iter::repeat(ScalarBitSet::new()).take(to_grow))?;300self.elems = new_elems.into_boxed_slice()?;301Ok(())302}303304/// Insert `i` into this bitset.305///306/// Returns whether the value was newly inserted. That is:307///308/// * If the set did not previously contain `i` then `true` is returned.309///310/// * If the set already contained `i` then `false` is returned.311///312/// # Example313///314/// ```315/// use cranelift_bitset::CompoundBitSet;316///317/// let mut bitset = CompoundBitSet::new();318///319/// // When an element is inserted that was not already present in the set,320/// // then `true` is returned.321/// let is_new = bitset.insert(1234);322/// assert!(is_new);323///324/// // The element is now present in the set.325/// assert!(bitset.contains(1234));326///327/// // And when the element is already in the set, `false` is returned from328/// // `insert`.329/// let is_new = bitset.insert(1234);330/// assert!(!is_new);331/// ```332#[inline]333pub fn insert(&mut self, i: usize) -> bool {334self.ensure_capacity(i + 1);335336let (word, bit) = Self::word_and_bit(i);337let is_new = self.elems[word].insert(bit);338339let i = u32::try_from(i).unwrap();340self.max = self.max.map(|max| cmp::max(max, i)).or(Some(i));341342is_new343}344345/// Remove `i` from this bitset.346///347/// Returns whether `i` was previously in this set or not.348///349/// # Example350///351/// ```352/// use cranelift_bitset::CompoundBitSet;353///354/// let mut bitset = CompoundBitSet::new();355///356/// // Removing an element that was not present in the set returns `false`.357/// let was_present = bitset.remove(456);358/// assert!(!was_present);359///360/// // And when the element was in the set, `true` is returned.361/// bitset.insert(456);362/// let was_present = bitset.remove(456);363/// assert!(was_present);364/// ```365#[inline]366pub fn remove(&mut self, i: usize) -> bool {367let (word, bit) = Self::word_and_bit(i);368if word < self.elems.len() {369let sub = &mut self.elems[word];370let was_present = sub.remove(bit);371if was_present && self.max() == Some(i) {372self.update_max(word);373}374was_present375} else {376false377}378}379380/// Update the `self.max` field, based on the old word index of `self.max`.381fn update_max(&mut self, word_of_old_max: usize) {382self.max = self.elems[0..word_of_old_max + 1]383.iter()384.enumerate()385.rev()386.filter_map(|(word, sub)| {387let bit = sub.max()?;388Some(u32::try_from(Self::elem(word, bit)).unwrap())389})390.next();391}392393/// Get the largest value in this set, or `None` if this set is empty.394///395/// # Example396///397/// ```398/// use cranelift_bitset::CompoundBitSet;399///400/// let mut bitset = CompoundBitSet::new();401///402/// // Returns `None` if the bitset is empty.403/// assert!(bitset.max().is_none());404///405/// bitset.insert(123);406/// bitset.insert(987);407/// bitset.insert(999);408///409/// // Otherwise, it returns the largest value in the set.410/// assert_eq!(bitset.max(), Some(999));411/// ```412#[inline]413pub fn max(&self) -> Option<usize> {414self.max.map(|m| usize::try_from(m).unwrap())415}416417/// Removes and returns the largest value in this set.418///419/// Returns `None` if this set is empty.420///421/// # Example422///423/// ```424/// use cranelift_bitset::CompoundBitSet;425///426/// let mut bitset = CompoundBitSet::new();427///428/// bitset.insert(111);429/// bitset.insert(222);430/// bitset.insert(333);431/// bitset.insert(444);432/// bitset.insert(555);433///434/// assert_eq!(bitset.pop(), Some(555));435/// assert_eq!(bitset.pop(), Some(444));436/// assert_eq!(bitset.pop(), Some(333));437/// assert_eq!(bitset.pop(), Some(222));438/// assert_eq!(bitset.pop(), Some(111));439/// assert_eq!(bitset.pop(), None);440/// ```441#[inline]442pub fn pop(&mut self) -> Option<usize> {443let max = self.max()?;444self.remove(max);445Some(max)446}447448/// Remove all elements from this bitset.449///450/// # Example451///452/// ```453/// use cranelift_bitset::CompoundBitSet;454///455/// let mut bitset = CompoundBitSet::new();456///457/// bitset.insert(100);458/// bitset.insert(200);459/// bitset.insert(300);460///461/// bitset.clear();462///463/// assert!(bitset.is_empty());464/// ```465#[inline]466pub fn clear(&mut self) {467let max = match self.max() {468Some(max) => max,469None => return,470};471let (word, _bit) = Self::word_and_bit(max);472debug_assert!(self.elems[word + 1..].iter().all(|sub| sub.is_empty()));473for sub in &mut self.elems[..=word] {474*sub = ScalarBitSet::new();475}476self.max = None;477}478479/// Iterate over the elements in this bitset.480///481/// The elements are always yielded in sorted order.482///483/// # Example484///485/// ```486/// use cranelift_bitset::CompoundBitSet;487///488/// let mut bitset = CompoundBitSet::new();489///490/// bitset.insert(0);491/// bitset.insert(4096);492/// bitset.insert(123);493/// bitset.insert(456);494/// bitset.insert(789);495///496/// assert_eq!(497/// bitset.iter().collect::<Vec<_>>(),498/// [0, 123, 456, 789, 4096],499/// );500/// ```501#[inline]502pub fn iter(&self) -> Iter<'_, T> {503Iter {504bitset: self,505word: 0,506sub: None,507}508}509510/// Returns an iterator over the words of this bit-set or the in-memory511/// representation of the bit set.512///513/// # Example514///515/// ```516/// use cranelift_bitset::{CompoundBitSet, ScalarBitSet};517///518/// let mut bitset = CompoundBitSet::<u32>::default();519///520/// assert_eq!(521/// bitset.iter_scalars().collect::<Vec<_>>(),522/// [],523/// );524///525/// bitset.insert(0);526///527/// assert_eq!(528/// bitset.iter_scalars().collect::<Vec<_>>(),529/// [ScalarBitSet(0x1)],530/// );531///532/// bitset.insert(1);533///534/// assert_eq!(535/// bitset.iter_scalars().collect::<Vec<_>>(),536/// [ScalarBitSet(0x3)],537/// );538///539/// bitset.insert(32);540///541/// assert_eq!(542/// bitset.iter_scalars().collect::<Vec<_>>(),543/// [ScalarBitSet(0x3), ScalarBitSet(0x1)],544/// );545/// ```546pub fn iter_scalars(&self) -> impl Iterator<Item = ScalarBitSet<T>> + '_ {547let nwords = match self.max {548Some(n) => 1 + (n as usize / Self::BITS_PER_SCALAR),549None => 0,550};551self.elems.iter().copied().take(nwords)552}553}554555impl<'a, T: ScalarBitSetStorage> IntoIterator for &'a CompoundBitSet<T> {556type Item = usize;557558type IntoIter = Iter<'a, T>;559560#[inline]561fn into_iter(self) -> Self::IntoIter {562self.iter()563}564}565566/// An iterator over the elements in a [`CompoundBitSet`].567pub struct Iter<'a, T = usize> {568bitset: &'a CompoundBitSet<T>,569word: usize,570sub: Option<scalar::Iter<T>>,571}572573impl<T: ScalarBitSetStorage> Iterator for Iter<'_, T> {574type Item = usize;575576#[inline]577fn next(&mut self) -> Option<usize> {578loop {579if let Some(sub) = &mut self.sub {580if let Some(bit) = sub.next() {581return Some(CompoundBitSet::<T>::elem(self.word, bit));582} else {583self.word += 1;584}585}586587self.sub = Some(self.bitset.elems.get(self.word)?.iter());588}589}590}591592#[cfg(test)]593mod tests {594use super::*;595596#[test]597fn zero_capacity_no_allocs() {598let set = CompoundBitSet::<u32>::with_capacity(0);599assert_eq!(set.capacity(), 0);600let set = CompoundBitSet::new();601assert_eq!(set.capacity(), 0);602}603}604605606