Auto merge of #54318 - nnethercote:use-HybridBitSet-in-SparseBitMatrix, r=pnkfelix
Use `HybridBitSet` in `SparseBitMatrix`. This fixes most of the remaining NLL memory regression. r? @pnkfelix, because you reviewed #54286. cc @nikomatsakis, because NLL cc @Mark-Simulacrum, because this removes `array_vec.rs` cc @lqd, because this massively improves `unic-ucd-name`, and probably other public crates
This commit is contained in:
commit
ff6422d7a3
@ -1,305 +0,0 @@
|
||||
// Copyright 2016 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A stack-allocated vector, allowing storage of N elements on the stack.
|
||||
|
||||
use std::marker::Unsize;
|
||||
use std::iter::Extend;
|
||||
use std::ptr::{self, drop_in_place, NonNull};
|
||||
use std::ops::{Deref, DerefMut, Range};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::slice;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
pub unsafe trait Array {
|
||||
type Element;
|
||||
type PartialStorage: Unsize<[ManuallyDrop<Self::Element>]>;
|
||||
const LEN: usize;
|
||||
}
|
||||
|
||||
unsafe impl<T> Array for [T; 1] {
|
||||
type Element = T;
|
||||
type PartialStorage = [ManuallyDrop<T>; 1];
|
||||
const LEN: usize = 1;
|
||||
}
|
||||
|
||||
unsafe impl<T> Array for [T; 8] {
|
||||
type Element = T;
|
||||
type PartialStorage = [ManuallyDrop<T>; 8];
|
||||
const LEN: usize = 8;
|
||||
}
|
||||
|
||||
unsafe impl<T> Array for [T; 32] {
|
||||
type Element = T;
|
||||
type PartialStorage = [ManuallyDrop<T>; 32];
|
||||
const LEN: usize = 32;
|
||||
}
|
||||
|
||||
pub struct ArrayVec<A: Array> {
|
||||
count: usize,
|
||||
values: A::PartialStorage
|
||||
}
|
||||
|
||||
impl<A> Hash for ArrayVec<A>
|
||||
where A: Array,
|
||||
A::Element: Hash {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
(&self[..]).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> Clone for ArrayVec<A>
|
||||
where A: Array,
|
||||
A::Element: Clone {
|
||||
fn clone(&self) -> Self {
|
||||
let mut v = ArrayVec::new();
|
||||
v.extend(self.iter().cloned());
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> ArrayVec<A> {
|
||||
pub fn new() -> Self {
|
||||
ArrayVec {
|
||||
count: 0,
|
||||
values: unsafe { ::std::mem::uninitialized() },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.count
|
||||
}
|
||||
|
||||
pub unsafe fn set_len(&mut self, len: usize) {
|
||||
self.count = len;
|
||||
}
|
||||
|
||||
/// Panics when the stack vector is full.
|
||||
pub fn push(&mut self, el: A::Element) {
|
||||
let arr = &mut self.values as &mut [ManuallyDrop<_>];
|
||||
arr[self.count] = ManuallyDrop::new(el);
|
||||
self.count += 1;
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<A::Element> {
|
||||
if self.count > 0 {
|
||||
let arr = &mut self.values as &mut [ManuallyDrop<_>];
|
||||
self.count -= 1;
|
||||
unsafe {
|
||||
let value = ptr::read(&*arr[self.count]);
|
||||
Some(value)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain<A>
|
||||
where R: RangeBounds<usize>
|
||||
{
|
||||
// Memory safety
|
||||
//
|
||||
// When the Drain is first created, it shortens the length of
|
||||
// the source vector to make sure no uninitialized or moved-from elements
|
||||
// are accessible at all if the Drain's destructor never gets to run.
|
||||
//
|
||||
// Drain will ptr::read out the values to remove.
|
||||
// When finished, remaining tail of the vec is copied back to cover
|
||||
// the hole, and the vector length is restored to the new length.
|
||||
//
|
||||
let len = self.len();
|
||||
let start = match range.start_bound() {
|
||||
Included(&n) => n,
|
||||
Excluded(&n) => n + 1,
|
||||
Unbounded => 0,
|
||||
};
|
||||
let end = match range.end_bound() {
|
||||
Included(&n) => n + 1,
|
||||
Excluded(&n) => n,
|
||||
Unbounded => len,
|
||||
};
|
||||
assert!(start <= end);
|
||||
assert!(end <= len);
|
||||
|
||||
unsafe {
|
||||
// set self.vec length's to start, to be safe in case Drain is leaked
|
||||
self.set_len(start);
|
||||
// Use the borrow in the IterMut to indicate borrowing behavior of the
|
||||
// whole Drain iterator (like &mut T).
|
||||
let range_slice = {
|
||||
let arr = &mut self.values as &mut [ManuallyDrop<<A as Array>::Element>];
|
||||
slice::from_raw_parts_mut(arr.as_mut_ptr().add(start),
|
||||
end - start)
|
||||
};
|
||||
Drain {
|
||||
tail_start: end,
|
||||
tail_len: len - end,
|
||||
iter: range_slice.iter(),
|
||||
array_vec: NonNull::from(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> Default for ArrayVec<A>
|
||||
where A: Array {
|
||||
fn default() -> Self {
|
||||
ArrayVec::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> fmt::Debug for ArrayVec<A>
|
||||
where A: Array,
|
||||
A::Element: fmt::Debug {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self[..].fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> Deref for ArrayVec<A> {
|
||||
type Target = [A::Element];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe {
|
||||
slice::from_raw_parts(&self.values as *const _ as *const A::Element, self.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> DerefMut for ArrayVec<A> {
|
||||
fn deref_mut(&mut self) -> &mut [A::Element] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(&mut self.values as *mut _ as *mut A::Element, self.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> Drop for ArrayVec<A> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
drop_in_place(&mut self[..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> Extend<A::Element> for ArrayVec<A> {
|
||||
fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item=A::Element> {
|
||||
for el in iter {
|
||||
self.push(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<A: Array> {
|
||||
indices: Range<usize>,
|
||||
store: A::PartialStorage,
|
||||
}
|
||||
|
||||
impl<A: Array> Drop for Iter<A> {
|
||||
fn drop(&mut self) {
|
||||
self.for_each(drop);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> Iterator for Iter<A> {
|
||||
type Item = A::Element;
|
||||
|
||||
fn next(&mut self) -> Option<A::Element> {
|
||||
let arr = &self.store as &[ManuallyDrop<_>];
|
||||
unsafe {
|
||||
self.indices.next().map(|i| ptr::read(&*arr[i]))
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.indices.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Drain<'a, A: Array>
|
||||
where A::Element: 'a
|
||||
{
|
||||
tail_start: usize,
|
||||
tail_len: usize,
|
||||
iter: slice::Iter<'a, ManuallyDrop<A::Element>>,
|
||||
array_vec: NonNull<ArrayVec<A>>,
|
||||
}
|
||||
|
||||
impl<'a, A: Array> Iterator for Drain<'a, A> {
|
||||
type Item = A::Element;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A::Element> {
|
||||
self.iter.next().map(|elt| unsafe { ptr::read(&**elt) })
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Array> Drop for Drain<'a, A> {
|
||||
fn drop(&mut self) {
|
||||
// exhaust self first
|
||||
self.for_each(drop);
|
||||
|
||||
if self.tail_len > 0 {
|
||||
unsafe {
|
||||
let source_array_vec: &mut ArrayVec<A> = self.array_vec.as_mut();
|
||||
// memmove back untouched tail, update to new length
|
||||
let start = source_array_vec.len();
|
||||
let tail = self.tail_start;
|
||||
{
|
||||
let arr =
|
||||
&mut source_array_vec.values as &mut [ManuallyDrop<<A as Array>::Element>];
|
||||
let src = arr.as_ptr().add(tail);
|
||||
let dst = arr.as_mut_ptr().add(start);
|
||||
ptr::copy(src, dst, self.tail_len);
|
||||
};
|
||||
source_array_vec.set_len(start + self.tail_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> IntoIterator for ArrayVec<A> {
|
||||
type Item = A::Element;
|
||||
type IntoIter = Iter<A>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let store = unsafe {
|
||||
ptr::read(&self.values)
|
||||
};
|
||||
let indices = 0..self.count;
|
||||
mem::forget(self);
|
||||
Iter {
|
||||
indices,
|
||||
store,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Array> IntoIterator for &'a ArrayVec<A> {
|
||||
type Item = &'a A::Element;
|
||||
type IntoIter = slice::Iter<'a, A::Element>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Array> IntoIterator for &'a mut ArrayVec<A> {
|
||||
type Item = &'a mut A::Element;
|
||||
type IntoIter = slice::IterMut<'a, A::Element>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use array_vec::ArrayVec;
|
||||
use indexed_vec::{Idx, IndexVec};
|
||||
use rustc_serialize;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
use std::marker::PhantomData;
|
||||
@ -61,21 +61,21 @@ impl<T: Idx> BitSet<T> {
|
||||
}
|
||||
|
||||
/// Sets all elements up to and including `size`.
|
||||
pub fn set_up_to(&mut self, bit: usize) {
|
||||
pub fn set_up_to(&mut self, elem: usize) {
|
||||
for word in &mut self.words {
|
||||
*word = !0;
|
||||
}
|
||||
self.clear_above(bit);
|
||||
self.clear_above(elem);
|
||||
}
|
||||
|
||||
/// Clear all elements above `bit`.
|
||||
fn clear_above(&mut self, bit: usize) {
|
||||
let first_clear_block = bit / WORD_BITS;
|
||||
/// Clear all elements above `elem`.
|
||||
fn clear_above(&mut self, elem: usize) {
|
||||
let first_clear_block = elem / WORD_BITS;
|
||||
|
||||
if first_clear_block < self.words.len() {
|
||||
// Within `first_clear_block`, the `bit % WORD_BITS` LSBs should
|
||||
// Within `first_clear_block`, the `elem % WORD_BITS` LSBs should
|
||||
// remain.
|
||||
let mask = (1 << (bit % WORD_BITS)) - 1;
|
||||
let mask = (1 << (elem % WORD_BITS)) - 1;
|
||||
self.words[first_clear_block] &= mask;
|
||||
|
||||
// All the blocks above `first_clear_block` are fully cleared.
|
||||
@ -96,10 +96,10 @@ impl<T: Idx> BitSet<T> {
|
||||
self.words.iter().map(|e| e.count_ones() as usize).sum()
|
||||
}
|
||||
|
||||
/// True if `self` contains the bit `bit`.
|
||||
/// True if `self` contains `elem`.
|
||||
#[inline]
|
||||
pub fn contains(&self, bit: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(bit);
|
||||
pub fn contains(&self, elem: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(elem);
|
||||
(self.words[word_index] & mask) != 0
|
||||
}
|
||||
|
||||
@ -118,10 +118,10 @@ impl<T: Idx> BitSet<T> {
|
||||
self.words.iter().all(|a| *a == 0)
|
||||
}
|
||||
|
||||
/// Insert a bit. Returns true if the bit has changed.
|
||||
/// Insert `elem`. Returns true if the set has changed.
|
||||
#[inline]
|
||||
pub fn insert(&mut self, bit: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(bit);
|
||||
pub fn insert(&mut self, elem: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(elem);
|
||||
let word_ref = &mut self.words[word_index];
|
||||
let word = *word_ref;
|
||||
let new_word = word | mask;
|
||||
@ -136,10 +136,10 @@ impl<T: Idx> BitSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the bit has changed.
|
||||
/// Returns true if the set has changed.
|
||||
#[inline]
|
||||
pub fn remove(&mut self, bit: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(bit);
|
||||
pub fn remove(&mut self, elem: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(elem);
|
||||
let word_ref = &mut self.words[word_index];
|
||||
let word = *word_ref;
|
||||
let new_word = word & !mask;
|
||||
@ -320,31 +320,44 @@ fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
|
||||
const SPARSE_MAX: usize = 8;
|
||||
|
||||
/// A fixed-size bitset type with a sparse representation and a maximum of
|
||||
/// SPARSE_MAX elements. The elements are stored as an unsorted vector with no
|
||||
/// duplicates.
|
||||
/// `SPARSE_MAX` elements. The elements are stored as a sorted `SmallVec` with
|
||||
/// no duplicates; although `SmallVec` can spill its elements to the heap, that
|
||||
/// never happens within this type because of the `SPARSE_MAX` limit.
|
||||
///
|
||||
/// This type is used by HybridBitSet; do not use directly.
|
||||
/// This type is used by `HybridBitSet`; do not use directly.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SparseBitSet<T: Idx>(ArrayVec<[T; SPARSE_MAX]>);
|
||||
pub struct SparseBitSet<T: Idx>(SmallVec<[T; SPARSE_MAX]>);
|
||||
|
||||
impl<T: Idx> SparseBitSet<T> {
|
||||
fn new_empty() -> Self {
|
||||
SparseBitSet(ArrayVec::new())
|
||||
SparseBitSet(SmallVec::new())
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.0.len() == 0
|
||||
}
|
||||
|
||||
fn contains(&self, elem: T) -> bool {
|
||||
self.0.contains(&elem)
|
||||
}
|
||||
|
||||
fn insert(&mut self, elem: T) -> bool {
|
||||
// Ensure there are no duplicates.
|
||||
if self.0.contains(&elem) {
|
||||
assert!(self.len() < SPARSE_MAX);
|
||||
if let Some(i) = self.0.iter().position(|&e| e >= elem) {
|
||||
if self.0[i] == elem {
|
||||
// `elem` is already in the set.
|
||||
false
|
||||
} else {
|
||||
// `elem` is smaller than one or more existing elements.
|
||||
self.0.insert(i, elem);
|
||||
true
|
||||
}
|
||||
} else {
|
||||
// `elem` is larger than all existing elements.
|
||||
self.0.push(elem);
|
||||
true
|
||||
}
|
||||
@ -352,10 +365,7 @@ impl<T: Idx> SparseBitSet<T> {
|
||||
|
||||
fn remove(&mut self, elem: T) -> bool {
|
||||
if let Some(i) = self.0.iter().position(|&e| e == elem) {
|
||||
// Swap the found element to the end, then pop it.
|
||||
let len = self.0.len();
|
||||
self.0.swap(i, len - 1);
|
||||
self.0.pop();
|
||||
self.0.remove(i);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -396,8 +406,8 @@ impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
|
||||
}
|
||||
|
||||
/// A fixed-size bitset type with a hybrid representation: sparse when there
|
||||
/// are up to a SPARSE_MAX elements in the set, but dense when there are more
|
||||
/// than SPARSE_MAX.
|
||||
/// are up to a `SPARSE_MAX` elements in the set, but dense when there are more
|
||||
/// than `SPARSE_MAX`.
|
||||
///
|
||||
/// This type is especially efficient for sets that typically have a small
|
||||
/// number of elements, but a large `domain_size`, and are cleared frequently.
|
||||
@ -411,15 +421,28 @@ pub enum HybridBitSet<T: Idx> {
|
||||
}
|
||||
|
||||
impl<T: Idx> HybridBitSet<T> {
|
||||
// FIXME: This function is used in conjunction with `mem::replace()` in
|
||||
// several pieces of awful code below. I can't work out how else to appease
|
||||
// the borrow checker.
|
||||
fn dummy() -> Self {
|
||||
// The cheapest HybridBitSet to construct, which is only used to get
|
||||
// around the borrow checker.
|
||||
HybridBitSet::Sparse(SparseBitSet::new_empty(), 0)
|
||||
}
|
||||
|
||||
pub fn new_empty(domain_size: usize) -> Self {
|
||||
HybridBitSet::Sparse(SparseBitSet::new_empty(), domain_size)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
let domain_size = match *self {
|
||||
pub fn domain_size(&self) -> usize {
|
||||
match *self {
|
||||
HybridBitSet::Sparse(_, size) => size,
|
||||
HybridBitSet::Dense(_, size) => size,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
let domain_size = self.domain_size();
|
||||
*self = HybridBitSet::new_empty(domain_size);
|
||||
}
|
||||
|
||||
@ -430,6 +453,22 @@ impl<T: Idx> HybridBitSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn superset(&self, other: &HybridBitSet<T>) -> bool {
|
||||
match (self, other) {
|
||||
(HybridBitSet::Dense(self_dense, _), HybridBitSet::Dense(other_dense, _)) => {
|
||||
self_dense.superset(other_dense)
|
||||
}
|
||||
_ => other.iter().all(|elem| self.contains(elem)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
HybridBitSet::Sparse(sparse, _) => sparse.is_empty(),
|
||||
HybridBitSet::Dense(dense, _) => dense.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, elem: T) -> bool {
|
||||
match self {
|
||||
HybridBitSet::Sparse(sparse, _) if sparse.len() < SPARSE_MAX => {
|
||||
@ -443,19 +482,15 @@ impl<T: Idx> HybridBitSet<T> {
|
||||
}
|
||||
HybridBitSet::Sparse(_, _) => {
|
||||
// The set is sparse and full. Convert to a dense set.
|
||||
//
|
||||
// FIXME: This code is awful, but I can't work out how else to
|
||||
// appease the borrow checker.
|
||||
let dummy = HybridBitSet::Sparse(SparseBitSet::new_empty(), 0);
|
||||
match mem::replace(self, dummy) {
|
||||
match mem::replace(self, HybridBitSet::dummy()) {
|
||||
HybridBitSet::Sparse(sparse, domain_size) => {
|
||||
let mut dense = sparse.to_dense(domain_size);
|
||||
let changed = dense.insert(elem);
|
||||
assert!(changed);
|
||||
mem::replace(self, HybridBitSet::Dense(dense, domain_size));
|
||||
*self = HybridBitSet::Dense(dense, domain_size);
|
||||
changed
|
||||
}
|
||||
_ => panic!("impossible"),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,6 +498,17 @@ impl<T: Idx> HybridBitSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_all(&mut self) {
|
||||
let domain_size = self.domain_size();
|
||||
match self {
|
||||
HybridBitSet::Sparse(_, _) => {
|
||||
let dense = BitSet::new_filled(domain_size);
|
||||
*self = HybridBitSet::Dense(dense, domain_size);
|
||||
}
|
||||
HybridBitSet::Dense(dense, _) => dense.insert_all(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, elem: T) -> bool {
|
||||
// Note: we currently don't bother going from Dense back to Sparse.
|
||||
match self {
|
||||
@ -471,6 +517,42 @@ impl<T: Idx> HybridBitSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union(&mut self, other: &HybridBitSet<T>) -> bool {
|
||||
match self {
|
||||
HybridBitSet::Sparse(_, _) => {
|
||||
match other {
|
||||
HybridBitSet::Sparse(other_sparse, _) => {
|
||||
// Both sets are sparse. Add the elements in
|
||||
// `other_sparse` to `self_hybrid` one at a time. This
|
||||
// may or may not cause `self_hybrid` to be densified.
|
||||
let mut self_hybrid = mem::replace(self, HybridBitSet::dummy());
|
||||
let mut changed = false;
|
||||
for elem in other_sparse.iter() {
|
||||
changed |= self_hybrid.insert(*elem);
|
||||
}
|
||||
*self = self_hybrid;
|
||||
changed
|
||||
}
|
||||
HybridBitSet::Dense(other_dense, _) => {
|
||||
// `self` is sparse and `other` is dense. Densify
|
||||
// `self` and then do the bitwise union.
|
||||
match mem::replace(self, HybridBitSet::dummy()) {
|
||||
HybridBitSet::Sparse(self_sparse, self_domain_size) => {
|
||||
let mut new_dense = self_sparse.to_dense(self_domain_size);
|
||||
let changed = new_dense.union(other_dense);
|
||||
*self = HybridBitSet::Dense(new_dense, self_domain_size);
|
||||
changed
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HybridBitSet::Dense(self_dense, _) => self_dense.union(other),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts to a dense set, consuming itself in the process.
|
||||
pub fn to_dense(self) -> BitSet<T> {
|
||||
match self {
|
||||
@ -479,7 +561,6 @@ impl<T: Idx> HybridBitSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Iteration order is unspecified.
|
||||
pub fn iter(&self) -> HybridIter<T> {
|
||||
match self {
|
||||
HybridBitSet::Sparse(sparse, _) => HybridIter::Sparse(sparse.iter()),
|
||||
@ -547,16 +628,16 @@ impl<T: Idx> GrowableBitSet<T> {
|
||||
GrowableBitSet { bit_set: BitSet::new_empty(bits) }
|
||||
}
|
||||
|
||||
/// Returns true if the bit has changed.
|
||||
/// Returns true if the set has changed.
|
||||
#[inline]
|
||||
pub fn insert(&mut self, bit: T) -> bool {
|
||||
self.grow(bit);
|
||||
self.bit_set.insert(bit)
|
||||
pub fn insert(&mut self, elem: T) -> bool {
|
||||
self.grow(elem);
|
||||
self.bit_set.insert(elem)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, bit: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(bit);
|
||||
pub fn contains(&self, elem: T) -> bool {
|
||||
let (word_index, mask) = word_index_and_mask(elem);
|
||||
if let Some(word) = self.bit_set.words.get(word_index) {
|
||||
(word & mask) != 0
|
||||
} else {
|
||||
@ -682,11 +763,10 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
|
||||
/// sparse representation.
|
||||
///
|
||||
/// Initially, every row has no explicit representation. If any bit within a
|
||||
/// row is set, the entire row is instantiated as
|
||||
/// `Some(<full-column-width-BitSet>)`. Furthermore, any previously
|
||||
/// uninstantiated rows prior to it will be instantiated as `None`. Those prior
|
||||
/// rows may themselves become fully instantiated later on if any of their bits
|
||||
/// are set.
|
||||
/// row is set, the entire row is instantiated as `Some(<HybridBitSet>)`.
|
||||
/// Furthermore, any previously uninstantiated rows prior to it will be
|
||||
/// instantiated as `None`. Those prior rows may themselves become fully
|
||||
/// instantiated later on if any of their bits are set.
|
||||
///
|
||||
/// `R` and `C` are index types used to identify rows and columns respectively;
|
||||
/// typically newtyped `usize` wrappers, but they can also just be `usize`.
|
||||
@ -697,7 +777,7 @@ where
|
||||
C: Idx,
|
||||
{
|
||||
num_columns: usize,
|
||||
rows: IndexVec<R, Option<BitSet<C>>>,
|
||||
rows: IndexVec<R, Option<HybridBitSet<C>>>,
|
||||
}
|
||||
|
||||
impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
|
||||
@ -709,14 +789,14 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_row(&mut self, row: R) -> &mut BitSet<C> {
|
||||
fn ensure_row(&mut self, row: R) -> &mut HybridBitSet<C> {
|
||||
// Instantiate any missing rows up to and including row `row` with an
|
||||
// empty BitSet.
|
||||
// empty HybridBitSet.
|
||||
self.rows.ensure_contains_elem(row, || None);
|
||||
|
||||
// Then replace row `row` with a full BitSet if necessary.
|
||||
// Then replace row `row` with a full HybridBitSet if necessary.
|
||||
let num_columns = self.num_columns;
|
||||
self.rows[row].get_or_insert_with(|| BitSet::new_empty(num_columns))
|
||||
self.rows[row].get_or_insert_with(|| HybridBitSet::new_empty(num_columns))
|
||||
}
|
||||
|
||||
/// Sets the cell at `(row, column)` to true. Put another way, insert
|
||||
@ -755,8 +835,8 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Merge a row, `from`, into the `into` row.
|
||||
pub fn union_into_row(&mut self, into: R, from: &BitSet<C>) -> bool {
|
||||
/// Union a row, `from`, into the `into` row.
|
||||
pub fn union_into_row(&mut self, into: R, from: &HybridBitSet<C>) -> bool {
|
||||
self.ensure_row(into).union(from)
|
||||
}
|
||||
|
||||
@ -775,7 +855,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
|
||||
self.row(row).into_iter().flat_map(|r| r.iter())
|
||||
}
|
||||
|
||||
pub fn row(&self, row: R) -> Option<&BitSet<C>> {
|
||||
pub fn row(&self, row: R) -> Option<&HybridBitSet<C>> {
|
||||
if let Some(Some(row)) = self.rows.get(row) {
|
||||
Some(row)
|
||||
} else {
|
||||
@ -866,7 +946,7 @@ fn bitset_iter_works_2() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn union_two_vecs() {
|
||||
fn union_two_sets() {
|
||||
let mut set1: BitSet<usize> = BitSet::new_empty(65);
|
||||
let mut set2: BitSet<usize> = BitSet::new_empty(65);
|
||||
assert!(set1.insert(3));
|
||||
@ -882,6 +962,74 @@ fn union_two_vecs() {
|
||||
assert!(set1.contains(64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hybrid_bitset() {
|
||||
let mut sparse038: HybridBitSet<usize> = HybridBitSet::new_empty(256);
|
||||
assert!(sparse038.is_empty());
|
||||
assert!(sparse038.insert(0));
|
||||
assert!(sparse038.insert(1));
|
||||
assert!(sparse038.insert(8));
|
||||
assert!(sparse038.insert(3));
|
||||
assert!(!sparse038.insert(3));
|
||||
assert!(sparse038.remove(1));
|
||||
assert!(!sparse038.is_empty());
|
||||
assert_eq!(sparse038.iter().collect::<Vec<_>>(), [0, 3, 8]);
|
||||
|
||||
for i in 0..256 {
|
||||
if i == 0 || i == 3 || i == 8 {
|
||||
assert!(sparse038.contains(i));
|
||||
} else {
|
||||
assert!(!sparse038.contains(i));
|
||||
}
|
||||
}
|
||||
|
||||
let mut sparse01358 = sparse038.clone();
|
||||
assert!(sparse01358.insert(1));
|
||||
assert!(sparse01358.insert(5));
|
||||
assert_eq!(sparse01358.iter().collect::<Vec<_>>(), [0, 1, 3, 5, 8]);
|
||||
|
||||
let mut dense10 = HybridBitSet::new_empty(256);
|
||||
for i in 0..10 {
|
||||
assert!(dense10.insert(i));
|
||||
}
|
||||
assert!(!dense10.is_empty());
|
||||
assert_eq!(dense10.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
|
||||
let mut dense256 = HybridBitSet::new_empty(256);
|
||||
assert!(dense256.is_empty());
|
||||
dense256.insert_all();
|
||||
assert!(!dense256.is_empty());
|
||||
for i in 0..256 {
|
||||
assert!(dense256.contains(i));
|
||||
}
|
||||
|
||||
assert!(sparse038.superset(&sparse038)); // sparse + sparse (self)
|
||||
assert!(sparse01358.superset(&sparse038)); // sparse + sparse
|
||||
assert!(dense10.superset(&sparse038)); // dense + sparse
|
||||
assert!(dense10.superset(&dense10)); // dense + dense (self)
|
||||
assert!(dense256.superset(&dense10)); // dense + dense
|
||||
|
||||
let mut hybrid = sparse038;
|
||||
assert!(!sparse01358.union(&hybrid)); // no change
|
||||
assert!(hybrid.union(&sparse01358));
|
||||
assert!(hybrid.superset(&sparse01358) && sparse01358.superset(&hybrid));
|
||||
assert!(!dense10.union(&sparse01358));
|
||||
assert!(!dense256.union(&dense10));
|
||||
let mut dense = dense10;
|
||||
assert!(dense.union(&dense256));
|
||||
assert!(dense.superset(&dense256) && dense256.superset(&dense));
|
||||
assert!(hybrid.union(&dense256));
|
||||
assert!(hybrid.superset(&dense256) && dense256.superset(&hybrid));
|
||||
|
||||
assert_eq!(dense256.iter().count(), 256);
|
||||
let mut dense0 = dense256;
|
||||
for i in 0..256 {
|
||||
assert!(dense0.remove(i));
|
||||
}
|
||||
assert!(!dense0.remove(0));
|
||||
assert!(dense0.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grow() {
|
||||
let mut set: GrowableBitSet<usize> = GrowableBitSet::with_capacity(65);
|
||||
|
@ -60,7 +60,6 @@ extern crate rustc_cratesio_shim;
|
||||
pub use rustc_serialize::hex::ToHex;
|
||||
|
||||
pub mod svh;
|
||||
pub mod array_vec;
|
||||
pub mod base_n;
|
||||
pub mod bit_set;
|
||||
pub mod const_cstr;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
use rustc::mir::{BasicBlock, Location, Mir};
|
||||
use rustc::ty::{self, RegionVid};
|
||||
use rustc_data_structures::bit_set::{BitSet, SparseBitMatrix};
|
||||
use rustc_data_structures::bit_set::{HybridBitSet, SparseBitMatrix};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use std::fmt::Debug;
|
||||
@ -184,7 +184,7 @@ impl<N: Idx> LivenessValues<N> {
|
||||
|
||||
/// Adds all the elements in the given bit array into the given
|
||||
/// region. Returns true if any of them are newly added.
|
||||
crate fn add_elements(&mut self, row: N, locations: &BitSet<PointIndex>) -> bool {
|
||||
crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
|
||||
debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
|
||||
self.points.union_into_row(row, locations)
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
|
||||
use rustc::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc::traits::query::type_op::TypeOp;
|
||||
use rustc::ty::{Ty, TypeFoldable};
|
||||
use rustc_data_structures::bit_set::BitSet;
|
||||
use rustc_data_structures::bit_set::HybridBitSet;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use std::rc::Rc;
|
||||
use util::liveness::LiveVariableMap;
|
||||
@ -121,16 +121,16 @@ where
|
||||
cx: LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>,
|
||||
|
||||
/// Set of points that define the current local.
|
||||
defs: BitSet<PointIndex>,
|
||||
defs: HybridBitSet<PointIndex>,
|
||||
|
||||
/// Points where the current variable is "use live" -- meaning
|
||||
/// that there is a future "full use" that may use its value.
|
||||
use_live_at: BitSet<PointIndex>,
|
||||
use_live_at: HybridBitSet<PointIndex>,
|
||||
|
||||
/// Points where the current variable is "drop live" -- meaning
|
||||
/// that there is no future "full use" that may use its value, but
|
||||
/// there is a future drop.
|
||||
drop_live_at: BitSet<PointIndex>,
|
||||
drop_live_at: HybridBitSet<PointIndex>,
|
||||
|
||||
/// Locations where drops may occur.
|
||||
drop_locations: Vec<Location>,
|
||||
@ -144,9 +144,9 @@ impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> {
|
||||
let num_points = cx.elements.num_points();
|
||||
LivenessResults {
|
||||
cx,
|
||||
defs: BitSet::new_empty(num_points),
|
||||
use_live_at: BitSet::new_empty(num_points),
|
||||
drop_live_at: BitSet::new_empty(num_points),
|
||||
defs: HybridBitSet::new_empty(num_points),
|
||||
use_live_at: HybridBitSet::new_empty(num_points),
|
||||
drop_live_at: HybridBitSet::new_empty(num_points),
|
||||
drop_locations: vec![],
|
||||
stack: vec![],
|
||||
}
|
||||
@ -448,7 +448,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> {
|
||||
fn add_use_live_facts_for(
|
||||
&mut self,
|
||||
value: impl TypeFoldable<'tcx>,
|
||||
live_at: &BitSet<PointIndex>,
|
||||
live_at: &HybridBitSet<PointIndex>,
|
||||
) {
|
||||
debug!("add_use_live_facts_for(value={:?})", value);
|
||||
|
||||
@ -465,7 +465,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> {
|
||||
dropped_local: Local,
|
||||
dropped_ty: Ty<'tcx>,
|
||||
drop_locations: &[Location],
|
||||
live_at: &BitSet<PointIndex>,
|
||||
live_at: &HybridBitSet<PointIndex>,
|
||||
) {
|
||||
debug!(
|
||||
"add_drop_live_constraint(\
|
||||
@ -508,7 +508,7 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> {
|
||||
elements: &RegionValueElements,
|
||||
typeck: &mut TypeChecker<'_, '_, 'tcx>,
|
||||
value: impl TypeFoldable<'tcx>,
|
||||
live_at: &BitSet<PointIndex>,
|
||||
live_at: &HybridBitSet<PointIndex>,
|
||||
) {
|
||||
debug!("make_all_regions_live(value={:?})", value);
|
||||
debug!(
|
||||
|
Loading…
Reference in New Issue
Block a user