about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndrew Poelstra <apoelstra@wpsoftware.net>2014-07-02 11:10:32 -0700
committerAndrew Poelstra <apoelstra@wpsoftware.net>2014-07-02 15:31:08 -0700
commit8ef0165a56bc788968fcec6debb510b58134f0d9 (patch)
tree0c50a05adbcb3a00f42850366c95bfdd6f52cd96
parent78b674152ed09f2e7f30f0080171b43e11f56f31 (diff)
downloadrust-8ef0165a56bc788968fcec6debb510b58134f0d9.tar.gz
rust-8ef0165a56bc788968fcec6debb510b58134f0d9.zip
collections::bitv: clean up and unit test `BitvSet::is_subset`
-rw-r--r--src/libcollections/bitv.rs91
1 files changed, 36 insertions, 55 deletions
diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs
index fdd690ccdd9..6d7c91ccfee 100644
--- a/src/libcollections/bitv.rs
+++ b/src/libcollections/bitv.rs
@@ -15,7 +15,7 @@ use core::prelude::*;
 use core::cmp;
 use core::default::Default;
 use core::fmt;
-use core::iter::{Map, Take, Zip};
+use core::iter::Take;
 use core::ops;
 use core::slice;
 use core::uint;
@@ -825,23 +825,16 @@ impl Set<uint> for BitvSet {
         self.intersection(other).count() > 0
     }
 
+    #[inline]
     fn is_subset(&self, other: &BitvSet) -> bool {
-        for (_, w1, w2) in self.commons(other) {
-            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 (mine, _, w) in self.outliers(other) {
-            if !mine {
-                return true;
-            } else if w != 0 {
-                return false;
-            }
-        }
-        return true;
+        let &BitvSet(ref self_bitv) = self;
+        let &BitvSet(ref other_bitv) = other;
+
+        // Check that `self` intersect `other` is self
+        self_bitv.mask_words(0).zip(other_bitv.mask_words(0))
+                               .all(|((_, w1), (_, w2))| w1 & w2 == w1) &&
+        // Check that `self` setminus `other` is empty
+        self_bitv.mask_words(other_bitv.storage.len()).all(|(_, w)| w == 0)
     }
 
     #[inline]
@@ -883,44 +876,6 @@ impl MutableSet<uint> for BitvSet {
     }
 }
 
-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.
-    fn commons<'a>(&'a self, other: &'a BitvSet)
-        -> Map<((uint, uint), (uint, uint)), (uint, uint, uint),
-               Zip<MaskWords<'a>, MaskWords<'a>>> {
-        let &BitvSet(ref self_bitv) = self;
-        let &BitvSet(ref other_bitv) = other;
-        self_bitv.mask_words(0).zip(other_bitv.mask_words(0))
-            .map(|((i, w1), (_, w2))| (i * uint::BITS, w1, w2))
-    }
-
-    /// 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`.
-    fn outliers<'a>(&'a self, other: &'a BitvSet)
-        -> Map<(uint, uint), (bool, uint, uint), MaskWords<'a>> {
-        let slen = self.capacity() / uint::BITS;
-        let olen = other.capacity() / uint::BITS;
-        let &BitvSet(ref self_bitv) = self;
-        let &BitvSet(ref other_bitv) = other;
-
-        if olen < slen {
-            self_bitv.mask_words(olen)
-                .map(|(i, w)| (true, i * uint::BITS, w))
-        } else {
-            other_bitv.mask_words(slen)
-                .map(|(i, w)| (false, i * uint::BITS, w))
-        }
-    }
-}
-
 pub struct BitPositions<'a> {
     set: &'a BitvSet,
     next_idx: uint
@@ -1595,6 +1550,32 @@ mod tests {
     }
 
     #[test]
+    fn test_bitv_set_subset() {
+        let mut set1 = BitvSet::new();
+        let mut set2 = BitvSet::new();
+
+        assert!(set1.is_subset(&set2)); //  {}  {}
+        set2.insert(100);
+        assert!(set1.is_subset(&set2)); //  {}  { 1 }
+        set2.insert(200);
+        assert!(set1.is_subset(&set2)); //  {}  { 1, 2 }
+        set1.insert(200);
+        assert!(set1.is_subset(&set2)); //  { 2 }  { 1, 2 }
+        set1.insert(300);
+        assert!(!set1.is_subset(&set2)); // { 2, 3 }  { 1, 2 }
+        set2.insert(300);
+        assert!(set1.is_subset(&set2)); // { 2, 3 }  { 1, 2, 3 }
+        set2.insert(400);
+        assert!(set1.is_subset(&set2)); // { 2, 3 }  { 1, 2, 3, 4 }
+        set2.remove(&100);
+        assert!(set1.is_subset(&set2)); // { 2, 3 }  { 2, 3, 4 }
+        set2.remove(&300);
+        assert!(!set1.is_subset(&set2)); // { 2, 3 }  { 2, 4 }
+        set1.remove(&300);
+        assert!(set1.is_subset(&set2)); // { 2 }  { 2, 4 }
+    }
+
+    #[test]
     fn test_bitv_remove() {
         let mut a = BitvSet::new();