Skip to content

Commit

Permalink
Add more functionality to BitMatrix
Browse files Browse the repository at this point in the history
  • Loading branch information
tmandry committed Jun 10, 2019
1 parent a38991f commit 66e7493
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 1 deletion.
84 changes: 83 additions & 1 deletion src/librustc_data_structures/bit_set.rs
Expand Up @@ -636,7 +636,7 @@ impl<T: Idx> GrowableBitSet<T> {
///
/// All operations that involve a row and/or column index will panic if the
/// index exceeds the relevant bound.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct BitMatrix<R: Idx, C: Idx> {
num_rows: usize,
num_columns: usize,
Expand All @@ -658,6 +658,23 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
}
}

/// Creates a new matrix, with `row` used as the value for every row.
pub fn from_row_n(row: &BitSet<C>, num_rows: usize) -> BitMatrix<R, C> {
let num_columns = row.domain_size();
let words_per_row = num_words(num_columns);
assert_eq!(words_per_row, row.words().len());
BitMatrix {
num_rows,
num_columns,
words: iter::repeat(row.words()).take(num_rows).flatten().cloned().collect(),
marker: PhantomData,
}
}

pub fn rows(&self) -> impl Iterator<Item = R> {
(0..self.num_rows).map(R::new)
}

/// The range of bits for a given row.
fn range(&self, row: R) -> (usize, usize) {
let words_per_row = num_words(self.num_columns);
Expand Down Expand Up @@ -737,6 +754,49 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
changed
}

/// Adds the bits from `with` to the bits from row `write`, and
/// returns `true` if anything changed.
pub fn union_row_with(&mut self, with: &BitSet<C>, write: R) -> bool {
assert!(write.index() < self.num_rows);
assert_eq!(with.domain_size(), self.num_columns);
let (write_start, write_end) = self.range(write);
let mut changed = false;
for (read_index, write_index) in (0..with.words().len()).zip(write_start..write_end) {
let word = self.words[write_index];
let new_word = word | with.words()[read_index];
self.words[write_index] = new_word;
changed |= word != new_word;
}
changed
}

/// Sets every cell in `row` to true.
pub fn insert_all_into_row(&mut self, row: R) {
assert!(row.index() < self.num_rows);
let (start, end) = self.range(row);
let words = &mut self.words[..];
for index in start..end {
words[index] = !0;
}
self.clear_excess_bits(row);
}

/// Clear excess bits in the final word of the row.
fn clear_excess_bits(&mut self, row: R) {
let num_bits_in_final_word = self.num_columns % WORD_BITS;
if num_bits_in_final_word > 0 {
let mask = (1 << num_bits_in_final_word) - 1;
let (_, end) = self.range(row);
let final_word_idx = end - 1;
self.words[final_word_idx] &= mask;
}
}

/// Gets a slice of the underlying words.
pub fn words(&self) -> &[Word] {
&self.words
}

/// Iterates through all the columns set to true in a given row of
/// the matrix.
pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> {
Expand All @@ -748,6 +808,12 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
marker: PhantomData,
}
}

/// Returns the number of elements in `row`.
pub fn count(&self, row: R) -> usize {
let (start, end) = self.range(row);
self.words[start..end].iter().map(|e| e.count_ones() as usize).sum()
}
}

/// A fixed-column-size, variable-row-size 2D bit matrix with a moderately
Expand Down Expand Up @@ -1057,6 +1123,7 @@ fn matrix_iter() {
matrix.insert(2, 99);
matrix.insert(4, 0);
matrix.union_rows(3, 5);
matrix.insert_all_into_row(6);

let expected = [99];
let mut iter = expected.iter();
Expand All @@ -1068,6 +1135,7 @@ fn matrix_iter() {

let expected = [22, 75];
let mut iter = expected.iter();
assert_eq!(matrix.count(3), expected.len());
for i in matrix.iter(3) {
let j = *iter.next().unwrap();
assert_eq!(i, j);
Expand All @@ -1076,6 +1144,7 @@ fn matrix_iter() {

let expected = [0];
let mut iter = expected.iter();
assert_eq!(matrix.count(4), expected.len());
for i in matrix.iter(4) {
let j = *iter.next().unwrap();
assert_eq!(i, j);
Expand All @@ -1084,11 +1153,24 @@ fn matrix_iter() {

let expected = [22, 75];
let mut iter = expected.iter();
assert_eq!(matrix.count(5), expected.len());
for i in matrix.iter(5) {
let j = *iter.next().unwrap();
assert_eq!(i, j);
}
assert!(iter.next().is_none());

assert_eq!(matrix.count(6), 100);
let mut count = 0;
for (idx, i) in matrix.iter(6).enumerate() {
assert_eq!(idx, i);
count += 1;
}
assert_eq!(count, 100);

if let Some(i) = matrix.iter(7).next() {
panic!("expected no elements in row, but contains element {:?}", i);
}
}

#[test]
Expand Down
10 changes: 10 additions & 0 deletions src/librustc_data_structures/stable_hasher.rs
Expand Up @@ -503,6 +503,16 @@ impl<I: indexed_vec::Idx, CTX> HashStable<CTX> for bit_set::BitSet<I>
}
}

impl<R: indexed_vec::Idx, C: indexed_vec::Idx, CTX> HashStable<CTX>
for bit_set::BitMatrix<R, C>
{
fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,
hasher: &mut StableHasher<W>) {
self.words().hash_stable(ctx, hasher);
}
}

impl_stable_hash_via_hash!(::std::path::Path);
impl_stable_hash_via_hash!(::std::path::PathBuf);

Expand Down

0 comments on commit 66e7493

Please sign in to comment.