cranelift_bitset/compound.rs
1//! Compound bit sets.
2
3use crate::scalar::{self, ScalarBitSet};
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 {
49 elems: Box<[ScalarBitSet<usize>]>,
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
60const BITS_PER_WORD: usize = mem::size_of::<usize>() * 8;
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 /// Construct a new, empty bit set with space reserved to store any element
80 /// `x` such that `x < capacity`.
81 ///
82 /// The actual capacity reserved may be greater than that requested.
83 ///
84 /// # Example
85 ///
86 /// ```
87 /// use cranelift_bitset::CompoundBitSet;
88 ///
89 /// let bitset = CompoundBitSet::with_capacity(4096);
90 ///
91 /// assert!(bitset.is_empty());
92 /// assert!(bitset.capacity() >= 4096);
93 /// ```
94 #[inline]
95 pub fn with_capacity(capacity: usize) -> Self {
96 let mut bitset = Self::new();
97 bitset.ensure_capacity(capacity);
98 bitset
99 }
100
101 /// Get the number of elements in this bitset.
102 ///
103 /// # Example
104 ///
105 /// ```
106 /// use cranelift_bitset::CompoundBitSet;
107 ///
108 /// let mut bitset = CompoundBitSet::new();
109 ///
110 /// assert_eq!(bitset.len(), 0);
111 ///
112 /// bitset.insert(24);
113 /// bitset.insert(130);
114 /// bitset.insert(3600);
115 ///
116 /// assert_eq!(bitset.len(), 3);
117 /// ```
118 #[inline]
119 pub fn len(&self) -> usize {
120 self.elems.iter().map(|sub| usize::from(sub.len())).sum()
121 }
122
123 /// Get `n + 1` where `n` is the largest value that can be stored inside
124 /// this set without growing the backing storage.
125 ///
126 /// That is, this set can store any value `x` such that `x <
127 /// bitset.capacity()` without growing the backing storage.
128 ///
129 /// # Example
130 ///
131 /// ```
132 /// use cranelift_bitset::CompoundBitSet;
133 ///
134 /// let mut bitset = CompoundBitSet::new();
135 ///
136 /// // New bitsets have zero capacity -- they allocate lazily.
137 /// assert_eq!(bitset.capacity(), 0);
138 ///
139 /// // Insert into the bitset, growing its capacity.
140 /// bitset.insert(999);
141 ///
142 /// // The bitset must now have capacity for at least `999` elements,
143 /// // perhaps more.
144 /// assert!(bitset.capacity() >= 999);
145 ///```
146 pub fn capacity(&self) -> usize {
147 self.elems.len() * BITS_PER_WORD
148 }
149
150 /// Is this bitset empty?
151 ///
152 /// # Example
153 ///
154 /// ```
155 /// use cranelift_bitset::CompoundBitSet;
156 ///
157 /// let mut bitset = CompoundBitSet::new();
158 ///
159 /// assert!(bitset.is_empty());
160 ///
161 /// bitset.insert(1234);
162 ///
163 /// assert!(!bitset.is_empty());
164 /// ```
165 #[inline]
166 pub fn is_empty(&self) -> bool {
167 self.len() == 0
168 }
169
170 /// Convert an element `i` into the `word` that can be used to index into
171 /// `self.elems` and the `bit` that can be tested in the
172 /// `ScalarBitSet<usize>` at `self.elems[word]`.
173 #[inline]
174 fn word_and_bit(i: usize) -> (usize, u8) {
175 let word = i / BITS_PER_WORD;
176 let bit = i % BITS_PER_WORD;
177 let bit = u8::try_from(bit).unwrap();
178 (word, bit)
179 }
180
181 /// The opposite of `word_and_bit`: convert the pair of an index into
182 /// `self.elems` and associated bit index into a set element.
183 #[inline]
184 fn elem(word: usize, bit: u8) -> usize {
185 let bit = usize::from(bit);
186 debug_assert!(bit < BITS_PER_WORD);
187 word * BITS_PER_WORD + bit
188 }
189
190 /// Is `i` contained in this bitset?
191 ///
192 /// # Example
193 ///
194 /// ```
195 /// use cranelift_bitset::CompoundBitSet;
196 ///
197 /// let mut bitset = CompoundBitSet::new();
198 ///
199 /// assert!(!bitset.contains(666));
200 ///
201 /// bitset.insert(666);
202 ///
203 /// assert!(bitset.contains(666));
204 /// ```
205 #[inline]
206 pub fn contains(&self, i: usize) -> bool {
207 let (word, bit) = Self::word_and_bit(i);
208 if word < self.elems.len() {
209 self.elems[word].contains(bit)
210 } else {
211 false
212 }
213 }
214
215 /// Ensure there is space in this bitset for the values `0..n`, growing the
216 /// backing storage if necessary.
217 ///
218 /// After calling `bitset.ensure_capacity(n)`, inserting any element `i`
219 /// where `i < n` is guaranteed to succeed without growing the bitset's
220 /// backing storage.
221 ///
222 /// # Example
223 ///
224 /// ```
225 /// # use cranelift_bitset::CompoundBitSet;
226 /// # let mut bitset = CompoundBitSet::new();
227 /// // We are going to do a series of inserts where `1000` will be the
228 /// // maximum value inserted. Make sure that our bitset has capacity for
229 /// // these elements once up front, to avoid growing the backing storage
230 /// // multiple times incrementally.
231 /// bitset.ensure_capacity(1001);
232 ///
233 /// for i in 0..=1000 {
234 /// if i % 2 == 0 {
235 /// // Inserting this value should not require growing the backing
236 /// // storage.
237 /// assert!(bitset.capacity() > i);
238 /// bitset.insert(i);
239 /// }
240 /// }
241 /// ```
242 #[inline]
243 pub fn ensure_capacity(&mut self, n: usize) {
244 let (word, _bit) = Self::word_and_bit(n);
245 if word >= self.elems.len() {
246 assert!(word < usize::try_from(isize::MAX).unwrap());
247
248 let delta = word - self.elems.len();
249 let to_grow = delta + 1;
250
251 // Amortize the cost of growing.
252 let to_grow = cmp::max(to_grow, self.elems.len() * 2);
253 // Don't make ridiculously small allocations.
254 let to_grow = cmp::max(to_grow, 4);
255
256 let new_elems = self
257 .elems
258 .iter()
259 .copied()
260 .chain(iter::repeat(ScalarBitSet::new()).take(to_grow))
261 .collect::<Box<[_]>>();
262 self.elems = new_elems;
263 }
264 }
265
266 /// Insert `i` into this bitset.
267 ///
268 /// Returns whether the value was newly inserted. That is:
269 ///
270 /// * If the set did not previously contain `i` then `true` is returned.
271 ///
272 /// * If the set already contained `i` then `false` is returned.
273 ///
274 /// # Example
275 ///
276 /// ```
277 /// use cranelift_bitset::CompoundBitSet;
278 ///
279 /// let mut bitset = CompoundBitSet::new();
280 ///
281 /// // When an element is inserted that was not already present in the set,
282 /// // then `true` is returned.
283 /// let is_new = bitset.insert(1234);
284 /// assert!(is_new);
285 ///
286 /// // The element is now present in the set.
287 /// assert!(bitset.contains(1234));
288 ///
289 /// // And when the element is already in the set, `false` is returned from
290 /// // `insert`.
291 /// let is_new = bitset.insert(1234);
292 /// assert!(!is_new);
293 /// ```
294 #[inline]
295 pub fn insert(&mut self, i: usize) -> bool {
296 self.ensure_capacity(i + 1);
297
298 let (word, bit) = Self::word_and_bit(i);
299 let is_new = self.elems[word].insert(bit);
300
301 let i = u32::try_from(i).unwrap();
302 self.max = self.max.map(|max| cmp::max(max, i)).or(Some(i));
303
304 is_new
305 }
306
307 /// Remove `i` from this bitset.
308 ///
309 /// Returns whether `i` was previously in this set or not.
310 ///
311 /// # Example
312 ///
313 /// ```
314 /// use cranelift_bitset::CompoundBitSet;
315 ///
316 /// let mut bitset = CompoundBitSet::new();
317 ///
318 /// // Removing an element that was not present in the set returns `false`.
319 /// let was_present = bitset.remove(456);
320 /// assert!(!was_present);
321 ///
322 /// // And when the element was in the set, `true` is returned.
323 /// bitset.insert(456);
324 /// let was_present = bitset.remove(456);
325 /// assert!(was_present);
326 /// ```
327 #[inline]
328 pub fn remove(&mut self, i: usize) -> bool {
329 let (word, bit) = Self::word_and_bit(i);
330 if word < self.elems.len() {
331 let sub = &mut self.elems[word];
332 let was_present = sub.remove(bit);
333 if was_present && self.max() == Some(i) {
334 self.update_max(word);
335 }
336 was_present
337 } else {
338 false
339 }
340 }
341
342 /// Update the `self.max` field, based on the old word index of `self.max`.
343 fn update_max(&mut self, word_of_old_max: usize) {
344 self.max = self.elems[0..word_of_old_max + 1]
345 .iter()
346 .enumerate()
347 .rev()
348 .filter_map(|(word, sub)| {
349 let bit = sub.max()?;
350 Some(u32::try_from(Self::elem(word, bit)).unwrap())
351 })
352 .next();
353 }
354
355 /// Get the largest value in this set, or `None` if this set is empty.
356 ///
357 /// # Example
358 ///
359 /// ```
360 /// use cranelift_bitset::CompoundBitSet;
361 ///
362 /// let mut bitset = CompoundBitSet::new();
363 ///
364 /// // Returns `None` if the bitset is empty.
365 /// assert!(bitset.max().is_none());
366 ///
367 /// bitset.insert(123);
368 /// bitset.insert(987);
369 /// bitset.insert(999);
370 ///
371 /// // Otherwise, it returns the largest value in the set.
372 /// assert_eq!(bitset.max(), Some(999));
373 /// ```
374 #[inline]
375 pub fn max(&self) -> Option<usize> {
376 self.max.map(|m| usize::try_from(m).unwrap())
377 }
378
379 /// Removes and returns the largest value in this set.
380 ///
381 /// Returns `None` if this set is empty.
382 ///
383 /// # Example
384 ///
385 /// ```
386 /// use cranelift_bitset::CompoundBitSet;
387 ///
388 /// let mut bitset = CompoundBitSet::new();
389 ///
390 /// bitset.insert(111);
391 /// bitset.insert(222);
392 /// bitset.insert(333);
393 /// bitset.insert(444);
394 /// bitset.insert(555);
395 ///
396 /// assert_eq!(bitset.pop(), Some(555));
397 /// assert_eq!(bitset.pop(), Some(444));
398 /// assert_eq!(bitset.pop(), Some(333));
399 /// assert_eq!(bitset.pop(), Some(222));
400 /// assert_eq!(bitset.pop(), Some(111));
401 /// assert_eq!(bitset.pop(), None);
402 /// ```
403 #[inline]
404 pub fn pop(&mut self) -> Option<usize> {
405 let max = self.max()?;
406 self.remove(max);
407 Some(max)
408 }
409
410 /// Remove all elements from this bitset.
411 ///
412 /// # Example
413 ///
414 /// ```
415 /// use cranelift_bitset::CompoundBitSet;
416 ///
417 /// let mut bitset = CompoundBitSet::new();
418 ///
419 /// bitset.insert(100);
420 /// bitset.insert(200);
421 /// bitset.insert(300);
422 ///
423 /// bitset.clear();
424 ///
425 /// assert!(bitset.is_empty());
426 /// ```
427 #[inline]
428 pub fn clear(&mut self) {
429 let max = match self.max() {
430 Some(max) => max,
431 None => return,
432 };
433 let (word, _bit) = Self::word_and_bit(max);
434 debug_assert!(self.elems[word + 1..].iter().all(|sub| sub.is_empty()));
435 for sub in &mut self.elems[..=word] {
436 *sub = ScalarBitSet::new();
437 }
438 self.max = None;
439 }
440
441 /// Iterate over the elements in this bitset.
442 ///
443 /// The elements are always yielded in sorted order.
444 ///
445 /// # Example
446 ///
447 /// ```
448 /// use cranelift_bitset::CompoundBitSet;
449 ///
450 /// let mut bitset = CompoundBitSet::new();
451 ///
452 /// bitset.insert(0);
453 /// bitset.insert(4096);
454 /// bitset.insert(123);
455 /// bitset.insert(456);
456 /// bitset.insert(789);
457 ///
458 /// assert_eq!(
459 /// bitset.iter().collect::<Vec<_>>(),
460 /// [0, 123, 456, 789, 4096],
461 /// );
462 /// ```
463 #[inline]
464 pub fn iter(&self) -> Iter<'_> {
465 Iter {
466 bitset: self,
467 word: 0,
468 sub: None,
469 }
470 }
471}
472
473impl<'a> IntoIterator for &'a CompoundBitSet {
474 type Item = usize;
475
476 type IntoIter = Iter<'a>;
477
478 #[inline]
479 fn into_iter(self) -> Self::IntoIter {
480 self.iter()
481 }
482}
483
484/// An iterator over the elements in a [`CompoundBitSet`].
485pub struct Iter<'a> {
486 bitset: &'a CompoundBitSet,
487 word: usize,
488 sub: Option<scalar::Iter<usize>>,
489}
490
491impl Iterator for Iter<'_> {
492 type Item = usize;
493
494 #[inline]
495 fn next(&mut self) -> Option<usize> {
496 loop {
497 if let Some(sub) = &mut self.sub {
498 if let Some(bit) = sub.next() {
499 return Some(CompoundBitSet::elem(self.word, bit));
500 } else {
501 self.word += 1;
502 }
503 }
504
505 self.sub = Some(self.bitset.elems.get(self.word)?.iter());
506 }
507 }
508}