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}