Skip to content

Bitv improvements #7703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 149 additions & 51 deletions src/libextra/bitv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use std::ops;
use std::uint;
use std::vec;

#[deriving(Clone)]
struct SmallBitv {
/// only the lowest nbits of this value are used. the rest is undefined.
bits: uint
Expand Down Expand Up @@ -107,6 +108,7 @@ impl SmallBitv {
pub fn negate(&mut self) { self.bits = !self.bits; }
}

#[deriving(Clone)]
struct BigBitv {
storage: ~[uint]
}
Expand Down Expand Up @@ -212,11 +214,13 @@ impl BigBitv {
}
}

enum BitvVariant { Big(~BigBitv), Small(~SmallBitv) }
#[deriving(Clone)]
enum BitvVariant { Big(BigBitv), Small(SmallBitv) }

enum Op {Union, Intersect, Assign, Difference}

/// The bitvector type
#[deriving(Clone)]
pub struct Bitv {
/// Internal representation of the bit vector (small or large)
rep: BitvVariant,
Expand All @@ -237,20 +241,20 @@ impl Bitv {
match self.rep {
Small(ref mut s) => match other.rep {
Small(ref s1) => match op {
Union => s.union(*s1, self.nbits),
Intersect => s.intersect(*s1, self.nbits),
Assign => s.become(*s1, self.nbits),
Difference => s.difference(*s1, self.nbits)
Union => s.union(s1, self.nbits),
Intersect => s.intersect(s1, self.nbits),
Assign => s.become(s1, self.nbits),
Difference => s.difference(s1, self.nbits)
},
Big(_) => die()
},
Big(ref mut s) => match other.rep {
Small(_) => die(),
Big(ref s1) => match op {
Union => s.union(*s1, self.nbits),
Intersect => s.intersect(*s1, self.nbits),
Assign => s.become(*s1, self.nbits),
Difference => s.difference(*s1, self.nbits)
Union => s.union(s1, self.nbits),
Intersect => s.intersect(s1, self.nbits),
Assign => s.become(s1, self.nbits),
Difference => s.difference(s1, self.nbits)
}
}
}
Expand All @@ -261,14 +265,14 @@ impl Bitv {
impl Bitv {
pub fn new(nbits: uint, init: bool) -> Bitv {
let rep = if nbits <= uint::bits {
Small(~SmallBitv::new(if init {!0} else {0}))
Small(SmallBitv::new(if init {!0} else {0}))
}
else {
let nelems = nbits/uint::bits +
if nbits % uint::bits == 0 {0} else {1};
let elem = if init {!0u} else {0u};
let s = vec::from_elem(nelems, elem);
Big(~BigBitv::new(s))
Big(BigBitv::new(s))
};
Bitv {rep: rep, nbits: nbits}
}
Expand Down Expand Up @@ -337,11 +341,11 @@ impl Bitv {
if self.nbits != v1.nbits { return false; }
match self.rep {
Small(ref b) => match v1.rep {
Small(ref b1) => b.equals(*b1, self.nbits),
Small(ref b1) => b.equals(b1, self.nbits),
_ => false
},
Big(ref s) => match v1.rep {
Big(ref s1) => s.equals(*s1, self.nbits),
Big(ref s1) => s.equals(s1, self.nbits),
Small(_) => return false
}
}
Expand Down Expand Up @@ -392,28 +396,23 @@ impl Bitv {
match self.rep {
Small(ref b) => b.is_true(self.nbits),
_ => {
for self.each() |i| { if !i { return false; } }
for self.iter().advance |i| { if !i { return false; } }
true
}
}
}

#[inline]
pub fn each(&self, f: &fn(bool) -> bool) -> bool {
let mut i = 0;
while i < self.nbits {
if !f(self.get(i)) { return false; }
i += 1;
}
return true;
pub fn iter<'a>(&'a self) -> BitvIterator<'a> {
BitvIterator {bitv: self, next_idx: 0}
}

/// Returns true if all bits are 0
pub fn is_false(&self) -> bool {
match self.rep {
Small(ref b) => b.is_false(self.nbits),
Big(_) => {
for self.each() |i| { if i { return false; } }
for self.iter().advance |i| { if i { return false; } }
true
}
}
Expand Down Expand Up @@ -477,7 +476,7 @@ impl Bitv {
*/
pub fn to_str(&self) -> ~str {
let mut rs = ~"";
for self.each() |i| {
for self.iter().advance |i| {
if i {
rs.push_char('1');
} else {
Expand Down Expand Up @@ -509,24 +508,6 @@ impl Bitv {

}

impl Clone for Bitv {
/// Makes a copy of a bitvector
#[inline]
fn clone(&self) -> Bitv {
match self.rep {
Small(ref b) => {
Bitv{nbits: self.nbits, rep: Small(~SmallBitv{bits: b.bits})}
}
Big(ref b) => {
let mut st = vec::from_elem(self.nbits / uint::bits + 1, 0u);
let len = st.len();
for uint::range(0, len) |i| { st[i] = b.storage[i]; };
Bitv{nbits: self.nbits, rep: Big(~BigBitv{storage: st})}
}
}
}
}

/**
* Transform a byte-vector into a bitv. Each byte becomes 8 bits,
* with the most significant bits of each byte coming first. Each
Expand Down Expand Up @@ -580,12 +561,37 @@ fn iterate_bits(base: uint, bits: uint, f: &fn(uint) -> bool) -> bool {
return true;
}

/// An iterator for Bitv
pub struct BitvIterator<'self> {
priv bitv: &'self Bitv,
priv next_idx: uint
}

impl<'self> Iterator<bool> for BitvIterator<'self> {
#[inline]
fn next(&mut self) -> Option<bool> {
if self.next_idx < self.bitv.nbits {
let idx = self.next_idx;
self.next_idx += 1;
Some(self.bitv.get(idx))
} else {
None
}
}

fn size_hint(&self) -> (uint, Option<uint>) {
let rem = self.bitv.nbits - self.next_idx;
(rem, Some(rem))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the lower bound be 0 because all of the bits could be off?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexcrichton it looks like this iterates over all the bits yielding false for 0 and true for 1, so it always traverses rem items.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, I thought this was the ones iterator.

}
}

/// An implementation of a set using a bit vector as an underlying
/// representation for holding numerical elements.
///
/// It should also be noted that the amount of storage necessary for holding a
/// set of objects is proportional to the maximum of the objects when viewed
/// as a uint.
#[deriving(Clone)]
pub struct BitvSet {
priv size: uint,

Expand All @@ -609,8 +615,8 @@ impl BitvSet {
}
let Bitv{rep, _} = bitv;
match rep {
Big(~b) => BitvSet{ size: size, bitv: b },
Small(~SmallBitv{bits}) =>
Big(b) => BitvSet{ size: size, bitv: b },
Small(SmallBitv{bits}) =>
BitvSet{ size: size, bitv: BigBitv{ storage: ~[bits] } },
}
}
Expand All @@ -623,7 +629,7 @@ impl BitvSet {
pub fn unwrap(self) -> Bitv {
let cap = self.capacity();
let BitvSet{bitv, _} = self;
return Bitv{ nbits:cap, rep: Big(~bitv) };
return Bitv{ nbits:cap, rep: Big(bitv) };
}

#[inline]
Expand Down Expand Up @@ -670,13 +676,8 @@ impl BitvSet {
self.other_op(other, |w1, w2| w1 ^ w2);
}

pub fn each(&self, blk: &fn(v: &uint) -> bool) -> bool {
for self.bitv.storage.iter().enumerate().advance |(i, &w)| {
if !iterate_bits(i * uint::bits, w, |b| blk(&b)) {
return false;
}
}
return true;
pub fn iter<'a>(&'a self) -> BitvSetIterator<'a> {
BitvSetIterator {set: self, next_idx: 0}
}
}

Expand Down Expand Up @@ -860,6 +861,31 @@ impl BitvSet {
}
}

pub struct BitvSetIterator<'self> {
priv set: &'self BitvSet,
priv next_idx: uint
}

impl<'self> Iterator<uint> for BitvSetIterator<'self> {
#[inline]
fn next(&mut self) -> Option<uint> {
while self.next_idx < self.set.capacity() {
let idx = self.next_idx;
self.next_idx += 1;

if self.set.contains(&idx) {
return Some(idx);
}
}

return None;
}

fn size_hint(&self) -> (uint, Option<uint>) {
(0, Some(self.set.capacity() - self.next_idx))
}
}

#[cfg(test)]
mod tests {
use extra::test::BenchHarness;
Expand Down Expand Up @@ -1241,6 +1267,25 @@ mod tests {
assert_eq!(from_bytes([0b00100110]).to_bools(), bools);
}

#[test]
fn test_bitv_iterator() {
let bools = [true, false, true, true];
let bitv = from_bools(bools);

for bitv.iter().zip(bools.iter()).advance |(act, &ex)| {
assert_eq!(ex, act);
}
}

#[test]
fn test_bitv_set_iterator() {
let bools = [true, false, true, true];
let bitv = BitvSet::from_bitv(from_bools(bools));

let idxs: ~[uint] = bitv.iter().collect();
assert_eq!(idxs, ~[0, 2, 3]);
}

#[test]
fn test_small_difference() {
let mut b1 = Bitv::new(3, false);
Expand Down Expand Up @@ -1417,6 +1462,25 @@ mod tests {
assert_eq!(a.capacity(), uint::bits);
}

#[test]
fn test_bitv_clone() {
let mut a = BitvSet::new();

assert!(a.insert(1));
assert!(a.insert(100));
assert!(a.insert(1000));

let mut b = a.clone();

assert_eq!(&a, &b);

assert!(b.remove(&1));
assert!(a.contains(&1));

assert!(a.remove(&1000));
assert!(b.contains(&1000));
}

fn rng() -> rand::IsaacRng {
let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
rand::IsaacRng::new_seeded(seed)
Expand Down Expand Up @@ -1504,4 +1568,38 @@ mod tests {
b1.union(&b2);
}
}

#[bench]
fn bench_btv_small_iter(b: &mut BenchHarness) {
let bitv = Bitv::new(uint::bits, false);
do b.iter {
let mut sum = 0;
for bitv.iter().advance |pres| {
sum += pres as uint;
}
}
}

#[bench]
fn bench_bitv_big_iter(b: &mut BenchHarness) {
let bitv = Bitv::new(BENCH_BITS, false);
do b.iter {
let mut sum = 0;
for bitv.iter().advance |pres| {
sum += pres as uint;
}
}
}

#[bench]
fn bench_bitvset_iter(b: &mut BenchHarness) {
let bitv = BitvSet::from_bitv(from_fn(BENCH_BITS,
|idx| {idx % 3 == 0}));
do b.iter {
let mut sum = 0;
for bitv.iter().advance |idx| {
sum += idx;
}
}
}
}