cranelift_bitset/
compound.rs

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