Improve BitSet APIs

A few small cleanups to `BitSet` and friends:

- Overload `clone_from` for `BitSet`.
- Improve `Debug` represenation of `HybridBitSet`.
- Make `HybridBitSet::domain_size` public.
- Don't require `T: Idx` at the type level. The `Idx` bound is still on
  most `BitSet` methods, but like `HashMap`, it doesn't need to be
  satisfied for the type to exist.
This commit is contained in:
Dylan MacKenzie 2020-08-27 18:07:27 -07:00
parent 85fbf49ce0
commit 149307efb7

View File

@ -28,13 +28,20 @@ pub const WORD_BITS: usize = WORD_BYTES * 8;
/// will panic if the bitsets have differing domain sizes. /// will panic if the bitsets have differing domain sizes.
/// ///
/// [`GrowableBitSet`]: struct.GrowableBitSet.html /// [`GrowableBitSet`]: struct.GrowableBitSet.html
#[derive(Clone, Eq, PartialEq, Decodable, Encodable)] #[derive(Eq, PartialEq, Decodable, Encodable)]
pub struct BitSet<T: Idx> { pub struct BitSet<T> {
domain_size: usize, domain_size: usize,
words: Vec<Word>, words: Vec<Word>,
marker: PhantomData<T>, marker: PhantomData<T>,
} }
impl<T> BitSet<T> {
/// Gets the domain size.
pub fn domain_size(&self) -> usize {
self.domain_size
}
}
impl<T: Idx> BitSet<T> { impl<T: Idx> BitSet<T> {
/// Creates a new, empty bitset with a given `domain_size`. /// Creates a new, empty bitset with a given `domain_size`.
#[inline] #[inline]
@ -52,11 +59,6 @@ impl<T: Idx> BitSet<T> {
result result
} }
/// Gets the domain size.
pub fn domain_size(&self) -> usize {
self.domain_size
}
/// Clear all elements. /// Clear all elements.
#[inline] #[inline]
pub fn clear(&mut self) { pub fn clear(&mut self) {
@ -75,12 +77,6 @@ impl<T: Idx> BitSet<T> {
} }
} }
/// Efficiently overwrite `self` with `other`.
pub fn overwrite(&mut self, other: &BitSet<T>) {
assert!(self.domain_size == other.domain_size);
self.words.clone_from_slice(&other.words);
}
/// Count the number of set bits in the set. /// Count the number of set bits in the set.
pub fn count(&self) -> usize { pub fn count(&self) -> usize {
self.words.iter().map(|e| e.count_ones() as usize).sum() self.words.iter().map(|e| e.count_ones() as usize).sum()
@ -243,6 +239,21 @@ impl<T: Idx> SubtractFromBitSet<T> for BitSet<T> {
} }
} }
impl<T> Clone for BitSet<T> {
fn clone(&self) -> Self {
BitSet { domain_size: self.domain_size, words: self.words.clone(), marker: PhantomData }
}
fn clone_from(&mut self, from: &Self) {
if self.domain_size != from.domain_size {
self.words.resize(from.domain_size, 0);
self.domain_size = from.domain_size;
}
self.words.copy_from_slice(&from.words);
}
}
impl<T: Idx> fmt::Debug for BitSet<T> { impl<T: Idx> fmt::Debug for BitSet<T> {
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
w.debug_list().entries(self.iter()).finish() w.debug_list().entries(self.iter()).finish()
@ -363,7 +374,7 @@ const SPARSE_MAX: usize = 8;
/// ///
/// This type is used by `HybridBitSet`; do not use directly. /// This type is used by `HybridBitSet`; do not use directly.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SparseBitSet<T: Idx> { pub struct SparseBitSet<T> {
domain_size: usize, domain_size: usize,
elems: ArrayVec<[T; SPARSE_MAX]>, elems: ArrayVec<[T; SPARSE_MAX]>,
} }
@ -464,18 +475,27 @@ impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
/// All operations that involve an element will panic if the element is equal /// All operations that involve an element will panic if the element is equal
/// to or greater than the domain size. All operations that involve two bitsets /// to or greater than the domain size. All operations that involve two bitsets
/// will panic if the bitsets have differing domain sizes. /// will panic if the bitsets have differing domain sizes.
#[derive(Clone, Debug)] #[derive(Clone)]
pub enum HybridBitSet<T: Idx> { pub enum HybridBitSet<T> {
Sparse(SparseBitSet<T>), Sparse(SparseBitSet<T>),
Dense(BitSet<T>), Dense(BitSet<T>),
} }
impl<T: Idx> fmt::Debug for HybridBitSet<T> {
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Sparse(b) => b.fmt(w),
Self::Dense(b) => b.fmt(w),
}
}
}
impl<T: Idx> HybridBitSet<T> { impl<T: Idx> HybridBitSet<T> {
pub fn new_empty(domain_size: usize) -> Self { pub fn new_empty(domain_size: usize) -> Self {
HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size)) HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size))
} }
fn domain_size(&self) -> usize { pub fn domain_size(&self) -> usize {
match self { match self {
HybridBitSet::Sparse(sparse) => sparse.domain_size, HybridBitSet::Sparse(sparse) => sparse.domain_size,
HybridBitSet::Dense(dense) => dense.domain_size, HybridBitSet::Dense(dense) => dense.domain_size,