Path: blob/main/cranelift/bitset/src/compound.rs
1692 views
//! Compound bit sets.12use crate::scalar::{self, ScalarBitSet, ScalarBitSetStorage};3use alloc::boxed::Box;4use core::{cmp, iter, mem};56/// A large bit set backed by dynamically-sized storage.7///8/// # Example9///10/// ```11/// use cranelift_bitset::CompoundBitSet;12///13/// // Create a new bitset.14/// let mut bitset = CompoundBitSet::new();15///16/// // Bitsets are initially empty.17/// assert!(bitset.is_empty());18/// assert_eq!(bitset.len(), 0);19///20/// // Insert into the bitset.21/// bitset.insert(444);22/// bitset.insert(555);23/// bitset.insert(666);24///25/// // Now the bitset is not empty.26/// assert_eq!(bitset.len(), 3);27/// assert!(!bitset.is_empty());28/// assert!(bitset.contains(444));29/// assert!(bitset.contains(555));30/// assert!(bitset.contains(666));31///32/// // Remove an element from the bitset.33/// let was_present = bitset.remove(666);34/// assert!(was_present);35/// assert!(!bitset.contains(666));36/// assert_eq!(bitset.len(), 2);37///38/// // Can iterate over the elements in the set.39/// let elems: Vec<_> = bitset.iter().collect();40/// assert_eq!(elems, [444, 555]);41/// ```42#[derive(Clone, Default, PartialEq, Eq)]43#[cfg_attr(44feature = "enable-serde",45derive(serde_derive::Serialize, serde_derive::Deserialize)46)]47pub struct CompoundBitSet<T = usize> {48elems: Box<[ScalarBitSet<T>]>,49max: Option<u32>,50}5152impl core::fmt::Debug for CompoundBitSet {53fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {54write!(f, "CompoundBitSet ")?;55f.debug_set().entries(self.iter()).finish()56}57}5859impl CompoundBitSet {60/// Construct a new, empty bit set.61///62/// # Example63///64/// ```65/// use cranelift_bitset::CompoundBitSet;66///67/// let bitset = CompoundBitSet::new();68///69/// assert!(bitset.is_empty());70/// ```71#[inline]72pub fn new() -> Self {73CompoundBitSet::default()74}75}7677impl<T: ScalarBitSetStorage> CompoundBitSet<T> {78const BITS_PER_SCALAR: usize = mem::size_of::<T>() * 8;7980/// Construct a new, empty bit set with space reserved to store any element81/// `x` such that `x < capacity`.82///83/// The actual capacity reserved may be greater than that requested.84///85/// # Example86///87/// ```88/// use cranelift_bitset::CompoundBitSet;89///90/// let bitset = CompoundBitSet::<u32>::with_capacity(4096);91///92/// assert!(bitset.is_empty());93/// assert!(bitset.capacity() >= 4096);94/// ```95#[inline]96pub fn with_capacity(capacity: usize) -> Self {97let mut bitset = Self::default();98bitset.ensure_capacity(capacity);99bitset100}101102/// Get the number of elements in this bitset.103///104/// # Example105///106/// ```107/// use cranelift_bitset::CompoundBitSet;108///109/// let mut bitset = CompoundBitSet::new();110///111/// assert_eq!(bitset.len(), 0);112///113/// bitset.insert(24);114/// bitset.insert(130);115/// bitset.insert(3600);116///117/// assert_eq!(bitset.len(), 3);118/// ```119#[inline]120pub fn len(&self) -> usize {121self.elems.iter().map(|sub| usize::from(sub.len())).sum()122}123124/// Get `n + 1` where `n` is the largest value that can be stored inside125/// this set without growing the backing storage.126///127/// That is, this set can store any value `x` such that `x <128/// bitset.capacity()` without growing the backing storage.129///130/// # Example131///132/// ```133/// use cranelift_bitset::CompoundBitSet;134///135/// let mut bitset = CompoundBitSet::new();136///137/// // New bitsets have zero capacity -- they allocate lazily.138/// assert_eq!(bitset.capacity(), 0);139///140/// // Insert into the bitset, growing its capacity.141/// bitset.insert(999);142///143/// // The bitset must now have capacity for at least `999` elements,144/// // perhaps more.145/// assert!(bitset.capacity() >= 999);146///```147pub fn capacity(&self) -> usize {148self.elems.len() * Self::BITS_PER_SCALAR149}150151/// Is this bitset empty?152///153/// # Example154///155/// ```156/// use cranelift_bitset::CompoundBitSet;157///158/// let mut bitset = CompoundBitSet::new();159///160/// assert!(bitset.is_empty());161///162/// bitset.insert(1234);163///164/// assert!(!bitset.is_empty());165/// ```166#[inline]167pub fn is_empty(&self) -> bool {168self.len() == 0169}170171/// Convert an element `i` into the `word` that can be used to index into172/// `self.elems` and the `bit` that can be tested in the173/// `ScalarBitSet<usize>` at `self.elems[word]`.174#[inline]175fn word_and_bit(i: usize) -> (usize, u8) {176let word = i / Self::BITS_PER_SCALAR;177let bit = i % Self::BITS_PER_SCALAR;178let bit = u8::try_from(bit).unwrap();179(word, bit)180}181182/// The opposite of `word_and_bit`: convert the pair of an index into183/// `self.elems` and associated bit index into a set element.184#[inline]185fn elem(word: usize, bit: u8) -> usize {186let bit = usize::from(bit);187debug_assert!(bit < Self::BITS_PER_SCALAR);188word * Self::BITS_PER_SCALAR + bit189}190191/// Is `i` contained in this bitset?192///193/// # Example194///195/// ```196/// use cranelift_bitset::CompoundBitSet;197///198/// let mut bitset = CompoundBitSet::new();199///200/// assert!(!bitset.contains(666));201///202/// bitset.insert(666);203///204/// assert!(bitset.contains(666));205/// ```206#[inline]207pub fn contains(&self, i: usize) -> bool {208let (word, bit) = Self::word_and_bit(i);209if word < self.elems.len() {210self.elems[word].contains(bit)211} else {212false213}214}215216/// Ensure there is space in this bitset for the values `0..n`, growing the217/// backing storage if necessary.218///219/// After calling `bitset.ensure_capacity(n)`, inserting any element `i`220/// where `i < n` is guaranteed to succeed without growing the bitset's221/// backing storage.222///223/// # Example224///225/// ```226/// # use cranelift_bitset::CompoundBitSet;227/// # let mut bitset = CompoundBitSet::new();228/// // We are going to do a series of inserts where `1000` will be the229/// // maximum value inserted. Make sure that our bitset has capacity for230/// // these elements once up front, to avoid growing the backing storage231/// // multiple times incrementally.232/// bitset.ensure_capacity(1001);233///234/// for i in 0..=1000 {235/// if i % 2 == 0 {236/// // Inserting this value should not require growing the backing237/// // storage.238/// assert!(bitset.capacity() > i);239/// bitset.insert(i);240/// }241/// }242/// ```243#[inline]244pub fn ensure_capacity(&mut self, n: usize) {245// Subtract one from the capacity to get the maximum bit that we might246// set. If `n` is 0 then nothing need be done as no capacity needs to be247// allocated.248let (word, _bit) = Self::word_and_bit(match n.checked_sub(1) {249None => return,250Some(n) => n,251});252if word >= self.elems.len() {253assert!(word < usize::try_from(isize::MAX).unwrap());254255let delta = word - self.elems.len();256let to_grow = delta + 1;257258// Amortize the cost of growing.259let to_grow = cmp::max(to_grow, self.elems.len() * 2);260// Don't make ridiculously small allocations.261let to_grow = cmp::max(to_grow, 4);262263let new_elems = self264.elems265.iter()266.copied()267.chain(iter::repeat(ScalarBitSet::new()).take(to_grow))268.collect::<Box<[_]>>();269self.elems = new_elems;270}271}272273/// Insert `i` into this bitset.274///275/// Returns whether the value was newly inserted. That is:276///277/// * If the set did not previously contain `i` then `true` is returned.278///279/// * If the set already contained `i` then `false` is returned.280///281/// # Example282///283/// ```284/// use cranelift_bitset::CompoundBitSet;285///286/// let mut bitset = CompoundBitSet::new();287///288/// // When an element is inserted that was not already present in the set,289/// // then `true` is returned.290/// let is_new = bitset.insert(1234);291/// assert!(is_new);292///293/// // The element is now present in the set.294/// assert!(bitset.contains(1234));295///296/// // And when the element is already in the set, `false` is returned from297/// // `insert`.298/// let is_new = bitset.insert(1234);299/// assert!(!is_new);300/// ```301#[inline]302pub fn insert(&mut self, i: usize) -> bool {303self.ensure_capacity(i + 1);304305let (word, bit) = Self::word_and_bit(i);306let is_new = self.elems[word].insert(bit);307308let i = u32::try_from(i).unwrap();309self.max = self.max.map(|max| cmp::max(max, i)).or(Some(i));310311is_new312}313314/// Remove `i` from this bitset.315///316/// Returns whether `i` was previously in this set or not.317///318/// # Example319///320/// ```321/// use cranelift_bitset::CompoundBitSet;322///323/// let mut bitset = CompoundBitSet::new();324///325/// // Removing an element that was not present in the set returns `false`.326/// let was_present = bitset.remove(456);327/// assert!(!was_present);328///329/// // And when the element was in the set, `true` is returned.330/// bitset.insert(456);331/// let was_present = bitset.remove(456);332/// assert!(was_present);333/// ```334#[inline]335pub fn remove(&mut self, i: usize) -> bool {336let (word, bit) = Self::word_and_bit(i);337if word < self.elems.len() {338let sub = &mut self.elems[word];339let was_present = sub.remove(bit);340if was_present && self.max() == Some(i) {341self.update_max(word);342}343was_present344} else {345false346}347}348349/// Update the `self.max` field, based on the old word index of `self.max`.350fn update_max(&mut self, word_of_old_max: usize) {351self.max = self.elems[0..word_of_old_max + 1]352.iter()353.enumerate()354.rev()355.filter_map(|(word, sub)| {356let bit = sub.max()?;357Some(u32::try_from(Self::elem(word, bit)).unwrap())358})359.next();360}361362/// Get the largest value in this set, or `None` if this set is empty.363///364/// # Example365///366/// ```367/// use cranelift_bitset::CompoundBitSet;368///369/// let mut bitset = CompoundBitSet::new();370///371/// // Returns `None` if the bitset is empty.372/// assert!(bitset.max().is_none());373///374/// bitset.insert(123);375/// bitset.insert(987);376/// bitset.insert(999);377///378/// // Otherwise, it returns the largest value in the set.379/// assert_eq!(bitset.max(), Some(999));380/// ```381#[inline]382pub fn max(&self) -> Option<usize> {383self.max.map(|m| usize::try_from(m).unwrap())384}385386/// Removes and returns the largest value in this set.387///388/// Returns `None` if this set is empty.389///390/// # Example391///392/// ```393/// use cranelift_bitset::CompoundBitSet;394///395/// let mut bitset = CompoundBitSet::new();396///397/// bitset.insert(111);398/// bitset.insert(222);399/// bitset.insert(333);400/// bitset.insert(444);401/// bitset.insert(555);402///403/// assert_eq!(bitset.pop(), Some(555));404/// assert_eq!(bitset.pop(), Some(444));405/// assert_eq!(bitset.pop(), Some(333));406/// assert_eq!(bitset.pop(), Some(222));407/// assert_eq!(bitset.pop(), Some(111));408/// assert_eq!(bitset.pop(), None);409/// ```410#[inline]411pub fn pop(&mut self) -> Option<usize> {412let max = self.max()?;413self.remove(max);414Some(max)415}416417/// Remove all elements from this bitset.418///419/// # Example420///421/// ```422/// use cranelift_bitset::CompoundBitSet;423///424/// let mut bitset = CompoundBitSet::new();425///426/// bitset.insert(100);427/// bitset.insert(200);428/// bitset.insert(300);429///430/// bitset.clear();431///432/// assert!(bitset.is_empty());433/// ```434#[inline]435pub fn clear(&mut self) {436let max = match self.max() {437Some(max) => max,438None => return,439};440let (word, _bit) = Self::word_and_bit(max);441debug_assert!(self.elems[word + 1..].iter().all(|sub| sub.is_empty()));442for sub in &mut self.elems[..=word] {443*sub = ScalarBitSet::new();444}445self.max = None;446}447448/// Iterate over the elements in this bitset.449///450/// The elements are always yielded in sorted order.451///452/// # Example453///454/// ```455/// use cranelift_bitset::CompoundBitSet;456///457/// let mut bitset = CompoundBitSet::new();458///459/// bitset.insert(0);460/// bitset.insert(4096);461/// bitset.insert(123);462/// bitset.insert(456);463/// bitset.insert(789);464///465/// assert_eq!(466/// bitset.iter().collect::<Vec<_>>(),467/// [0, 123, 456, 789, 4096],468/// );469/// ```470#[inline]471pub fn iter(&self) -> Iter<'_, T> {472Iter {473bitset: self,474word: 0,475sub: None,476}477}478479/// Returns an iterator over the words of this bit-set or the in-memory480/// representation of the bit set.481///482/// # Example483///484/// ```485/// use cranelift_bitset::{CompoundBitSet, ScalarBitSet};486///487/// let mut bitset = CompoundBitSet::<u32>::default();488///489/// assert_eq!(490/// bitset.iter_scalars().collect::<Vec<_>>(),491/// [],492/// );493///494/// bitset.insert(0);495///496/// assert_eq!(497/// bitset.iter_scalars().collect::<Vec<_>>(),498/// [ScalarBitSet(0x1)],499/// );500///501/// bitset.insert(1);502///503/// assert_eq!(504/// bitset.iter_scalars().collect::<Vec<_>>(),505/// [ScalarBitSet(0x3)],506/// );507///508/// bitset.insert(32);509///510/// assert_eq!(511/// bitset.iter_scalars().collect::<Vec<_>>(),512/// [ScalarBitSet(0x3), ScalarBitSet(0x1)],513/// );514/// ```515pub fn iter_scalars(&self) -> impl Iterator<Item = ScalarBitSet<T>> + '_ {516let nwords = match self.max {517Some(n) => 1 + (n as usize / Self::BITS_PER_SCALAR),518None => 0,519};520self.elems.iter().copied().take(nwords)521}522}523524impl<'a, T: ScalarBitSetStorage> IntoIterator for &'a CompoundBitSet<T> {525type Item = usize;526527type IntoIter = Iter<'a, T>;528529#[inline]530fn into_iter(self) -> Self::IntoIter {531self.iter()532}533}534535/// An iterator over the elements in a [`CompoundBitSet`].536pub struct Iter<'a, T = usize> {537bitset: &'a CompoundBitSet<T>,538word: usize,539sub: Option<scalar::Iter<T>>,540}541542impl<T: ScalarBitSetStorage> Iterator for Iter<'_, T> {543type Item = usize;544545#[inline]546fn next(&mut self) -> Option<usize> {547loop {548if let Some(sub) = &mut self.sub {549if let Some(bit) = sub.next() {550return Some(CompoundBitSet::<T>::elem(self.word, bit));551} else {552self.word += 1;553}554}555556self.sub = Some(self.bitset.elems.get(self.word)?.iter());557}558}559}560561#[cfg(test)]562mod tests {563use super::*;564565#[test]566fn zero_capacity_no_allocs() {567let set = CompoundBitSet::<u32>::with_capacity(0);568assert_eq!(set.capacity(), 0);569let set = CompoundBitSet::new();570assert_eq!(set.capacity(), 0);571}572}573574575