From 082d8314da6b6b99854f0a70f5ea8e27f2602f79 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Sun, 29 Jul 2012 16:00:55 -0700
Subject: [PATCH] Rewrite bitv to use classes and optimize its representation

Rewrote bitv as a class that uses a 32-bit int as its representation
for bit vectors of 32 bits or less, and a vector (the old representation)
otherwise. I didn't benchmark very much, but a bit of informal benchmarking
suggested this is a win.

Closes #2341
---
 src/libstd/bitv.rs                            | 824 +++++++++++-------
 src/libsyntax/ext/pipes/liveness.rs           |   4 +-
 src/rustc/middle/tstate/ann.rs                |  68 +-
 src/rustc/middle/tstate/auxiliary.rs          |  24 +-
 .../middle/tstate/pre_post_conditions.rs      |   4 +-
 src/rustc/middle/tstate/states.rs             |  36 +-
 src/rustc/middle/tstate/tritv.rs              | 326 ++++---
 src/test/bench/sudoku.rs                      |   6 +-
 src/test/compile-fail/for-loop-decl.rs        |   4 +-
 src/test/run-pass/bitv-perf-test.rs           |  13 +
 10 files changed, 726 insertions(+), 583 deletions(-)
 create mode 100644 src/test/run-pass/bitv-perf-test.rs

diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs
index 145ceba4ae5..a9b3910ec19 100644
--- a/src/libstd/bitv.rs
+++ b/src/libstd/bitv.rs
@@ -1,3 +1,5 @@
+import vec::{to_mut, from_elem};
+
 export bitv;
 export union;
 export intersect;
@@ -17,94 +19,265 @@ export to_str;
 export eq_vec;
 export methods;
 
-// FIXME (#2341): With recursive object types, we could implement binary
-// methods like union, intersection, and difference. At that point, we could
-// write an optimizing version of this module that produces a different obj
-// for the case where nbits <= 32.
-
-/// The bitvector type
-type bitv = {storage: ~[mut uint], nbits: uint};
-
-#[cfg(target_arch="x86")]
-const uint_bits: uint = 32;
-#[cfg(target_arch="x86_64")]
-const uint_bits: uint = 64;
-
-/**
- * Constructs a bitvector
- *
- * # Arguments
- *
- * * nbits - The number of bits in the bitvector
- * * init - If true then the bits are initialized to 1, otherwise 0
- */
-fn bitv(nbits: uint, init: bool) -> bitv {
-    let elt = if init { !0u } else { 0u };
-    let storage = vec::to_mut(vec::from_elem(nbits / uint_bits + 1u, elt));
-    ret {storage: storage, nbits: nbits};
+class small_bitv {
+    let mut bits: u32;
+    new(bits: u32) { self.bits = bits; }
+    priv {
+        #[inline(always)]
+        fn bits_op(right_bits: u32, f: fn(u32, u32) -> u32) -> bool {
+            let old_b: u32 = self.bits;
+            let new_b = f(old_b, right_bits);
+            self.bits = new_b;
+            old_b != new_b
+        }
+    }
+    #[inline(always)]
+    fn union(s: &small_bitv) -> bool {
+        self.bits_op(s.bits, |u1, u2| { u1 | u2 })
+    }
+    #[inline(always)]
+    fn intersect(s: &small_bitv) -> bool {
+        self.bits_op(s.bits, |u1, u2| { u1 & u2 })
+    }
+    #[inline(always)]
+    fn become(s: &small_bitv) -> bool {
+        let old = self.bits;
+        self.bits = s.bits;
+        old != self.bits
+    }
+    #[inline(always)]
+    fn difference(s: &small_bitv) -> bool {
+        let old = self.bits;
+        self.bits &= !s.bits;
+        old != self.bits
+    }
+    #[inline(always)]
+    pure fn get(i: uint) -> bool {
+        (self.bits & (1 << i)) != 0
+    }
+    #[inline(always)]
+    fn set(i: uint, x: bool) {
+        if x {
+            self.bits |= 1<<i;
+        }
+        else {
+            self.bits &= !(i as u32);
+        }
+    }
+    #[inline(always)]
+    fn equals(b: &small_bitv) -> bool { self.bits == b.bits }
+    #[inline(always)]
+    fn clear() { self.bits = 0; }
+    #[inline(always)]
+    fn set_all() { self.bits = !0; }
+    #[inline(always)]
+    fn is_true() -> bool { self.bits == !0 }
+    #[inline(always)]
+    fn is_false() -> bool { self.bits == 0 }
+    #[inline(always)]
+    fn invert() { self.bits = !self.bits; }
 }
 
-fn process(v0: bitv, v1: bitv, op: fn(uint, uint) -> uint) -> bool {
-    let len = vec::len(v1.storage);
-    assert (vec::len(v0.storage) == len);
-    assert (v0.nbits == v1.nbits);
-    let mut changed = false;
-    for uint::range(0u, len) |i| {
-        let w0 = v0.storage[i];
-        let w1 = v1.storage[i];
-        let w = op(w0, w1);
-        if w0 != w { changed = true; v0.storage[i] = w; }
-    };
-    ret changed;
+class big_bitv {
+// only mut b/c of clone and lack of other constructor
+    let mut storage: ~[mut uint];
+    new(-storage: ~[mut uint]) {
+        self.storage <- storage;
+    }
+    priv {
+        #[inline(always)]
+        fn process(b: &big_bitv, op: fn(uint, uint) -> uint) -> bool {
+            let len = b.storage.len();
+            assert (self.storage.len() == len);
+            let mut changed = false;
+            do uint::range(0, len) |i| {
+                let w0 = self.storage[i];
+                let w1 = b.storage[i];
+                let w = op(w0, w1);
+                if w0 != w unchecked { changed = true; self.storage[i] = w; };
+                true
+            };
+            changed
+        }
+    }
+    #[inline(always)]
+     fn each_storage(op: fn(&uint) -> bool) {
+        for uint::range(0, self.storage.len()) |i| {
+            let mut w = self.storage[i];
+            let b = !op(w);
+            self.storage[i] = w;
+            if !b { break; }
+        }
+     }
+    #[inline(always)]
+    fn invert() { for self.each_storage() |w| { w = !w } }
+    #[inline(always)]
+    fn union(b: &big_bitv)     -> bool { self.process(b, lor) }
+    #[inline(always)]
+    fn intersect(b: &big_bitv) -> bool { self.process(b, land) }
+    #[inline(always)]
+    fn become(b: &big_bitv)    -> bool { self.process(b, right) }
+    #[inline(always)]
+    fn difference(b: &big_bitv) -> bool {
+        self.invert();
+        let b = self.intersect(b);
+        self.invert();
+        b
+    }
+    #[inline(always)]
+    pure fn get(i: uint) -> bool {
+        let w = i / uint_bits;
+        let b = i % uint_bits;
+        let x = 1 & self.storage[w] >> b;
+        x == 1
+    }
+    #[inline(always)]
+    fn set(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 };
+    }
+    #[inline(always)]
+    fn equals(b: &big_bitv) -> bool {
+        let len = b.storage.len();
+        for uint::iterate(0, len) |i| {
+            if self.storage[i] != b.storage[i] { ret false; }
+        }
+    }
 }
 
+enum a_bitv { big(~big_bitv), small(~small_bitv) }
+
+enum op {union, intersect, assign, difference}
+
+// The bitvector type
+class bitv {
+    let rep: a_bitv;
+    let nbits: uint;
+
+    new(nbits: uint, init: bool) {
+        self.nbits = nbits;
+        if nbits <= 32 {
+          self.rep = small(~small_bitv(if init {!0} else {0}));
+        }
+        else {
+          let s = to_mut(from_elem(nbits / uint_bits + 1,
+                                        if init {!0} else {0}));
+          self.rep = big(~big_bitv(s));
+        };
+    }
+
+    priv {
+        fn die() -> ! {
+            fail ~"Tried to do operation on bit vectors with \
+                  different sizes";
+        }
+        #[inline(always)]
+        fn do_op(op: op, other: &bitv) -> bool {
+            if self.nbits != other.nbits {
+                self.die();
+            }
+            alt self.rep {
+              small(s) {
+                alt other.rep {
+                  small(s1) {
+                    alt op {
+                      union      { s.union(s1) }
+                      intersect  { s.intersect(s1) }
+                      assign     { s.become(s1) }
+                      difference { s.difference(s1) }
+                    }
+                  }
+                 big(s1) {
+                     self.die();
+                 }
+              }
+            }
+            big(s) {
+                alt other.rep {
+                  small(_) { self.die(); }
+                  big(s1) {
+                    alt op {
+                      union      { s.union(s1) }
+                      intersect  { s.intersect(s1) }
+                      assign     { s.become(s1) }
+                      difference { s.difference(s1) }
+                    }
+                  }
+                }
+            }
+          }
+        }
+    }
 
 /**
  * Calculates the union of two bitvectors
  *
- * Sets `v0` to the union of `v0` and `v1`. Both bitvectors must be the
- * same length. Returns 'true' if `v0` was changed.
- */
-fn union(v0: bitv, v1: bitv) -> bool {
-    process(v0, v1, |a, b| a | b)
-}
+ * Sets `self` to the union of `self` and `v1`. Both bitvectors must be
+ * the same length. Returns 'true' if `self` changed.
+*/
+    #[inline(always)]
+    fn union(v1: &bitv) -> bool { self.do_op(union, v1) }
 
 /**
  * Calculates the intersection of two bitvectors
  *
- * Sets `v0` to the intersection of `v0` and `v1`. Both bitvectors must be the
- * same length. Returns 'true' if `v0` was changed.
- */
-fn intersect(v0: bitv, v1: bitv) -> bool {
-    process(v0, v1, |a, b| a & b)
-}
-
-fn right(_w0: uint, w1: uint) -> uint { ret w1; }
+ * Sets `self` to the intersection of `self` and `v1`. Both bitvectors must be
+ * the same length. Returns 'true' if `self` changed.
+*/
+    #[inline(always)]
+    fn intersect(v1: &bitv) -> bool { self.do_op(intersect, v1) }
 
 /**
- * Assigns the value of `v1` to `v0`
+ * Assigns the value of `v1` to `self`
  *
- * Both bitvectors must be the same length. Returns `true` if `v0` was changed
+ * Both bitvectors must be the same length. Returns `true` if `self` was
+ * changed
  */
-fn assign(v0: bitv, v1: bitv) -> bool {
-    let sub = right; ret process(v0, v1, sub);
-}
+    #[inline(always)]
+    fn assign(v: &bitv) -> bool { self.do_op(assign, v) }
 
-/// Makes a copy of a bitvector
-fn clone(v: bitv) -> bitv {
-    copy v
-}
+    /// Makes a copy of a bitvector
+    #[inline(always)]
+    fn clone() -> ~bitv {
+        ~alt self.rep {
+          small(b) {
+            bitv{nbits: self.nbits, rep: small(~small_bitv{bits: b.bits})}
+          }
+          big(b) {
+            let st = to_mut(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(~big_bitv{storage: st})}
+          }
+        }
+    }
 
-/// Retrieve the value at index `i`
-#[inline(always)]
-pure fn get(v: bitv, i: uint) -> bool {
-    assert (i < v.nbits);
-    let bits = uint_bits;
-    let w = i / bits;
-    let b = i % bits;
-    let x = 1u & v.storage[w] >> b;
-    ret x == 1u;
-}
+    /// Retrieve the value at index `i`
+    #[inline(always)]
+    pure fn get(i: uint) -> bool {
+       assert (i < self.nbits);
+       alt self.rep {
+         big(b)   { b.get(i) }
+         small(s) { s.get(i) }
+       }
+    }
+
+/**
+ * Set the value of a bit at a given index
+ *
+ * `i` must be less than the length of the bitvector.
+ */
+    #[inline(always)]
+    fn set(i: uint, x: bool) {
+      assert (i < self.nbits);
+      alt self.rep {
+        big(b) { b.set(i, x); }
+        small(s) { s.set(i, x); }
+      }
+    }
 
 /**
  * Compares two bitvectors
@@ -112,25 +285,57 @@ pure fn get(v: bitv, i: uint) -> bool {
  * Both bitvectors must be the same length. Returns `true` if both bitvectors
  * contain identical elements.
  */
-fn equal(v0: bitv, v1: bitv) -> bool {
-    if v0.nbits != v1.nbits { ret false; }
-    let len = vec::len(v1.storage);
-    for uint::iterate(0u, len) |i| {
-        if v0.storage[i] != v1.storage[i] { ret false; }
+    #[inline(always)]
+    fn equal(v1: bitv) -> bool {
+      if self.nbits != v1.nbits { ret false; }
+      alt self.rep {
+        small(b) {
+          alt v1.rep {
+            small(b1) { b.equals(b1) }
+            _ { false }
+          }
+        }
+        big(s) {
+          alt v1.rep {
+            big(s1) {
+              s.equals(s1)
+            }
+            small(_) { ret false; }
+          }
+        }
+      }
     }
-}
 
-/// Set all bits to 0
-#[inline(always)]
-fn clear(v: bitv) { for each_storage(v) |w| { w = 0u } }
+    /// Set all bits to 0
+    #[inline(always)]
+    fn clear() {
+        alt self.rep {
+          small(b) { b.clear(); }
+          big(s) {
+            for s.each_storage() |w| { w = 0u }
+          }
+        }
+    }
 
-/// Set all bits to 1
-#[inline(always)]
-fn set_all(v: bitv) { for each_storage(v) |w| { w = !0u } }
+    /// Set all bits to 1
+    #[inline(always)]
+    fn set_all() {
+      alt self.rep {
+        small(b) { b.set_all(); }
+        big(s) {
+          for s.each_storage() |w| { w = !0u } }
+      }
+    }
 
-/// Invert all bits
-#[inline(always)]
-fn invert(v: bitv) { for each_storage(v) |w| { w = !w } }
+    /// Invert all bits
+    #[inline(always)]
+    fn invert() {
+      alt self.rep {
+        small(b) { b.invert(); }
+        big(s) {
+          for s.each_storage() |w| { w = !w } }
+      }
+    }
 
 /**
  * Calculate the difference between two bitvectors
@@ -140,81 +345,68 @@ fn invert(v: bitv) { for each_storage(v) |w| { w = !w } }
  *
  * Returns `true` if `v0` was changed.
  */
-fn difference(v0: bitv, v1: bitv) -> bool {
-    invert(v1);
-    let b = intersect(v0, v1);
-    invert(v1);
-    ret b;
-}
+   #[inline(always)]
+    fn difference(v: ~bitv) -> bool { self.do_op(difference, v) }
+
+        /// Returns true if all bits are 1
+    #[inline(always)]
+    fn is_true() -> bool {
+      alt self.rep {
+        small(b) { b.is_true() }
+        _ {
+          for self.each() |i| { if !i { ret false; } }
+          true
+        }
+      }
+    }
+
+    #[inline(always)]
+    fn each(f: fn(bool) -> bool) {
+        let mut i = 0;
+        while i < self.nbits {
+            if !f(self.get(i)) { break; }
+            i += 1;
+        }
+    }
+
+    /// Returns true if all bits are 0
+
+    fn is_false() -> bool {
+      alt self.rep {
+        small(b) { b.is_false() }
+        big(_) {
+          for self.each() |i| { if i { ret false; } }
+          true
+        }
+      }
+    }
+
+    fn init_to_vec(i: uint) -> uint {
+      ret if self.get(i) { 1 } else { 0 };
+    }
 
 /**
- * Set the value of a bit at a given index
- *
- * `i` must be less than the length of the bitvector.
- */
-#[inline(always)]
-fn set(v: bitv, i: uint, x: bool) {
-    assert (i < v.nbits);
-    let bits = uint_bits;
-    let w = i / bits;
-    let b = i % bits;
-    let flag = 1u << b;
-    v.storage[w] = if x { v.storage[w] | flag } else { v.storage[w] & !flag };
-}
-
-
-/// Returns true if all bits are 1
-fn is_true(v: bitv) -> bool {
-    for each(v) |i| { if !i { ret false; } }
-    ret true;
-}
-
-
-/// Returns true if all bits are 0
-fn is_false(v: bitv) -> bool {
-    for each(v) |i| { if i { ret false; } }
-    ret true;
-}
-
-/**
- * Converts the bitvector to a vector of uint with the same length.
+ * Converts `self` to a vector of uint with the same length.
  *
  * Each uint in the resulting vector has either value 0u or 1u.
  */
-fn to_vec(v: bitv) -> ~[uint] {
-    vec::from_fn::<uint>(v.nbits, |i| if get(v, i) { 1 } else { 0 })
-}
-
-#[inline(always)]
-fn each(v: bitv, f: fn(bool) -> bool) {
-    let mut i = 0u;
-    while i < v.nbits {
-        if !f(get(v, i)) { break; }
-        i = i + 1u;
+    fn to_vec() -> ~[uint] {
+      let sub = |x| self.init_to_vec(x);
+      ret vec::from_fn::<uint>(self.nbits, sub);
     }
-}
-
-#[inline(always)]
-fn each_storage(v: bitv, op: fn(&uint) -> bool) {
-    for uint::range(0u, vec::len(v.storage)) |i| {
-        let mut w = v.storage[i];
-        let b = !op(w);
-        v.storage[i] = w;
-        if !b { break; }
-    }
-}
 
 /**
- * Converts the bitvector to a string.
+ * Converts `self` to a string.
  *
- * The resulting string has the same length as the bitvector, and each
+ * The resulting string has the same length as `self`, and each
  * character is either '0' or '1'.
  */
-fn to_str(v: bitv) -> ~str {
-    let mut rs = ~"";
-    for each(v) |i| { if i { rs += ~"1"; } else { rs += ~"0"; } }
-    ret rs;
-}
+     fn to_str() -> ~str {
+       let mut rs = ~"";
+       for self.each() |i| { if i { rs += "1"; } else { rs += "0"; } };
+       rs
+     }
+
 
 /**
  * Compare a bitvector to a vector of uint
@@ -222,59 +414,17 @@ fn to_str(v: bitv) -> ~str {
  * 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(v0: bitv, v1: ~[uint]) -> bool {
-    assert (v0.nbits == vec::len::<uint>(v1));
-    let len = v0.nbits;
-    let mut i = 0u;
-    while i < len {
-        let w0 = get(v0, i);
-        let w1 = v1[i];
-        if !w0 && w1 != 0u || w0 && w1 == 0u { ret false; }
-        i = i + 1u;
-    }
-    ret true;
-}
-
-trait methods {
-    fn union(rhs: bitv) -> bool;
-    fn intersect(rhs: bitv) -> bool;
-    fn assign(rhs: bitv) -> bool;
-    pure fn get(i: uint) -> bool;
-    fn [](i: uint) -> bool;
-    fn eq(rhs: bitv) -> bool;
-    fn clear();
-    fn set_all();
-    fn invert();
-    fn difference(rhs: bitv) -> bool;
-    fn set(i: uint, x: bool);
-    fn is_true() -> bool;
-    fn is_false() -> bool;
-    fn to_vec() -> ~[uint];
-    fn each(f: fn(bool) -> bool);
-    fn each_storage(f: fn(&uint) -> bool);
-    fn eq_vec(v: ~[uint]) -> bool;
-
-    fn ones(f: fn(uint) -> bool);
-}
-
-impl of methods for bitv {
-    fn union(rhs: bitv) -> bool { union(self, rhs) }
-    fn intersect(rhs: bitv) -> bool { intersect(self, rhs) }
-    fn assign(rhs: bitv) -> bool { assign(self, rhs) }
-    pure fn get(i: uint) -> bool { get(self, i) }
-    fn [](i: uint) -> bool { self.get(i) }
-    fn eq(rhs: bitv) -> bool { equal(self, rhs) }
-    fn clear() { clear(self) }
-    fn set_all() { set_all(self) }
-    fn invert() { invert(self) }
-    fn difference(rhs: bitv) -> bool { difference(self, rhs) }
-    fn set(i: uint, x: bool) { set(self, i, x) }
-    fn is_true() -> bool { is_true(self) }
-    fn is_false() -> bool { is_false(self) }
-    fn to_vec() -> ~[uint] { to_vec(self) }
-    fn each(f: fn(bool) -> bool) { each(self, f) }
-    fn each_storage(f: fn(&uint) -> bool) { each_storage(self, f) }
-    fn eq_vec(v: ~[uint]) -> bool { eq_vec(self, v) }
+     fn eq_vec(v: ~[uint]) -> bool {
+       assert self.nbits == v.len();
+       let mut i = 0;
+       while i < self.nbits {
+           let w0 = self.get(i);
+           let w1 = v[i];
+           if !w0 && w1 != 0u || w0 && w1 == 0u { ret false; }
+           i = i + 1;
+       }
+       true
+     }
 
     fn ones(f: fn(uint) -> bool) {
         for uint::range(0, self.nbits) |i| {
@@ -283,7 +433,16 @@ impl of methods for bitv {
             }
         }
     }
-}
+
+} // end of bitv class
+
+const uint_bits: uint = 32u + (1u << 32u >> 27u);
+
+pure fn lor(w0: uint, w1: uint) -> uint { ret w0 | w1; }
+
+pure fn land(w0: uint, w1: uint) -> uint { ret w0 & w1; }
+
+pure fn right(_w0: uint, w1: uint) -> uint { ret w1; }
 
 impl extensions of ops::index<uint,bool> for bitv {
     pure fn index(&&i: uint) -> bool {
@@ -291,19 +450,15 @@ impl extensions of ops::index<uint,bool> for bitv {
     }
 }
 
-impl of to_str::to_str for bitv {
-    fn to_str() -> ~str { to_str(self) }
-}
-
 #[cfg(test)]
 mod tests {
     #[test]
     fn test_to_str() {
         let zerolen = bitv(0u, false);
-        assert to_str(zerolen) == ~"";
+        assert zerolen.to_str() == ~"";
 
         let eightbits = bitv(8u, false);
-        assert to_str(eightbits) == ~"00000000";
+        assert eightbits.to_str() == ~"00000000";
     }
 
     #[test]
@@ -312,16 +467,16 @@ mod tests {
         let mut exp;
         act = bitv(0u, false);
         exp = vec::from_elem::<uint>(0u, 0u);
-        assert (eq_vec(act, exp));
+        assert act.eq_vec(exp);
     }
 
     #[test]
     fn test_1_element() {
         let mut act;
         act = bitv(1u, false);
-        assert (eq_vec(act, ~[0u]));
+        assert act.eq_vec(~[0u]);
         act = bitv(1u, true);
-        assert (eq_vec(act, ~[1u]));
+        assert act.eq_vec(~[1u]);
     }
 
     #[test]
@@ -330,37 +485,37 @@ mod tests {
         // all 0
 
         act = bitv(10u, false);
-        assert (eq_vec(act, ~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u]));
+        assert (act.eq_vec(~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u]));
         // all 1
 
         act = bitv(10u, true);
-        assert (eq_vec(act, ~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u]));
+        assert (act.eq_vec(~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u]));
         // mixed
 
         act = bitv(10u, false);
-        set(act, 0u, true);
-        set(act, 1u, true);
-        set(act, 2u, true);
-        set(act, 3u, true);
-        set(act, 4u, true);
-        assert (eq_vec(act, ~[1u, 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u, 0u]));
+        act.set(0u, true);
+        act.set(1u, true);
+        act.set(2u, true);
+        act.set(3u, true);
+        act.set(4u, true);
+        assert (act.eq_vec(~[1u, 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u, 0u]));
         // mixed
 
         act = bitv(10u, false);
-        set(act, 5u, true);
-        set(act, 6u, true);
-        set(act, 7u, true);
-        set(act, 8u, true);
-        set(act, 9u, true);
-        assert (eq_vec(act, ~[0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u]));
+        act.set(5u, true);
+        act.set(6u, true);
+        act.set(7u, true);
+        act.set(8u, true);
+        act.set(9u, true);
+        assert (act.eq_vec(~[0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u]));
         // mixed
 
         act = bitv(10u, false);
-        set(act, 0u, true);
-        set(act, 3u, true);
-        set(act, 6u, true);
-        set(act, 9u, true);
-        assert (eq_vec(act, ~[1u, 0u, 0u, 1u, 0u, 0u, 1u, 0u, 0u, 1u]));
+        act.set(0u, true);
+        act.set(3u, true);
+        act.set(6u, true);
+        act.set(9u, true);
+        assert (act.eq_vec(~[1u, 0u, 0u, 1u, 0u, 0u, 1u, 0u, 0u, 1u]));
     }
 
     #[test]
@@ -369,68 +524,68 @@ mod tests {
         // all 0
 
         act = bitv(31u, false);
-        assert (eq_vec(act,
+        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);
-        assert (eq_vec(act,
+        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);
-        set(act, 0u, true);
-        set(act, 1u, true);
-        set(act, 2u, true);
-        set(act, 3u, true);
-        set(act, 4u, true);
-        set(act, 5u, true);
-        set(act, 6u, true);
-        set(act, 7u, true);
-        assert (eq_vec(act,
+        act.set(0u, true);
+        act.set(1u, true);
+        act.set(2u, true);
+        act.set(3u, true);
+        act.set(4u, true);
+        act.set(5u, true);
+        act.set(6u, true);
+        act.set(7u, true);
+        assert (act.eq_vec(
                        ~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 0u]));
         // mixed
 
         act = bitv(31u, false);
-        set(act, 16u, true);
-        set(act, 17u, true);
-        set(act, 18u, true);
-        set(act, 19u, true);
-        set(act, 20u, true);
-        set(act, 21u, true);
-        set(act, 22u, true);
-        set(act, 23u, true);
-        assert (eq_vec(act,
+        act.set(16u, true);
+        act.set(17u, true);
+        act.set(18u, true);
+        act.set(19u, true);
+        act.set(20u, true);
+        act.set(21u, true);
+        act.set(22u, true);
+        act.set(23u, true);
+        assert (act.eq_vec(
                        ~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 0u,
                         0u, 0u, 0u, 0u, 0u]));
         // mixed
 
         act = bitv(31u, false);
-        set(act, 24u, true);
-        set(act, 25u, true);
-        set(act, 26u, true);
-        set(act, 27u, true);
-        set(act, 28u, true);
-        set(act, 29u, true);
-        set(act, 30u, true);
-        assert (eq_vec(act,
+        act.set(24u, true);
+        act.set(25u, true);
+        act.set(26u, true);
+        act.set(27u, true);
+        act.set(28u, true);
+        act.set(29u, true);
+        act.set(30u, true);
+        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, 1u, 1u,
                         1u, 1u, 1u, 1u, 1u]));
         // mixed
 
         act = bitv(31u, false);
-        set(act, 3u, true);
-        set(act, 17u, true);
-        set(act, 30u, true);
-        assert (eq_vec(act,
+        act.set(3u, true);
+        act.set(17u, true);
+        act.set(30u, true);
+        assert (act.eq_vec(
                        ~[0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 1u]));
@@ -442,70 +597,70 @@ mod tests {
         // all 0
 
         act = bitv(32u, false);
-        assert (eq_vec(act,
+        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);
-        assert (eq_vec(act,
+        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);
-        set(act, 0u, true);
-        set(act, 1u, true);
-        set(act, 2u, true);
-        set(act, 3u, true);
-        set(act, 4u, true);
-        set(act, 5u, true);
-        set(act, 6u, true);
-        set(act, 7u, true);
-        assert (eq_vec(act,
+        act.set(0u, true);
+        act.set(1u, true);
+        act.set(2u, true);
+        act.set(3u, true);
+        act.set(4u, true);
+        act.set(5u, true);
+        act.set(6u, true);
+        act.set(7u, true);
+        assert (act.eq_vec(
                        ~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 0u, 0u]));
         // mixed
 
         act = bitv(32u, false);
-        set(act, 16u, true);
-        set(act, 17u, true);
-        set(act, 18u, true);
-        set(act, 19u, true);
-        set(act, 20u, true);
-        set(act, 21u, true);
-        set(act, 22u, true);
-        set(act, 23u, true);
-        assert (eq_vec(act,
+        act.set(16u, true);
+        act.set(17u, true);
+        act.set(18u, true);
+        act.set(19u, true);
+        act.set(20u, true);
+        act.set(21u, true);
+        act.set(22u, true);
+        act.set(23u, true);
+        assert (act.eq_vec(
                        ~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 0u,
                         0u, 0u, 0u, 0u, 0u, 0u]));
         // mixed
 
         act = bitv(32u, false);
-        set(act, 24u, true);
-        set(act, 25u, true);
-        set(act, 26u, true);
-        set(act, 27u, true);
-        set(act, 28u, true);
-        set(act, 29u, true);
-        set(act, 30u, true);
-        set(act, 31u, true);
-        assert (eq_vec(act,
+        act.set(24u, true);
+        act.set(25u, true);
+        act.set(26u, true);
+        act.set(27u, true);
+        act.set(28u, true);
+        act.set(29u, true);
+        act.set(30u, true);
+        act.set(31u, true);
+        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, 1u, 1u,
                         1u, 1u, 1u, 1u, 1u, 1u]));
         // mixed
 
         act = bitv(32u, false);
-        set(act, 3u, true);
-        set(act, 17u, true);
-        set(act, 30u, true);
-        set(act, 31u, true);
-        assert (eq_vec(act,
+        act.set(3u, true);
+        act.set(17u, true);
+        act.set(30u, true);
+        act.set(31u, true);
+        assert (act.eq_vec(
                        ~[0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 1u, 1u]));
@@ -517,71 +672,71 @@ mod tests {
         // all 0
 
         act = bitv(33u, false);
-        assert (eq_vec(act,
+        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);
-        assert (eq_vec(act,
+        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);
-        set(act, 0u, true);
-        set(act, 1u, true);
-        set(act, 2u, true);
-        set(act, 3u, true);
-        set(act, 4u, true);
-        set(act, 5u, true);
-        set(act, 6u, true);
-        set(act, 7u, true);
-        assert (eq_vec(act,
+        act.set(0u, true);
+        act.set(1u, true);
+        act.set(2u, true);
+        act.set(3u, true);
+        act.set(4u, true);
+        act.set(5u, true);
+        act.set(6u, true);
+        act.set(7u, true);
+        assert (act.eq_vec(
                        ~[1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 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]));
         // mixed
 
         act = bitv(33u, false);
-        set(act, 16u, true);
-        set(act, 17u, true);
-        set(act, 18u, true);
-        set(act, 19u, true);
-        set(act, 20u, true);
-        set(act, 21u, true);
-        set(act, 22u, true);
-        set(act, 23u, true);
-        assert (eq_vec(act,
+        act.set(16u, true);
+        act.set(17u, true);
+        act.set(18u, true);
+        act.set(19u, true);
+        act.set(20u, true);
+        act.set(21u, true);
+        act.set(22u, true);
+        act.set(23u, true);
+        assert (act.eq_vec(
                        ~[0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 0u,
                         0u, 0u, 0u, 0u, 0u, 0u, 0u]));
         // mixed
 
         act = bitv(33u, false);
-        set(act, 24u, true);
-        set(act, 25u, true);
-        set(act, 26u, true);
-        set(act, 27u, true);
-        set(act, 28u, true);
-        set(act, 29u, true);
-        set(act, 30u, true);
-        set(act, 31u, true);
-        assert (eq_vec(act,
+        act.set(24u, true);
+        act.set(25u, true);
+        act.set(26u, true);
+        act.set(27u, true);
+        act.set(28u, true);
+        act.set(29u, true);
+        act.set(30u, true);
+        act.set(31u, true);
+        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, 1u, 1u,
                         1u, 1u, 1u, 1u, 1u, 1u, 0u]));
         // mixed
 
         act = bitv(33u, false);
-        set(act, 3u, true);
-        set(act, 17u, true);
-        set(act, 30u, true);
-        set(act, 31u, true);
-        set(act, 32u, true);
-        assert (eq_vec(act,
+        act.set(3u, true);
+        act.set(17u, true);
+        act.set(30u, true);
+        act.set(31u, true);
+        act.set(32u, true);
+        assert (act.eq_vec(
                        ~[0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
                         0u, 0u, 0u, 0u, 1u, 1u, 1u]));
@@ -591,16 +746,15 @@ mod tests {
     fn test_equal_differing_sizes() {
         let v0 = bitv(10u, false);
         let v1 = bitv(11u, false);
-        assert !equal(v0, v1);
+        assert !v0.equal(v1);
     }
 
     #[test]
     fn test_equal_greatly_differing_sizes() {
         let v0 = bitv(10u, false);
         let v1 = bitv(110u, false);
-        assert !equal(v0, v1);
+        assert !v0.equal(v1);
     }
-
 }
 
 //
diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs
index d8467e36c84..c3ae0fb80fd 100644
--- a/src/libsyntax/ext/pipes/liveness.rs
+++ b/src/libsyntax/ext/pipes/liveness.rs
@@ -29,7 +29,7 @@ updating the states using rule (2) until there are no changes.
 
 import dvec::extensions;
 
-import std::bitv::{bitv, methods};
+import std::bitv::{bitv};
 
 import proto::methods;
 import ast_builder::empty_span;
@@ -38,7 +38,7 @@ 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 bv = ~bitv(num_states, false);
         for state.reachable |s| {
             bv.set(s.id, true);
         }
diff --git a/src/rustc/middle/tstate/ann.rs b/src/rustc/middle/tstate/ann.rs
index d1f19ba6e1f..7729c3ffc1d 100644
--- a/src/rustc/middle/tstate/ann.rs
+++ b/src/rustc/middle/tstate/ann.rs
@@ -53,8 +53,8 @@ fn empty_poststate(num_vars: uint) -> poststate {
 
 fn false_postcond(num_vars: uint) -> postcond {
     let rslt = create_tritv(num_vars);
-    tritv_set_all(rslt);
-    ret rslt;
+    rslt.set_all();
+    rslt
 }
 
 fn empty_pre_post(num_vars: uint) -> pre_and_post {
@@ -76,15 +76,11 @@ fn get_pre(&&p: pre_and_post) -> precond { ret p.precondition; }
 
 fn get_post(&&p: pre_and_post) -> postcond { ret p.postcondition; }
 
-fn difference(p1: precond, p2: precond) -> bool {
-    ret tritv_difference(p1, p2);
-}
+fn difference(p1: precond, p2: precond) -> bool { p1.difference(p2) }
 
-fn union(p1: precond, p2: precond) -> bool { ret tritv_union(p1, p2); }
+fn union(p1: precond, p2: precond) -> bool { p1.union(p2) }
 
-fn intersect(p1: precond, p2: precond) -> bool {
-    ret tritv_intersect(p1, p2);
-}
+fn intersect(p1: precond, p2: precond) -> bool { p1.intersect(p2) }
 
 fn pps_len(p: pre_and_post) -> uint {
     // gratuitous check
@@ -95,13 +91,13 @@ fn pps_len(p: pre_and_post) -> uint {
 
 fn require(i: uint, p: pre_and_post) {
     // sets the ith bit in p's pre
-    tritv_set(i, p.precondition, ttrue);
+    p.precondition.set(i, ttrue);
 }
 
 fn require_and_preserve(i: uint, p: pre_and_post) {
     // sets the ith bit in p's pre and post
-    tritv_set(i, p.precondition, ttrue);
-    tritv_set(i, p.postcondition, ttrue);
+    p.precondition.set(i, ttrue);
+    p.postcondition.set(i, ttrue);
 }
 
 fn set_in_postcond(i: uint, p: pre_and_post) -> bool {
@@ -110,8 +106,8 @@ fn set_in_postcond(i: uint, p: pre_and_post) -> bool {
 }
 
 fn set_in_postcond_(i: uint, p: postcond) -> bool {
-    let was_set = tritv_get(p, i);
-    tritv_set(i, p, ttrue);
+    let was_set = p.get(i);
+    p.set(i, ttrue);
     ret was_set != ttrue;
 }
 
@@ -121,8 +117,8 @@ fn set_in_poststate(i: uint, s: pre_and_post_state) -> bool {
 }
 
 fn set_in_poststate_(i: uint, p: poststate) -> bool {
-    let was_set = tritv_get(p, i);
-    tritv_set(i, p, ttrue);
+    let was_set = p.get(i);
+    p.set(i, ttrue);
     ret was_set != ttrue;
 
 }
@@ -133,8 +129,8 @@ fn clear_in_poststate(i: uint, s: pre_and_post_state) -> bool {
 }
 
 fn clear_in_poststate_(i: uint, s: poststate) -> bool {
-    let was_set = tritv_get(s, i);
-    tritv_set(i, s, tfalse);
+    let was_set = s.get(i);
+    s.set(i, tfalse);
     ret was_set != tfalse;
 }
 
@@ -144,61 +140,61 @@ fn clear_in_prestate(i: uint, s: pre_and_post_state) -> bool {
 }
 
 fn clear_in_prestate_(i: uint, s: prestate) -> bool {
-    let was_set = tritv_get(s, i);
-    tritv_set(i, s, tfalse);
+    let was_set = s.get(i);
+    s.set(i, tfalse);
     ret was_set != tfalse;
 }
 
 fn clear_in_postcond(i: uint, s: pre_and_post) -> bool {
     // sets the ith bit in p's post
-    let was_set = tritv_get(s.postcondition, i);
-    tritv_set(i, s.postcondition, tfalse);
+    let was_set = s.postcondition.get(i);
+    s.postcondition.set(i, tfalse);
     ret was_set != tfalse;
 }
 
 // Sets all the bits in a's precondition to equal the
 // corresponding bit in p's precondition.
 fn set_precondition(a: ts_ann, p: precond) {
-    tritv_copy(a.conditions.precondition, p);
+    a.conditions.precondition.become(p);
 }
 
 
 // Sets all the bits in a's postcondition to equal the
 // corresponding bit in p's postcondition.
 fn set_postcondition(a: ts_ann, p: postcond) {
-    tritv_copy(a.conditions.postcondition, p);
+    a.conditions.postcondition.become(p);
 }
 
 
 // Sets all the bits in a's prestate to equal the
 // corresponding bit in p's prestate.
 fn set_prestate(a: ts_ann, p: prestate) -> bool {
-    ret tritv_copy(a.states.prestate, p);
+    a.states.prestate.become(p)
 }
 
 
 // Sets all the bits in a's postcondition to equal the
 // corresponding bit in p's postcondition.
 fn set_poststate(a: ts_ann, p: poststate) -> bool {
-    ret tritv_copy(a.states.poststate, p);
+    a.states.poststate.become(p)
 }
 
 
 // Set all the bits in p that are set in new
 fn extend_prestate(p: prestate, newv: poststate) -> bool {
-    ret tritv_union(p, newv);
+    p.union(newv)
 }
 
 
 // Set all the bits in p that are set in new
 fn extend_poststate(p: poststate, newv: poststate) -> bool {
-    ret tritv_union(p, newv);
+    p.union(newv)
 }
 
 // Sets the given bit in p to "don't care"
 fn relax_prestate(i: uint, p: prestate) -> bool {
-    let was_set = tritv_get(p, i);
-    tritv_set(i, p, dont_care);
+    let was_set = p.get(i);
+    p.set(i, dont_care);
     ret was_set != dont_care;
 }
 
@@ -211,10 +207,10 @@ fn relax_poststate(i: uint, p: poststate) -> bool {
 fn relax_precond(i: uint, p: precond) { relax_prestate(i, p); }
 
 // Sets all the bits in p to "don't care"
-fn clear(p: precond) { tritv_clear(p); }
+fn clear(p: precond) { p.clear(); }
 
 // Sets all the bits in p to true
-fn set(p: precond) { tritv_set_all(p); }
+fn set(p: precond) { p.set_all(); }
 
 fn ann_precond(a: ts_ann) -> precond { ret a.conditions.precondition; }
 
@@ -227,16 +223,16 @@ fn pp_clone(p: pre_and_post) -> pre_and_post {
          postcondition: clone(p.postcondition)};
 }
 
-fn clone(p: prestate) -> prestate { ret tritv_clone(p); }
+fn clone(p: prestate) -> prestate { p.clone() }
 
 
 // returns true if a implies b
 // that is, returns true except if for some bits c and d,
 // c = 1 and d = either 0 or "don't know"
 fn implies(a: t, b: t) -> bool {
-    let tmp = tritv_clone(b);
-    tritv_difference(tmp, a);
-    ret tritv_doesntcare(tmp);
+    let tmp = b.clone();
+    tmp.difference(a);
+    tmp.doesntcare()
 }
 
 fn trit_str(t: trit) -> ~str {
diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs
index a098757175c..1e6bcd52ede 100644
--- a/src/rustc/middle/tstate/auxiliary.rs
+++ b/src/rustc/middle/tstate/auxiliary.rs
@@ -15,7 +15,7 @@ import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate,
                      clear_in_poststate_};
 import driver::session::session;
 import dvec::{dvec, extensions};
-import tritv::{dont_care, tfalse, tritv_get, ttrue};
+import tritv::{trit, tfalse, ttrue, dont_care, t};
 
 import syntax::print::pprust::{constr_args_to_str, lit_to_str};
 
@@ -59,7 +59,7 @@ fn tritv_to_str(fcx: fn_ctxt, v: tritv::t) -> ~str {
     let mut s = ~"";
     let mut comma = false;
     for constraints(fcx).each |p| {
-        alt tritv_get(v, p.bit_num) {
+        alt v.get(p.bit_num) {
           dont_care { }
           tt {
             s +=
@@ -80,8 +80,8 @@ fn first_difference_string(fcx: fn_ctxt, expected: tritv::t, actual: tritv::t)
    -> ~str {
     let mut s = ~"";
     for constraints(fcx).each |c| {
-        if tritv_get(expected, c.bit_num) == ttrue &&
-               tritv_get(actual, c.bit_num) != ttrue {
+      if expected.get(c.bit_num) == ttrue &&
+         actual.get(c.bit_num) != ttrue {
             s = constraint_to_str(fcx.ccx.tcx, c.c);
             break;
         }
@@ -108,8 +108,8 @@ fn log_cond(v: ~[uint]) { log(debug, tos(v)); }
 fn log_cond_err(v: ~[uint]) { log(error, tos(v)); }
 
 fn log_pp(pp: pre_and_post) {
-    let p1 = tritv::to_vec(pp.precondition);
-    let p2 = tritv::to_vec(pp.postcondition);
+    let p1 = pp.precondition.to_vec();
+    let p2 = pp.postcondition.to_vec();
     #debug("pre:");
     log_cond(p1);
     #debug("post:");
@@ -117,8 +117,8 @@ fn log_pp(pp: pre_and_post) {
 }
 
 fn log_pp_err(pp: pre_and_post) {
-    let p1 = tritv::to_vec(pp.precondition);
-    let p2 = tritv::to_vec(pp.postcondition);
+    let p1 = pp.precondition.to_vec();
+    let p2 = pp.postcondition.to_vec();
     #error("pre:");
     log_cond_err(p1);
     #error("post:");
@@ -126,8 +126,8 @@ fn log_pp_err(pp: pre_and_post) {
 }
 
 fn log_states(pp: pre_and_post_state) {
-    let p1 = tritv::to_vec(pp.prestate);
-    let p2 = tritv::to_vec(pp.poststate);
+    let p1 = pp.prestate.to_vec();
+    let p2 = pp.poststate.to_vec();
     #debug("prestate:");
     log_cond(p1);
     #debug("poststate:");
@@ -135,8 +135,8 @@ fn log_states(pp: pre_and_post_state) {
 }
 
 fn log_states_err(pp: pre_and_post_state) {
-    let p1 = tritv::to_vec(pp.prestate);
-    let p2 = tritv::to_vec(pp.poststate);
+    let p1 = pp.prestate.to_vec();
+    let p2 = pp.poststate.to_vec();
     #error("prestate:");
     log_cond_err(p1);
     #error("poststate:");
diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs
index 591f152acb3..36b7d9c7308 100644
--- a/src/rustc/middle/tstate/pre_post_conditions.rs
+++ b/src/rustc/middle/tstate/pre_post_conditions.rs
@@ -184,7 +184,7 @@ fn handle_update(fcx: fn_ctxt, parent: @expr, lhs: @expr, rhs: @expr,
     alt lhs.node {
       expr_path(p) {
         let post = expr_postcond(fcx.ccx, parent);
-        let tmp = tritv_clone(post);
+        let tmp = post.clone();
 
         alt ty {
           oper_move {
@@ -497,7 +497,7 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) {
                     /* Clear out anything that the previous initializer
                     guaranteed */
                     let e_pp = expr_pp(fcx.ccx, an_init.expr);
-                    tritv_copy(prev_pp.precondition,
+                    prev_pp.precondition.become(
                                seq_preconds(fcx, ~[prev_pp, e_pp]));
 
                     /* Include the LHSs too, since those aren't in the
diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs
index ebe476b3d7f..e427841103f 100644
--- a/src/rustc/middle/tstate/states.rs
+++ b/src/rustc/middle/tstate/states.rs
@@ -1,6 +1,6 @@
 import ann::*;
 import aux::*;
-import tritv::{tritv_clone, tritv_set, ttrue};
+import tritv::*;
 
 import syntax::print::pprust::block_to_str;
 import bitvectors::*;
@@ -57,14 +57,14 @@ fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path,
 fn seq_states(fcx: fn_ctxt, pres: prestate, bindings: ~[binding]) ->
    {changed: bool, post: poststate} {
     let mut changed = false;
-    let mut post = tritv_clone(pres);
+    let mut post = pres.clone();
     for bindings.each |b| {
         alt b.rhs {
           some(an_init) {
             // an expression, with or without a destination
             changed |=
                 find_pre_post_state_expr(fcx, post, an_init.expr) || changed;
-            post = tritv_clone(expr_poststate(fcx.ccx, an_init.expr));
+            post = expr_poststate(fcx.ccx, an_init.expr).clone();
             for b.lhs.each |d| {
                 alt an_init.expr.node {
                   expr_path(p) {
@@ -93,7 +93,7 @@ fn find_pre_post_state_sub(fcx: fn_ctxt, pres: prestate, e: @expr,
 
     changed = set_prestate_ann(fcx.ccx, parent, pres) || changed;
 
-    let post = tritv_clone(expr_poststate(fcx.ccx, e));
+    let post = expr_poststate(fcx.ccx, e).clone();
     alt c {
       none { }
       some(c1) { set_in_poststate_(bit_num(fcx, c1), post); }
@@ -113,7 +113,7 @@ fn find_pre_post_state_two(fcx: fn_ctxt, pres: prestate, lhs: @expr,
             changed;
     forbid_upvar(fcx, rhs.id, rhs.span, ty);
 
-    let post = tritv_clone(expr_poststate(fcx.ccx, rhs));
+    let post = expr_poststate(fcx.ccx, rhs).clone();
 
     alt lhs.node {
       expr_path(p) {
@@ -121,7 +121,7 @@ fn find_pre_post_state_two(fcx: fn_ctxt, pres: prestate, lhs: @expr,
         // changed flag
         // tmp remembers "old" constraints we'd otherwise forget,
         // for substitution purposes
-        let tmp = tritv_clone(post);
+        let tmp = post.clone();
 
         alt ty {
           oper_move {
@@ -210,8 +210,8 @@ fn join_then_else(fcx: fn_ctxt, antec: @expr, conseq: blk,
         alt chk {
           if_check {
             let c: sp_constr = expr_to_constr(fcx.ccx.tcx, antec);
-            let conseq_prestate = tritv_clone(expr_poststate(fcx.ccx, antec));
-            tritv_set(bit_num(fcx, c.node), conseq_prestate, ttrue);
+            let conseq_prestate = expr_poststate(fcx.ccx, antec).clone();
+            conseq_prestate.set(bit_num(fcx, c.node), ttrue);
             changed |=
                 find_pre_post_state_block(fcx, conseq_prestate, conseq) |
                     set_poststate_ann(fcx.ccx, id,
@@ -235,8 +235,8 @@ fn join_then_else(fcx: fn_ctxt, antec: @expr, conseq: blk,
         alt chk {
           if_check {
             let c: sp_constr = expr_to_constr(fcx.ccx.tcx, antec);
-            conseq_prestate = tritv_clone(conseq_prestate);
-            tritv_set(bit_num(fcx, c.node), conseq_prestate, ttrue);
+            conseq_prestate = conseq_prestate.clone();
+            conseq_prestate.set(bit_num(fcx, c.node),  ttrue);
           }
           _ { }
         }
@@ -270,7 +270,7 @@ fn find_pre_post_state_cap_clause(fcx: fn_ctxt, e_id: node_id,
 {
     let ccx = fcx.ccx;
     let pres_changed = set_prestate_ann(ccx, e_id, pres);
-    let post = tritv_clone(pres);
+    let post = pres.clone();
     for (*cap_clause).each |cap_item| {
         if cap_item.is_move {
             forget_in_poststate(fcx, post, cap_item.id);
@@ -432,7 +432,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
                 worst case, the body could invalidate all preds and
                 deinitialize everything before breaking */
             let post = empty_poststate(num_constrs);
-            tritv::tritv_kill(post);
+            post.kill();
             ret changed | set_poststate_ann(fcx.ccx, e.id, post);
         } else {
             ret changed | set_poststate_ann(fcx.ccx, e.id,
@@ -507,8 +507,8 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool {
 
     #debug["[ %s ]", *fcx.name];
     #debug["*At beginning: stmt = %s", stmt_to_str(*s)];
-    #debug["*prestate = %s", tritv::to_str(stmt_ann.states.prestate)];
-    #debug["*poststate = %s", tritv::to_str(stmt_ann.states.prestate)];
+    #debug["*prestate = %s", stmt_ann.states.prestate.to_str()];
+    #debug["*poststate = %s", stmt_ann.states.prestate.to_str()];
 
     alt s.node {
       stmt_decl(adecl, id) {
@@ -525,8 +525,8 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool {
                 set_poststate(stmt_ann, c_and_p.post) | c_and_p.changed;
 
             #debug["Summary: stmt = %s", stmt_to_str(*s)];
-            #debug["prestate = %s", tritv::to_str(stmt_ann.states.prestate)];
-            #debug["poststate = %s",tritv::to_str(stmt_ann.states.poststate)];
+            #debug["prestate = %s", stmt_ann.states.prestate.to_str()];
+            #debug["poststate = %s", stmt_ann.states.poststate.to_str()];
             #debug["changed = %s", bool::to_str(changed)];
 
             ret changed;
@@ -545,8 +545,8 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool {
 
 
         #debug["Finally: %s", stmt_to_str(*s)];
-        #debug["prestate = %s", tritv::to_str(stmt_ann.states.prestate)];
-        #debug["poststate = %s", tritv::to_str(stmt_ann.states.poststate)];
+        #debug["prestate = %s", stmt_ann.states.prestate.to_str()];
+        #debug["poststate = %s", stmt_ann.states.poststate.to_str()];
         #debug["changed = %s", bool::to_str(changed)];
 
         ret changed;
diff --git a/src/rustc/middle/tstate/tritv.rs b/src/rustc/middle/tstate/tritv.rs
index fc158262cb6..1e78b82fba8 100644
--- a/src/rustc/middle/tstate/tritv.rs
+++ b/src/rustc/middle/tstate/tritv.rs
@@ -1,24 +1,8 @@
-import std::bitv;
+import std::bitv::*;
 
 export t;
 export create_tritv;
-export tritv_clone;
-export tritv_set;
-export to_vec;
-export trit;
-export dont_care;
-export ttrue;
-export tfalse;
-export tritv_get;
-export tritv_set_all;
-export tritv_difference;
-export tritv_union;
-export tritv_intersect;
-export tritv_copy;
-export tritv_clear;
-export tritv_kill;
-export tritv_doesntcare;
-export to_str;
+export trit, tfalse, ttrue, dont_care;
 
 /* for a fixed index:
    10 = "this constraint may or may not be true after execution"
@@ -31,17 +15,160 @@ export to_str;
  per discussion at).
 */
 
-type t = {uncertain: bitv::bitv, val: bitv::bitv, nbits: uint};
 enum trit { ttrue, tfalse, dont_care, }
 
-fn create_tritv(len: uint) -> t {
-    ret {uncertain: bitv::bitv(len, true),
-         val: bitv::bitv(len, false),
-         nbits: len};
+class t {
+    // Shouldn't be mut; instead we should have a different
+    // constructor that takes two bitvs
+    let mut uncertain: bitv;
+    let mut val: bitv;
+    let nbits: uint;
+    // next two should be private (#2297)
+    fn set_uncertain(-b: bitv) {
+        self.uncertain <- b;
+    }
+    fn set_val(-b: bitv) {
+        self.val <- b;
+    }
+    fn clone() -> t {
+        let rs = t(self.nbits);
+        let r = self.uncertain.clone();
+        rs.set_uncertain(r);
+        let r1 = self.val.clone();
+        rs.set_val(r1);
+        rs
+    }
+    fn difference(p: t) -> bool {
+        assert (self.nbits == p.nbits);
+        let mut changed = false;
+        for uint::range(0, p.nbits) |i| {
+           let old = p.get(i);
+           let newv = minus(old, p.get(i));
+           changed = change(changed, old, newv);
+           self.set(i, newv);
+        };
+        changed
+    }
+    pure fn get(i: uint) -> trit {
+        let b1 = self.uncertain.get(i);
+        let b2 = self.val.get(i);
+        assert (!(b1 && b2));
+        if b1 { dont_care } else if b2 { ttrue } else { tfalse }
+    }
+    pure fn set(i: uint, t: trit) -> bool {
+        let old = self.get(i);
+        alt t {
+          dont_care {
+            self.uncertain.set(i, true);
+            self.val.set(i, false);
+          }
+          ttrue {
+            self.uncertain.set(i, false);
+            self.val.set(i, true);
+          }
+          tfalse {
+            self.uncertain.set(i, false);
+            self.val.set(i, false);
+          }
+        }
+        change(false, old, t)
+    }
+
+    fn set_all() {
+      for uint::range(0u, self.nbits) |i| {
+         self.set(i, ttrue);
+      }
+    }
+
+    fn clear() {
+      for uint::range(0, self.nbits) |i| {
+         self.set(i, dont_care);
+      }
+    }
+
+    fn kill() {
+       for uint::range(0, self.nbits) |i| {
+           self.set(i, dont_care);
+       }
+    }
+
+    fn doesntcare() -> bool {
+        for uint::range(0, self.nbits) |i| {
+           if self.get(i) != dont_care { ret false; }
+        }
+        true
+    }
+
+    fn to_vec() -> ~[uint] {
+      let mut rslt: ~[uint] = ~[];
+      for uint::range(0, self.nbits) |i| {
+        vec::push(rslt,
+                  alt self.get(i) {
+                      dont_care { 2 }
+                      ttrue     { 1 }
+                      tfalse    { 0 }
+                  });
+      };
+      rslt
+    }
+
+    fn to_str() -> str {
+       let mut rs: str = "";
+       for uint::range(0, self.nbits) |i| {
+        rs +=
+            alt self.get(i) {
+              dont_care { "?" }
+              ttrue { "1" }
+              tfalse { "0" }
+            };
+       };
+       rs
+    }
+
+    fn intersect(p: t) -> bool {
+      assert (self.nbits == p.nbits);
+      let mut changed = false;
+      for uint::range(0, self.nbits) |i| {
+        let old = self.get(i);
+        let newv = trit_and(old, p.get(i));
+        changed = change(changed, old, newv);
+        self.set(i, newv);
+       }
+      ret changed;
+    }
+
+    fn become(source: t) -> bool {
+      assert (self.nbits == source.nbits);
+      let changed = !self.uncertain.equal(source.uncertain) ||
+          !self.val.equal(source.val);
+      self.uncertain.assign(source.uncertain);
+      self.val.assign(source.val);
+      changed
+    }
+
+    fn union(p: t) -> bool {
+        assert (self.nbits == p.nbits);
+        let mut changed = false;
+        for uint::range(0, self.nbits) |i| {
+           let old = self.get(i);
+           let newv = trit_or(old, p.get(i));
+           changed = change(changed, old, newv);
+           self.set(i, newv);
+        }
+        ret changed;
+    }
+
+    new(len: uint) {
+        self.uncertain = mk_bitv(len, true);
+        self.val = mk_bitv(len, false);
+        self.nbits = len;
+    }
 }
 
+fn create_tritv(len: uint) -> t { t(len) }
 
-fn trit_minus(a: trit, b: trit) -> trit {
+
+fn minus(a: trit, b: trit) -> trit {
 
     /*   2 - anything = 2
          1 - 1 = 2
@@ -56,10 +183,6 @@ fn trit_minus(a: trit, b: trit) -> trit {
         alt b {
           ttrue { dont_care }
           tfalse { ttrue }
-
-
-
-
           /* internally contradictory, but
              I guess it'll get flagged? */
           dont_care {
@@ -70,18 +193,14 @@ fn trit_minus(a: trit, b: trit) -> trit {
       tfalse {
         alt b {
           ttrue { tfalse }
-
-
-
-
           /* see above comment */
           _ {
             tfalse
           }
         }
       }
+     }
     }
-}
 
 fn trit_or(a: trit, b: trit) -> trit {
     alt a {
@@ -137,148 +256,9 @@ fn trit_and(a: trit, b: trit) -> trit {
     // a and b were both dont_care
 }
 
-fn change(changed: bool, old: trit, newv: trit) -> bool {
+pure fn change(changed: bool, old: trit, newv: trit) -> bool {
     changed || newv != old
 }
-
-fn tritv_difference(p1: t, p2: t) -> bool {
-    let mut i: uint = 0u;
-    assert (p1.nbits == p2.nbits);
-    let sz: uint = p1.nbits;
-    let mut changed = false;
-    while i < sz {
-        let old = tritv_get(p1, i);
-        let newv = trit_minus(old, tritv_get(p2, i));
-        changed = change(changed, old, newv);
-        tritv_set(i, p1, newv);
-        i += 1u;
-    }
-    ret changed;
-}
-
-fn tritv_union(p1: t, p2: t) -> bool {
-    let mut i: uint = 0u;
-    assert (p1.nbits == p2.nbits);
-    let sz: uint = p1.nbits;
-    let mut changed = false;
-    while i < sz {
-        let old = tritv_get(p1, i);
-        let newv = trit_or(old, tritv_get(p2, i));
-        changed = change(changed, old, newv);
-        tritv_set(i, p1, newv);
-        i += 1u;
-    }
-    ret changed;
-}
-
-fn tritv_intersect(p1: t, p2: t) -> bool {
-    let mut i: uint = 0u;
-    assert (p1.nbits == p2.nbits);
-    let sz: uint = p1.nbits;
-    let mut changed = false;
-    while i < sz {
-        let old = tritv_get(p1, i);
-        let newv = trit_and(old, tritv_get(p2, i));
-        changed = change(changed, old, newv);
-        tritv_set(i, p1, newv);
-        i += 1u;
-    }
-    ret changed;
-}
-
-fn tritv_get(v: t, i: uint) -> trit {
-    let b1 = bitv::get(v.uncertain, i);
-    let b2 = bitv::get(v.val, i);
-    assert (!(b1 && b2));
-    if b1 { dont_care } else if b2 { ttrue } else { tfalse }
-}
-
-fn tritv_set(i: uint, v: t, t: trit) -> bool {
-    let old = tritv_get(v, i);
-    alt t {
-      dont_care {
-        bitv::set(v.uncertain, i, true);
-        bitv::set(v.val, i, false);
-      }
-      ttrue { bitv::set(v.uncertain, i, false); bitv::set(v.val, i, true); }
-      tfalse {
-        bitv::set(v.uncertain, i, false);
-        bitv::set(v.val, i, false);
-      }
-    }
-    ret change(false, old, t);
-}
-
-fn tritv_copy(target: t, source: t) -> bool {
-    assert (target.nbits == source.nbits);
-    let changed =
-        !bitv::equal(target.uncertain, source.uncertain) ||
-            !bitv::equal(target.val, source.val);
-    bitv::assign(target.uncertain, source.uncertain);
-    bitv::assign(target.val, source.val);
-    ret changed;
-}
-
-fn tritv_set_all(v: t) {
-    let mut i: uint = 0u;
-    while i < v.nbits { tritv_set(i, v, ttrue); i += 1u; }
-}
-
-fn tritv_clear(v: t) {
-    let mut i: uint = 0u;
-    while i < v.nbits { tritv_set(i, v, dont_care); i += 1u; }
-}
-
-fn tritv_kill(v: t) {
-    let mut i: uint = 0u;
-    while i < v.nbits { tritv_set(i, v, tfalse); i += 1u; }
-}
-
-fn tritv_clone(v: t) -> t {
-    ret {uncertain: bitv::clone(v.uncertain),
-         val: bitv::clone(v.val),
-         nbits: v.nbits};
-}
-
-fn tritv_doesntcare(v: t) -> bool {
-    let mut i: uint = 0u;
-    while i < v.nbits {
-        if tritv_get(v, i) != dont_care { ret false; }
-        i += 1u;
-    }
-    ret true;
-}
-
-fn to_vec(v: t) -> ~[uint] {
-    let mut i: uint = 0u;
-    let mut rslt: ~[uint] = ~[];
-    while i < v.nbits {
-        vec::push(rslt,
-                  alt tritv_get(v, i) {
-                      dont_care { 2u }
-                      ttrue { 1u }
-                      tfalse { 0u }
-                  });
-        i += 1u;
-    }
-    ret rslt;
-}
-
-fn to_str(v: t) -> ~str {
-    let mut i: uint = 0u;
-    let mut rs: ~str = ~"";
-    while i < v.nbits {
-        rs +=
-            alt tritv_get(v, i) {
-              dont_care { ~"?" }
-              ttrue { ~"1" }
-              tfalse { ~"0" }
-            };
-        i += 1u;
-    }
-    ret rs;
-}
-
 //
 // Local Variables:
 // mode: rust
diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs
index 3eeb16f9379..f1bf1ec8d0a 100644
--- a/src/test/bench/sudoku.rs
+++ b/src/test/bench/sudoku.rs
@@ -52,7 +52,7 @@ fn solve_grid(g: grid_t) {
             // colors not yet used
             let avail = bitv::bitv(10u, false);
             for u8::range(start_color, 10u8) |color| {
-                bitv::set(avail, color as uint, true);
+                avail.set(color as uint, true);
             }
 
             // drop colors already in use in neighbourhood
@@ -60,7 +60,7 @@ fn solve_grid(g: grid_t) {
 
             // find first remaining color that is available
             for uint::range(1u, 10u) |i| {
-                if bitv::get(avail, i) {
+                if avail.get(i) {
                     g[row][col] = i as u8;
                     ret true;
                 }
@@ -74,7 +74,7 @@ fn solve_grid(g: grid_t) {
     fn drop_colors(g: grid, avail: bitv::bitv, row: u8, col: u8) {
         fn drop_color(g: grid, colors: bitv::bitv, row: u8, col: u8) {
             let color = g[row][col];
-            if color != 0u8 { bitv::set(colors, color as uint, false); }
+            if color != 0u8 { colors.set(color as uint, false); }
         }
 
         let it = |a,b| drop_color(g, avail, a, b);
diff --git a/src/test/compile-fail/for-loop-decl.rs b/src/test/compile-fail/for-loop-decl.rs
index 00f9433eef0..2252672f1b5 100644
--- a/src/test/compile-fail/for-loop-decl.rs
+++ b/src/test/compile-fail/for-loop-decl.rs
@@ -6,12 +6,12 @@ import std::bitv;
 type fn_info = {vars: hashmap<uint, var_info>};
 type var_info = {a: uint, b: uint};
 
-fn bitv_to_str(enclosing: fn_info, v: bitv::bitv) -> str {
+fn bitv_to_str(enclosing: fn_info, v: ~bitv::bitv) -> str {
     let s = "";
 
     // error is that the value type in the hash map is var_info, not a box
     for enclosing.vars.each_value |val| {
-        if bitv::get(v, val) { s += "foo"; }
+        if v.get(val) { s += "foo"; }
     }
     ret s;
 }
diff --git a/src/test/run-pass/bitv-perf-test.rs b/src/test/run-pass/bitv-perf-test.rs
new file mode 100644
index 00000000000..2e4b567e619
--- /dev/null
+++ b/src/test/run-pass/bitv-perf-test.rs
@@ -0,0 +1,13 @@
+use std;
+import std::bitv::*;
+
+fn bitv_test() -> bool {
+    let v1 = ~bitv(31, false);
+    let v2 = ~bitv(31, true);
+    v1.union(v2);
+    true
+}
+
+fn main() {
+    do iter::repeat(1000000) || {bitv_test()};
+}
\ No newline at end of file