bitfield: keep track of # of set bit

This commit is contained in:
2016-12-17 00:31:49 -05:00
parent 2a1c5ec40e
commit 29599cfb02

View File

@@ -3,13 +3,16 @@ use std::fmt;
pub struct BitField { pub struct BitField {
bits: Vec<u8>, bits: Vec<u8>,
len: u32, len: u32,
num_set: u32,
} }
impl BitField { impl BitField {
pub fn new(bits: Vec<u8>, len: u32) -> BitField { pub fn new(bits: Vec<u8>, len: u32) -> BitField {
let num_set = bits.iter().map(|b| b.count_ones()).sum::<u32>();
BitField { BitField {
bits: bits, bits: bits,
len: len, len: len,
num_set: num_set,
} }
} }
@@ -17,41 +20,57 @@ impl BitField {
BitField { BitField {
bits: vec![0u8; f64::ceil(len as f64 / 8.) as usize], bits: vec![0u8; f64::ceil(len as f64 / 8.) as usize],
len: len, len: len,
num_set: 0,
} }
} }
#[inline]
fn calc_positions(&self, index: u32) -> (u32, u32) {
(index / 8, index % 8)
}
#[inline] #[inline]
pub fn len(&self) -> u32 { pub fn len(&self) -> u32 {
self.len self.len
} }
#[inline]
pub fn num_set(&self) -> u32 {
self.num_set
}
#[inline] #[inline]
pub fn is_set(&self, index: u32) -> bool { pub fn is_set(&self, index: u32) -> bool {
let idx = index / 8; let (idx, offset) = self.calc_positions(index);
let offset = index % 8;
(self.bits[idx as usize] & (1 << 7 - offset)) != 0 (self.bits[idx as usize] & (1 << 7 - offset)) != 0
} }
#[inline] #[inline]
pub fn set(&mut self, index: u32) { pub fn set(&mut self, index: u32) {
let idx = index / 8; if !self.is_set(index) {
let offset = index % 8; let (idx, offset) = self.calc_positions(index);
self.bits[idx as usize] |= 1 << 7 - offset; self.bits[idx as usize] |= 1 << 7 - offset;
self.num_set += 1;
}
} }
#[inline] #[inline]
pub fn unset(&mut self, index: u32) { pub fn unset(&mut self, index: u32) {
let idx = index / 8; if self.is_set(index) {
let offset = index % 8; let (idx, offset) = self.calc_positions(index);
self.bits[idx as usize] ^= 1 << 7 - offset; self.bits[idx as usize] ^= 1 << 7 - offset;
self.num_set -= 1;
}
} }
#[inline]
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
&self.bits &self.bits
} }
#[inline]
pub fn set_ratio(&self) -> f64 { pub fn set_ratio(&self) -> f64 {
self.bits.iter().map(|b| b.count_ones()).sum::<u32>() as f64 / self.len as f64 self.num_set as f64 / self.len as f64
} }
} }
@@ -84,6 +103,8 @@ fn test_bitfield_is_set() {
assert!(bf.is_set(0xd)); assert!(bf.is_set(0xd));
assert!(bf.is_set(0xe)); assert!(bf.is_set(0xe));
assert!(bf.is_set(0xf)); assert!(bf.is_set(0xf));
assert_eq!(bf.num_set(), 12);
} }
#[test] #[test]
@@ -97,6 +118,8 @@ fn test_bitfield_set() {
assert_eq!(bf.bits[1], 128); assert_eq!(bf.bits[1], 128);
bf.set(15); bf.set(15);
assert_eq!(bf.bits[1], 129); assert_eq!(bf.bits[1], 129);
assert_eq!(bf.num_set(), 4);
} }
#[test] #[test]
@@ -110,6 +133,8 @@ fn test_bitfield_unset() {
assert_eq!(bf.bits[1], 255-128); assert_eq!(bf.bits[1], 255-128);
bf.unset(15); bf.unset(15);
assert_eq!(bf.bits[1], 255-128-1); assert_eq!(bf.bits[1], 255-128-1);
assert_eq!(bf.num_set(), 12);
} }
#[test] #[test]