diff options
| author | bors <bors@rust-lang.org> | 2020-08-30 15:57:57 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-08-30 15:57:57 +0000 |
| commit | 85fbf49ce0e2274d0acf798f6e703747674feec3 (patch) | |
| tree | 158a05eb3f204a8e72939b58427d0c2787a4eade /compiler/rustc_index/src | |
| parent | db534b3ac286cf45688c3bbae6aa6e77439e52d2 (diff) | |
| parent | 9e5f7d5631b8f4009ac1c693e585d4b7108d4275 (diff) | |
| download | rust-85fbf49ce0e2274d0acf798f6e703747674feec3.tar.gz rust-85fbf49ce0e2274d0acf798f6e703747674feec3.zip | |
Auto merge of #74862 - mark-i-m:mv-compiler, r=petrochenkov
Move almost all compiler crates to compiler/ This PR implements https://github.com/rust-lang/compiler-team/issues/336 and moves all `rustc_*` crates from `src` to the new `compiler` directory. `librustc_foo` directories are renamed to `rustc_foo`. `src` directories are introduced inside `rustc_*` directories to mirror the scheme already use for `library` crates.
Diffstat (limited to 'compiler/rustc_index/src')
| -rw-r--r-- | compiler/rustc_index/src/bit_set.rs | 1164 | ||||
| -rw-r--r-- | compiler/rustc_index/src/bit_set/tests.rs | 366 | ||||
| -rw-r--r-- | compiler/rustc_index/src/lib.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_index/src/vec.rs | 846 | ||||
| -rw-r--r-- | compiler/rustc_index/src/vec/tests.rs | 51 |
5 files changed, 2438 insertions, 0 deletions
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs new file mode 100644 index 00000000000..c43d1a6830d --- /dev/null +++ b/compiler/rustc_index/src/bit_set.rs @@ -0,0 +1,1164 @@ +use crate::vec::{Idx, IndexVec}; +use arrayvec::ArrayVec; +use std::fmt; +use std::iter; +use std::marker::PhantomData; +use std::mem; +use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl}; +use std::slice; + +use rustc_macros::{Decodable, Encodable}; + +#[cfg(test)] +mod tests; + +pub type Word = u64; +pub const WORD_BYTES: usize = mem::size_of::<Word>(); +pub const WORD_BITS: usize = WORD_BYTES * 8; + +/// A fixed-size bitset type with a dense representation. +/// +/// NOTE: Use [`GrowableBitSet`] if you need support for resizing after creation. +/// +/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also +/// just be `usize`. +/// +/// All operations that involve an element will panic if the element is equal +/// to or greater than the domain size. All operations that involve two bitsets +/// will panic if the bitsets have differing domain sizes. +/// +/// [`GrowableBitSet`]: struct.GrowableBitSet.html +#[derive(Clone, Eq, PartialEq, Decodable, Encodable)] +pub struct BitSet<T: Idx> { + domain_size: usize, + words: Vec<Word>, + marker: PhantomData<T>, +} + +impl<T: Idx> BitSet<T> { + /// Creates a new, empty bitset with a given `domain_size`. + #[inline] + pub fn new_empty(domain_size: usize) -> BitSet<T> { + let num_words = num_words(domain_size); + BitSet { domain_size, words: vec![0; num_words], marker: PhantomData } + } + + /// Creates a new, filled bitset with a given `domain_size`. + #[inline] + pub fn new_filled(domain_size: usize) -> BitSet<T> { + let num_words = num_words(domain_size); + let mut result = BitSet { domain_size, words: vec![!0; num_words], marker: PhantomData }; + result.clear_excess_bits(); + result + } + + /// Gets the domain size. + pub fn domain_size(&self) -> usize { + self.domain_size + } + + /// Clear all elements. + #[inline] + pub fn clear(&mut self) { + for word in &mut self.words { + *word = 0; + } + } + + /// Clear excess bits in the final word. + fn clear_excess_bits(&mut self) { + let num_bits_in_final_word = self.domain_size % WORD_BITS; + if num_bits_in_final_word > 0 { + let mask = (1 << num_bits_in_final_word) - 1; + let final_word_idx = self.words.len() - 1; + self.words[final_word_idx] &= mask; + } + } + + /// Efficiently overwrite `self` with `other`. + pub fn overwrite(&mut self, other: &BitSet<T>) { + assert!(self.domain_size == other.domain_size); + self.words.clone_from_slice(&other.words); + } + + /// Count the number of set bits in the set. + pub fn count(&self) -> usize { + self.words.iter().map(|e| e.count_ones() as usize).sum() + } + + /// Returns `true` if `self` contains `elem`. + #[inline] + pub fn contains(&self, elem: T) -> bool { + assert!(elem.index() < self.domain_size); + let (word_index, mask) = word_index_and_mask(elem); + (self.words[word_index] & mask) != 0 + } + + /// Is `self` is a (non-strict) superset of `other`? + #[inline] + pub fn superset(&self, other: &BitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + self.words.iter().zip(&other.words).all(|(a, b)| (a & b) == *b) + } + + /// Is the set empty? + #[inline] + pub fn is_empty(&self) -> bool { + self.words.iter().all(|a| *a == 0) + } + + /// Insert `elem`. Returns whether the set has changed. + #[inline] + pub fn insert(&mut self, elem: T) -> bool { + assert!(elem.index() < self.domain_size); + 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; + *word_ref = new_word; + new_word != word + } + + /// Sets all bits to true. + pub fn insert_all(&mut self) { + for word in &mut self.words { + *word = !0; + } + self.clear_excess_bits(); + } + + /// Returns `true` if the set has changed. + #[inline] + pub fn remove(&mut self, elem: T) -> bool { + assert!(elem.index() < self.domain_size); + 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; + *word_ref = new_word; + new_word != word + } + + /// Sets `self = self | other` and returns `true` if `self` changed + /// (i.e., if new bits were added). + pub fn union(&mut self, other: &impl UnionIntoBitSet<T>) -> bool { + other.union_into(self) + } + + /// Sets `self = self - other` and returns `true` if `self` changed. + /// (i.e., if any bits were removed). + pub fn subtract(&mut self, other: &impl SubtractFromBitSet<T>) -> bool { + other.subtract_from(self) + } + + /// Sets `self = self & other` and return `true` if `self` changed. + /// (i.e., if any bits were removed). + pub fn intersect(&mut self, other: &BitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + bitwise(&mut self.words, &other.words, |a, b| a & b) + } + + /// Gets a slice of the underlying words. + pub fn words(&self) -> &[Word] { + &self.words + } + + /// Iterates over the indices of set bits in a sorted order. + #[inline] + pub fn iter(&self) -> BitIter<'_, T> { + BitIter::new(&self.words) + } + + /// Duplicates the set as a hybrid set. + pub fn to_hybrid(&self) -> HybridBitSet<T> { + // Note: we currently don't bother trying to make a Sparse set. + HybridBitSet::Dense(self.to_owned()) + } + + /// Set `self = self | other`. In contrast to `union` returns `true` if the set contains at + /// least one bit that is not in `other` (i.e. `other` is not a superset of `self`). + /// + /// This is an optimization for union of a hybrid bitset. + fn reverse_union_sparse(&mut self, sparse: &SparseBitSet<T>) -> bool { + assert!(sparse.domain_size == self.domain_size); + self.clear_excess_bits(); + + let mut not_already = false; + // Index of the current word not yet merged. + let mut current_index = 0; + // Mask of bits that came from the sparse set in the current word. + let mut new_bit_mask = 0; + for (word_index, mask) in sparse.iter().map(|x| word_index_and_mask(*x)) { + // Next bit is in a word not inspected yet. + if word_index > current_index { + self.words[current_index] |= new_bit_mask; + // Were there any bits in the old word that did not occur in the sparse set? + not_already |= (self.words[current_index] ^ new_bit_mask) != 0; + // Check all words we skipped for any set bit. + not_already |= self.words[current_index + 1..word_index].iter().any(|&x| x != 0); + // Update next word. + current_index = word_index; + // Reset bit mask, no bits have been merged yet. + new_bit_mask = 0; + } + // Add bit and mark it as coming from the sparse set. + // self.words[word_index] |= mask; + new_bit_mask |= mask; + } + self.words[current_index] |= new_bit_mask; + // Any bits in the last inspected word that were not in the sparse set? + not_already |= (self.words[current_index] ^ new_bit_mask) != 0; + // Any bits in the tail? Note `clear_excess_bits` before. + not_already |= self.words[current_index + 1..].iter().any(|&x| x != 0); + + not_already + } +} + +/// This is implemented by all the bitsets so that BitSet::union() can be +/// passed any type of bitset. +pub trait UnionIntoBitSet<T: Idx> { + // Performs `other = other | self`. + fn union_into(&self, other: &mut BitSet<T>) -> bool; +} + +/// This is implemented by all the bitsets so that BitSet::subtract() can be +/// passed any type of bitset. +pub trait SubtractFromBitSet<T: Idx> { + // Performs `other = other - self`. + fn subtract_from(&self, other: &mut BitSet<T>) -> bool; +} + +impl<T: Idx> UnionIntoBitSet<T> for BitSet<T> { + fn union_into(&self, other: &mut BitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + bitwise(&mut other.words, &self.words, |a, b| a | b) + } +} + +impl<T: Idx> SubtractFromBitSet<T> for BitSet<T> { + fn subtract_from(&self, other: &mut BitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + bitwise(&mut other.words, &self.words, |a, b| a & !b) + } +} + +impl<T: Idx> fmt::Debug for BitSet<T> { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + w.debug_list().entries(self.iter()).finish() + } +} + +impl<T: Idx> ToString for BitSet<T> { + fn to_string(&self) -> String { + let mut result = String::new(); + let mut sep = '['; + + // Note: this is a little endian printout of bytes. + + // i tracks how many bits we have printed so far. + let mut i = 0; + for word in &self.words { + let mut word = *word; + for _ in 0..WORD_BYTES { + // for each byte in `word`: + let remain = self.domain_size - i; + // If less than a byte remains, then mask just that many bits. + let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; + assert!(mask <= 0xFF); + let byte = word & mask; + + result.push_str(&format!("{}{:02x}", sep, byte)); + + if remain <= 8 { + break; + } + word >>= 8; + i += 8; + sep = '-'; + } + sep = '|'; + } + result.push(']'); + + result + } +} + +pub struct BitIter<'a, T: Idx> { + /// A copy of the current word, but with any already-visited bits cleared. + /// (This lets us use `trailing_zeros()` to find the next set bit.) When it + /// is reduced to 0, we move onto the next word. + word: Word, + + /// The offset (measured in bits) of the current word. + offset: usize, + + /// Underlying iterator over the words. + iter: slice::Iter<'a, Word>, + + marker: PhantomData<T>, +} + +impl<'a, T: Idx> BitIter<'a, T> { + #[inline] + fn new(words: &'a [Word]) -> BitIter<'a, T> { + // We initialize `word` and `offset` to degenerate values. On the first + // call to `next()` we will fall through to getting the first word from + // `iter`, which sets `word` to the first word (if there is one) and + // `offset` to 0. Doing it this way saves us from having to maintain + // additional state about whether we have started. + BitIter { + word: 0, + offset: usize::MAX - (WORD_BITS - 1), + iter: words.iter(), + marker: PhantomData, + } + } +} + +impl<'a, T: Idx> Iterator for BitIter<'a, T> { + type Item = T; + fn next(&mut self) -> Option<T> { + loop { + if self.word != 0 { + // Get the position of the next set bit in the current word, + // then clear the bit. + let bit_pos = self.word.trailing_zeros() as usize; + let bit = 1 << bit_pos; + self.word ^= bit; + return Some(T::new(bit_pos + self.offset)); + } + + // Move onto the next word. `wrapping_add()` is needed to handle + // the degenerate initial value given to `offset` in `new()`. + let word = self.iter.next()?; + self.word = *word; + self.offset = self.offset.wrapping_add(WORD_BITS); + } + } +} + +#[inline] +fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool +where + Op: Fn(Word, Word) -> Word, +{ + assert_eq!(out_vec.len(), in_vec.len()); + let mut changed = false; + for (out_elem, in_elem) in out_vec.iter_mut().zip(in_vec.iter()) { + let old_val = *out_elem; + let new_val = op(old_val, *in_elem); + *out_elem = new_val; + changed |= old_val != new_val; + } + changed +} + +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 a sorted `ArrayVec` with +/// no duplicates. +/// +/// This type is used by `HybridBitSet`; do not use directly. +#[derive(Clone, Debug)] +pub struct SparseBitSet<T: Idx> { + domain_size: usize, + elems: ArrayVec<[T; SPARSE_MAX]>, +} + +impl<T: Idx> SparseBitSet<T> { + fn new_empty(domain_size: usize) -> Self { + SparseBitSet { domain_size, elems: ArrayVec::new() } + } + + fn len(&self) -> usize { + self.elems.len() + } + + fn is_empty(&self) -> bool { + self.elems.len() == 0 + } + + fn contains(&self, elem: T) -> bool { + assert!(elem.index() < self.domain_size); + self.elems.contains(&elem) + } + + fn insert(&mut self, elem: T) -> bool { + assert!(elem.index() < self.domain_size); + let changed = if let Some(i) = self.elems.iter().position(|&e| e >= elem) { + if self.elems[i] == elem { + // `elem` is already in the set. + false + } else { + // `elem` is smaller than one or more existing elements. + self.elems.insert(i, elem); + true + } + } else { + // `elem` is larger than all existing elements. + self.elems.push(elem); + true + }; + assert!(self.len() <= SPARSE_MAX); + changed + } + + fn remove(&mut self, elem: T) -> bool { + assert!(elem.index() < self.domain_size); + if let Some(i) = self.elems.iter().position(|&e| e == elem) { + self.elems.remove(i); + true + } else { + false + } + } + + fn to_dense(&self) -> BitSet<T> { + let mut dense = BitSet::new_empty(self.domain_size); + for elem in self.elems.iter() { + dense.insert(*elem); + } + dense + } + + fn iter(&self) -> slice::Iter<'_, T> { + self.elems.iter() + } +} + +impl<T: Idx> UnionIntoBitSet<T> for SparseBitSet<T> { + fn union_into(&self, other: &mut BitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + let mut changed = false; + for elem in self.iter() { + changed |= other.insert(*elem); + } + changed + } +} + +impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> { + fn subtract_from(&self, other: &mut BitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + let mut changed = false; + for elem in self.iter() { + changed |= other.remove(*elem); + } + changed + } +} + +/// 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`. +/// +/// This type is especially efficient for sets that typically have a small +/// number of elements, but a large `domain_size`, and are cleared frequently. +/// +/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also +/// just be `usize`. +/// +/// All operations that involve an element will panic if the element is equal +/// to or greater than the domain size. All operations that involve two bitsets +/// will panic if the bitsets have differing domain sizes. +#[derive(Clone, Debug)] +pub enum HybridBitSet<T: Idx> { + Sparse(SparseBitSet<T>), + Dense(BitSet<T>), +} + +impl<T: Idx> HybridBitSet<T> { + pub fn new_empty(domain_size: usize) -> Self { + HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size)) + } + + fn domain_size(&self) -> usize { + match self { + HybridBitSet::Sparse(sparse) => sparse.domain_size, + HybridBitSet::Dense(dense) => dense.domain_size, + } + } + + pub fn clear(&mut self) { + let domain_size = self.domain_size(); + *self = HybridBitSet::new_empty(domain_size); + } + + pub fn contains(&self, elem: T) -> bool { + match self { + HybridBitSet::Sparse(sparse) => sparse.contains(elem), + HybridBitSet::Dense(dense) => dense.contains(elem), + } + } + + pub fn superset(&self, other: &HybridBitSet<T>) -> bool { + match (self, other) { + (HybridBitSet::Dense(self_dense), HybridBitSet::Dense(other_dense)) => { + self_dense.superset(other_dense) + } + _ => { + assert!(self.domain_size() == other.domain_size()); + 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 { + // No need to check `elem` against `self.domain_size` here because all + // the match cases check it, one way or another. + match self { + HybridBitSet::Sparse(sparse) if sparse.len() < SPARSE_MAX => { + // The set is sparse and has space for `elem`. + sparse.insert(elem) + } + HybridBitSet::Sparse(sparse) if sparse.contains(elem) => { + // The set is sparse and does not have space for `elem`, but + // that doesn't matter because `elem` is already present. + false + } + HybridBitSet::Sparse(sparse) => { + // The set is sparse and full. Convert to a dense set. + let mut dense = sparse.to_dense(); + let changed = dense.insert(elem); + assert!(changed); + *self = HybridBitSet::Dense(dense); + changed + } + HybridBitSet::Dense(dense) => dense.insert(elem), + } + } + + pub fn insert_all(&mut self) { + let domain_size = self.domain_size(); + match self { + HybridBitSet::Sparse(_) => { + *self = HybridBitSet::Dense(BitSet::new_filled(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 { + HybridBitSet::Sparse(sparse) => sparse.remove(elem), + HybridBitSet::Dense(dense) => dense.remove(elem), + } + } + + pub fn union(&mut self, other: &HybridBitSet<T>) -> bool { + match self { + HybridBitSet::Sparse(self_sparse) => { + match other { + HybridBitSet::Sparse(other_sparse) => { + // Both sets are sparse. Add the elements in + // `other_sparse` to `self` one at a time. This + // may or may not cause `self` to be densified. + assert_eq!(self.domain_size(), other.domain_size()); + let mut changed = false; + for elem in other_sparse.iter() { + changed |= self.insert(*elem); + } + changed + } + HybridBitSet::Dense(other_dense) => { + // `self` is sparse and `other` is dense. To + // merge them, we have two available strategies: + // * Densify `self` then merge other + // * Clone other then integrate bits from `self` + // The second strategy requires dedicated method + // since the usual `union` returns the wrong + // result. In the dedicated case the computation + // is slightly faster if the bits of the sparse + // bitset map to only few words of the dense + // representation, i.e. indices are near each + // other. + // + // Benchmarking seems to suggest that the second + // option is worth it. + let mut new_dense = other_dense.clone(); + let changed = new_dense.reverse_union_sparse(self_sparse); + *self = HybridBitSet::Dense(new_dense); + changed + } + } + } + + 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 { + HybridBitSet::Sparse(sparse) => sparse.to_dense(), + HybridBitSet::Dense(dense) => dense, + } + } + + pub fn iter(&self) -> HybridIter<'_, T> { + match self { + HybridBitSet::Sparse(sparse) => HybridIter::Sparse(sparse.iter()), + HybridBitSet::Dense(dense) => HybridIter::Dense(dense.iter()), + } + } +} + +impl<T: Idx> UnionIntoBitSet<T> for HybridBitSet<T> { + fn union_into(&self, other: &mut BitSet<T>) -> bool { + match self { + HybridBitSet::Sparse(sparse) => sparse.union_into(other), + HybridBitSet::Dense(dense) => dense.union_into(other), + } + } +} + +impl<T: Idx> SubtractFromBitSet<T> for HybridBitSet<T> { + fn subtract_from(&self, other: &mut BitSet<T>) -> bool { + match self { + HybridBitSet::Sparse(sparse) => sparse.subtract_from(other), + HybridBitSet::Dense(dense) => dense.subtract_from(other), + } + } +} + +pub enum HybridIter<'a, T: Idx> { + Sparse(slice::Iter<'a, T>), + Dense(BitIter<'a, T>), +} + +impl<'a, T: Idx> Iterator for HybridIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option<T> { + match self { + HybridIter::Sparse(sparse) => sparse.next().copied(), + HybridIter::Dense(dense) => dense.next(), + } + } +} + +/// A resizable bitset type with a dense representation. +/// +/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also +/// just be `usize`. +/// +/// All operations that involve an element will panic if the element is equal +/// to or greater than the domain size. +#[derive(Clone, Debug, PartialEq)] +pub struct GrowableBitSet<T: Idx> { + bit_set: BitSet<T>, +} + +impl<T: Idx> GrowableBitSet<T> { + /// Ensure that the set can hold at least `min_domain_size` elements. + pub fn ensure(&mut self, min_domain_size: usize) { + if self.bit_set.domain_size < min_domain_size { + self.bit_set.domain_size = min_domain_size; + } + + let min_num_words = num_words(min_domain_size); + if self.bit_set.words.len() < min_num_words { + self.bit_set.words.resize(min_num_words, 0) + } + } + + pub fn new_empty() -> GrowableBitSet<T> { + GrowableBitSet { bit_set: BitSet::new_empty(0) } + } + + pub fn with_capacity(capacity: usize) -> GrowableBitSet<T> { + GrowableBitSet { bit_set: BitSet::new_empty(capacity) } + } + + /// Returns `true` if the set has changed. + #[inline] + pub fn insert(&mut self, elem: T) -> bool { + self.ensure(elem.index() + 1); + self.bit_set.insert(elem) + } + + #[inline] + 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 { false } + } +} + +/// A fixed-size 2D bit matrix type with a dense representation. +/// +/// `R` and `C` are index types used to identify rows and columns respectively; +/// typically newtyped `usize` wrappers, but they can also just be `usize`. +/// +/// All operations that involve a row and/or column index will panic if the +/// index exceeds the relevant bound. +#[derive(Clone, Eq, PartialEq, Decodable, Encodable)] +pub struct BitMatrix<R: Idx, C: Idx> { + num_rows: usize, + num_columns: usize, + words: Vec<Word>, + marker: PhantomData<(R, C)>, +} + +impl<R: Idx, C: Idx> BitMatrix<R, C> { + /// Creates a new `rows x columns` matrix, initially empty. + pub fn new(num_rows: usize, num_columns: usize) -> BitMatrix<R, C> { + // For every element, we need one bit for every other + // element. Round up to an even number of words. + let words_per_row = num_words(num_columns); + BitMatrix { + num_rows, + num_columns, + words: vec![0; num_rows * words_per_row], + marker: PhantomData, + } + } + + /// 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); + let start = row.index() * words_per_row; + (start, start + words_per_row) + } + + /// Sets the cell at `(row, column)` to true. Put another way, insert + /// `column` to the bitset for `row`. + /// + /// Returns `true` if this changed the matrix. + pub fn insert(&mut self, row: R, column: C) -> bool { + assert!(row.index() < self.num_rows && column.index() < self.num_columns); + let (start, _) = self.range(row); + let (word_index, mask) = word_index_and_mask(column); + let words = &mut self.words[..]; + let word = words[start + word_index]; + let new_word = word | mask; + words[start + word_index] = new_word; + word != new_word + } + + /// Do the bits from `row` contain `column`? Put another way, is + /// the matrix cell at `(row, column)` true? Put yet another way, + /// if the matrix represents (transitive) reachability, can + /// `row` reach `column`? + pub fn contains(&self, row: R, column: C) -> bool { + assert!(row.index() < self.num_rows && column.index() < self.num_columns); + let (start, _) = self.range(row); + let (word_index, mask) = word_index_and_mask(column); + (self.words[start + word_index] & mask) != 0 + } + + /// Returns those indices that are true in rows `a` and `b`. This + /// is an *O*(*n*) operation where *n* is the number of elements + /// (somewhat independent from the actual size of the + /// intersection, in particular). + pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> { + assert!(row1.index() < self.num_rows && row2.index() < self.num_rows); + let (row1_start, row1_end) = self.range(row1); + let (row2_start, row2_end) = self.range(row2); + let mut result = Vec::with_capacity(self.num_columns); + for (base, (i, j)) in (row1_start..row1_end).zip(row2_start..row2_end).enumerate() { + let mut v = self.words[i] & self.words[j]; + for bit in 0..WORD_BITS { + if v == 0 { + break; + } + if v & 0x1 != 0 { + result.push(C::new(base * WORD_BITS + bit)); + } + v >>= 1; + } + } + result + } + + /// Adds the bits from row `read` to the bits from row `write`, and + /// returns `true` if anything changed. + /// + /// This is used when computing transitive reachability because if + /// you have an edge `write -> read`, because in that case + /// `write` can reach everything that `read` can (and + /// potentially more). + pub fn union_rows(&mut self, read: R, write: R) -> bool { + assert!(read.index() < self.num_rows && write.index() < self.num_rows); + let (read_start, read_end) = self.range(read); + let (write_start, write_end) = self.range(write); + let words = &mut self.words[..]; + let mut changed = false; + for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) { + let word = words[write_index]; + let new_word = word | words[read_index]; + words[write_index] = new_word; + changed |= word != new_word; + } + 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(&self, row: R) -> BitIter<'_, C> { + assert!(row.index() < self.num_rows); + let (start, end) = self.range(row); + BitIter::new(&self.words[start..end]) + } + + /// 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() + } +} + +impl<R: Idx, C: Idx> fmt::Debug for BitMatrix<R, C> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// Forces its contents to print in regular mode instead of alternate mode. + struct OneLinePrinter<T>(T); + impl<T: fmt::Debug> fmt::Debug for OneLinePrinter<T> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{:?}", self.0) + } + } + + write!(fmt, "BitMatrix({}x{}) ", self.num_rows, self.num_columns)?; + let items = self.rows().flat_map(|r| self.iter(r).map(move |c| (r, c))); + fmt.debug_set().entries(items.map(OneLinePrinter)).finish() + } +} + +/// A fixed-column-size, variable-row-size 2D bit matrix with a moderately +/// sparse representation. +/// +/// Initially, every row has no explicit representation. If any bit within a +/// 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`. +#[derive(Clone, Debug)] +pub struct SparseBitMatrix<R, C> +where + R: Idx, + C: Idx, +{ + num_columns: usize, + rows: IndexVec<R, Option<HybridBitSet<C>>>, +} + +impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { + /// Creates a new empty sparse bit matrix with no rows or columns. + pub fn new(num_columns: usize) -> Self { + Self { num_columns, rows: IndexVec::new() } + } + + fn ensure_row(&mut self, row: R) -> &mut HybridBitSet<C> { + // Instantiate any missing rows up to and including row `row` with an + // empty HybridBitSet. + self.rows.ensure_contains_elem(row, || None); + + // Then replace row `row` with a full HybridBitSet if necessary. + let num_columns = self.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 + /// `column` to the bitset for `row`. + /// + /// Returns `true` if this changed the matrix. + pub fn insert(&mut self, row: R, column: C) -> bool { + self.ensure_row(row).insert(column) + } + + /// Do the bits from `row` contain `column`? Put another way, is + /// the matrix cell at `(row, column)` true? Put yet another way, + /// if the matrix represents (transitive) reachability, can + /// `row` reach `column`? + pub fn contains(&self, row: R, column: C) -> bool { + self.row(row).map_or(false, |r| r.contains(column)) + } + + /// Adds the bits from row `read` to the bits from row `write`, and + /// returns `true` if anything changed. + /// + /// This is used when computing transitive reachability because if + /// you have an edge `write -> read`, because in that case + /// `write` can reach everything that `read` can (and + /// potentially more). + pub fn union_rows(&mut self, read: R, write: R) -> bool { + if read == write || self.row(read).is_none() { + return false; + } + + self.ensure_row(write); + if let (Some(read_row), Some(write_row)) = self.rows.pick2_mut(read, write) { + write_row.union(read_row) + } else { + unreachable!() + } + } + + /// 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) + } + + /// Insert all bits in the given row. + pub fn insert_all_into_row(&mut self, row: R) { + self.ensure_row(row).insert_all(); + } + + pub fn rows(&self) -> impl Iterator<Item = R> { + self.rows.indices() + } + + /// Iterates through all the columns set to true in a given row of + /// the matrix. + pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a { + self.row(row).into_iter().flat_map(|r| r.iter()) + } + + pub fn row(&self, row: R) -> Option<&HybridBitSet<C>> { + if let Some(Some(row)) = self.rows.get(row) { Some(row) } else { None } + } +} + +#[inline] +fn num_words<T: Idx>(domain_size: T) -> usize { + (domain_size.index() + WORD_BITS - 1) / WORD_BITS +} + +#[inline] +fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) { + let elem = elem.index(); + let word_index = elem / WORD_BITS; + let mask = 1 << (elem % WORD_BITS); + (word_index, mask) +} + +/// Integral type used to represent the bit set. +pub trait FiniteBitSetTy: + BitAnd<Output = Self> + + BitAndAssign + + BitOrAssign + + Clone + + Copy + + Shl + + Not<Output = Self> + + PartialEq + + Sized +{ + /// Size of the domain representable by this type, e.g. 64 for `u64`. + const DOMAIN_SIZE: u32; + + /// Value which represents the `FiniteBitSet` having every bit set. + const FILLED: Self; + /// Value which represents the `FiniteBitSet` having no bits set. + const EMPTY: Self; + + /// Value for one as the integral type. + const ONE: Self; + /// Value for zero as the integral type. + const ZERO: Self; + + /// Perform a checked left shift on the integral type. + fn checked_shl(self, rhs: u32) -> Option<Self>; + /// Perform a checked right shift on the integral type. + fn checked_shr(self, rhs: u32) -> Option<Self>; +} + +impl FiniteBitSetTy for u32 { + const DOMAIN_SIZE: u32 = 32; + + const FILLED: Self = Self::MAX; + const EMPTY: Self = Self::MIN; + + const ONE: Self = 1u32; + const ZERO: Self = 0u32; + + fn checked_shl(self, rhs: u32) -> Option<Self> { + self.checked_shl(rhs) + } + + fn checked_shr(self, rhs: u32) -> Option<Self> { + self.checked_shr(rhs) + } +} + +impl std::fmt::Debug for FiniteBitSet<u32> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:032b}", self.0) + } +} + +impl FiniteBitSetTy for u64 { + const DOMAIN_SIZE: u32 = 64; + + const FILLED: Self = Self::MAX; + const EMPTY: Self = Self::MIN; + + const ONE: Self = 1u64; + const ZERO: Self = 0u64; + + fn checked_shl(self, rhs: u32) -> Option<Self> { + self.checked_shl(rhs) + } + + fn checked_shr(self, rhs: u32) -> Option<Self> { + self.checked_shr(rhs) + } +} + +impl std::fmt::Debug for FiniteBitSet<u64> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:064b}", self.0) + } +} + +impl FiniteBitSetTy for u128 { + const DOMAIN_SIZE: u32 = 128; + + const FILLED: Self = Self::MAX; + const EMPTY: Self = Self::MIN; + + const ONE: Self = 1u128; + const ZERO: Self = 0u128; + + fn checked_shl(self, rhs: u32) -> Option<Self> { + self.checked_shl(rhs) + } + + fn checked_shr(self, rhs: u32) -> Option<Self> { + self.checked_shr(rhs) + } +} + +impl std::fmt::Debug for FiniteBitSet<u128> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:0128b}", self.0) + } +} + +/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range +/// representable by `T` are considered set. +#[derive(Copy, Clone, Eq, PartialEq, Decodable, Encodable)] +pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T); + +impl<T: FiniteBitSetTy> FiniteBitSet<T> { + /// Creates a new, empty bitset. + pub fn new_empty() -> Self { + Self(T::EMPTY) + } + + /// Sets the `index`th bit. + pub fn set(&mut self, index: u32) { + self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO); + } + + /// Unsets the `index`th bit. + pub fn clear(&mut self, index: u32) { + self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO); + } + + /// Sets the `i`th to `j`th bits. + pub fn set_range(&mut self, range: Range<u32>) { + let bits = T::FILLED + .checked_shl(range.end - range.start) + .unwrap_or(T::ZERO) + .not() + .checked_shl(range.start) + .unwrap_or(T::ZERO); + self.0 |= bits; + } + + /// Is the set empty? + pub fn is_empty(&self) -> bool { + self.0 == T::EMPTY + } + + /// Returns the domain size of the bitset. + pub fn within_domain(&self, index: u32) -> bool { + index < T::DOMAIN_SIZE + } + + /// Returns if the `index`th bit is set. + pub fn contains(&self, index: u32) -> Option<bool> { + self.within_domain(index) + .then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE) + } +} + +impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> { + fn default() -> Self { + Self::new_empty() + } +} diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs new file mode 100644 index 00000000000..6cc3e9427d1 --- /dev/null +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -0,0 +1,366 @@ +use super::*; + +extern crate test; +use test::Bencher; + +#[test] +fn test_new_filled() { + for i in 0..128 { + let idx_buf = BitSet::new_filled(i); + let elems: Vec<usize> = idx_buf.iter().collect(); + let expected: Vec<usize> = (0..i).collect(); + assert_eq!(elems, expected); + } +} + +#[test] +fn bitset_iter_works() { + let mut bitset: BitSet<usize> = BitSet::new_empty(100); + bitset.insert(1); + bitset.insert(10); + bitset.insert(19); + bitset.insert(62); + bitset.insert(63); + bitset.insert(64); + bitset.insert(65); + bitset.insert(66); + bitset.insert(99); + assert_eq!(bitset.iter().collect::<Vec<_>>(), [1, 10, 19, 62, 63, 64, 65, 66, 99]); +} + +#[test] +fn bitset_iter_works_2() { + let mut bitset: BitSet<usize> = BitSet::new_empty(320); + bitset.insert(0); + bitset.insert(127); + bitset.insert(191); + bitset.insert(255); + bitset.insert(319); + assert_eq!(bitset.iter().collect::<Vec<_>>(), [0, 127, 191, 255, 319]); +} + +#[test] +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)); + assert!(!set1.insert(3)); + assert!(set2.insert(5)); + assert!(set2.insert(64)); + assert!(set1.union(&set2)); + assert!(!set1.union(&set2)); + assert!(set1.contains(3)); + assert!(!set1.contains(4)); + assert!(set1.contains(5)); + assert!(!set1.contains(63)); + 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); + for index in 0..65 { + assert!(set.insert(index)); + assert!(!set.insert(index)); + } + set.ensure(128); + + // Check if the bits set before growing are still set + for index in 0..65 { + assert!(set.contains(index)); + } + + // Check if the new bits are all un-set + for index in 65..128 { + assert!(!set.contains(index)); + } + + // Check that we can set all new bits without running out of bounds + for index in 65..128 { + assert!(set.insert(index)); + assert!(!set.insert(index)); + } +} + +#[test] +fn matrix_intersection() { + let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(200, 200); + + // (*) Elements reachable from both 2 and 65. + + matrix.insert(2, 3); + matrix.insert(2, 6); + matrix.insert(2, 10); // (*) + matrix.insert(2, 64); // (*) + matrix.insert(2, 65); + matrix.insert(2, 130); + matrix.insert(2, 160); // (*) + + matrix.insert(64, 133); + + matrix.insert(65, 2); + matrix.insert(65, 8); + matrix.insert(65, 10); // (*) + matrix.insert(65, 64); // (*) + matrix.insert(65, 68); + matrix.insert(65, 133); + matrix.insert(65, 160); // (*) + + let intersection = matrix.intersect_rows(2, 64); + assert!(intersection.is_empty()); + + let intersection = matrix.intersect_rows(2, 65); + assert_eq!(intersection, &[10, 64, 160]); +} + +#[test] +fn matrix_iter() { + let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(64, 100); + matrix.insert(3, 22); + matrix.insert(3, 75); + 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(); + for i in matrix.iter(2) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + 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); + } + assert!(iter.next().is_none()); + + 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); + } + assert!(iter.next().is_none()); + + 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] +fn sparse_matrix_iter() { + let mut matrix: SparseBitMatrix<usize, usize> = SparseBitMatrix::new(100); + matrix.insert(3, 22); + matrix.insert(3, 75); + matrix.insert(2, 99); + matrix.insert(4, 0); + matrix.union_rows(3, 5); + + let expected = [99]; + let mut iter = expected.iter(); + for i in matrix.iter(2) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [22, 75]; + let mut iter = expected.iter(); + for i in matrix.iter(3) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [0]; + let mut iter = expected.iter(); + for i in matrix.iter(4) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [22, 75]; + let mut iter = expected.iter(); + for i in matrix.iter(5) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); +} + +/// Merge dense hybrid set into empty sparse hybrid set. +#[bench] +fn union_hybrid_sparse_empty_to_dense(b: &mut Bencher) { + let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(256); + for i in 0..10 { + assert!(pre_dense.insert(i)); + } + let pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(256); + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into full hybrid set with same indices. +#[bench] +fn union_hybrid_sparse_full_to_dense(b: &mut Bencher) { + let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(256); + for i in 0..10 { + assert!(pre_dense.insert(i)); + } + let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(256); + for i in 0..SPARSE_MAX { + assert!(pre_sparse.insert(i)); + } + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into full hybrid set with indices over the whole domain. +#[bench] +fn union_hybrid_sparse_domain_to_dense(b: &mut Bencher) { + let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX * 64); + for i in 0..10 { + assert!(pre_dense.insert(i)); + } + let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX * 64); + for i in 0..SPARSE_MAX { + assert!(pre_sparse.insert(i * 64)); + } + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into empty hybrid set where the domain is very small. +#[bench] +fn union_hybrid_sparse_empty_small_domain(b: &mut Bencher) { + let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX); + for i in 0..SPARSE_MAX { + assert!(pre_dense.insert(i)); + } + let pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX); + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} + +/// Merge dense hybrid set into full hybrid set where the domain is very small. +#[bench] +fn union_hybrid_sparse_full_small_domain(b: &mut Bencher) { + let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX); + for i in 0..SPARSE_MAX { + assert!(pre_dense.insert(i)); + } + let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX); + for i in 0..SPARSE_MAX { + assert!(pre_sparse.insert(i)); + } + b.iter(|| { + let dense = pre_dense.clone(); + let mut sparse = pre_sparse.clone(); + sparse.union(&dense); + }) +} diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs new file mode 100644 index 00000000000..7ee881b0639 --- /dev/null +++ b/compiler/rustc_index/src/lib.rs @@ -0,0 +1,11 @@ +#![feature(allow_internal_unstable)] +#![feature(bool_to_option)] +#![feature(const_fn)] +#![feature(const_panic)] +#![feature(extend_one)] +#![feature(unboxed_closures)] +#![feature(test)] +#![feature(fn_traits)] + +pub mod bit_set; +pub mod vec; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs new file mode 100644 index 00000000000..2420f82c041 --- /dev/null +++ b/compiler/rustc_index/src/vec.rs @@ -0,0 +1,846 @@ +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + +use std::fmt; +use std::fmt::Debug; +use std::hash::Hash; +use std::iter::{self, FromIterator}; +use std::marker::PhantomData; +use std::ops::{Index, IndexMut, Range, RangeBounds}; +use std::slice; +use std::vec; + +/// Represents some newtyped `usize` wrapper. +/// +/// Purpose: avoid mixing indexes for different bitvector domains. +pub trait Idx: Copy + 'static + Ord + Debug + Hash { + fn new(idx: usize) -> Self; + + fn index(self) -> usize; + + fn increment_by(&mut self, amount: usize) { + *self = self.plus(amount); + } + + fn plus(self, amount: usize) -> Self { + Self::new(self.index() + amount) + } +} + +impl Idx for usize { + #[inline] + fn new(idx: usize) -> Self { + idx + } + #[inline] + fn index(self) -> usize { + self + } +} + +impl Idx for u32 { + #[inline] + fn new(idx: usize) -> Self { + assert!(idx <= u32::MAX as usize); + idx as u32 + } + #[inline] + fn index(self) -> usize { + self as usize + } +} + +/// Creates a struct type `S` that can be used as an index with +/// `IndexVec` and so on. +/// +/// There are two ways of interacting with these indices: +/// +/// - The `From` impls are the preferred way. So you can do +/// `S::from(v)` with a `usize` or `u32`. And you can convert back +/// to an integer with `u32::from(s)`. +/// +/// - Alternatively, you can use the methods `S::new(v)` and `s.index()` +/// to create/return a value. +/// +/// Internally, the index uses a u32, so the index must not exceed +/// `u32::MAX`. You can also customize things like the `Debug` impl, +/// what traits are derived, and so forth via the macro. +#[macro_export] +#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)] +macro_rules! newtype_index { + // ---- public rules ---- + + // Use default constants + ($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => ( + $crate::newtype_index!( + // Leave out derives marker so we can use its absence to ensure it comes first + @attrs [$(#[$attrs])*] + @type [$name] + // shave off 256 indices at the end to allow space for packing these indices into enums + @max [0xFFFF_FF00] + @vis [$v] + @debug_format ["{}"]); + ); + + // Define any constants + ($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => ( + $crate::newtype_index!( + // Leave out derives marker so we can use its absence to ensure it comes first + @attrs [$(#[$attrs])*] + @type [$name] + // shave off 256 indices at the end to allow space for packing these indices into enums + @max [0xFFFF_FF00] + @vis [$v] + @debug_format ["{}"] + $($tokens)+); + ); + + // ---- private rules ---- + + // Base case, user-defined constants (if any) have already been defined + (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt]) => ( + $(#[$attrs])* + #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)] + #[rustc_layout_scalar_valid_range_end($max)] + $v struct $type { + private: u32 + } + + impl Clone for $type { + fn clone(&self) -> Self { + *self + } + } + + impl $type { + $v const MAX_AS_U32: u32 = $max; + + $v const MAX: Self = Self::from_u32($max); + + #[inline] + $v const fn from_usize(value: usize) -> Self { + assert!(value <= ($max as usize)); + unsafe { + Self::from_u32_unchecked(value as u32) + } + } + + #[inline] + $v const fn from_u32(value: u32) -> Self { + assert!(value <= $max); + unsafe { + Self::from_u32_unchecked(value) + } + } + + #[inline] + $v const unsafe fn from_u32_unchecked(value: u32) -> Self { + Self { private: value } + } + + /// Extracts the value of this index as an integer. + #[inline] + $v const fn index(self) -> usize { + self.as_usize() + } + + /// Extracts the value of this index as a `u32`. + #[inline] + $v const fn as_u32(self) -> u32 { + self.private + } + + /// Extracts the value of this index as a `usize`. + #[inline] + $v const fn as_usize(self) -> usize { + self.as_u32() as usize + } + } + + impl std::ops::Add<usize> for $type { + type Output = Self; + + fn add(self, other: usize) -> Self { + Self::from_usize(self.index() + other) + } + } + + impl $crate::vec::Idx for $type { + #[inline] + fn new(value: usize) -> Self { + Self::from_usize(value) + } + + #[inline] + fn index(self) -> usize { + self.as_usize() + } + } + + unsafe impl ::std::iter::Step for $type { + #[inline] + fn steps_between(start: &Self, end: &Self) -> Option<usize> { + <usize as ::std::iter::Step>::steps_between( + &Self::index(*start), + &Self::index(*end), + ) + } + + #[inline] + fn forward_checked(start: Self, u: usize) -> Option<Self> { + Self::index(start).checked_add(u).map(Self::from_usize) + } + + #[inline] + fn backward_checked(start: Self, u: usize) -> Option<Self> { + Self::index(start).checked_sub(u).map(Self::from_usize) + } + } + + impl From<$type> for u32 { + #[inline] + fn from(v: $type) -> u32 { + v.as_u32() + } + } + + impl From<$type> for usize { + #[inline] + fn from(v: $type) -> usize { + v.as_usize() + } + } + + impl From<usize> for $type { + #[inline] + fn from(value: usize) -> Self { + Self::from_usize(value) + } + } + + impl From<u32> for $type { + #[inline] + fn from(value: u32) -> Self { + Self::from_u32(value) + } + } + + $crate::newtype_index!( + @handle_debug + @derives [$($derives,)*] + @type [$type] + @debug_format [$debug_format]); + ); + + // base case for handle_debug where format is custom. No Debug implementation is emitted. + (@handle_debug + @derives [$($_derives:ident,)*] + @type [$type:ident] + @debug_format [custom]) => (); + + // base case for handle_debug, no debug overrides found, so use default + (@handle_debug + @derives [] + @type [$type:ident] + @debug_format [$debug_format:tt]) => ( + impl ::std::fmt::Debug for $type { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(fmt, $debug_format, self.as_u32()) + } + } + ); + + // Debug is requested for derive, don't generate any Debug implementation. + (@handle_debug + @derives [Debug, $($derives:ident,)*] + @type [$type:ident] + @debug_format [$debug_format:tt]) => (); + + // It's not Debug, so just pop it off the front of the derives stack and check the rest. + (@handle_debug + @derives [$_derive:ident, $($derives:ident,)*] + @type [$type:ident] + @debug_format [$debug_format:tt]) => ( + $crate::newtype_index!( + @handle_debug + @derives [$($derives,)*] + @type [$type] + @debug_format [$debug_format]); + ); + + // Append comma to end of derives list if it's missing + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + derive [$($derives:ident),*] + $($tokens:tt)*) => ( + $crate::newtype_index!( + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + derive [$($derives,)*] + $($tokens)*); + ); + + // By not including the @derives marker in this list nor in the default args, we can force it + // to come first if it exists. When encodable is custom, just use the derives list as-is. + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + derive [$($derives:ident,)+] + ENCODABLE = custom + $($tokens:tt)*) => ( + $crate::newtype_index!( + @attrs [$(#[$attrs])*] + @derives [$($derives,)+] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $($tokens)*); + ); + + // By not including the @derives marker in this list nor in the default args, we can force it + // to come first if it exists. When encodable isn't custom, add serialization traits by default. + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + derive [$($derives:ident,)+] + $($tokens:tt)*) => ( + $crate::newtype_index!( + @derives [$($derives,)+] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $($tokens)*); + $crate::newtype_index!(@serializable $type); + ); + + // The case where no derives are added, but encodable is overridden. Don't + // derive serialization traits + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + ENCODABLE = custom + $($tokens:tt)*) => ( + $crate::newtype_index!( + @derives [] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $($tokens)*); + ); + + // The case where no derives are added, add serialization derives by default + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + $($tokens:tt)*) => ( + $crate::newtype_index!( + @derives [] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $($tokens)*); + $crate::newtype_index!(@serializable $type); + ); + + (@serializable $type:ident) => ( + impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for $type { + fn decode(d: &mut D) -> Result<Self, D::Error> { + d.read_u32().map(Self::from_u32) + } + } + impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for $type { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + e.emit_u32(self.private) + } + } + ); + + // Rewrite final without comma to one that includes comma + (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + $name:ident = $constant:expr) => ( + $crate::newtype_index!( + @derives [$($derives,)*] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $name = $constant,); + ); + + // Rewrite final const without comma to one that includes comma + (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + $(#[doc = $doc:expr])* + const $name:ident = $constant:expr) => ( + $crate::newtype_index!( + @derives [$($derives,)*] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $(#[doc = $doc])* const $name = $constant,); + ); + + // Replace existing default for max + (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$_max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + MAX = $max:expr, + $($tokens:tt)*) => ( + $crate::newtype_index!( + @derives [$($derives,)*] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $($tokens)*); + ); + + // Replace existing default for debug_format + (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$_debug_format:tt] + DEBUG_FORMAT = $debug_format:tt, + $($tokens:tt)*) => ( + $crate::newtype_index!( + @derives [$($derives,)*] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $($tokens)*); + ); + + // Assign a user-defined constant + (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] + @type [$type:ident] + @max [$max:expr] + @vis [$v:vis] + @debug_format [$debug_format:tt] + $(#[doc = $doc:expr])* + const $name:ident = $constant:expr, + $($tokens:tt)*) => ( + $(#[doc = $doc])* + $v const $name: $type = $type::from_u32($constant); + $crate::newtype_index!( + @derives [$($derives,)*] + @attrs [$(#[$attrs])*] + @type [$type] + @max [$max] + @vis [$v] + @debug_format [$debug_format] + $($tokens)*); + ); +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct IndexVec<I: Idx, T> { + pub raw: Vec<T>, + _marker: PhantomData<fn(&I)>, +} + +// Whether `IndexVec` is `Send` depends only on the data, +// not the phantom data. +unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {} + +impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for IndexVec<I, T> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + Encodable::encode(&self.raw, s) + } +} + +impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for &IndexVec<I, T> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + Encodable::encode(&self.raw, s) + } +} + +impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> { + fn decode(d: &mut D) -> Result<Self, D::Error> { + Decodable::decode(d).map(|v| IndexVec { raw: v, _marker: PhantomData }) + } +} + +impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.raw, fmt) + } +} + +pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>; + +impl<I: Idx, T> IndexVec<I, T> { + #[inline] + pub fn new() -> Self { + IndexVec { raw: Vec::new(), _marker: PhantomData } + } + + #[inline] + pub fn from_raw(raw: Vec<T>) -> Self { + IndexVec { raw, _marker: PhantomData } + } + + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData } + } + + #[inline] + pub fn from_elem<S>(elem: T, universe: &IndexVec<I, S>) -> Self + where + T: Clone, + { + IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData } + } + + #[inline] + pub fn from_elem_n(elem: T, n: usize) -> Self + where + T: Clone, + { + IndexVec { raw: vec![elem; n], _marker: PhantomData } + } + + /// Create an `IndexVec` with `n` elements, where the value of each + /// element is the result of `func(i)`. (The underlying vector will + /// be allocated only once, with a capacity of at least `n`.) + #[inline] + pub fn from_fn_n(func: impl FnMut(I) -> T, n: usize) -> Self { + let indices = (0..n).map(I::new); + Self::from_raw(indices.map(func).collect()) + } + + #[inline] + pub fn push(&mut self, d: T) -> I { + let idx = I::new(self.len()); + self.raw.push(d); + idx + } + + #[inline] + pub fn pop(&mut self) -> Option<T> { + self.raw.pop() + } + + #[inline] + pub fn len(&self) -> usize { + self.raw.len() + } + + /// Gives the next index that will be assigned when `push` is + /// called. + #[inline] + pub fn next_index(&self) -> I { + I::new(self.len()) + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.raw.is_empty() + } + + #[inline] + pub fn into_iter(self) -> vec::IntoIter<T> { + self.raw.into_iter() + } + + #[inline] + pub fn into_iter_enumerated(self) -> Enumerated<I, vec::IntoIter<T>> { + self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn iter(&self) -> slice::Iter<'_, T> { + self.raw.iter() + } + + #[inline] + pub fn iter_enumerated(&self) -> Enumerated<I, slice::Iter<'_, T>> { + self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn indices(&self) -> iter::Map<Range<usize>, IntoIdx<I>> { + (0..self.len()).map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> { + self.raw.iter_mut() + } + + #[inline] + pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<'_, T>> { + self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn drain<'a, R: RangeBounds<usize>>( + &'a mut self, + range: R, + ) -> impl Iterator<Item = T> + 'a { + self.raw.drain(range) + } + + #[inline] + pub fn drain_enumerated<'a, R: RangeBounds<usize>>( + &'a mut self, + range: R, + ) -> impl Iterator<Item = (I, T)> + 'a { + self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn last(&self) -> Option<I> { + self.len().checked_sub(1).map(I::new) + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.raw.shrink_to_fit() + } + + #[inline] + pub fn swap(&mut self, a: I, b: I) { + self.raw.swap(a.index(), b.index()) + } + + #[inline] + pub fn truncate(&mut self, a: usize) { + self.raw.truncate(a) + } + + #[inline] + pub fn get(&self, index: I) -> Option<&T> { + self.raw.get(index.index()) + } + + #[inline] + pub fn get_mut(&mut self, index: I) -> Option<&mut T> { + self.raw.get_mut(index.index()) + } + + /// Returns mutable references to two distinct elements, a and b. Panics if a == b. + #[inline] + pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) { + let (ai, bi) = (a.index(), b.index()); + assert!(ai != bi); + + if ai < bi { + let (c1, c2) = self.raw.split_at_mut(bi); + (&mut c1[ai], &mut c2[0]) + } else { + let (c2, c1) = self.pick2_mut(b, a); + (c1, c2) + } + } + + /// Returns mutable references to three distinct elements or panics otherwise. + #[inline] + pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) { + let (ai, bi, ci) = (a.index(), b.index(), c.index()); + assert!(ai != bi && bi != ci && ci != ai); + let len = self.raw.len(); + assert!(ai < len && bi < len && ci < len); + let ptr = self.raw.as_mut_ptr(); + unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) } + } + + pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> { + IndexVec { raw: self.raw, _marker: PhantomData } + } +} + +impl<I: Idx, T: Clone> IndexVec<I, T> { + /// Grows the index vector so that it contains an entry for + /// `elem`; if that is already true, then has no + /// effect. Otherwise, inserts new values as needed by invoking + /// `fill_value`. + #[inline] + pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + let min_new_len = elem.index() + 1; + if self.len() < min_new_len { + self.raw.resize_with(min_new_len, fill_value); + } + } + + #[inline] + pub fn resize(&mut self, new_len: usize, value: T) { + self.raw.resize(new_len, value) + } + + #[inline] + pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + let min_new_len = elem.index() + 1; + self.raw.resize_with(min_new_len, fill_value); + } +} + +impl<I: Idx, T: Ord> IndexVec<I, T> { + #[inline] + pub fn binary_search(&self, value: &T) -> Result<I, I> { + match self.raw.binary_search(value) { + Ok(i) => Ok(Idx::new(i)), + Err(i) => Err(Idx::new(i)), + } + } +} + +impl<I: Idx, T> Index<I> for IndexVec<I, T> { + type Output = T; + + #[inline] + fn index(&self, index: I) -> &T { + &self.raw[index.index()] + } +} + +impl<I: Idx, T> IndexMut<I> for IndexVec<I, T> { + #[inline] + fn index_mut(&mut self, index: I) -> &mut T { + &mut self.raw[index.index()] + } +} + +impl<I: Idx, T> Default for IndexVec<I, T> { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl<I: Idx, T> Extend<T> for IndexVec<I, T> { + #[inline] + fn extend<J: IntoIterator<Item = T>>(&mut self, iter: J) { + self.raw.extend(iter); + } + + #[inline] + fn extend_one(&mut self, item: T) { + self.raw.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.raw.reserve(additional); + } +} + +impl<I: Idx, T> FromIterator<T> for IndexVec<I, T> { + #[inline] + fn from_iter<J>(iter: J) -> Self + where + J: IntoIterator<Item = T>, + { + IndexVec { raw: FromIterator::from_iter(iter), _marker: PhantomData } + } +} + +impl<I: Idx, T> IntoIterator for IndexVec<I, T> { + type Item = T; + type IntoIter = vec::IntoIter<T>; + + #[inline] + fn into_iter(self) -> vec::IntoIter<T> { + self.raw.into_iter() + } +} + +impl<'a, I: Idx, T> IntoIterator for &'a IndexVec<I, T> { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + + #[inline] + fn into_iter(self) -> slice::Iter<'a, T> { + self.raw.iter() + } +} + +impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + + #[inline] + fn into_iter(self) -> slice::IterMut<'a, T> { + self.raw.iter_mut() + } +} + +pub struct IntoIdx<I: Idx> { + _marker: PhantomData<fn(&I)>, +} +impl<I: Idx, T> FnOnce<((usize, T),)> for IntoIdx<I> { + type Output = (I, T); + + extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output { + (I::new(n), t) + } +} + +impl<I: Idx, T> FnMut<((usize, T),)> for IntoIdx<I> { + extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output { + (I::new(n), t) + } +} + +impl<I: Idx> FnOnce<(usize,)> for IntoIdx<I> { + type Output = I; + + extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output { + I::new(n) + } +} + +impl<I: Idx> FnMut<(usize,)> for IntoIdx<I> { + extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output { + I::new(n) + } +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_index/src/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs new file mode 100644 index 00000000000..15c43c72c7b --- /dev/null +++ b/compiler/rustc_index/src/vec/tests.rs @@ -0,0 +1,51 @@ +#![allow(dead_code)] +newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA }); + +#[test] +fn index_size_is_optimized() { + use std::mem::size_of; + + assert_eq!(size_of::<MyIdx>(), 4); + // Uses 0xFFFF_FFFB + assert_eq!(size_of::<Option<MyIdx>>(), 4); + // Uses 0xFFFF_FFFC + assert_eq!(size_of::<Option<Option<MyIdx>>>(), 4); + // Uses 0xFFFF_FFFD + assert_eq!(size_of::<Option<Option<Option<MyIdx>>>>(), 4); + // Uses 0xFFFF_FFFE + assert_eq!(size_of::<Option<Option<Option<Option<MyIdx>>>>>(), 4); + // Uses 0xFFFF_FFFF + assert_eq!(size_of::<Option<Option<Option<Option<Option<MyIdx>>>>>>(), 4); + // Uses a tag + assert_eq!(size_of::<Option<Option<Option<Option<Option<Option<MyIdx>>>>>>>(), 8); +} + +#[test] +fn range_iterator_iterates_forwards() { + let range = MyIdx::from_u32(1)..MyIdx::from_u32(4); + assert_eq!( + range.collect::<Vec<_>>(), + [MyIdx::from_u32(1), MyIdx::from_u32(2), MyIdx::from_u32(3)] + ); +} + +#[test] +fn range_iterator_iterates_backwards() { + let range = MyIdx::from_u32(1)..MyIdx::from_u32(4); + assert_eq!( + range.rev().collect::<Vec<_>>(), + [MyIdx::from_u32(3), MyIdx::from_u32(2), MyIdx::from_u32(1)] + ); +} + +#[test] +fn range_count_is_correct() { + let range = MyIdx::from_u32(1)..MyIdx::from_u32(4); + assert_eq!(range.count(), 3); +} + +#[test] +fn range_size_hint_is_correct() { + let range = MyIdx::from_u32(1)..MyIdx::from_u32(4); + assert_eq!(range.size_hint(), (3, Some(3))); +} |
