| //! 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()); |
| } |
| } |
| } |