Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/bitset/src/compound.rs
1692 views
1
//! Compound bit sets.
2
3
use crate::scalar::{self, ScalarBitSet, ScalarBitSetStorage};
4
use alloc::boxed::Box;
5
use 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
)]
48
pub struct CompoundBitSet<T = usize> {
49
elems: Box<[ScalarBitSet<T>]>,
50
max: Option<u32>,
51
}
52
53
impl 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
60
impl 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
78
impl<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
525
impl<'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`].
537
pub struct Iter<'a, T = usize> {
538
bitset: &'a CompoundBitSet<T>,
539
word: usize,
540
sub: Option<scalar::Iter<T>>,
541
}
542
543
impl<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)]
563
mod 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
}
574
575