use std::fmt;
pub mod err;
pub use err::Error;
const NUM_WORD_BITS: usize = std::mem::size_of::<usize>() * 8;
pub struct CountedBitmap {
bits: Vec<usize>,
length: usize,
remain: usize
}
impl fmt::Debug for CountedBitmap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let blocks: Vec<String> = self
.iter_ones_block()
.map(|(first, last)| {
if first != last {
format!("{}-{}", first, last)
} else {
format!("{}", first)
}
})
.collect();
let set_blocks = blocks.join(",");
write!(
f,
"BMap {{ length: {}, remain: {}, [{}] }}",
self.length, self.remain, set_blocks
)
}
}
impl CountedBitmap {
pub fn new(bitcount: usize) -> Self {
let align = NUM_WORD_BITS; let num = bitcount;
let len = (num + align - 1) / align;
let bits = vec![0; len];
Self {
bits,
length: bitcount,
remain: bitcount
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.length
}
pub fn is_empty(&self) -> bool {
self.remain == self.length
}
#[inline(always)]
pub fn remain(&self) -> usize {
self.remain
}
pub fn progress(&self) -> f64 {
if self.is_empty() {
1.0
} else {
let done = (self.length - self.remain) as f64;
done / self.len() as f64
}
}
#[inline(always)]
pub fn is_finished(&self) -> bool {
self.remain == 0
}
#[inline(always)]
pub fn is_set(&self, idx: usize) -> Result<bool, Error> {
let (iword, bitval) = self.get_bidx(idx)?;
let v = unsafe { self.bits.get_unchecked(iword) };
Ok(v & bitval != 0)
}
#[inline(always)]
pub fn set(&mut self, idx: usize) -> Result<(), Error> {
let (iword, bitval) = self.get_bidx(idx)?;
let v = unsafe { self.bits.get_unchecked_mut(iword) };
if *v & bitval == 0 {
*v |= bitval;
self.remain -= 1;
}
Ok(())
}
#[inline]
pub unsafe fn set_unchecked(&mut self, idx: usize) {
let (iword, bitval) = self.get_bidx_unchecked(idx);
let v = self.bits.get_unchecked_mut(iword);
if *v & bitval == 0 {
*v |= bitval;
self.remain -= 1;
}
}
#[inline(always)]
pub fn unset(&mut self, idx: usize) -> Result<(), Error> {
let (iword, bitval) = self.get_bidx(idx)?;
let v = unsafe { self.bits.get_unchecked_mut(iword) };
if *v & bitval != 0 {
*v &= !bitval;
self.remain += 1;
}
Ok(())
}
pub fn clear(&mut self) {
self.bits.as_mut_slice().fill(0);
self.remain = self.length;
}
pub fn cond_set<F>(&mut self, idx: usize, mut f: F) -> Result<bool, Error>
where
F: FnMut() -> bool
{
let (iword, bitval) = self.get_bidx(idx)?;
let v = unsafe { self.bits.get_unchecked_mut(iword) };
if *v & bitval == 0 && f() {
*v |= bitval;
self.remain -= 1;
Ok(true)
} else {
Ok(false)
}
}
}
impl CountedBitmap {
pub fn iter(&self) -> BitIter {
BitIter { bmap: self, idx: 0 }
}
pub fn iter_zeroes(&self) -> BitValIter {
BitValIter {
bmap: self,
idx: 0,
set: false
}
}
pub fn iter_ones(&self) -> BitValIter {
BitValIter {
bmap: self,
idx: 0,
set: true
}
}
pub fn iter_zeroes_block(&self) -> BitBlocksIter {
BitBlocksIter {
bmap: self,
idx: 0,
set: false
}
}
pub fn iter_ones_block(&self) -> BitBlocksIter {
BitBlocksIter {
bmap: self,
idx: 0,
set: true
}
}
}
pub struct BitIter<'a> {
bmap: &'a CountedBitmap,
idx: usize
}
impl<'a> Iterator for BitIter<'a> {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.bmap.len() {
let val = self.bmap.is_set_unchecked(self.idx);
self.idx += 1;
Some(val)
} else {
None
}
}
}
impl<'a> ExactSizeIterator for BitIter<'a> {
fn len(&self) -> usize {
self.bmap.len()
}
}
pub struct BitValIter<'a> {
bmap: &'a CountedBitmap,
idx: usize,
set: bool
}
impl<'a> Iterator for BitValIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.idx < self.bmap.length {
let val = self.bmap.is_set_unchecked(self.idx);
if self.set == val {
let idx = self.idx;
self.idx += 1;
return Some(idx);
} else {
self.idx += 1;
continue;
}
}
None
}
}
impl<'a> ExactSizeIterator for BitValIter<'a> {
fn len(&self) -> usize {
if self.set {
self.bmap.length - self.bmap.remain
} else {
self.bmap.remain
}
}
}
pub struct BitBlocksIter<'a> {
bmap: &'a CountedBitmap,
idx: usize,
set: bool
}
impl<'a> Iterator for BitBlocksIter<'a> {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
while self.idx < self.bmap.length {
let val = self.bmap.is_set_unchecked(self.idx);
if self.set != val {
self.idx += 1;
continue;
}
let low = self.idx;
self.idx += 1;
let high = loop {
if self.idx < self.bmap.length {
let val = self.bmap.is_set_unchecked(self.idx);
if self.set == val {
self.idx += 1;
continue;
} else {
let idx = self.idx - 1;
self.idx += 1;
break idx;
}
} else {
break self.idx - 1;
}
};
return Some((low, high));
}
None
}
}
impl CountedBitmap {
#[allow(dead_code)]
fn word_count(&self) -> usize {
self.bits.len()
}
#[inline(always)]
fn get_bidx(&self, idx: usize) -> Result<(usize, usize), Error> {
if idx >= self.length {
return Err(Error::OutOfBounds);
}
let t = self.get_bidx_unchecked(idx);
Ok(t)
}
#[inline(always)]
fn get_bidx_unchecked(&self, idx: usize) -> (usize, usize) {
let iword = idx / NUM_WORD_BITS;
let ibit = idx % NUM_WORD_BITS;
let bitval = 1 << ibit;
(iword, bitval)
}
#[inline(always)]
fn is_set_unchecked(&self, idx: usize) -> bool {
let (iword, bitval) = self.get_bidx_unchecked(idx);
let v = unsafe { self.bits.get_unchecked(iword) };
v & bitval != 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn size() {
let bmap = CountedBitmap::new(0);
assert_eq!(bmap.len(), 0);
assert_eq!(bmap.word_count(), 0);
let bmap = CountedBitmap::new(1);
assert_eq!(bmap.len(), 1);
assert_eq!(bmap.word_count(), 1);
let idx = NUM_WORD_BITS - 1;
let bmap = CountedBitmap::new(idx);
assert_eq!(bmap.len(), idx);
assert_eq!(bmap.word_count(), 1);
let bmap = CountedBitmap::new(NUM_WORD_BITS);
assert_eq!(bmap.len(), NUM_WORD_BITS);
assert_eq!(bmap.word_count(), 1);
let idx = NUM_WORD_BITS + 1;
let bmap = CountedBitmap::new(idx);
assert_eq!(bmap.len(), idx);
assert_eq!(bmap.word_count(), 2);
}
#[test]
fn finished() {
let bmap = CountedBitmap::new(0);
assert!(bmap.is_finished());
let mut bmap = CountedBitmap::new(1);
assert!(!bmap.is_finished());
bmap.set(0).unwrap();
assert!(bmap.is_finished());
}
#[test]
fn dbg_output0() {
let bmap = CountedBitmap::new(3);
let s = format!("{:?}", bmap);
assert_eq!(s, "BMap { length: 3, remain: 3, [] }");
}
#[test]
fn dbg_output1() {
let mut bmap = CountedBitmap::new(3);
bmap.set(1).unwrap();
let s = format!("{:?}", bmap);
assert_eq!(s, "BMap { length: 3, remain: 2, [1] }");
}
#[test]
fn dbg_output2() {
let mut bmap = CountedBitmap::new(5);
bmap.set(1).unwrap();
bmap.set(2).unwrap();
let s = format!("{:?}", bmap);
assert_eq!(s, "BMap { length: 5, remain: 3, [1-2] }");
}
#[test]
fn dbg_output3() {
let mut bmap = CountedBitmap::new(7);
bmap.set(1).unwrap();
bmap.set(2).unwrap();
bmap.set(4).unwrap();
bmap.set(5).unwrap();
let s = format!("{:?}", bmap);
assert_eq!(s, "BMap { length: 7, remain: 3, [1-2,4-5] }");
}
}