Browse Source
* Introduce the `cranelift-bitset` crate The eventual goal is to deduplicate bitset types between Cranelift and Wasmtime, especially their use in stack maps. * Use the `cranelift-bitset` crate inside both Cranelift and Wasmtime Mostly for stack maps, also for a variety of other random things where `cranelift_codegen::bitset::BitSet` was previously used. * Fix stack maps unit test in cranelift-codegen * Uncomment `no_std` declaration * Fix `CompountBitSet::reserve` method * Fix `CompoundBitSet::insert` method * Keep track of the max in a `CompoundBitSet` Makes a bunch of other stuff easier, and will be needed for replacing `cranelift_entity::EntitySet`'s bitset with this thing anyways. * Add missing parens * Fix a bug around insert and reserve * Implement `with_capacity` in terms of `new` and `reserve` * Rename `reserve` to `ensure_capacity`pull/8836/head
Nick Fitzgerald
5 months ago
committed by
GitHub
19 changed files with 1267 additions and 259 deletions
@ -0,0 +1,20 @@ |
|||
[package] |
|||
authors = ["The Cranelift Project Developers"] |
|||
name = "cranelift-bitset" |
|||
version = "0.110.0" |
|||
description = "Various bitset stuff for use inside Cranelift" |
|||
license = "Apache-2.0 WITH LLVM-exception" |
|||
documentation = "https://docs.rs/cranelift-bitset" |
|||
repository = "https://github.com/bytecodealliance/wasmtime" |
|||
readme = "README.md" |
|||
edition.workspace = true |
|||
|
|||
[lints] |
|||
workspace = true |
|||
|
|||
[dependencies] |
|||
serde = { workspace = true, optional = true } |
|||
serde_derive = { workspace = true, optional = true } |
|||
|
|||
[features] |
|||
enable-serde = ["dep:serde", "dep:serde_derive"] |
@ -0,0 +1,495 @@ |
|||
//! Compound bit sets.
|
|||
|
|||
use crate::scalar::{self, ScalarBitSet}; |
|||
use alloc::{vec, vec::Vec}; |
|||
use core::mem; |
|||
|
|||
/// A large bit set backed by dynamically-sized storage.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// // Create a new bitset.
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// // Bitsets are initially empty.
|
|||
/// assert!(bitset.is_empty());
|
|||
/// assert_eq!(bitset.len(), 0);
|
|||
///
|
|||
/// // Insert into the bitset.
|
|||
/// bitset.insert(444);
|
|||
/// bitset.insert(555);
|
|||
/// bitset.insert(666);
|
|||
///
|
|||
/// // Now the bitset is not empty.
|
|||
/// assert_eq!(bitset.len(), 3);
|
|||
/// assert!(!bitset.is_empty());
|
|||
/// assert!(bitset.contains(444));
|
|||
/// assert!(bitset.contains(555));
|
|||
/// assert!(bitset.contains(666));
|
|||
///
|
|||
/// // Remove an element from the bitset.
|
|||
/// let was_present = bitset.remove(666);
|
|||
/// assert!(was_present);
|
|||
/// assert!(!bitset.contains(666));
|
|||
/// assert_eq!(bitset.len(), 2);
|
|||
///
|
|||
/// // Can iterate over the elements in the set.
|
|||
/// let elems: Vec<_> = bitset.iter().collect();
|
|||
/// assert_eq!(elems, [444, 555]);
|
|||
/// ```
|
|||
#[derive(Clone, PartialEq, Eq)] |
|||
#[cfg_attr(
|
|||
feature = "enable-serde", |
|||
derive(serde_derive::Serialize, serde_derive::Deserialize) |
|||
)] |
|||
pub struct CompoundBitSet { |
|||
elems: Vec<ScalarBitSet<usize>>, |
|||
len: usize, |
|||
max: Option<usize>, |
|||
} |
|||
|
|||
impl core::fmt::Debug for CompoundBitSet { |
|||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
|||
write!(f, "CompoundBitSet ")?; |
|||
f.debug_set().entries(self.iter()).finish() |
|||
} |
|||
} |
|||
|
|||
impl Default for CompoundBitSet { |
|||
#[inline] |
|||
fn default() -> Self { |
|||
Self::new() |
|||
} |
|||
} |
|||
|
|||
const BITS_PER_WORD: usize = mem::size_of::<usize>() * 8; |
|||
|
|||
impl CompoundBitSet { |
|||
/// Construct a new, empty bit set.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// assert!(bitset.is_empty());
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn new() -> Self { |
|||
CompoundBitSet { |
|||
elems: vec![], |
|||
len: 0, |
|||
max: None, |
|||
} |
|||
} |
|||
|
|||
/// Construct a new, empty bit set with space reserved to store any element
|
|||
/// `x` such that `x < capacity`.
|
|||
///
|
|||
/// The actual capacity reserved may be greater than that requested.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let bitset = CompoundBitSet::with_capacity(4096);
|
|||
///
|
|||
/// assert!(bitset.is_empty());
|
|||
/// assert!(bitset.capacity() >= 4096);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn with_capacity(capacity: usize) -> Self { |
|||
let mut bitset = Self::new(); |
|||
bitset.ensure_capacity(capacity); |
|||
bitset |
|||
} |
|||
|
|||
/// Get the number of elements in this bitset.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// assert_eq!(bitset.len(), 0);
|
|||
///
|
|||
/// bitset.insert(24);
|
|||
/// bitset.insert(130);
|
|||
/// bitset.insert(3600);
|
|||
///
|
|||
/// assert_eq!(bitset.len(), 3);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn len(&self) -> usize { |
|||
self.len |
|||
} |
|||
|
|||
/// Get `n + 1` where `n` is the largest value that can be stored inside
|
|||
/// this set without growing the backing storage.
|
|||
///
|
|||
/// That is, this set can store any value `x` such that `x <
|
|||
/// bitset.capacity()` without growing the backing storage.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// // New bitsets have zero capacity -- they allocate lazily.
|
|||
/// assert_eq!(bitset.capacity(), 0);
|
|||
///
|
|||
/// // Insert into the bitset, growing its capacity.
|
|||
/// bitset.insert(999);
|
|||
///
|
|||
/// // The bitset must now have capacity for at least `999` elements,
|
|||
/// // perhaps more.
|
|||
/// assert!(bitset.capacity() >= 999);
|
|||
///```
|
|||
pub fn capacity(&self) -> usize { |
|||
self.elems.capacity() * BITS_PER_WORD |
|||
} |
|||
|
|||
/// Is this bitset empty?
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// assert!(bitset.is_empty());
|
|||
///
|
|||
/// bitset.insert(1234);
|
|||
///
|
|||
/// assert!(!bitset.is_empty());
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn is_empty(&self) -> bool { |
|||
self.len == 0 |
|||
} |
|||
|
|||
/// Convert an element `i` into the `word` that can be used to index into
|
|||
/// `self.elems` and the `bit` that can be tested in the
|
|||
/// `ScalarBitSet<usize>` at `self.elems[word]`.
|
|||
#[inline] |
|||
fn word_and_bit(i: usize) -> (usize, u8) { |
|||
let word = i / BITS_PER_WORD; |
|||
let bit = i % BITS_PER_WORD; |
|||
let bit = u8::try_from(bit).unwrap(); |
|||
(word, bit) |
|||
} |
|||
|
|||
/// The opposite of `word_and_bit`: convert the pair of an index into
|
|||
/// `self.elems` and associated bit index into a set element.
|
|||
#[inline] |
|||
fn elem(word: usize, bit: u8) -> usize { |
|||
let bit = usize::from(bit); |
|||
debug_assert!(bit < BITS_PER_WORD); |
|||
word * BITS_PER_WORD + bit |
|||
} |
|||
|
|||
/// Is `i` contained in this bitset?
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// assert!(!bitset.contains(666));
|
|||
///
|
|||
/// bitset.insert(666);
|
|||
///
|
|||
/// assert!(bitset.contains(666));
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn contains(&self, i: usize) -> bool { |
|||
let (word, bit) = Self::word_and_bit(i); |
|||
if word < self.elems.len() { |
|||
self.elems[word].contains(bit) |
|||
} else { |
|||
false |
|||
} |
|||
} |
|||
|
|||
/// Ensure there is space in this bitset for the values `0..n`, growing the
|
|||
/// backing storage if necessary.
|
|||
///
|
|||
/// After calling `bitset.ensure_capacity(n)`, inserting any element `i`
|
|||
/// where `i < n` is guaranteed to succeed without growing the bitset's
|
|||
/// backing storage.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// # use cranelift_bitset::CompoundBitSet;
|
|||
/// # let mut bitset = CompoundBitSet::new();
|
|||
/// // We are going to do a series of inserts where `1000` will be the
|
|||
/// // maximum value inserted. Make sure that our bitset has capacity for
|
|||
/// // these elements once up front, to avoid growing the backing storage
|
|||
/// // multiple times incrementally.
|
|||
/// bitset.ensure_capacity(1001);
|
|||
///
|
|||
/// for i in 0..=1000 {
|
|||
/// if i % 2 == 0 {
|
|||
/// // Inserting this value should not require growing the backing
|
|||
/// // storage.
|
|||
/// assert!(bitset.capacity() > i);
|
|||
/// bitset.insert(i);
|
|||
/// }
|
|||
/// }
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn ensure_capacity(&mut self, n: usize) { |
|||
let (word, _bit) = Self::word_and_bit(n); |
|||
if word >= self.elems.len() { |
|||
self.elems.resize_with(word + 1, ScalarBitSet::new); |
|||
} |
|||
} |
|||
|
|||
/// Insert `i` into this bitset.
|
|||
///
|
|||
/// Returns whether the value was newly inserted. That is:
|
|||
///
|
|||
/// * If the set did not previously contain `i` then `true` is returned.
|
|||
///
|
|||
/// * If the set already contained `i` then `false` is returned.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// // When an element is inserted that was not already present in the set,
|
|||
/// // then `true` is returned.
|
|||
/// let is_new = bitset.insert(1234);
|
|||
/// assert!(is_new);
|
|||
///
|
|||
/// // The element is now present in the set.
|
|||
/// assert!(bitset.contains(1234));
|
|||
///
|
|||
/// // And when the element is already in the set, `false` is returned from
|
|||
/// // `insert`.
|
|||
/// let is_new = bitset.insert(1234);
|
|||
/// assert!(!is_new);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn insert(&mut self, i: usize) -> bool { |
|||
self.ensure_capacity(i + 1); |
|||
let (word, bit) = Self::word_and_bit(i); |
|||
let is_new = self.elems[word].insert(bit); |
|||
self.len += is_new as usize; |
|||
self.max = self.max.map(|max| core::cmp::max(max, i)).or(Some(i)); |
|||
is_new |
|||
} |
|||
|
|||
/// Remove `i` from this bitset.
|
|||
///
|
|||
/// Returns whether `i` was previously in this set or not.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// // Removing an element that was not present in the set returns `false`.
|
|||
/// let was_present = bitset.remove(456);
|
|||
/// assert!(!was_present);
|
|||
///
|
|||
/// // And when the element was in the set, `true` is returned.
|
|||
/// bitset.insert(456);
|
|||
/// let was_present = bitset.remove(456);
|
|||
/// assert!(was_present);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn remove(&mut self, i: usize) -> bool { |
|||
let (word, bit) = Self::word_and_bit(i); |
|||
if word < self.elems.len() { |
|||
let sub = &mut self.elems[word]; |
|||
let was_present = sub.remove(bit); |
|||
self.len -= was_present as usize; |
|||
if was_present && self.max == Some(i) { |
|||
self.update_max(word); |
|||
} |
|||
was_present |
|||
} else { |
|||
false |
|||
} |
|||
} |
|||
|
|||
/// Update the `self.max` field, based on the old word index of `self.max`.
|
|||
fn update_max(&mut self, word_of_old_max: usize) { |
|||
self.max = self.elems[0..word_of_old_max + 1] |
|||
.iter() |
|||
.enumerate() |
|||
.rev() |
|||
.filter_map(|(word, sub)| { |
|||
let bit = sub.max()?; |
|||
Some(Self::elem(word, bit)) |
|||
}) |
|||
.next(); |
|||
} |
|||
|
|||
/// Get the largest value in this set, or `None` if this set is empty.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// // Returns `None` if the bitset is empty.
|
|||
/// assert!(bitset.max().is_none());
|
|||
///
|
|||
/// bitset.insert(123);
|
|||
/// bitset.insert(987);
|
|||
/// bitset.insert(999);
|
|||
///
|
|||
/// // Otherwise, it returns the largest value in the set.
|
|||
/// assert_eq!(bitset.max(), Some(999));
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn max(&self) -> Option<usize> { |
|||
self.max |
|||
} |
|||
|
|||
/// Removes and returns the largest value in this set.
|
|||
///
|
|||
/// Returns `None` if this set is empty.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// bitset.insert(111);
|
|||
/// bitset.insert(222);
|
|||
/// bitset.insert(333);
|
|||
/// bitset.insert(444);
|
|||
/// bitset.insert(555);
|
|||
///
|
|||
/// assert_eq!(bitset.pop(), Some(555));
|
|||
/// assert_eq!(bitset.pop(), Some(444));
|
|||
/// assert_eq!(bitset.pop(), Some(333));
|
|||
/// assert_eq!(bitset.pop(), Some(222));
|
|||
/// assert_eq!(bitset.pop(), Some(111));
|
|||
/// assert_eq!(bitset.pop(), None);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn pop(&mut self) -> Option<usize> { |
|||
let max = self.max?; |
|||
self.remove(max); |
|||
Some(max) |
|||
} |
|||
|
|||
/// Remove all elements from this bitset.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// bitset.insert(100);
|
|||
/// bitset.insert(200);
|
|||
/// bitset.insert(300);
|
|||
///
|
|||
/// bitset.clear();
|
|||
///
|
|||
/// assert!(bitset.is_empty());
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn clear(&mut self) { |
|||
self.elems.clear(); |
|||
self.len = 0; |
|||
self.max = None; |
|||
} |
|||
|
|||
/// Iterate over the elements in this bitset.
|
|||
///
|
|||
/// The elements are always yielded in sorted order.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::CompoundBitSet;
|
|||
///
|
|||
/// let mut bitset = CompoundBitSet::new();
|
|||
///
|
|||
/// bitset.insert(0);
|
|||
/// bitset.insert(4096);
|
|||
/// bitset.insert(123);
|
|||
/// bitset.insert(456);
|
|||
/// bitset.insert(789);
|
|||
///
|
|||
/// assert_eq!(
|
|||
/// bitset.iter().collect::<Vec<_>>(),
|
|||
/// [0, 123, 456, 789, 4096],
|
|||
/// );
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn iter(&self) -> Iter<'_> { |
|||
Iter { |
|||
bitset: self, |
|||
word: 0, |
|||
sub: None, |
|||
} |
|||
} |
|||
} |
|||
|
|||
impl<'a> IntoIterator for &'a CompoundBitSet { |
|||
type Item = usize; |
|||
|
|||
type IntoIter = Iter<'a>; |
|||
|
|||
#[inline] |
|||
fn into_iter(self) -> Self::IntoIter { |
|||
self.iter() |
|||
} |
|||
} |
|||
|
|||
/// An iterator over the elements in a [`CompoundBitSet`].
|
|||
pub struct Iter<'a> { |
|||
bitset: &'a CompoundBitSet, |
|||
word: usize, |
|||
sub: Option<scalar::Iter<usize>>, |
|||
} |
|||
|
|||
impl Iterator for Iter<'_> { |
|||
type Item = usize; |
|||
|
|||
#[inline] |
|||
fn next(&mut self) -> Option<usize> { |
|||
loop { |
|||
if let Some(sub) = &mut self.sub { |
|||
if let Some(bit) = sub.next() { |
|||
return Some(CompoundBitSet::elem(self.word, bit)); |
|||
} else { |
|||
self.word += 1; |
|||
} |
|||
} |
|||
|
|||
self.sub = Some(self.bitset.elems.get(self.word)?.iter()); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,19 @@ |
|||
//! Bitsets for Cranelift.
|
|||
//!
|
|||
//! This module provides two bitset implementations:
|
|||
//!
|
|||
//! 1. [`ScalarBitSet`]: A small bitset built on top of a single integer.
|
|||
//!
|
|||
//! 2. [`CompoundBitSet`]: A bitset that can store more bits than fit in a
|
|||
//! single integer, but which internally has heap allocations.
|
|||
|
|||
#![deny(missing_docs)] |
|||
#![no_std] |
|||
|
|||
extern crate alloc; |
|||
|
|||
pub mod compound; |
|||
pub mod scalar; |
|||
|
|||
pub use compound::CompoundBitSet; |
|||
pub use scalar::ScalarBitSet; |
@ -0,0 +1,575 @@ |
|||
//! Scalar bitsets.
|
|||
|
|||
use core::mem::size_of; |
|||
use core::ops::{Add, BitAnd, BitOr, Not, Shl, Shr, Sub}; |
|||
|
|||
/// A small bitset built on top of a single primitive integer type.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// // Create a new bitset backed with a `u32`.
|
|||
/// let mut bitset = ScalarBitSet::<u32>::new();
|
|||
///
|
|||
/// // Bitsets are initially empty.
|
|||
/// assert!(bitset.is_empty());
|
|||
/// assert_eq!(bitset.len(), 0);
|
|||
///
|
|||
/// // Insert into the bitset.
|
|||
/// bitset.insert(4);
|
|||
/// bitset.insert(5);
|
|||
/// bitset.insert(6);
|
|||
///
|
|||
/// // Now the bitset is not empty.
|
|||
/// assert_eq!(bitset.len(), 3);
|
|||
/// assert!(!bitset.is_empty());
|
|||
/// assert!(bitset.contains(4));
|
|||
/// assert!(bitset.contains(5));
|
|||
/// assert!(bitset.contains(6));
|
|||
///
|
|||
/// // Remove an element from the bitset.
|
|||
/// let was_present = bitset.remove(6);
|
|||
/// assert!(was_present);
|
|||
/// assert!(!bitset.contains(6));
|
|||
/// assert_eq!(bitset.len(), 2);
|
|||
///
|
|||
/// // Can iterate over the elements in the set.
|
|||
/// let elems: Vec<_> = bitset.iter().collect();
|
|||
/// assert_eq!(elems, [4, 5]);
|
|||
/// ```
|
|||
#[derive(Clone, Copy, PartialEq, Eq)] |
|||
#[cfg_attr(
|
|||
feature = "enable-serde", |
|||
derive(serde_derive::Serialize, serde_derive::Deserialize) |
|||
)] |
|||
pub struct ScalarBitSet<T>(pub T); |
|||
|
|||
impl<T> core::fmt::Debug for ScalarBitSet<T> |
|||
where |
|||
T: ScalarBitSetStorage, |
|||
{ |
|||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
|||
let mut s = f.debug_struct(core::any::type_name::<Self>()); |
|||
for i in 0..Self::capacity() { |
|||
use alloc::string::ToString; |
|||
let i = u8::try_from(i).unwrap(); |
|||
s.field(&i.to_string(), &self.contains(i)); |
|||
} |
|||
s.finish() |
|||
} |
|||
} |
|||
|
|||
impl<T> Default for ScalarBitSet<T> |
|||
where |
|||
T: ScalarBitSetStorage, |
|||
{ |
|||
#[inline] |
|||
fn default() -> Self { |
|||
Self::new() |
|||
} |
|||
} |
|||
|
|||
impl<T> ScalarBitSet<T> |
|||
where |
|||
T: ScalarBitSetStorage, |
|||
{ |
|||
/// Create a new, empty bitset.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let bitset = ScalarBitSet::<u64>::new();
|
|||
///
|
|||
/// assert!(bitset.is_empty());
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn new() -> Self { |
|||
Self(T::from(0)) |
|||
} |
|||
|
|||
/// Construct a bitset with the half-open range `[lo, hi)` inserted.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let bitset = ScalarBitSet::<u64>::from_range(3, 6);
|
|||
///
|
|||
/// assert_eq!(bitset.len(), 3);
|
|||
///
|
|||
/// assert!(bitset.contains(3));
|
|||
/// assert!(bitset.contains(4));
|
|||
/// assert!(bitset.contains(5));
|
|||
/// ```
|
|||
///
|
|||
/// # Panics
|
|||
///
|
|||
/// Panics if `lo > hi` or if `hi > Self::capacity()`.
|
|||
///
|
|||
/// ```should_panic
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// // The lower bound may not be larger than the upper bound.
|
|||
/// let bitset = ScalarBitSet::<u64>::from_range(6, 3);
|
|||
/// ```
|
|||
///
|
|||
/// ```should_panic
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// // The bounds must fit within the backing scalar type.
|
|||
/// let bitset = ScalarBitSet::<u64>::from_range(3, 69);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn from_range(lo: u8, hi: u8) -> Self { |
|||
assert!(lo <= hi); |
|||
assert!(hi <= Self::capacity()); |
|||
|
|||
let one = T::from(1); |
|||
|
|||
// We can't just do (one << hi) - one here as the shift may overflow
|
|||
let hi_rng = if hi >= 1 { |
|||
(one << (hi - 1)) + ((one << (hi - 1)) - one) |
|||
} else { |
|||
T::from(0) |
|||
}; |
|||
|
|||
let lo_rng = (one << lo) - one; |
|||
|
|||
Self(hi_rng - lo_rng) |
|||
} |
|||
|
|||
/// The maximum number of bits that can be stored in this bitset.
|
|||
///
|
|||
/// If you need more bits than this, use a
|
|||
/// [`CompoundBitSet`][crate::CompoundBitSet] instead of a `ScalarBitSet`.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// assert_eq!(ScalarBitSet::<u8>::capacity(), 8);
|
|||
/// assert_eq!(ScalarBitSet::<u64>::capacity(), 64);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn capacity() -> u8 { |
|||
u8::try_from(size_of::<T>()).unwrap() * 8 |
|||
} |
|||
|
|||
/// Get the number of elements in this set.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u64>::new();
|
|||
///
|
|||
/// assert_eq!(bitset.len(), 0);
|
|||
///
|
|||
/// bitset.insert(24);
|
|||
/// bitset.insert(13);
|
|||
/// bitset.insert(36);
|
|||
///
|
|||
/// assert_eq!(bitset.len(), 3);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn len(&self) -> u8 { |
|||
self.0.count_ones() |
|||
} |
|||
|
|||
/// Is this bitset empty?
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u16>::new();
|
|||
///
|
|||
/// assert!(bitset.is_empty());
|
|||
///
|
|||
/// bitset.insert(10);
|
|||
///
|
|||
/// assert!(!bitset.is_empty());
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn is_empty(&self) -> bool { |
|||
self.0 == T::from(0) |
|||
} |
|||
|
|||
/// Check whether this bitset contains `i`.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u8>::new();
|
|||
///
|
|||
/// assert!(!bitset.contains(7));
|
|||
///
|
|||
/// bitset.insert(7);
|
|||
///
|
|||
/// assert!(bitset.contains(7));
|
|||
/// ```
|
|||
///
|
|||
/// # Panics
|
|||
///
|
|||
/// Panics if `i` is greater than or equal to [`Self::capacity()`][Self::capacity].
|
|||
///
|
|||
/// ```should_panic
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u8>::new();
|
|||
///
|
|||
/// // A `ScalarBitSet<u8>` can only hold the elements `0..=7`, so `8` is
|
|||
/// // out of bounds and will trigger a panic.
|
|||
/// bitset.contains(8);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn contains(&self, i: u8) -> bool { |
|||
assert!(i < Self::capacity()); |
|||
self.0 & (T::from(1) << i) != T::from(0) |
|||
} |
|||
|
|||
/// Insert `i` into this bitset.
|
|||
///
|
|||
/// Returns whether the value was newly inserted. That is:
|
|||
///
|
|||
/// * If the set did not previously contain `i` then `true` is returned.
|
|||
///
|
|||
/// * If the set already contained `i` then `false` is returned.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u8>::new();
|
|||
///
|
|||
/// // When an element is inserted that was not already present in the set,
|
|||
/// // then `true` is returned.
|
|||
/// let is_new = bitset.insert(7);
|
|||
/// assert!(is_new);
|
|||
///
|
|||
/// // The element is now present in the set.
|
|||
/// assert!(bitset.contains(7));
|
|||
///
|
|||
/// // And when the element is already in the set, `false` is returned from
|
|||
/// // `insert`.
|
|||
/// let is_new = bitset.insert(7);
|
|||
/// assert!(!is_new);
|
|||
/// ```
|
|||
///
|
|||
/// # Panics
|
|||
///
|
|||
/// Panics if `i` is greater than or equal to [`Self::capacity()`][Self::capacity].
|
|||
///
|
|||
/// ```should_panic
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u32>::new();
|
|||
///
|
|||
/// // A `ScalarBitSet<u32>` can only hold the elements `0..=31`, so `42` is
|
|||
/// // out of bounds and will trigger a panic.
|
|||
/// bitset.insert(42);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn insert(&mut self, i: u8) -> bool { |
|||
let is_new = !self.contains(i); |
|||
self.0 = self.0 | (T::from(1) << i); |
|||
is_new |
|||
} |
|||
|
|||
/// Remove `i` from this bitset.
|
|||
///
|
|||
/// Returns whether `i` was previously in this set or not.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u128>::new();
|
|||
///
|
|||
/// // Removing an element that was not present in the set returns `false`.
|
|||
/// let was_present = bitset.remove(100);
|
|||
/// assert!(!was_present);
|
|||
///
|
|||
/// // And when the element was in the set, `true` is returned.
|
|||
/// bitset.insert(100);
|
|||
/// let was_present = bitset.remove(100);
|
|||
/// assert!(was_present);
|
|||
/// ```
|
|||
///
|
|||
/// # Panics
|
|||
///
|
|||
/// Panics if `i` is greater than or equal to [`Self::capacity()`][Self::capacity].
|
|||
///
|
|||
/// ```should_panic
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u16>::new();
|
|||
///
|
|||
/// // A `ScalarBitSet<u16>` can only hold the elements `0..=15`, so `20` is
|
|||
/// // out of bounds and will trigger a panic.
|
|||
/// bitset.remove(20);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn remove(&mut self, i: u8) -> bool { |
|||
let was_present = self.contains(i); |
|||
self.0 = self.0 & !(T::from(1) << i); |
|||
was_present |
|||
} |
|||
|
|||
/// Remove all entries from this bitset.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u32>::new();
|
|||
///
|
|||
/// bitset.insert(10);
|
|||
/// bitset.insert(20);
|
|||
/// bitset.insert(30);
|
|||
///
|
|||
/// bitset.clear();
|
|||
///
|
|||
/// assert!(bitset.is_empty());
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn clear(&mut self) { |
|||
self.0 = T::from(0); |
|||
} |
|||
|
|||
/// Remove and return the largest value in the bitset.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u64>::new();
|
|||
///
|
|||
/// bitset.insert(0);
|
|||
/// bitset.insert(24);
|
|||
/// bitset.insert(13);
|
|||
/// bitset.insert(36);
|
|||
///
|
|||
/// assert_eq!(bitset.pop(), Some(36));
|
|||
/// assert_eq!(bitset.pop(), Some(24));
|
|||
/// assert_eq!(bitset.pop(), Some(13));
|
|||
/// assert_eq!(bitset.pop(), Some(0));
|
|||
/// assert_eq!(bitset.pop(), None);
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn pop(&mut self) -> Option<u8> { |
|||
let max = self.max()?; |
|||
self.remove(max); |
|||
Some(max) |
|||
} |
|||
|
|||
/// Return the smallest number contained in this bitset or `None` if this
|
|||
/// bitset is empty.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u64>::new();
|
|||
///
|
|||
/// // When the bitset is empty, `min` returns `None`.
|
|||
/// assert_eq!(bitset.min(), None);
|
|||
///
|
|||
/// bitset.insert(28);
|
|||
/// bitset.insert(1);
|
|||
/// bitset.insert(63);
|
|||
///
|
|||
/// // When the bitset is not empty, it returns the smallest element.
|
|||
/// assert_eq!(bitset.min(), Some(1));
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn min(&self) -> Option<u8> { |
|||
if self.0 == T::from(0) { |
|||
None |
|||
} else { |
|||
Some(self.0.trailing_zeros()) |
|||
} |
|||
} |
|||
|
|||
/// Return the largest number contained in the bitset or None if this bitset
|
|||
/// is empty
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u64>::new();
|
|||
///
|
|||
/// // When the bitset is empty, `max` returns `None`.
|
|||
/// assert_eq!(bitset.max(), None);
|
|||
///
|
|||
/// bitset.insert(0);
|
|||
/// bitset.insert(36);
|
|||
/// bitset.insert(49);
|
|||
///
|
|||
/// // When the bitset is not empty, it returns the smallest element.
|
|||
/// assert_eq!(bitset.max(), Some(49));
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn max(&self) -> Option<u8> { |
|||
if self.0 == T::from(0) { |
|||
None |
|||
} else { |
|||
let leading_zeroes = self.0.leading_zeros(); |
|||
Some(Self::capacity() - leading_zeroes - 1) |
|||
} |
|||
} |
|||
|
|||
/// Iterate over the items in this set.
|
|||
///
|
|||
/// Items are always yielded in sorted order.
|
|||
///
|
|||
/// # Example
|
|||
///
|
|||
/// ```
|
|||
/// use cranelift_bitset::ScalarBitSet;
|
|||
///
|
|||
/// let mut bitset = ScalarBitSet::<u64>::new();
|
|||
///
|
|||
/// bitset.insert(19);
|
|||
/// bitset.insert(3);
|
|||
/// bitset.insert(63);
|
|||
/// bitset.insert(0);
|
|||
///
|
|||
/// assert_eq!(
|
|||
/// bitset.iter().collect::<Vec<_>>(),
|
|||
/// [0, 3, 19, 63],
|
|||
/// );
|
|||
/// ```
|
|||
#[inline] |
|||
pub fn iter(&self) -> Iter<T> { |
|||
Iter { |
|||
value: self.0, |
|||
index: 0, |
|||
} |
|||
} |
|||
} |
|||
|
|||
impl<T> IntoIterator for ScalarBitSet<T> |
|||
where |
|||
T: ScalarBitSetStorage, |
|||
{ |
|||
type Item = u8; |
|||
|
|||
type IntoIter = Iter<T>; |
|||
|
|||
#[inline] |
|||
fn into_iter(self) -> Self::IntoIter { |
|||
self.iter() |
|||
} |
|||
} |
|||
|
|||
impl<'a, T> IntoIterator for &'a ScalarBitSet<T> |
|||
where |
|||
T: ScalarBitSetStorage, |
|||
{ |
|||
type Item = u8; |
|||
|
|||
type IntoIter = Iter<T>; |
|||
|
|||
#[inline] |
|||
fn into_iter(self) -> Self::IntoIter { |
|||
self.iter() |
|||
} |
|||
} |
|||
|
|||
/// A trait implemented by all integers that can be used as the backing storage
|
|||
/// for a [`ScalarBitSet`].
|
|||
///
|
|||
/// You shouldn't have to implement this yourself, it is already implemented for
|
|||
/// `u{8,16,32,64,128}` and if you need more bits than that, then use
|
|||
/// [`CompoundBitSet`][crate::CompoundBitSet] instead.
|
|||
pub trait ScalarBitSetStorage: |
|||
Default |
|||
+ From<u8> |
|||
+ Shl<u8, Output = Self> |
|||
+ Shr<u8, Output = Self> |
|||
+ BitAnd<Output = Self> |
|||
+ BitOr<Output = Self> |
|||
+ Not<Output = Self> |
|||
+ Sub<Output = Self> |
|||
+ Add<Output = Self> |
|||
+ PartialEq |
|||
+ Copy |
|||
{ |
|||
/// Count the number of leading zeros.
|
|||
fn leading_zeros(self) -> u8; |
|||
|
|||
/// Count the number of trailing zeros.
|
|||
fn trailing_zeros(self) -> u8; |
|||
|
|||
/// Count the number of bits set in this integer.
|
|||
fn count_ones(self) -> u8; |
|||
} |
|||
|
|||
macro_rules! impl_storage { |
|||
( $int:ty ) => { |
|||
impl ScalarBitSetStorage for $int { |
|||
fn leading_zeros(self) -> u8 { |
|||
u8::try_from(self.leading_zeros()).unwrap() |
|||
} |
|||
|
|||
fn trailing_zeros(self) -> u8 { |
|||
u8::try_from(self.trailing_zeros()).unwrap() |
|||
} |
|||
|
|||
fn count_ones(self) -> u8 { |
|||
u8::try_from(self.count_ones()).unwrap() |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
|
|||
impl_storage!(u8); |
|||
impl_storage!(u16); |
|||
impl_storage!(u32); |
|||
impl_storage!(u64); |
|||
impl_storage!(u128); |
|||
impl_storage!(usize); |
|||
|
|||
/// An iterator over the elements in a [`ScalarBitSet`].
|
|||
pub struct Iter<T> { |
|||
value: T, |
|||
index: u8, |
|||
} |
|||
|
|||
impl<T> Iterator for Iter<T> |
|||
where |
|||
T: ScalarBitSetStorage, |
|||
{ |
|||
type Item = u8; |
|||
|
|||
#[inline] |
|||
fn next(&mut self) -> Option<u8> { |
|||
if self.value == T::from(0) { |
|||
None |
|||
} else { |
|||
let trailing_zeros = self.value.trailing_zeros(); |
|||
let elem = self.index + trailing_zeros; |
|||
self.index += trailing_zeros + 1; |
|||
self.value = self.value >> (trailing_zeros + 1); |
|||
Some(elem) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,78 @@ |
|||
use cranelift_bitset::*; |
|||
|
|||
#[test] |
|||
fn contains() { |
|||
let s = ScalarBitSet::<u8>(255); |
|||
for i in 0..7 { |
|||
assert!(s.contains(i)); |
|||
} |
|||
|
|||
let s1 = ScalarBitSet::<u8>(0); |
|||
for i in 0..7 { |
|||
assert!(!s1.contains(i)); |
|||
} |
|||
|
|||
let s2 = ScalarBitSet::<u8>(127); |
|||
for i in 0..6 { |
|||
assert!(s2.contains(i)); |
|||
} |
|||
assert!(!s2.contains(7)); |
|||
|
|||
let s3 = ScalarBitSet::<u8>(2 | 4 | 64); |
|||
assert!(!s3.contains(0) && !s3.contains(3) && !s3.contains(4)); |
|||
assert!(!s3.contains(5) && !s3.contains(7)); |
|||
assert!(s3.contains(1) && s3.contains(2) && s3.contains(6)); |
|||
|
|||
let s4 = ScalarBitSet::<u16>(4 | 8 | 256 | 1024); |
|||
assert!( |
|||
!s4.contains(0) |
|||
&& !s4.contains(1) |
|||
&& !s4.contains(4) |
|||
&& !s4.contains(5) |
|||
&& !s4.contains(6) |
|||
&& !s4.contains(7) |
|||
&& !s4.contains(9) |
|||
&& !s4.contains(11) |
|||
); |
|||
assert!(s4.contains(2) && s4.contains(3) && s4.contains(8) && s4.contains(10)); |
|||
} |
|||
|
|||
#[test] |
|||
fn minmax() { |
|||
let s = ScalarBitSet::<u8>(255); |
|||
assert_eq!(s.min(), Some(0)); |
|||
assert_eq!(s.max(), Some(7)); |
|||
assert!(s.min() == Some(0) && s.max() == Some(7)); |
|||
let s1 = ScalarBitSet::<u8>(0); |
|||
assert!(s1.min() == None && s1.max() == None); |
|||
let s2 = ScalarBitSet::<u8>(127); |
|||
assert!(s2.min() == Some(0) && s2.max() == Some(6)); |
|||
let s3 = ScalarBitSet::<u8>(2 | 4 | 64); |
|||
assert!(s3.min() == Some(1) && s3.max() == Some(6)); |
|||
let s4 = ScalarBitSet::<u16>(4 | 8 | 256 | 1024); |
|||
assert!(s4.min() == Some(2) && s4.max() == Some(10)); |
|||
} |
|||
|
|||
#[test] |
|||
fn from_range() { |
|||
let s = ScalarBitSet::<u8>::from_range(5, 5); |
|||
assert!(s.0 == 0); |
|||
|
|||
let s = ScalarBitSet::<u8>::from_range(0, 8); |
|||
assert!(s.0 == 255); |
|||
|
|||
let s = ScalarBitSet::<u16>::from_range(0, 8); |
|||
assert!(s.0 == 255u16); |
|||
|
|||
let s = ScalarBitSet::<u16>::from_range(0, 16); |
|||
assert!(s.0 == 65535u16); |
|||
|
|||
let s = ScalarBitSet::<u8>::from_range(5, 6); |
|||
assert!(s.0 == 32u8); |
|||
|
|||
let s = ScalarBitSet::<u8>::from_range(3, 7); |
|||
assert!(s.0 == 8 | 16 | 32 | 64); |
|||
|
|||
let s = ScalarBitSet::<u16>::from_range(5, 11); |
|||
assert!(s.0 == 32 | 64 | 128 | 256 | 512 | 1024); |
|||
} |
@ -1,187 +0,0 @@ |
|||
//! Small Bitset
|
|||
//!
|
|||
//! This module defines a struct `BitSet<T>` encapsulating a bitset built over the type T.
|
|||
//! T is intended to be a primitive unsigned type. Currently it can be any type between u8 and u32
|
|||
//!
|
|||
//! If you would like to add support for larger bitsets in the future, you need to change the trait
|
|||
//! bound `Into<u32>` and the `u32` in the implementation of `max_bits()`.
|
|||
|
|||
use core::mem::size_of; |
|||
use core::ops::{Add, BitOr, Shl, Sub}; |
|||
|
|||
/// A small bitset built on a single primitive integer type
|
|||
#[derive(Clone, Copy, Default, PartialEq, Eq)] |
|||
#[cfg_attr(
|
|||
feature = "enable-serde", |
|||
derive(serde_derive::Serialize, serde_derive::Deserialize) |
|||
)] |
|||
pub struct BitSet<T>(pub T); |
|||
|
|||
impl<T> std::fmt::Debug for BitSet<T> |
|||
where |
|||
T: Into<u32> |
|||
+ From<u8> |
|||
+ BitOr<T, Output = T> |
|||
+ Shl<u8, Output = T> |
|||
+ Sub<T, Output = T> |
|||
+ Add<T, Output = T> |
|||
+ PartialEq |
|||
+ Copy, |
|||
{ |
|||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
|||
let mut s = f.debug_struct(std::any::type_name::<Self>()); |
|||
for i in 0..Self::bits() { |
|||
use std::string::ToString; |
|||
let i = u32::try_from(i).unwrap(); |
|||
s.field(&i.to_string(), &self.contains(i)); |
|||
} |
|||
s.finish() |
|||
} |
|||
} |
|||
|
|||
impl<T> BitSet<T> |
|||
where |
|||
T: Into<u32> |
|||
+ From<u8> |
|||
+ BitOr<T, Output = T> |
|||
+ Shl<u8, Output = T> |
|||
+ Sub<T, Output = T> |
|||
+ Add<T, Output = T> |
|||
+ PartialEq |
|||
+ Copy, |
|||
{ |
|||
/// Maximum number of bits supported by this BitSet instance
|
|||
pub fn bits() -> usize { |
|||
size_of::<T>() * 8 |
|||
} |
|||
|
|||
/// Maximum number of bits supported by any bitset instance atm.
|
|||
pub fn max_bits() -> usize { |
|||
size_of::<u32>() * 8 |
|||
} |
|||
|
|||
/// Check if this BitSet contains the number num
|
|||
pub fn contains(&self, num: u32) -> bool { |
|||
debug_assert!((num as usize) < Self::bits()); |
|||
debug_assert!((num as usize) < Self::max_bits()); |
|||
self.0.into() & (1 << num) != 0 |
|||
} |
|||
|
|||
/// Return the smallest number contained in the bitset or None if empty
|
|||
pub fn min(&self) -> Option<u8> { |
|||
if self.0.into() == 0 { |
|||
None |
|||
} else { |
|||
Some(self.0.into().trailing_zeros() as u8) |
|||
} |
|||
} |
|||
|
|||
/// Return the largest number contained in the bitset or None if empty
|
|||
pub fn max(&self) -> Option<u8> { |
|||
if self.0.into() == 0 { |
|||
None |
|||
} else { |
|||
let leading_zeroes = self.0.into().leading_zeros() as usize; |
|||
Some((Self::max_bits() - leading_zeroes - 1) as u8) |
|||
} |
|||
} |
|||
|
|||
/// Construct a BitSet with the half-open range [lo,hi) filled in
|
|||
pub fn from_range(lo: u8, hi: u8) -> Self { |
|||
debug_assert!(lo <= hi); |
|||
debug_assert!((hi as usize) <= Self::bits()); |
|||
let one: T = T::from(1); |
|||
// I can't just do (one << hi) - one here as the shift may overflow
|
|||
let hi_rng = if hi >= 1 { |
|||
(one << (hi - 1)) + ((one << (hi - 1)) - one) |
|||
} else { |
|||
T::from(0) |
|||
}; |
|||
|
|||
let lo_rng = (one << lo) - one; |
|||
|
|||
Self(hi_rng - lo_rng) |
|||
} |
|||
} |
|||
|
|||
#[cfg(test)] |
|||
mod tests { |
|||
use super::*; |
|||
|
|||
#[test] |
|||
fn contains() { |
|||
let s = BitSet::<u8>(255); |
|||
for i in 0..7 { |
|||
assert!(s.contains(i)); |
|||
} |
|||
|
|||
let s1 = BitSet::<u8>(0); |
|||
for i in 0..7 { |
|||
assert!(!s1.contains(i)); |
|||
} |
|||
|
|||
let s2 = BitSet::<u8>(127); |
|||
for i in 0..6 { |
|||
assert!(s2.contains(i)); |
|||
} |
|||
assert!(!s2.contains(7)); |
|||
|
|||
let s3 = BitSet::<u8>(2 | 4 | 64); |
|||
assert!(!s3.contains(0) && !s3.contains(3) && !s3.contains(4)); |
|||
assert!(!s3.contains(5) && !s3.contains(7)); |
|||
assert!(s3.contains(1) && s3.contains(2) && s3.contains(6)); |
|||
|
|||
let s4 = BitSet::<u16>(4 | 8 | 256 | 1024); |
|||
assert!( |
|||
!s4.contains(0) |
|||
&& !s4.contains(1) |
|||
&& !s4.contains(4) |
|||
&& !s4.contains(5) |
|||
&& !s4.contains(6) |
|||
&& !s4.contains(7) |
|||
&& !s4.contains(9) |
|||
&& !s4.contains(11) |
|||
); |
|||
assert!(s4.contains(2) && s4.contains(3) && s4.contains(8) && s4.contains(10)); |
|||
} |
|||
|
|||
#[test] |
|||
fn minmax() { |
|||
let s = BitSet::<u8>(255); |
|||
assert_eq!(s.min(), Some(0)); |
|||
assert_eq!(s.max(), Some(7)); |
|||
assert!(s.min() == Some(0) && s.max() == Some(7)); |
|||
let s1 = BitSet::<u8>(0); |
|||
assert!(s1.min() == None && s1.max() == None); |
|||
let s2 = BitSet::<u8>(127); |
|||
assert!(s2.min() == Some(0) && s2.max() == Some(6)); |
|||
let s3 = BitSet::<u8>(2 | 4 | 64); |
|||
assert!(s3.min() == Some(1) && s3.max() == Some(6)); |
|||
let s4 = BitSet::<u16>(4 | 8 | 256 | 1024); |
|||
assert!(s4.min() == Some(2) && s4.max() == Some(10)); |
|||
} |
|||
|
|||
#[test] |
|||
fn from_range() { |
|||
let s = BitSet::<u8>::from_range(5, 5); |
|||
assert!(s.0 == 0); |
|||
|
|||
let s = BitSet::<u8>::from_range(0, 8); |
|||
assert!(s.0 == 255); |
|||
|
|||
let s = BitSet::<u16>::from_range(0, 8); |
|||
assert!(s.0 == 255u16); |
|||
|
|||
let s = BitSet::<u16>::from_range(0, 16); |
|||
assert!(s.0 == 65535u16); |
|||
|
|||
let s = BitSet::<u8>::from_range(5, 6); |
|||
assert!(s.0 == 32u8); |
|||
|
|||
let s = BitSet::<u8>::from_range(3, 7); |
|||
assert!(s.0 == 8 | 16 | 32 | 64); |
|||
|
|||
let s = BitSet::<u16>::from_range(5, 11); |
|||
assert!(s.0 == 32 | 64 | 128 | 256 | 512 | 1024); |
|||
} |
|||
} |
Loading…
Reference in new issue