auto merge of #7703 : sfackler/rust/bitv, r=alexcrichton
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.
This commit is contained in:
commit
6dfb0e5ad3
@ -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
|
||||
@ -107,6 +108,7 @@ impl SmallBitv {
|
||||
pub fn negate(&mut self) { self.bits = !self.bits; }
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
struct BigBitv {
|
||||
storage: ~[uint]
|
||||
}
|
||||
@ -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,
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -392,20 +396,15 @@ 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
|
||||
@ -413,7 +412,7 @@ impl Bitv {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
@ -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
|
||||
@ -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,
|
||||
|
||||
@ -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] } },
|
||||
}
|
||||
}
|
||||
@ -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]
|
||||
@ -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}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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);
|
||||
@ -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)
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user