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