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}