Skip to content

Commit

Permalink
auto merge of rust-lang#7703 : sfackler/rust/bitv, r=alexcrichton
Browse files Browse the repository at this point in the history
Switched Bitv and BitvSet to external iterators. They still use some internal iterators internally (ha).

Derived clone for all Bitv types.

Removed indirection in BitvVariant. It previously held a unique pointer to the appropriate Bitv struct, even though those structs are the size of a pointer themselves. BitvVariant is the same size (16 bytes) as it was previously.
  • Loading branch information
bors committed Jul 23, 2013
2 parents ff34064 + fd757a8 commit 6dfb0e5
Showing 1 changed file with 149 additions and 51 deletions.
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))
}
}

/// 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;
}
}
}
}

0 comments on commit 6dfb0e5

Please sign in to comment.