extern crate unreachable; use std::ops; use std::iter::FromIterator; use std::default::Default; use std::collections::HashMap; mod hasher; use hasher::BitBuildHasher; const BITS: u64 = 64; type Block = u64; type Storage = HashMap; #[inline] fn block_bit(x: u64, d: u64) -> (u64, u64) { (x / d, x % d) } #[derive(Debug)] pub struct BitSet { blocks: Storage, nbits: usize, } impl BitSet { #[inline] pub fn new() -> BitSet { BitSet { blocks: Storage::default(), nbits: 0, } } #[inline] pub fn with_capacity(capacity: usize) -> BitSet { BitSet { blocks: Storage::with_capacity_and_hasher(capacity, Default::default()), nbits: 0, } } #[inline] pub fn capacity(&self) -> usize { self.blocks.len() * BITS as usize } #[inline] pub fn len(&self) -> usize { self.nbits } #[inline] pub fn is_empty(&self) -> bool { self.nbits == 0 } #[inline] pub fn insert(&mut self, value: u64) -> bool { let (block, bit) = block_bit(value, BITS); let block = self.blocks.entry(block).or_insert(0); let n = 1 << bit; if (*block & n) == 0 { *block |= n; self.nbits += 1; true } else { false } } #[inline] pub fn remove(&mut self, value: u64) -> bool { let (block, bit) = block_bit(value, BITS); let block = self.blocks.entry(block).or_insert(0); let n = 1 << bit; if (*block & n) != 0 { *block &= !n; self.nbits -= 1; true } else { false } } #[inline] pub fn contains(&self, value: u64) -> bool { let (block, bit) = block_bit(value, BITS); match self.blocks.get(&block) { Some(block) => (block & (1 << bit)) != 0, None => false, } } #[inline] pub fn extend_from_bitset(&mut self, other: &Self) { for (key, value) in &other.blocks { *self.blocks.entry(*key).or_insert(0) |= value; } self.nbits = self.blocks .values() .map(|block| block.count_ones() as usize) .sum(); } } impl Default for BitSet { #[inline] fn default() -> BitSet { BitSet::new() } } impl FromIterator for BitSet { #[inline] fn from_iter>(iter: I) -> BitSet { let mut set = BitSet::new(); set.extend(iter); set } } impl Extend for BitSet { #[inline] fn extend>(&mut self, iter: I) { for i in iter { self.insert(i); } } } impl<'a> Extend<&'a u64> for BitSet { #[inline] fn extend>(&mut self, iter: I) { for i in iter { self.insert(*i); } } } impl ops::BitOr for BitSet { type Output = Self; #[inline] fn bitor(mut self, rhs: Self) -> Self { for (key, value) in &rhs.blocks { *self.blocks.entry(*key).or_insert(0) |= value; } self.nbits = self.blocks .values() .map(|block| block.count_ones() as usize) .sum(); self } } impl<'a> ops::BitOr<&'a Self> for BitSet { type Output = Self; #[inline] fn bitor(mut self, rhs: &'a Self) -> Self { for (key, value) in &rhs.blocks { *self.blocks.entry(*key).or_insert(0) |= value; } self.nbits = self.blocks .values() .map(|block| block.count_ones() as usize) .sum(); self } } #[cfg(test)] mod tests { use super::*; #[test] fn insert() { let mut set = BitSet::with_capacity(10); assert_eq!(set.contains(0), false); assert_eq!(set.contains(10), false); set.insert(0); set.insert(10); assert_eq!(set.contains(0), true); assert_eq!(set.contains(10), true); assert_eq!(set.contains(100), false); set.insert(100); assert_eq!(set.contains(100), true); } #[test] fn from_iter() { let set = [1, 2, 3, 10, 100].iter().cloned().collect::(); assert_eq!(set.len(), 5); assert_eq!(set.contains(1), true); assert_eq!(set.contains(2), true); assert_eq!(set.contains(3), true); assert_eq!(set.contains(10), true); assert_eq!(set.contains(100), true); } #[test] fn bitor() { let set_a = [1, 2, 3].iter().cloned().collect::(); let set_b = [3, 4, 5].iter().cloned().collect::(); let set = set_a | set_b; assert_eq!(set.len(), 5); assert_eq!(set.contains(1), true); assert_eq!(set.contains(2), true); assert_eq!(set.contains(3), true); assert_eq!(set.contains(4), true); assert_eq!(set.contains(5), true); } #[test] fn extend_from_bitset() { let mut set = [1, 2, 3].iter().cloned().collect::(); let other = [3, 4, 5].iter().cloned().collect::(); set.extend_from_bitset(&other); assert_eq!(set.len(), 5); assert_eq!(set.contains(1), true); assert_eq!(set.contains(2), true); assert_eq!(set.contains(3), true); assert_eq!(set.contains(4), true); assert_eq!(set.contains(5), true); } }