Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/bitset/src/compound.rs
3054 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
use wasmtime_core::alloc::{TryExtend, Vec};
7
use 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
)]
50
pub struct CompoundBitSet<T = usize> {
51
elems: Box<[ScalarBitSet<T>]>,
52
max: Option<u32>,
53
}
54
55
impl 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
62
impl 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
80
impl<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
556
impl<'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`].
568
pub struct Iter<'a, T = usize> {
569
bitset: &'a CompoundBitSet<T>,
570
word: usize,
571
sub: Option<scalar::Iter<T>>,
572
}
573
574
impl<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)]
594
mod 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
}
605
606