Skip to content

Commit 8c9bdda

Browse files
committed
Correct internal BitvSet 0-padding, fixes #16542
1 parent 02f9fd8 commit 8c9bdda

File tree

1 file changed

+114
-3
lines changed

1 file changed

+114
-3
lines changed

src/libcollections/bitv.rs

+114-3
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@ use std::hash;
7676
use {Collection, Mutable, Set, MutableSet, MutableSeq};
7777
use vec::Vec;
7878

79+
// Take two BitV's, and return iterators of their words, where the shorter one
80+
// has been padded with 0's
81+
macro_rules! match_words(
82+
($a_expr:expr, $b_expr:expr) => ({
83+
let a = $a_expr;
84+
let b = $b_expr;
85+
let a_len = a.storage.len();
86+
let b_len = b.storage.len();
87+
88+
// have to uselessly pretend to pad the longer one for type matching
89+
if a_len < b_len {
90+
(a.mask_words(0).chain(iter::Repeat::new(0u).enumerate().take(b_len).skip(a_len)),
91+
b.mask_words(0).chain(iter::Repeat::new(0u).enumerate().take(0).skip(0)))
92+
} else {
93+
(a.mask_words(0).chain(iter::Repeat::new(0u).enumerate().take(0).skip(0)),
94+
b.mask_words(0).chain(iter::Repeat::new(0u).enumerate().take(a_len).skip(b_len)))
95+
}
96+
})
97+
)
7998

8099
static TRUE: bool = true;
81100
static FALSE: bool = false;
@@ -970,7 +989,7 @@ impl<'a> RandomAccessIterator<bool> for Bits<'a> {
970989
/// assert!(bv.eq_vec([true, true, false, true,
971990
/// false, false, false, false]));
972991
/// ```
973-
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)]
992+
#[deriving(Clone)]
974993
pub struct BitvSet(Bitv);
975994

976995
impl Default for BitvSet {
@@ -993,6 +1012,32 @@ impl Extendable<bool> for BitvSet {
9931012
}
9941013
}
9951014

1015+
impl PartialOrd for BitvSet {
1016+
#[inline]
1017+
fn partial_cmp(&self, other: &BitvSet) -> Option<Ordering> {
1018+
let (a_iter, b_iter) = match_words!(self.get_ref(), other.get_ref());
1019+
iter::order::partial_cmp(a_iter, b_iter)
1020+
}
1021+
}
1022+
1023+
impl Ord for BitvSet {
1024+
#[inline]
1025+
fn cmp(&self, other: &BitvSet) -> Ordering {
1026+
let (a_iter, b_iter) = match_words!(self.get_ref(), other.get_ref());
1027+
iter::order::cmp(a_iter, b_iter)
1028+
}
1029+
}
1030+
1031+
impl cmp::PartialEq for BitvSet {
1032+
#[inline]
1033+
fn eq(&self, other: &BitvSet) -> bool {
1034+
let (a_iter, b_iter) = match_words!(self.get_ref(), other.get_ref());
1035+
iter::order::eq(a_iter, b_iter)
1036+
}
1037+
}
1038+
1039+
impl cmp::Eq for BitvSet {}
1040+
9961041
impl BitvSet {
9971042
/// Create a new bit vector set with initially no contents.
9981043
///
@@ -1142,10 +1187,18 @@ impl BitvSet {
11421187
// Unwrap Bitvs
11431188
let &BitvSet(ref mut self_bitv) = self;
11441189
let &BitvSet(ref other_bitv) = other;
1190+
11451191
// Expand the vector if necessary
11461192
self_bitv.reserve(other_bitv.capacity());
1147-
// Apply values
1148-
for (i, w) in other_bitv.mask_words(0) {
1193+
1194+
// virtually pad other with 0's for equal lengths
1195+
let self_len = self_bitv.storage.len();
1196+
let other_len = other_bitv.storage.len();
1197+
let mut other_words = other_bitv.mask_words(0)
1198+
.chain(iter::Repeat::new(0u).enumerate().take(self_len).skip(other_len));
1199+
1200+
// Apply values found in other
1201+
for (i, w) in other_words {
11491202
let old = self_bitv.storage[i];
11501203
let new = f(old, w);
11511204
*self_bitv.storage.get_mut(i) = new;
@@ -2214,6 +2267,64 @@ mod tests {
22142267
assert!(set1.is_subset(&set2)); // { 2 } { 2, 4 }
22152268
}
22162269

2270+
#[test]
2271+
fn test_bitv_set_intersect_with() {
2272+
// Explicitly 0'ed bits
2273+
let mut a = BitvSet::from_bitv(from_bytes([0b10100010]));
2274+
let mut b = BitvSet::from_bitv(from_bytes([0b00000000]));
2275+
let c = a.clone();
2276+
a.intersect_with(&b);
2277+
b.intersect_with(&c);
2278+
assert!(a.is_empty());
2279+
assert!(b.is_empty());
2280+
2281+
// Uninitialized bits should behave like 0's
2282+
let mut a = BitvSet::from_bitv(from_bytes([0b10100010]));
2283+
let mut b = BitvSet::new();
2284+
let c = a.clone();
2285+
a.intersect_with(&b);
2286+
b.intersect_with(&c);
2287+
assert!(a.is_empty());
2288+
assert!(b.is_empty());
2289+
2290+
// Standard
2291+
let mut a = BitvSet::from_bitv(from_bytes([0b10100010]));
2292+
let mut b = BitvSet::from_bitv(from_bytes([0b01100010]));
2293+
let c = a.clone();
2294+
a.intersect_with(&b);
2295+
b.intersect_with(&c);
2296+
assert_eq!(a.len(), 2);
2297+
assert_eq!(b.len(), 2);
2298+
}
2299+
2300+
#[test]
2301+
fn test_bitv_set_eq() {
2302+
let a = BitvSet::from_bitv(from_bytes([0b10100010]));
2303+
let b = BitvSet::from_bitv(from_bytes([0b00000000]));
2304+
let c = BitvSet::new();
2305+
2306+
assert!(a == a);
2307+
assert!(a != b);
2308+
assert!(a != c);
2309+
assert!(b == b);
2310+
assert!(b == c);
2311+
assert!(c == c);
2312+
}
2313+
2314+
#[test]
2315+
fn test_bitv_set_cmp() {
2316+
let a = BitvSet::from_bitv(from_bytes([0b10100010]));
2317+
let b = BitvSet::from_bitv(from_bytes([0b00000000]));
2318+
let c = BitvSet::new();
2319+
2320+
assert_eq!(a.cmp(&b), Greater);
2321+
assert_eq!(a.cmp(&c), Greater);
2322+
assert_eq!(b.cmp(&a), Less);
2323+
assert_eq!(b.cmp(&c), Equal);
2324+
assert_eq!(c.cmp(&a), Less);
2325+
assert_eq!(c.cmp(&b), Equal);
2326+
}
2327+
22172328
#[test]
22182329
fn test_bitv_remove() {
22192330
let mut a = BitvSet::new();

0 commit comments

Comments
 (0)