From 91fae2791292c7374143e82814a375a12bfd4e83 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 17 Feb 2013 17:07:51 -0500 Subject: [PATCH 1/6] Modernize bitv mut fields and explicit self --- src/libstd/bitv.rs | 266 ++++++++++++++-------------- src/libsyntax/ext/pipes/liveness.rs | 12 +- src/test/bench/sudoku.rs | 4 +- src/test/run-pass/bitv-perf-test.rs | 4 +- 4 files changed, 144 insertions(+), 142 deletions(-) diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 75b97f494bd..c72f9ec2f98 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -16,11 +16,7 @@ use core::vec; struct SmallBitv { /// only the lowest nbits of this value are used. the rest is undefined. - mut bits: u32 -} - -fn SmallBitv(bits: u32) -> SmallBitv { - SmallBitv {bits: bits} + bits: u32 } /// a mask that has a 1 for each defined bit in a small_bitv, assuming n bits @@ -30,9 +26,13 @@ fn small_mask(nbits: uint) -> u32 { } impl SmallBitv { + static fn new(bits: u32) -> SmallBitv { + SmallBitv {bits: bits} + } #[inline(always)] - fn bits_op(right_bits: u32, nbits: uint, f: fn(u32, u32) -> u32) -> bool { + fn bits_op(&mut self, right_bits: u32, nbits: uint, + f: fn(u32, u32) -> u32) -> bool { let mask = small_mask(nbits); let old_b: u32 = self.bits; let new_b = f(old_b, right_bits); @@ -41,32 +41,32 @@ impl SmallBitv { } #[inline(always)] - fn union(s: &SmallBitv, nbits: uint) -> bool { + fn union(&mut self, s: &SmallBitv, nbits: uint) -> bool { self.bits_op(s.bits, nbits, |u1, u2| u1 | u2) } #[inline(always)] - fn intersect(s: &SmallBitv, nbits: uint) -> bool { + fn intersect(&mut self, s: &SmallBitv, nbits: uint) -> bool { self.bits_op(s.bits, nbits, |u1, u2| u1 & u2) } #[inline(always)] - fn become(s: &SmallBitv, nbits: uint) -> bool { + fn become(&mut self, s: &SmallBitv, nbits: uint) -> bool { self.bits_op(s.bits, nbits, |_u1, u2| u2) } #[inline(always)] - fn difference(s: &SmallBitv, nbits: uint) -> bool { + fn difference(&mut self, s: &SmallBitv, nbits: uint) -> bool { self.bits_op(s.bits, nbits, |u1, u2| u1 & !u2) } #[inline(always)] - pure fn get(i: uint) -> bool { + pure fn get(&self, i: uint) -> bool { (self.bits & (1 << i)) != 0 } #[inline(always)] - fn set(i: uint, x: bool) { + fn set(&mut self, i: uint, x: bool) { if x { self.bits |= 1< bool { + fn equals(&self, b: &SmallBitv, nbits: uint) -> bool { let mask = small_mask(nbits); mask & self.bits == mask & b.bits } #[inline(always)] - fn clear() { self.bits = 0; } + fn clear(&mut self) { self.bits = 0; } #[inline(always)] - fn set_all() { self.bits = !0; } + fn set_all(&mut self) { self.bits = !0; } #[inline(always)] - fn is_true(nbits: uint) -> bool { + fn is_true(&self, nbits: uint) -> bool { small_mask(nbits) & !self.bits == 0 } #[inline(always)] - fn is_false(nbits: uint) -> bool { + fn is_false(&self, nbits: uint) -> bool { small_mask(nbits) & self.bits == 0 } #[inline(always)] - fn invert() { self.bits = !self.bits; } + fn invert(&mut self) { self.bits = !self.bits; } } struct BigBitv { - // only mut b/c of clone and lack of other constructor - mut storage: ~[uint] -} - -fn BigBitv(storage: ~[uint]) -> BigBitv { - BigBitv {storage: storage} + storage: ~[uint] } /** @@ -128,9 +123,13 @@ fn big_mask(nbits: uint, elem: uint) -> uint { } impl BigBitv { + static fn new(storage: ~[uint]) -> BigBitv { + BigBitv {storage: storage} + } #[inline(always)] - fn process(b: &BigBitv, nbits: uint, op: fn(uint, uint) -> uint) -> bool { + fn process(&mut self, b: &BigBitv, nbits: uint, + op: fn(uint, uint) -> uint) -> bool { let len = b.storage.len(); assert (self.storage.len() == len); let mut changed = false; @@ -151,7 +150,7 @@ impl BigBitv { } #[inline(always)] - fn each_storage(op: fn(v: &mut uint) -> bool) { + fn each_storage(&mut self, op: fn(v: &mut uint) -> bool) { for uint::range(0, self.storage.len()) |i| { let mut w = self.storage[i]; let b = op(&mut w); @@ -161,30 +160,30 @@ impl BigBitv { } #[inline(always)] - fn invert() { for self.each_storage() |w| { *w = !*w } } + fn invert(&mut self) { for self.each_storage |w| { *w = !*w } } #[inline(always)] - fn union(b: &BigBitv, nbits: uint) -> bool { + fn union(&mut self, b: &BigBitv, nbits: uint) -> bool { self.process(b, nbits, lor) } #[inline(always)] - fn intersect(b: &BigBitv, nbits: uint) -> bool { + fn intersect(&mut self, b: &BigBitv, nbits: uint) -> bool { self.process(b, nbits, land) } #[inline(always)] - fn become(b: &BigBitv, nbits: uint) -> bool { + fn become(&mut self, b: &BigBitv, nbits: uint) -> bool { self.process(b, nbits, right) } #[inline(always)] - fn difference(b: &BigBitv, nbits: uint) -> bool { + fn difference(&mut self, b: &BigBitv, nbits: uint) -> bool { self.process(b, nbits, difference) } #[inline(always)] - pure fn get(i: uint) -> bool { + pure fn get(&self, i: uint) -> bool { let w = i / uint_bits; let b = i % uint_bits; let x = 1 & self.storage[w] >> b; @@ -192,16 +191,16 @@ impl BigBitv { } #[inline(always)] - fn set(i: uint, x: bool) { + fn set(&mut self, i: uint, x: bool) { let w = i / uint_bits; let b = i % uint_bits; let flag = 1 << b; self.storage[w] = if x { self.storage[w] | flag } - else { self.storage[w] & !flag }; + else { self.storage[w] & !flag }; } #[inline(always)] - fn equals(b: &BigBitv, nbits: uint) -> bool { + fn equals(&self, b: &BigBitv, nbits: uint) -> bool { let len = b.storage.len(); for uint::iterate(0, len) |i| { let mask = big_mask(nbits, i); @@ -223,33 +222,19 @@ pub struct Bitv { nbits: uint } -pub fn Bitv (nbits: uint, init: bool) -> Bitv { - let rep = if nbits <= 32 { - Small(~SmallBitv(if init {!0} else {0})) - } - else { - let nelems = nbits/uint_bits + - if nbits % uint_bits == 0 {0} else {1}; - let elem = if init {!0} else {0}; - let s = from_elem(nelems, elem); - Big(~BigBitv(s)) - }; - Bitv {rep: rep, nbits: nbits} -} - priv impl Bitv { - fn die() -> ! { + fn die(&self) -> ! { fail!(~"Tried to do operation on bit vectors with different sizes"); } #[inline(always)] - fn do_op(op: Op, other: &Bitv) -> bool { + fn do_op(&mut self, op: Op, other: &Bitv) -> bool { if self.nbits != other.nbits { self.die(); } match self.rep { - Small(ref s) => match other.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), @@ -258,7 +243,7 @@ priv impl Bitv { }, Big(_) => self.die() }, - Big(ref s) => match other.rep { + Big(ref mut s) => match other.rep { Small(_) => self.die(), Big(ref s1) => match op { Union => s.union(*s1, self.nbits), @@ -273,6 +258,19 @@ priv impl Bitv { } impl Bitv { + static fn new(nbits: uint, init: bool) -> Bitv { + let rep = if nbits <= 32 { + 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 {!0} else {0}; + let s = from_elem(nelems, elem); + Big(~BigBitv::new(s)) + }; + Bitv {rep: rep, nbits: nbits} + } /** * Calculates the union of two bitvectors @@ -281,7 +279,7 @@ impl Bitv { * the same length. Returns 'true' if `self` changed. */ #[inline(always)] - fn union(v1: &Bitv) -> bool { self.do_op(Union, v1) } + fn union(&mut self, v1: &Bitv) -> bool { self.do_op(Union, v1) } /** * Calculates the intersection of two bitvectors @@ -290,7 +288,7 @@ impl Bitv { * must be the same length. Returns 'true' if `self` changed. */ #[inline(always)] - fn intersect(v1: &Bitv) -> bool { self.do_op(Intersect, v1) } + fn intersect(&mut self, v1: &Bitv) -> bool { self.do_op(Intersect, v1) } /** * Assigns the value of `v1` to `self` @@ -299,11 +297,11 @@ impl Bitv { * changed */ #[inline(always)] - fn assign(v: &Bitv) -> bool { self.do_op(Assign, v) } + fn assign(&mut self, v: &Bitv) -> bool { self.do_op(Assign, v) } /// Retrieve the value at index `i` #[inline(always)] - pure fn get(i: uint) -> bool { + pure fn get(&self, i: uint) -> bool { assert (i < self.nbits); match self.rep { Big(ref b) => b.get(i), @@ -317,11 +315,11 @@ impl Bitv { * `i` must be less than the length of the bitvector. */ #[inline(always)] - fn set(i: uint, x: bool) { + fn set(&mut self, i: uint, x: bool) { assert (i < self.nbits); match self.rep { - Big(ref b) => b.set(i, x), - Small(ref s) => s.set(i, x) + Big(ref mut b) => b.set(i, x), + Small(ref mut s) => s.set(i, x) } } @@ -332,7 +330,7 @@ impl Bitv { * bitvectors contain identical elements. */ #[inline(always)] - fn equal(v1: &Bitv) -> bool { + fn equal(&self, v1: &Bitv) -> bool { if self.nbits != v1.nbits { return false; } match self.rep { Small(ref b) => match v1.rep { @@ -348,27 +346,27 @@ impl Bitv { /// Set all bits to 0 #[inline(always)] - fn clear() { + fn clear(&mut self) { match self.rep { - Small(ref b) => b.clear(), - Big(ref s) => for s.each_storage() |w| { *w = 0u } + Small(ref mut b) => b.clear(), + Big(ref mut s) => for s.each_storage() |w| { *w = 0u } } } /// Set all bits to 1 #[inline(always)] - fn set_all() { + fn set_all(&mut self) { match self.rep { - Small(ref b) => b.set_all(), - Big(ref s) => for s.each_storage() |w| { *w = !0u } } + Small(ref mut b) => b.set_all(), + Big(ref mut s) => for s.each_storage() |w| { *w = !0u } } } /// Invert all bits #[inline(always)] - fn invert() { + fn invert(&mut self) { match self.rep { - Small(ref b) => b.invert(), - Big(ref s) => for s.each_storage() |w| { *w = !*w } } + Small(ref mut b) => b.invert(), + Big(ref mut s) => for s.each_storage() |w| { *w = !*w } } } /** @@ -381,11 +379,11 @@ impl Bitv { * Returns `true` if `v0` was changed. */ #[inline(always)] - fn difference(v: &Bitv) -> bool { self.do_op(Difference, v) } + fn difference(&mut self, v: &Bitv) -> bool { self.do_op(Difference, v) } /// Returns true if all bits are 1 #[inline(always)] - fn is_true() -> bool { + fn is_true(&self) -> bool { match self.rep { Small(ref b) => b.is_true(self.nbits), _ => { @@ -396,7 +394,7 @@ impl Bitv { } #[inline(always)] - fn each(f: fn(bool) -> bool) { + fn each(&self, f: fn(bool) -> bool) { let mut i = 0; while i < self.nbits { if !f(self.get(i)) { break; } @@ -405,7 +403,7 @@ impl Bitv { } /// Returns true if all bits are 0 - fn is_false() -> bool { + fn is_false(&self) -> bool { match self.rep { Small(ref b) => b.is_false(self.nbits), Big(_) => { @@ -415,7 +413,7 @@ impl Bitv { } } - fn init_to_vec(i: uint) -> uint { + fn init_to_vec(&self, i: uint) -> uint { return if self.get(i) { 1 } else { 0 }; } @@ -424,7 +422,7 @@ impl Bitv { * * Each uint in the resulting vector has either value 0u or 1u. */ - fn to_vec() -> ~[uint] { + fn to_vec(&self) -> ~[uint] { vec::from_fn(self.nbits, |x| self.init_to_vec(x)) } @@ -434,7 +432,7 @@ impl Bitv { * size of the bitv is not a multiple of 8 then trailing bits * will be filled-in with false/0 */ - fn to_bytes() -> ~[u8] { + fn to_bytes(&self) -> ~[u8] { fn bit (bitv: &Bitv, byte: uint, bit: uint) -> u8 { let offset = byte * 8 + bit; @@ -448,21 +446,21 @@ impl Bitv { let len = self.nbits/8 + if self.nbits % 8 == 0 { 0 } else { 1 }; vec::from_fn(len, |i| - bit(&self, i, 0) | - bit(&self, i, 1) | - bit(&self, i, 2) | - bit(&self, i, 3) | - bit(&self, i, 4) | - bit(&self, i, 5) | - bit(&self, i, 6) | - bit(&self, i, 7) + bit(self, i, 0) | + bit(self, i, 1) | + bit(self, i, 2) | + bit(self, i, 3) | + bit(self, i, 4) | + bit(self, i, 5) | + bit(self, i, 6) | + bit(self, i, 7) ) } /** * Transform self into a [bool] by turning each bit into a bool */ - fn to_bools() -> ~[bool] { + fn to_bools(&self) -> ~[bool] { vec::from_fn(self.nbits, |i| self[i]) } @@ -485,7 +483,7 @@ impl Bitv { * The uint vector is expected to only contain the values 0u and 1u. Both * the bitvector and vector must have the same length */ - fn eq_vec(v: ~[uint]) -> bool { + fn eq_vec(&self, v: ~[uint]) -> bool { assert self.nbits == v.len(); let mut i = 0; while i < self.nbits { @@ -497,7 +495,7 @@ impl Bitv { true } - fn ones(f: fn(uint) -> bool) { + fn ones(&self, f: fn(uint) -> bool) { for uint::range(0, self.nbits) |i| { if self.get(i) { if !f(i) { break } @@ -551,7 +549,7 @@ pub fn from_bools(bools: &[bool]) -> Bitv { * index is f(index). */ pub fn from_fn(len: uint, f: fn(index: uint) -> bool) -> Bitv { - let bitv = Bitv(len, false); + let mut bitv = Bitv::new(len, false); for uint::range(0, len) |i| { bitv.set(i, f(i)); } @@ -586,10 +584,10 @@ mod tests { #[test] pub fn test_to_str() { - let zerolen = Bitv(0u, false); + let zerolen = Bitv::new(0u, false); assert zerolen.to_str() == ~""; - let eightbits = Bitv(8u, false); + let eightbits = Bitv::new(8u, false); assert eightbits.to_str() == ~"00000000"; } @@ -597,7 +595,7 @@ mod tests { pub fn test_0_elements() { let mut act; let mut exp; - act = Bitv(0u, false); + act = Bitv::new(0u, false); exp = vec::from_elem::(0u, 0u); assert act.eq_vec(exp); } @@ -605,15 +603,15 @@ mod tests { #[test] pub fn test_1_element() { let mut act; - act = Bitv(1u, false); + act = Bitv::new(1u, false); assert act.eq_vec(~[0u]); - act = Bitv(1u, true); + act = Bitv::new(1u, true); assert act.eq_vec(~[1u]); } #[test] pub fn test_2_elements() { - let b = bitv::Bitv(2, false); + let mut b = bitv::Bitv::new(2, false); b.set(0, true); b.set(1, false); assert b.to_str() == ~"10"; @@ -624,15 +622,15 @@ mod tests { let mut act; // all 0 - act = Bitv(10u, false); + act = Bitv::new(10u, false); assert (act.eq_vec(~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u])); // all 1 - act = Bitv(10u, true); + act = Bitv::new(10u, true); assert (act.eq_vec(~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u])); // mixed - act = Bitv(10u, false); + act = Bitv::new(10u, false); act.set(0u, true); act.set(1u, true); act.set(2u, true); @@ -641,7 +639,7 @@ mod tests { assert (act.eq_vec(~[1u, 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u, 0u])); // mixed - act = Bitv(10u, false); + act = Bitv::new(10u, false); act.set(5u, true); act.set(6u, true); act.set(7u, true); @@ -650,7 +648,7 @@ mod tests { assert (act.eq_vec(~[0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u])); // mixed - act = Bitv(10u, false); + act = Bitv::new(10u, false); act.set(0u, true); act.set(3u, true); act.set(6u, true); @@ -663,21 +661,21 @@ mod tests { let mut act; // all 0 - act = Bitv(31u, false); + act = Bitv::new(31u, false); assert (act.eq_vec( ~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u])); // all 1 - act = Bitv(31u, true); + act = Bitv::new(31u, true); assert (act.eq_vec( ~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u])); // mixed - act = Bitv(31u, false); + act = Bitv::new(31u, false); act.set(0u, true); act.set(1u, true); act.set(2u, true); @@ -692,7 +690,7 @@ mod tests { 0u, 0u, 0u, 0u, 0u])); // mixed - act = Bitv(31u, false); + act = Bitv::new(31u, false); act.set(16u, true); act.set(17u, true); act.set(18u, true); @@ -707,7 +705,7 @@ mod tests { 0u, 0u, 0u, 0u, 0u])); // mixed - act = Bitv(31u, false); + act = Bitv::new(31u, false); act.set(24u, true); act.set(25u, true); act.set(26u, true); @@ -721,7 +719,7 @@ mod tests { 1u, 1u, 1u, 1u, 1u])); // mixed - act = Bitv(31u, false); + act = Bitv::new(31u, false); act.set(3u, true); act.set(17u, true); act.set(30u, true); @@ -736,21 +734,21 @@ mod tests { let mut act; // all 0 - act = Bitv(32u, false); + act = Bitv::new(32u, false); assert (act.eq_vec( ~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u])); // all 1 - act = Bitv(32u, true); + act = Bitv::new(32u, true); assert (act.eq_vec( ~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u])); // mixed - act = Bitv(32u, false); + act = Bitv::new(32u, false); act.set(0u, true); act.set(1u, true); act.set(2u, true); @@ -765,7 +763,7 @@ mod tests { 0u, 0u, 0u, 0u, 0u, 0u])); // mixed - act = Bitv(32u, false); + act = Bitv::new(32u, false); act.set(16u, true); act.set(17u, true); act.set(18u, true); @@ -780,7 +778,7 @@ mod tests { 0u, 0u, 0u, 0u, 0u, 0u])); // mixed - act = Bitv(32u, false); + act = Bitv::new(32u, false); act.set(24u, true); act.set(25u, true); act.set(26u, true); @@ -795,7 +793,7 @@ mod tests { 1u, 1u, 1u, 1u, 1u, 1u])); // mixed - act = Bitv(32u, false); + act = Bitv::new(32u, false); act.set(3u, true); act.set(17u, true); act.set(30u, true); @@ -811,21 +809,21 @@ mod tests { let mut act; // all 0 - act = Bitv(33u, false); + act = Bitv::new(33u, false); assert (act.eq_vec( ~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u])); // all 1 - act = Bitv(33u, true); + act = Bitv::new(33u, true); assert (act.eq_vec( ~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u])); // mixed - act = Bitv(33u, false); + act = Bitv::new(33u, false); act.set(0u, true); act.set(1u, true); act.set(2u, true); @@ -840,7 +838,7 @@ mod tests { 0u, 0u, 0u, 0u, 0u, 0u, 0u])); // mixed - act = Bitv(33u, false); + act = Bitv::new(33u, false); act.set(16u, true); act.set(17u, true); act.set(18u, true); @@ -855,7 +853,7 @@ mod tests { 0u, 0u, 0u, 0u, 0u, 0u, 0u])); // mixed - act = Bitv(33u, false); + act = Bitv::new(33u, false); act.set(24u, true); act.set(25u, true); act.set(26u, true); @@ -870,7 +868,7 @@ mod tests { 1u, 1u, 1u, 1u, 1u, 1u, 0u])); // mixed - act = Bitv(33u, false); + act = Bitv::new(33u, false); act.set(3u, true); act.set(17u, true); act.set(30u, true); @@ -884,24 +882,24 @@ mod tests { #[test] pub fn test_equal_differing_sizes() { - let v0 = Bitv(10u, false); - let v1 = Bitv(11u, false); + let v0 = Bitv::new(10u, false); + let v1 = Bitv::new(11u, false); assert !v0.equal(&v1); } #[test] pub fn test_equal_greatly_differing_sizes() { - let v0 = Bitv(10u, false); - let v1 = Bitv(110u, false); + let v0 = Bitv::new(10u, false); + let v1 = Bitv::new(110u, false); assert !v0.equal(&v1); } #[test] pub fn test_equal_sneaky_small() { - let a = bitv::Bitv(1, false); + let mut a = bitv::Bitv::new(1, false); a.set(0, true); - let b = bitv::Bitv(1, true); + let mut b = bitv::Bitv::new(1, true); b.set(0, true); assert a.equal(&b); @@ -909,12 +907,12 @@ mod tests { #[test] pub fn test_equal_sneaky_big() { - let a = bitv::Bitv(100, false); + let mut a = bitv::Bitv::new(100, false); for uint::range(0, 100) |i| { a.set(i, true); } - let b = bitv::Bitv(100, true); + let mut b = bitv::Bitv::new(100, true); for uint::range(0, 100) |i| { b.set(i, true); } @@ -931,11 +929,11 @@ mod tests { #[test] pub fn test_to_bytes() { - let bv = Bitv(3, true); + let mut bv = Bitv::new(3, true); bv.set(1, false); assert bv.to_bytes() == ~[0b10100000]; - let bv = Bitv(9, false); + let mut bv = Bitv::new(9, false); bv.set(2, true); bv.set(8, true); assert bv.to_bytes() == ~[0b00100000, 0b10000000]; @@ -954,8 +952,8 @@ mod tests { #[test] pub fn test_small_difference() { - let b1 = Bitv(3, false); - let b2 = Bitv(3, false); + let mut b1 = Bitv::new(3, false); + let mut b2 = Bitv::new(3, false); b1.set(0, true); b1.set(1, true); b2.set(1, true); @@ -968,8 +966,8 @@ mod tests { #[test] pub fn test_big_difference() { - let b1 = Bitv(100, false); - let b2 = Bitv(100, false); + let mut b1 = Bitv::new(100, false); + let mut b2 = Bitv::new(100, false); b1.set(0, true); b1.set(40, true); b2.set(40, true); @@ -982,7 +980,7 @@ mod tests { #[test] pub fn test_small_clear() { - let b = Bitv(14, true); + let mut b = Bitv::new(14, true); b.clear(); for b.ones |i| { fail!(fmt!("found 1 at %?", i)); @@ -991,7 +989,7 @@ mod tests { #[test] pub fn test_big_clear() { - let b = Bitv(140, true); + let mut b = Bitv::new(140, true); b.clear(); for b.ones |i| { fail!(fmt!("found 1 at %?", i)); diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs index c690c89c025..a7f01d75648 100644 --- a/src/libsyntax/ext/pipes/liveness.rs +++ b/src/libsyntax/ext/pipes/liveness.rs @@ -43,13 +43,13 @@ use ext::base::ext_ctxt; use ext::pipes::proto::protocol; use core::str; -use std::bitv::{Bitv}; +use std::bitv::Bitv; pub fn analyze(proto: protocol, _cx: ext_ctxt) { debug!("initializing colive analysis"); let num_states = proto.num_states(); - let colive = do (copy proto.states).map_to_vec |state| { - let bv = ~Bitv(num_states, false); + let mut colive = do (copy proto.states).map_to_vec |state| { + let mut bv = ~Bitv::new(num_states, false); for state.reachable |s| { bv.set(s.id, true); } @@ -61,15 +61,19 @@ pub fn analyze(proto: protocol, _cx: ext_ctxt) { while changed { changed = false; debug!("colive iteration %?", i); + let mut new_colive = ~[]; for colive.eachi |i, this_colive| { + let mut result = ~this_colive.clone(); let this = proto.get_state_by_id(i); for this_colive.ones |j| { let next = proto.get_state_by_id(j); if this.dir == next.dir { - changed = changed || this_colive.union(colive[j]); + changed = result.union(colive[j]) || changed; } } + new_colive.push(result) } + colive = new_colive; i += 1; } diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 885eaf01c44..a3a3ef85f45 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -58,7 +58,7 @@ pub fn solve_grid(g: grid_t) { fn next_color(mut g: grid, row: u8, col: u8, start_color: u8) -> bool { if start_color < 10u8 { // colors not yet used - let avail = bitv::Bitv(10u, false); + let mut avail = bitv::Bitv::new(10u, false); for u8::range(start_color, 10u8) |color| { avail.set(color as uint, true); } @@ -80,7 +80,7 @@ pub fn solve_grid(g: grid_t) { // find colors available in neighbourhood of (row, col) fn drop_colors(g: grid, avail: bitv::Bitv, row: u8, col: u8) { - fn drop_color(g: grid, colors: bitv::Bitv, row: u8, col: u8) { + fn drop_color(g: grid, mut colors: bitv::Bitv, row: u8, col: u8) { let color = g[row][col]; if color != 0u8 { colors.set(color as uint, false); } } diff --git a/src/test/run-pass/bitv-perf-test.rs b/src/test/run-pass/bitv-perf-test.rs index 097db4436fd..6cb0cf4e377 100644 --- a/src/test/run-pass/bitv-perf-test.rs +++ b/src/test/run-pass/bitv-perf-test.rs @@ -14,8 +14,8 @@ extern mod std; use std::bitv::*; fn bitv_test() -> bool { - let v1 = ~Bitv(31, false); - let v2 = ~Bitv(31, true); + let mut v1 = ~Bitv::new(31, false); + let v2 = ~Bitv::new(31, true); v1.union(v2); true } From a01ef8ef87d9697307c5d4fec4d1fa1ede0d65ae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 17 Feb 2013 17:54:18 -0500 Subject: [PATCH 2/6] Change SmallBitv to use uint instead of u32 --- src/libstd/bitv.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index c72f9ec2f98..4d995c733be 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -16,25 +16,25 @@ use core::vec; struct SmallBitv { /// only the lowest nbits of this value are used. the rest is undefined. - bits: u32 + bits: uint } /// a mask that has a 1 for each defined bit in a small_bitv, assuming n bits #[inline(always)] -fn small_mask(nbits: uint) -> u32 { +fn small_mask(nbits: uint) -> uint { (1 << nbits) - 1 } impl SmallBitv { - static fn new(bits: u32) -> SmallBitv { + static fn new(bits: uint) -> SmallBitv { SmallBitv {bits: bits} } #[inline(always)] - fn bits_op(&mut self, right_bits: u32, nbits: uint, - f: fn(u32, u32) -> u32) -> bool { + fn bits_op(&mut self, right_bits: uint, nbits: uint, + f: fn(uint, uint) -> uint) -> bool { let mask = small_mask(nbits); - let old_b: u32 = self.bits; + let old_b: uint = self.bits; let new_b = f(old_b, right_bits); self.bits = new_b; mask & old_b != mask & new_b @@ -71,7 +71,7 @@ impl SmallBitv { self.bits |= 1< Bitv { - let rep = if nbits <= 32 { + let rep = if nbits <= uint::bits { Small(~SmallBitv::new(if init {!0} else {0})) } else { From dc7e6abab78124ffdec7568afe5297eded1f1966 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 17 Feb 2013 17:56:07 -0500 Subject: [PATCH 3/6] Remove the 'uint_bits' constant in bitv --- src/libstd/bitv.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 4d995c733be..87cdc04eb0d 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -112,8 +112,8 @@ struct BigBitv { */ #[inline(always)] fn big_mask(nbits: uint, elem: uint) -> uint { - let rmd = nbits % uint_bits; - let nelems = nbits/uint_bits + if rmd == 0 {0} else {1}; + let rmd = nbits % uint::bits; + let nelems = nbits/uint::bits + if rmd == 0 {0} else {1}; if elem < nelems - 1 || rmd == 0 { !0 @@ -184,16 +184,16 @@ impl BigBitv { #[inline(always)] pure fn get(&self, i: uint) -> bool { - let w = i / uint_bits; - let b = i % uint_bits; + let w = i / uint::bits; + let b = i % uint::bits; let x = 1 & self.storage[w] >> b; x == 1 } #[inline(always)] fn set(&mut self, i: uint, x: bool) { - let w = i / uint_bits; - let b = i % uint_bits; + let w = i / uint::bits; + let b = i % uint::bits; let flag = 1 << b; self.storage[w] = if x { self.storage[w] | flag } else { self.storage[w] & !flag }; @@ -263,8 +263,8 @@ impl Bitv { Small(~SmallBitv::new(if init {!0} else {0})) } else { - let nelems = nbits/uint_bits + - if nbits % uint_bits == 0 {0} else {1}; + let nelems = nbits/uint::bits + + if nbits % uint::bits == 0 {0} else {1}; let elem = if init {!0} else {0}; let s = from_elem(nelems, elem); Big(~BigBitv::new(s)) @@ -514,7 +514,7 @@ impl Clone for Bitv { Bitv{nbits: self.nbits, rep: Small(~SmallBitv{bits: b.bits})} } Big(ref b) => { - let mut st = from_elem(self.nbits / uint_bits + 1, 0); + let mut st = from_elem(self.nbits / uint::bits + 1, 0); let len = st.len(); for uint::range(0, len) |i| { st[i] = b.storage[i]; }; Bitv{nbits: self.nbits, rep: Big(~BigBitv{storage: st})} @@ -556,8 +556,6 @@ pub fn from_fn(len: uint, f: fn(index: uint) -> bool) -> Bitv { bitv } -const uint_bits: uint = 32u + (1u << 32u >> 27u); - pure fn lor(w0: uint, w1: uint) -> uint { return w0 | w1; } pure fn land(w0: uint, w1: uint) -> uint { return w0 & w1; } From 393a4b41f60612f234394b58b8e3bf3261ca9566 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 17 Feb 2013 17:58:55 -0500 Subject: [PATCH 4/6] Favor local closures instead of global functions --- src/libstd/bitv.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 87cdc04eb0d..c01e0d9d94c 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -164,22 +164,22 @@ impl BigBitv { #[inline(always)] fn union(&mut self, b: &BigBitv, nbits: uint) -> bool { - self.process(b, nbits, lor) + self.process(b, nbits, |w1, w2| w1 | w2) } #[inline(always)] fn intersect(&mut self, b: &BigBitv, nbits: uint) -> bool { - self.process(b, nbits, land) + self.process(b, nbits, |w1, w2| w1 & w2) } #[inline(always)] fn become(&mut self, b: &BigBitv, nbits: uint) -> bool { - self.process(b, nbits, right) + self.process(b, nbits, |_, w| w) } #[inline(always)] fn difference(&mut self, b: &BigBitv, nbits: uint) -> bool { - self.process(b, nbits, difference) + self.process(b, nbits, |w1, w2| w1 & !w2) } #[inline(always)] @@ -556,13 +556,9 @@ pub fn from_fn(len: uint, f: fn(index: uint) -> bool) -> Bitv { bitv } -pure fn lor(w0: uint, w1: uint) -> uint { return w0 | w1; } -pure fn land(w0: uint, w1: uint) -> uint { return w0 & w1; } -pure fn difference(w0: uint, w1: uint) -> uint { return w0 & !w1; } -pure fn right(_w0: uint, w1: uint) -> uint { return w1; } impl ops::Index for Bitv { pure fn index(&self, i: uint) -> bool { From bf8ed45adc485e0e8e678e7b43b0c67ff93392f5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 17 Feb 2013 20:01:47 -0500 Subject: [PATCH 5/6] Implement Set container on top of a bit vector --- src/libstd/bitv.rs | 512 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 471 insertions(+), 41 deletions(-) diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index c01e0d9d94c..955729ed2fe 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::container::{Container, Mutable, Set}; +use core::num::NumCast; use core::ops; use core::prelude::*; use core::uint; -use core::vec::{cast_to_mut, from_elem}; +use core::vec::from_elem; use core::vec; struct SmallBitv { @@ -133,18 +135,15 @@ impl BigBitv { let len = b.storage.len(); assert (self.storage.len() == len); let mut changed = false; - do uint::range(0, len) |i| { + for uint::range(0, len) |i| { let mask = big_mask(nbits, i); let w0 = self.storage[i] & mask; let w1 = b.storage[i] & mask; let w = op(w0, w1) & mask; if w0 != w { - unsafe { - changed = true; - self.storage[i] = w; - } + changed = true; + self.storage[i] = w; } - true } changed } @@ -556,16 +555,317 @@ pub fn from_fn(len: uint, f: fn(index: uint) -> bool) -> Bitv { bitv } - - - - impl ops::Index for Bitv { pure fn index(&self, i: uint) -> bool { self.get(i) } } +#[inline(always)] +pure fn iterate_bits(base: uint, bits: uint, f: fn(uint) -> bool) -> bool { + if bits == 0 { + return true; + } + for uint::range(0, uint::bits) |i| { + if bits & (1 << i) != 0 { + if !f(base + i) { + return false; + } + } + } + return true; +} + +/// 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. +pub struct BitvSet { + priv size: uint, + + // In theory this is a Bitv instead of always a BigBitv, but knowing that + // there's an array of storage makes our lives a whole lot easier when + // performing union/intersection/etc operations + priv bitv: BigBitv +} + +impl BitvSet { + /// Creates a new bit vector set with initially no contents + static fn new() -> BitvSet { + BitvSet{ size: 0, bitv: BigBitv::new(~[0]) } + } + + /// Creates a new bit vector set from the given bit vector + static fn from_bitv(bitv: Bitv) -> BitvSet { + let mut size = 0; + for bitv.ones |_| { + size += 1; + } + let Bitv{rep, _} = bitv; + match rep { + Big(~b) => BitvSet{ size: size, bitv: b }, + Small(~SmallBitv{bits}) => + BitvSet{ size: size, bitv: BigBitv{ storage: ~[bits] } }, + } + } + + /// Returns the capacity in bits for this bit vector. Inserting any + /// element less than this amount will not trigger a resizing. + pure fn capacity(&self) -> uint { self.bitv.storage.len() * uint::bits } + + /// Consumes this set to return the underlying bit vector + fn unwrap(self) -> Bitv { + let cap = self.capacity(); + let BitvSet{bitv, _} = self; + return Bitv{ nbits:cap, rep: Big(~bitv) }; + } + + #[inline(always)] + priv fn other_op(&mut self, other: &BitvSet, f: fn(uint, uint) -> uint) { + fn nbits(mut w: uint) -> uint { + let mut bits = 0; + for uint::bits.times { + if w == 0 { + break; + } + bits += w & 1; + w >>= 1; + } + return bits; + } + if self.capacity() < other.capacity() { + self.bitv.storage.grow(other.capacity() / uint::bits, &0); + } + for other.bitv.storage.eachi |i, &w| { + let old = self.bitv.storage[i]; + let new = f(old, w); + self.bitv.storage[i] = new; + self.size += nbits(new) - nbits(old); + } + } + + /// Union in-place with the specified other bit vector + fn union_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 | w2); + } + + /// Intersect in-place with the specified other bit vector + fn intersect_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 & w2); + } + + /// Difference in-place with the specified other bit vector + fn difference_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 & !w2); + } + + /// Symmetric difference in-place with the specified other bit vector + fn symmetric_difference_with(&mut self, other: &BitvSet) { + self.other_op(other, |w1, w2| w1 ^ w2); + } +} + +impl BaseIter for BitvSet { + pure fn size_hint(&self) -> Option { Some(self.len()) } + + pure fn each(&self, blk: fn(v: &uint) -> bool) { + for self.bitv.storage.eachi |i, &w| { + if !iterate_bits(i * uint::bits, w, |b| blk(&b)) { + return; + } + } + } +} + +impl cmp::Eq for BitvSet { + pure fn eq(&self, other: &BitvSet) -> bool { + if self.size != other.size { + return false; + } + for self.each_common(other) |_, w1, w2| { + if w1 != w2 { + return false; + } + } + for self.each_outlier(other) |_, _, w| { + if w != 0 { + return false; + } + } + return true; + } + + pure fn ne(&self, other: &BitvSet) -> bool { !self.eq(other) } +} + +impl Container for BitvSet { + pure fn len(&self) -> uint { self.size } + pure fn is_empty(&self) -> bool { self.size == 0 } +} + +impl Mutable for BitvSet { + fn clear(&mut self) { + for self.bitv.each_storage |w| { *w = 0; } + self.size = 0; + } +} + +impl Set for BitvSet { + pure fn contains(&self, value: &uint) -> bool { + *value < self.bitv.storage.len() * uint::bits && self.bitv.get(*value) + } + + fn insert(&mut self, value: uint) -> bool { + if self.contains(&value) { + return false; + } + let nbits = self.capacity(); + if value >= nbits { + let newsize = uint::max(value, nbits * 2) / uint::bits + 1; + assert newsize > self.bitv.storage.len(); + self.bitv.storage.grow(newsize, &0); + } + self.size += 1; + self.bitv.set(value, true); + return true; + } + + fn remove(&mut self, value: &uint) -> bool { + if !self.contains(value) { + return false; + } + self.size -= 1; + self.bitv.set(*value, false); + + // Attempt to truncate our storage + let mut i = self.bitv.storage.len(); + while i > 1 && self.bitv.storage[i - 1] == 0 { + i -= 1; + } + self.bitv.storage.truncate(i); + + return true; + } + + pure fn is_disjoint(&self, other: &BitvSet) -> bool { + for self.intersection(other) |_| { + return false; + } + return true; + } + + pure fn is_subset(&self, other: &BitvSet) -> bool { + for self.each_common(other) |_, w1, w2| { + if w1 & w2 != w1 { + return false; + } + } + /* If anything is not ours, then everything is not ours so we're + definitely a subset in that case. Otherwise if there's any stray + ones that 'other' doesn't have, we're not a subset. */ + for self.each_outlier(other) |mine, _, w| { + if !mine { + return true; + } else if w != 0 { + return false; + } + } + return true; + } + + pure fn is_superset(&self, other: &BitvSet) -> bool { + other.is_subset(self) + } + + pure fn difference(&self, other: &BitvSet, f: fn(&uint) -> bool) { + for self.each_common(other) |i, w1, w2| { + if !iterate_bits(i, w1 & !w2, |b| f(&b)) { + return; + } + } + /* everything we have that they don't also shows up */ + self.each_outlier(other, |mine, i, w| + !mine || iterate_bits(i, w, |b| f(&b)) + ); + } + + pure fn symmetric_difference(&self, other: &BitvSet, + f: fn(&uint) -> bool) { + for self.each_common(other) |i, w1, w2| { + if !iterate_bits(i, w1 ^ w2, |b| f(&b)) { + return; + } + } + self.each_outlier(other, |_, i, w| + iterate_bits(i, w, |b| f(&b)) + ); + } + + pure fn intersection(&self, other: &BitvSet, f: fn(&uint) -> bool) { + for self.each_common(other) |i, w1, w2| { + if !iterate_bits(i, w1 & w2, |b| f(&b)) { + return; + } + } + } + + pure fn union(&self, other: &BitvSet, f: fn(&uint) -> bool) { + for self.each_common(other) |i, w1, w2| { + if !iterate_bits(i, w1 | w2, |b| f(&b)) { + return; + } + } + self.each_outlier(other, |_, i, w| + iterate_bits(i, w, |b| f(&b)) + ); + } +} + +priv impl BitvSet { + /// Visits each of the words that the two bit vectors (self and other) + /// both have in common. The three yielded arguments are (bit location, + /// w1, w2) where the bit location is the number of bits offset so far, + /// and w1/w2 are the words coming from the two vectors self, other. + pure fn each_common(&self, other: &BitvSet, + f: fn(uint, uint, uint) -> bool) { + let min = uint::min(self.bitv.storage.len(), + other.bitv.storage.len()); + for self.bitv.storage.view(0, min).eachi |i, &w| { + if !f(i * uint::bits, w, other.bitv.storage[i]) { + return; + } + } + } + + /// Visits each word in self or other that extends beyond the other. This + /// will only iterate through one of the vectors, and it only iterates + /// over the portion that doesn't overlap with the other one. + /// + /// The yielded arguments are a bool, the bit offset, and a word. The bool + /// is true if the word comes from 'self', and false if it comes from + /// 'other'. + pure fn each_outlier(&self, other: &BitvSet, + f: fn(bool, uint, uint) -> bool) { + let len1 = self.bitv.storage.len(); + let len2 = other.bitv.storage.len(); + let min = uint::min(len1, len2); + + /* only one of these loops will execute and that's the point */ + for self.bitv.storage.view(min, len1).eachi |i, &w| { + if !f(true, (i + min) * uint::bits, w) { + return; + } + } + for other.bitv.storage.view(min, len2).eachi |i, &w| { + if !f(false, (i + min) * uint::bits, w) { + return; + } + } + } +} + #[cfg(test)] mod tests { use core::prelude::*; @@ -946,48 +1246,178 @@ mod tests { #[test] pub fn test_small_difference() { - let mut b1 = Bitv::new(3, false); - let mut b2 = Bitv::new(3, false); - b1.set(0, true); - b1.set(1, true); - b2.set(1, true); - b2.set(2, true); - assert b1.difference(&b2); - assert b1[0]; - assert !b1[1]; - assert !b1[2]; + let mut b1 = Bitv::new(3, false); + let mut b2 = Bitv::new(3, false); + b1.set(0, true); + b1.set(1, true); + b2.set(1, true); + b2.set(2, true); + assert b1.difference(&b2); + assert b1[0]; + assert !b1[1]; + assert !b1[2]; } #[test] pub fn test_big_difference() { - let mut b1 = Bitv::new(100, false); - let mut b2 = Bitv::new(100, false); - b1.set(0, true); - b1.set(40, true); - b2.set(40, true); - b2.set(80, true); - assert b1.difference(&b2); - assert b1[0]; - assert !b1[40]; - assert !b1[80]; + let mut b1 = Bitv::new(100, false); + let mut b2 = Bitv::new(100, false); + b1.set(0, true); + b1.set(40, true); + b2.set(40, true); + b2.set(80, true); + assert b1.difference(&b2); + assert b1[0]; + assert !b1[40]; + assert !b1[80]; } #[test] pub fn test_small_clear() { - let mut b = Bitv::new(14, true); - b.clear(); - for b.ones |i| { - fail!(fmt!("found 1 at %?", i)); - } + let mut b = Bitv::new(14, true); + b.clear(); + for b.ones |i| { + fail!(fmt!("found 1 at %?", i)); + } } #[test] pub fn test_big_clear() { - let mut b = Bitv::new(140, true); - b.clear(); - for b.ones |i| { - fail!(fmt!("found 1 at %?", i)); - } + let mut b = Bitv::new(140, true); + b.clear(); + for b.ones |i| { + fail!(fmt!("found 1 at %?", i)); + } + } + + #[test] + pub fn test_bitv_set_basic() { + let mut b = BitvSet::new(); + assert b.insert(3); + assert !b.insert(3); + assert b.contains(&3); + assert b.insert(400); + assert !b.insert(400); + assert b.contains(&400); + assert b.len() == 2; + } + + #[test] + fn test_bitv_set_intersection() { + let mut a = BitvSet::new(); + let mut b = BitvSet::new(); + + assert a.insert(11); + assert a.insert(1); + assert a.insert(3); + assert a.insert(77); + assert a.insert(103); + assert a.insert(5); + + assert b.insert(2); + assert b.insert(11); + assert b.insert(77); + assert b.insert(5); + assert b.insert(3); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for a.intersection(&b) |x| { + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); + } + + #[test] + fn test_bitv_set_difference() { + let mut a = BitvSet::new(); + let mut b = BitvSet::new(); + + assert a.insert(1); + assert a.insert(3); + assert a.insert(5); + assert a.insert(200); + assert a.insert(500); + + assert b.insert(3); + assert b.insert(200); + + let mut i = 0; + let expected = [1, 5, 500]; + for a.difference(&b) |x| { + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); + } + + #[test] + fn test_bitv_set_symmetric_difference() { + let mut a = BitvSet::new(); + let mut b = BitvSet::new(); + + assert a.insert(1); + assert a.insert(3); + assert a.insert(5); + assert a.insert(9); + assert a.insert(11); + + assert b.insert(3); + assert b.insert(9); + assert b.insert(14); + assert b.insert(220); + + let mut i = 0; + let expected = [1, 5, 11, 14, 220]; + for a.symmetric_difference(&b) |x| { + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); + } + + #[test] + pub fn test_bitv_set_union() { + let mut a = BitvSet::new(); + let mut b = BitvSet::new(); + assert a.insert(1); + assert a.insert(3); + assert a.insert(5); + assert a.insert(9); + assert a.insert(11); + assert a.insert(160); + assert a.insert(19); + assert a.insert(24); + + assert b.insert(1); + assert b.insert(5); + assert b.insert(9); + assert b.insert(13); + assert b.insert(19); + + let mut i = 0; + let expected = [1, 3, 5, 9, 11, 13, 19, 24, 160]; + for a.union(&b) |x| { + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); + } + + #[test] + pub fn test_bitv_remove() { + let mut a = BitvSet::new(); + + assert a.insert(1); + assert a.remove(&1); + + assert a.insert(100); + assert a.remove(&100); + + assert a.insert(1000); + assert a.remove(&1000); + assert a.capacity() == uint::bits; } } From cf2ddf0437e347be4fb830772421ef1534cdab0e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 18 Feb 2013 01:24:14 -0500 Subject: [PATCH 6/6] Add benchmarks to measure differences in bit vectors --- src/libstd/bitv.rs | 92 +++++++++++++++++++ src/test/bench/core-set.rs | 180 +++++++++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 src/test/bench/core-set.rs diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 955729ed2fe..5ba10a9eb14 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -869,12 +869,16 @@ priv impl BitvSet { #[cfg(test)] mod tests { use core::prelude::*; + use std::test::BenchHarness; use bitv::*; use bitv; use core::uint; use core::vec; + use core::rand; + + const bench_bits : uint = 1 << 14; #[test] pub fn test_to_str() { @@ -1419,6 +1423,94 @@ mod tests { assert a.remove(&1000); assert a.capacity() == uint::bits; } + + fn rng() -> rand::Rng { + let seed = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + rand::seeded_rng(&seed) + } + + #[bench] + pub fn bench_uint_small(b: &mut BenchHarness) { + let r = rng(); + let mut bitv = 0 as uint; + do b.iter { + bitv |= (1 << ((r.next() as uint) % uint::bits)); + } + } + + #[bench] + pub fn bench_small_bitv_small(b: &mut BenchHarness) { + let r = rng(); + let mut bitv = SmallBitv::new(uint::bits); + do b.iter { + bitv.set((r.next() as uint) % uint::bits, true); + } + } + + #[bench] + pub fn bench_big_bitv_small(b: &mut BenchHarness) { + let r = rng(); + let mut bitv = BigBitv::new(~[0]); + do b.iter { + bitv.set((r.next() as uint) % uint::bits, true); + } + } + + #[bench] + pub fn bench_big_bitv_big(b: &mut BenchHarness) { + let r = rng(); + let mut storage = ~[]; + storage.grow(bench_bits / uint::bits, &0); + let mut bitv = BigBitv::new(storage); + do b.iter { + bitv.set((r.next() as uint) % bench_bits, true); + } + } + + #[bench] + pub fn bench_bitv_big(b: &mut BenchHarness) { + let r = rng(); + let mut bitv = Bitv::new(bench_bits, false); + do b.iter { + bitv.set((r.next() as uint) % bench_bits, true); + } + } + + #[bench] + pub fn bench_bitv_small(b: &mut BenchHarness) { + let r = rng(); + let mut bitv = Bitv::new(uint::bits, false); + do b.iter { + bitv.set((r.next() as uint) % uint::bits, true); + } + } + + #[bench] + pub fn bench_bitv_set_small(b: &mut BenchHarness) { + let r = rng(); + let mut bitv = BitvSet::new(); + do b.iter { + bitv.insert((r.next() as uint) % uint::bits); + } + } + + #[bench] + pub fn bench_bitv_set_big(b: &mut BenchHarness) { + let r = rng(); + let mut bitv = BitvSet::new(); + do b.iter { + bitv.insert((r.next() as uint) % bench_bits); + } + } + + #[bench] + pub fn bench_bitv_big_union(b: &mut BenchHarness) { + let mut b1 = Bitv::new(bench_bits, false); + let mut b2 = Bitv::new(bench_bits, false); + do b.iter { + b1.union(&b2); + } + } } // diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs new file mode 100644 index 00000000000..cfb27329174 --- /dev/null +++ b/src/test/bench/core-set.rs @@ -0,0 +1,180 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern mod std; +use core::hashmap::linear::LinearSet; +use std::bitv::BitvSet; +use std::treemap::TreeSet; +use core::io::WriterUtil; + +struct Results { + sequential_ints: float, + random_ints: float, + delete_ints: float, + + sequential_strings: float, + random_strings: float, + delete_strings: float +} + +fn timed(result: &mut float, op: fn()) { + let start = std::time::precise_time_s(); + op(); + let end = std::time::precise_time_s(); + *result = (end - start); +} + +impl Results { + fn bench_int>(&mut self, rng: @rand::Rng, num_keys: uint, + rand_cap: uint, f: fn() -> T) { + { + let mut set = f(); + do timed(&mut self.sequential_ints) { + for uint::range(0, num_keys) |i| { + set.insert(i); + } + + for uint::range(0, num_keys) |i| { + assert set.contains(&i); + } + } + } + + { + let mut set = f(); + do timed(&mut self.random_ints) { + for num_keys.times { + set.insert((rng.next() as uint) % rand_cap); + } + } + } + + { + let mut set = f(); + for uint::range(0, num_keys) |i| { + set.insert(i); + } + + do timed(&mut self.delete_ints) { + for uint::range(0, num_keys) |i| { + assert set.remove(&i); + } + } + } + } + + fn bench_str>(&mut self, rng: @rand::Rng, num_keys: uint, + f: fn() -> T) { + { + let mut set = f(); + do timed(&mut self.sequential_strings) { + for uint::range(0, num_keys) |i| { + let s = uint::to_str(i); + set.insert(s); + } + + for uint::range(0, num_keys) |i| { + let s = uint::to_str(i); + assert set.contains(&s); + } + } + } + + { + let mut set = f(); + do timed(&mut self.random_strings) { + for num_keys.times { + let s = uint::to_str(rng.next() as uint); + set.insert(s); + } + } + } + + { + let mut set = f(); + for uint::range(0, num_keys) |i| { + set.insert(uint::to_str(i)); + } + do timed(&mut self.delete_strings) { + for uint::range(0, num_keys) |i| { + assert set.remove(&uint::to_str(i)); + } + } + } + } +} + +fn write_header(header: &str) { + io::stdout().write_str(header); + io::stdout().write_str("\n"); +} + +fn write_row(label: &str, value: float) { + io::stdout().write_str(fmt!("%30s %f s\n", label, value)); +} + +fn write_results(label: &str, results: &Results) { + write_header(label); + write_row("sequential_ints", results.sequential_ints); + write_row("random_ints", results.random_ints); + write_row("delete_ints", results.delete_ints); + write_row("sequential_strings", results.sequential_strings); + write_row("random_strings", results.random_strings); + write_row("delete_strings", results.delete_strings); +} + +fn empty_results() -> Results { + Results { + sequential_ints: 0f, + random_ints: 0f, + delete_ints: 0f, + + sequential_strings: 0f, + random_strings: 0f, + delete_strings: 0f, + } +} + +fn main() { + let args = os::args(); + let num_keys = { + if args.len() == 2 { + uint::from_str(args[1]).get() + } else { + 100 // woefully inadequate for any real measurement + } + }; + + let seed = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let max = 200000; + + { + let rng = rand::seeded_rng(&seed); + let mut results = empty_results(); + results.bench_int(rng, num_keys, max, || LinearSet::new::()); + results.bench_str(rng, num_keys, || LinearSet::new::<~str>()); + write_results("core::hashmap::LinearSet", &results); + } + + { + let rng = rand::seeded_rng(&seed); + let mut results = empty_results(); + results.bench_int(rng, num_keys, max, || TreeSet::new::()); + results.bench_str(rng, num_keys, || TreeSet::new::<~str>()); + write_results("std::treemap::TreeSet", &results); + } + + { + let rng = rand::seeded_rng(&seed); + let mut results = empty_results(); + results.bench_int(rng, num_keys, max, || BitvSet::new()); + write_results("std::bitv::BitvSet", &results); + } +}