Skip to main content

cranelift_bitset/
compound.rs

1//! Compound bit sets.
2
3use crate::scalar::{self, ScalarBitSet, ScalarBitSetStorage};
4use alloc::boxed::Box;
5use core::{cmp, iter, mem};
6use wasmtime_core::alloc::{TryExtend, Vec};
7use wasmtime_core::error::OutOfMemory;
8
9/// A large bit set backed by dynamically-sized storage.
10///
11/// # Example
12///
13/// ```
14/// use cranelift_bitset::CompoundBitSet;
15///
16/// // Create a new bitset.
17/// let mut bitset = CompoundBitSet::new();
18///
19/// // Bitsets are initially empty.
20/// assert!(bitset.is_empty());
21/// assert_eq!(bitset.len(), 0);
22///
23/// // Insert into the bitset.
24/// bitset.insert(444);
25/// bitset.insert(555);
26/// bitset.insert(666);
27///
28/// // Now the bitset is not empty.
29/// assert_eq!(bitset.len(), 3);
30/// assert!(!bitset.is_empty());
31/// assert!(bitset.contains(444));
32/// assert!(bitset.contains(555));
33/// assert!(bitset.contains(666));
34///
35/// // Remove an element from the bitset.
36/// let was_present = bitset.remove(666);
37/// assert!(was_present);
38/// assert!(!bitset.contains(666));
39/// assert_eq!(bitset.len(), 2);
40///
41/// // Can iterate over the elements in the set.
42/// let elems: Vec<_> = bitset.iter().collect();
43/// assert_eq!(elems, [444, 555]);
44/// ```
45#[derive(Clone, Default, PartialEq, Eq)]
46#[cfg_attr(
47    feature = "enable-serde",
48    derive(serde_derive::Serialize, serde_derive::Deserialize)
49)]
50pub struct CompoundBitSet<T = usize> {
51    elems: Box<[ScalarBitSet<T>]>,
52    max: Option<u32>,
53}
54
55impl core::fmt::Debug for CompoundBitSet {
56    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57        write!(f, "CompoundBitSet ")?;
58        f.debug_set().entries(self.iter()).finish()
59    }
60}
61
62impl CompoundBitSet {
63    /// Construct a new, empty bit set.
64    ///
65    /// # Example
66    ///
67    /// ```
68    /// use cranelift_bitset::CompoundBitSet;
69    ///
70    /// let bitset = CompoundBitSet::new();
71    ///
72    /// assert!(bitset.is_empty());
73    /// ```
74    #[inline]
75    pub fn new() -> Self {
76        CompoundBitSet::default()
77    }
78}
79
80impl<T: ScalarBitSetStorage> CompoundBitSet<T> {
81    const BITS_PER_SCALAR: usize = mem::size_of::<T>() * 8;
82
83    /// Construct a new, empty bit set with space reserved to store any element
84    /// `x` such that `x < capacity`.
85    ///
86    /// The actual capacity reserved may be greater than that requested.
87    ///
88    /// # Panics
89    ///
90    /// Panics on allocation failure. Use [`CompoundBitSet::try_with_capacity`]
91    /// to handle allocation failure.
92    ///
93    /// # Example
94    ///
95    /// ```
96    /// use cranelift_bitset::CompoundBitSet;
97    ///
98    /// let bitset = CompoundBitSet::<u32>::with_capacity(4096);
99    ///
100    /// assert!(bitset.is_empty());
101    /// assert!(bitset.capacity() >= 4096);
102    /// ```
103    #[inline]
104    pub fn with_capacity(capacity: usize) -> Self {
105        Self::try_with_capacity(capacity).unwrap()
106    }
107
108    /// Like [`CompoundBitSet::with_capacity`] but returns an error on
109    /// allocation failure.
110    #[inline]
111    pub fn try_with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {
112        let mut bitset = Self::default();
113        bitset.try_ensure_capacity(capacity)?;
114        Ok(bitset)
115    }
116
117    /// Get the number of elements in this bitset.
118    ///
119    /// # Example
120    ///
121    /// ```
122    /// use cranelift_bitset::CompoundBitSet;
123    ///
124    /// let mut bitset = CompoundBitSet::new();
125    ///
126    /// assert_eq!(bitset.len(), 0);
127    ///
128    /// bitset.insert(24);
129    /// bitset.insert(130);
130    /// bitset.insert(3600);
131    ///
132    /// assert_eq!(bitset.len(), 3);
133    /// ```
134    #[inline]
135    pub fn len(&self) -> usize {
136        self.elems.iter().map(|sub| usize::from(sub.len())).sum()
137    }
138
139    /// Get `n + 1` where `n` is the largest value that can be stored inside
140    /// this set without growing the backing storage.
141    ///
142    /// That is, this set can store any value `x` such that `x <
143    /// bitset.capacity()` without growing the backing storage.
144    ///
145    /// # Example
146    ///
147    /// ```
148    /// use cranelift_bitset::CompoundBitSet;
149    ///
150    /// let mut bitset = CompoundBitSet::new();
151    ///
152    /// // New bitsets have zero capacity -- they allocate lazily.
153    /// assert_eq!(bitset.capacity(), 0);
154    ///
155    /// // Insert into the bitset, growing its capacity.
156    /// bitset.insert(999);
157    ///
158    /// // The bitset must now have capacity for at least `999` elements,
159    /// // perhaps more.
160    /// assert!(bitset.capacity() >= 999);
161    ///```
162    pub fn capacity(&self) -> usize {
163        self.elems.len() * Self::BITS_PER_SCALAR
164    }
165
166    /// Is this bitset empty?
167    ///
168    /// # Example
169    ///
170    /// ```
171    /// use cranelift_bitset::CompoundBitSet;
172    ///
173    /// let mut bitset = CompoundBitSet::new();
174    ///
175    /// assert!(bitset.is_empty());
176    ///
177    /// bitset.insert(1234);
178    ///
179    /// assert!(!bitset.is_empty());
180    /// ```
181    #[inline]
182    pub fn is_empty(&self) -> bool {
183        self.len() == 0
184    }
185
186    /// Convert an element `i` into the `word` that can be used to index into
187    /// `self.elems` and the `bit` that can be tested in the
188    /// `ScalarBitSet<usize>` at `self.elems[word]`.
189    #[inline]
190    fn word_and_bit(i: usize) -> (usize, u8) {
191        let word = i / Self::BITS_PER_SCALAR;
192        let bit = i % Self::BITS_PER_SCALAR;
193        let bit = u8::try_from(bit).unwrap();
194        (word, bit)
195    }
196
197    /// The opposite of `word_and_bit`: convert the pair of an index into
198    /// `self.elems` and associated bit index into a set element.
199    #[inline]
200    fn elem(word: usize, bit: u8) -> usize {
201        let bit = usize::from(bit);
202        debug_assert!(bit < Self::BITS_PER_SCALAR);
203        word * Self::BITS_PER_SCALAR + bit
204    }
205
206    /// Is `i` contained in this bitset?
207    ///
208    /// # Example
209    ///
210    /// ```
211    /// use cranelift_bitset::CompoundBitSet;
212    ///
213    /// let mut bitset = CompoundBitSet::new();
214    ///
215    /// assert!(!bitset.contains(666));
216    ///
217    /// bitset.insert(666);
218    ///
219    /// assert!(bitset.contains(666));
220    /// ```
221    #[inline]
222    pub fn contains(&self, i: usize) -> bool {
223        let (word, bit) = Self::word_and_bit(i);
224        if word < self.elems.len() {
225            self.elems[word].contains(bit)
226        } else {
227            false
228        }
229    }
230
231    /// Ensure there is space in this bitset for the values `0..n`, growing the
232    /// backing storage if necessary.
233    ///
234    /// After calling `bitset.ensure_capacity(n)`, inserting any element `i`
235    /// where `i < n` is guaranteed to succeed without growing the bitset's
236    /// backing storage.
237    ///
238    /// # Panics
239    ///
240    /// Panics on allocation failure. Use
241    /// [`CompoundBitSet::try_ensure_capacity`] to handle allocation failure.
242    ///
243    /// # Example
244    ///
245    /// ```
246    /// # use cranelift_bitset::CompoundBitSet;
247    /// # let mut bitset = CompoundBitSet::new();
248    /// // We are going to do a series of inserts where `1000` will be the
249    /// // maximum value inserted. Make sure that our bitset has capacity for
250    /// // these elements once up front, to avoid growing the backing storage
251    /// // multiple times incrementally.
252    /// bitset.ensure_capacity(1001);
253    ///
254    /// for i in 0..=1000 {
255    ///     if i % 2 == 0 {
256    ///         // Inserting this value should not require growing the backing
257    ///         // storage.
258    ///         assert!(bitset.capacity() > i);
259    ///         bitset.insert(i);
260    ///     }
261    /// }
262    /// ```
263    #[inline]
264    pub fn ensure_capacity(&mut self, n: usize) {
265        self.try_ensure_capacity(n).unwrap()
266    }
267
268    /// Like [`CompoundBitSet::ensure_capacity`] but returns an error on
269    /// allocation failure.
270    #[inline]
271    pub fn try_ensure_capacity(&mut self, n: usize) -> Result<(), OutOfMemory> {
272        // Subtract one from the capacity to get the maximum bit that we might
273        // set. If `n` is 0 then nothing need be done as no capacity needs to be
274        // allocated.
275        let (word, _bit) = Self::word_and_bit(match n.checked_sub(1) {
276            None => return Ok(()),
277            Some(n) => n,
278        });
279
280        if word < self.elems.len() {
281            // Already have capacity.
282            return Ok(());
283        }
284
285        // Need to allocate additional capacity.
286
287        assert!(word < usize::try_from(isize::MAX).unwrap());
288
289        let delta = word - self.elems.len();
290        let to_grow = delta + 1;
291
292        // Amortize the cost of growing by at least growing another
293        // `self.elems.len()`, so the new length is double the old length.
294        let to_grow = cmp::max(to_grow, self.elems.len());
295        // Don't make ridiculously small allocations.
296        let to_grow = cmp::max(to_grow, 4);
297
298        let mut new_elems = Vec::from(mem::take(&mut self.elems));
299        new_elems.reserve_exact(to_grow)?;
300        new_elems.try_extend(iter::repeat(ScalarBitSet::new()).take(to_grow))?;
301        self.elems = new_elems.into_boxed_slice()?;
302        Ok(())
303    }
304
305    /// Insert `i` into this bitset.
306    ///
307    /// Returns whether the value was newly inserted. That is:
308    ///
309    /// * If the set did not previously contain `i` then `true` is returned.
310    ///
311    /// * If the set already contained `i` then `false` is returned.
312    ///
313    /// # Example
314    ///
315    /// ```
316    /// use cranelift_bitset::CompoundBitSet;
317    ///
318    /// let mut bitset = CompoundBitSet::new();
319    ///
320    /// // When an element is inserted that was not already present in the set,
321    /// // then `true` is returned.
322    /// let is_new = bitset.insert(1234);
323    /// assert!(is_new);
324    ///
325    /// // The element is now present in the set.
326    /// assert!(bitset.contains(1234));
327    ///
328    /// // And when the element is already in the set, `false` is returned from
329    /// // `insert`.
330    /// let is_new = bitset.insert(1234);
331    /// assert!(!is_new);
332    /// ```
333    #[inline]
334    pub fn insert(&mut self, i: usize) -> bool {
335        self.ensure_capacity(i + 1);
336
337        let (word, bit) = Self::word_and_bit(i);
338        let is_new = self.elems[word].insert(bit);
339
340        let i = u32::try_from(i).unwrap();
341        self.max = self.max.map(|max| cmp::max(max, i)).or(Some(i));
342
343        is_new
344    }
345
346    /// Remove `i` from this bitset.
347    ///
348    /// Returns whether `i` was previously in this set or not.
349    ///
350    /// # Example
351    ///
352    /// ```
353    /// use cranelift_bitset::CompoundBitSet;
354    ///
355    /// let mut bitset = CompoundBitSet::new();
356    ///
357    /// // Removing an element that was not present in the set returns `false`.
358    /// let was_present = bitset.remove(456);
359    /// assert!(!was_present);
360    ///
361    /// // And when the element was in the set, `true` is returned.
362    /// bitset.insert(456);
363    /// let was_present = bitset.remove(456);
364    /// assert!(was_present);
365    /// ```
366    #[inline]
367    pub fn remove(&mut self, i: usize) -> bool {
368        let (word, bit) = Self::word_and_bit(i);
369        if word < self.elems.len() {
370            let sub = &mut self.elems[word];
371            let was_present = sub.remove(bit);
372            if was_present && self.max() == Some(i) {
373                self.update_max(word);
374            }
375            was_present
376        } else {
377            false
378        }
379    }
380
381    /// Update the `self.max` field, based on the old word index of `self.max`.
382    fn update_max(&mut self, word_of_old_max: usize) {
383        self.max = self.elems[0..word_of_old_max + 1]
384            .iter()
385            .enumerate()
386            .rev()
387            .filter_map(|(word, sub)| {
388                let bit = sub.max()?;
389                Some(u32::try_from(Self::elem(word, bit)).unwrap())
390            })
391            .next();
392    }
393
394    /// Get the largest value in this set, or `None` if this set is empty.
395    ///
396    /// # Example
397    ///
398    /// ```
399    /// use cranelift_bitset::CompoundBitSet;
400    ///
401    /// let mut bitset = CompoundBitSet::new();
402    ///
403    /// // Returns `None` if the bitset is empty.
404    /// assert!(bitset.max().is_none());
405    ///
406    /// bitset.insert(123);
407    /// bitset.insert(987);
408    /// bitset.insert(999);
409    ///
410    /// // Otherwise, it returns the largest value in the set.
411    /// assert_eq!(bitset.max(), Some(999));
412    /// ```
413    #[inline]
414    pub fn max(&self) -> Option<usize> {
415        self.max.map(|m| usize::try_from(m).unwrap())
416    }
417
418    /// Removes and returns the largest value in this set.
419    ///
420    /// Returns `None` if this set is empty.
421    ///
422    /// # Example
423    ///
424    /// ```
425    /// use cranelift_bitset::CompoundBitSet;
426    ///
427    /// let mut bitset = CompoundBitSet::new();
428    ///
429    /// bitset.insert(111);
430    /// bitset.insert(222);
431    /// bitset.insert(333);
432    /// bitset.insert(444);
433    /// bitset.insert(555);
434    ///
435    /// assert_eq!(bitset.pop(), Some(555));
436    /// assert_eq!(bitset.pop(), Some(444));
437    /// assert_eq!(bitset.pop(), Some(333));
438    /// assert_eq!(bitset.pop(), Some(222));
439    /// assert_eq!(bitset.pop(), Some(111));
440    /// assert_eq!(bitset.pop(), None);
441    /// ```
442    #[inline]
443    pub fn pop(&mut self) -> Option<usize> {
444        let max = self.max()?;
445        self.remove(max);
446        Some(max)
447    }
448
449    /// Remove all elements from this bitset.
450    ///
451    /// # Example
452    ///
453    /// ```
454    /// use cranelift_bitset::CompoundBitSet;
455    ///
456    /// let mut bitset = CompoundBitSet::new();
457    ///
458    /// bitset.insert(100);
459    /// bitset.insert(200);
460    /// bitset.insert(300);
461    ///
462    /// bitset.clear();
463    ///
464    /// assert!(bitset.is_empty());
465    /// ```
466    #[inline]
467    pub fn clear(&mut self) {
468        let max = match self.max() {
469            Some(max) => max,
470            None => return,
471        };
472        let (word, _bit) = Self::word_and_bit(max);
473        debug_assert!(self.elems[word + 1..].iter().all(|sub| sub.is_empty()));
474        for sub in &mut self.elems[..=word] {
475            *sub = ScalarBitSet::new();
476        }
477        self.max = None;
478    }
479
480    /// Iterate over the elements in this bitset.
481    ///
482    /// The elements are always yielded in sorted order.
483    ///
484    /// # Example
485    ///
486    /// ```
487    /// use cranelift_bitset::CompoundBitSet;
488    ///
489    /// let mut bitset = CompoundBitSet::new();
490    ///
491    /// bitset.insert(0);
492    /// bitset.insert(4096);
493    /// bitset.insert(123);
494    /// bitset.insert(456);
495    /// bitset.insert(789);
496    ///
497    /// assert_eq!(
498    ///     bitset.iter().collect::<Vec<_>>(),
499    ///     [0, 123, 456, 789, 4096],
500    /// );
501    /// ```
502    #[inline]
503    pub fn iter(&self) -> Iter<'_, T> {
504        Iter {
505            bitset: self,
506            word: 0,
507            sub: None,
508        }
509    }
510
511    /// Returns an iterator over the words of this bit-set or the in-memory
512    /// representation of the bit set.
513    ///
514    /// # Example
515    ///
516    /// ```
517    /// use cranelift_bitset::{CompoundBitSet, ScalarBitSet};
518    ///
519    /// let mut bitset = CompoundBitSet::<u32>::default();
520    ///
521    /// assert_eq!(
522    ///     bitset.iter_scalars().collect::<Vec<_>>(),
523    ///     [],
524    /// );
525    ///
526    /// bitset.insert(0);
527    ///
528    /// assert_eq!(
529    ///     bitset.iter_scalars().collect::<Vec<_>>(),
530    ///     [ScalarBitSet(0x1)],
531    /// );
532    ///
533    /// bitset.insert(1);
534    ///
535    /// assert_eq!(
536    ///     bitset.iter_scalars().collect::<Vec<_>>(),
537    ///     [ScalarBitSet(0x3)],
538    /// );
539    ///
540    /// bitset.insert(32);
541    ///
542    /// assert_eq!(
543    ///     bitset.iter_scalars().collect::<Vec<_>>(),
544    ///     [ScalarBitSet(0x3), ScalarBitSet(0x1)],
545    /// );
546    /// ```
547    pub fn iter_scalars(&self) -> impl Iterator<Item = ScalarBitSet<T>> + '_ {
548        let nwords = match self.max {
549            Some(n) => 1 + (n as usize / Self::BITS_PER_SCALAR),
550            None => 0,
551        };
552        self.elems.iter().copied().take(nwords)
553    }
554}
555
556impl<'a, T: ScalarBitSetStorage> IntoIterator for &'a CompoundBitSet<T> {
557    type Item = usize;
558
559    type IntoIter = Iter<'a, T>;
560
561    #[inline]
562    fn into_iter(self) -> Self::IntoIter {
563        self.iter()
564    }
565}
566
567/// An iterator over the elements in a [`CompoundBitSet`].
568pub struct Iter<'a, T = usize> {
569    bitset: &'a CompoundBitSet<T>,
570    word: usize,
571    sub: Option<scalar::Iter<T>>,
572}
573
574impl<T: ScalarBitSetStorage> Iterator for Iter<'_, T> {
575    type Item = usize;
576
577    #[inline]
578    fn next(&mut self) -> Option<usize> {
579        loop {
580            if let Some(sub) = &mut self.sub {
581                if let Some(bit) = sub.next() {
582                    return Some(CompoundBitSet::<T>::elem(self.word, bit));
583                } else {
584                    self.word += 1;
585                }
586            }
587
588            self.sub = Some(self.bitset.elems.get(self.word)?.iter());
589        }
590    }
591}
592
593#[cfg(test)]
594mod tests {
595    use super::*;
596
597    #[test]
598    fn zero_capacity_no_allocs() {
599        let set = CompoundBitSet::<u32>::with_capacity(0);
600        assert_eq!(set.capacity(), 0);
601        let set = CompoundBitSet::new();
602        assert_eq!(set.capacity(), 0);
603    }
604}