use std::borrow::{Borrow, BorrowMut}; use std::hash::Hash; use std::marker::PhantomData; use std::ops::{Deref, DerefMut, RangeBounds}; use std::{fmt, slice, vec}; #[cfg(feature = "nightly")] use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use crate::{Idx, IndexSlice}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. /// /// ## Why use this instead of a `Vec`? /// /// An `IndexVec` allows element access only via a specific associated index type, meaning that /// trying to use the wrong index type (possibly accessing an invalid element) will fail at /// compile time. /// /// It also documents what the index is indexing: in a `HashMap` it's not /// immediately clear what the `usize` means, while a `HashMap` makes it obvious. /// /// ```compile_fail /// use rustc_index::{Idx, IndexVec}; /// /// fn f(vec1: IndexVec, idx1: I1, idx2: I2) { /// &vec1[idx1]; // Ok /// &vec1[idx2]; // Compile error! /// } /// ``` /// /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// /// This allows to index the IndexVec with the new index type. /// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct IndexVec { pub raw: Vec, _marker: PhantomData, } impl IndexVec { /// Constructs a new, empty `IndexVec`. #[inline] pub const fn new() -> Self { IndexVec::from_raw(Vec::new()) } /// Constructs a new `IndexVec` from a `Vec`. #[inline] pub const fn from_raw(raw: Vec) -> Self { IndexVec { raw, _marker: PhantomData } } #[inline] pub fn with_capacity(capacity: usize) -> Self { IndexVec::from_raw(Vec::with_capacity(capacity)) } /// Creates a new vector with a copy of `elem` for each index in `universe`. /// /// Thus `IndexVec::from_elem(elem, &universe)` is equivalent to /// `IndexVec::::from_elem_n(elem, universe.len())`. That can help /// type inference as it ensures that the resulting vector uses the same /// index type as `universe`, rather than something potentially surprising. /// /// For example, if you want to store data for each local in a MIR body, /// using `let mut uses = IndexVec::from_elem(vec![], &body.local_decls);` /// ensures that `uses` is an `IndexVec`, and thus can give /// better error messages later if one accidentally mismatches indices. #[inline] pub fn from_elem(elem: T, universe: &IndexSlice) -> Self where T: Clone, { IndexVec::from_raw(vec![elem; universe.len()]) } /// Creates a new IndexVec with n copies of the `elem`. #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where T: Clone, { IndexVec::from_raw(vec![elem; n]) } /// 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 { // Allow the optimizer to elide the bounds checking when creating each index. let _ = I::new(n); IndexVec::from_raw((0..n).map(I::new).map(func).collect()) } #[inline] pub fn as_slice(&self) -> &IndexSlice { IndexSlice::from_raw(&self.raw) } #[inline] pub fn as_mut_slice(&mut self) -> &mut IndexSlice { IndexSlice::from_raw_mut(&mut self.raw) } /// Pushes an element to the array returning the index where it was pushed to. #[inline] pub fn push(&mut self, d: T) -> I { let idx = self.next_index(); self.raw.push(d); idx } #[inline] pub fn pop(&mut self) -> Option { self.raw.pop() } #[inline] pub fn into_iter(self) -> vec::IntoIter { self.raw.into_iter() } #[inline] pub fn into_iter_enumerated( self, ) -> impl DoubleEndedIterator + ExactSizeIterator { // Allow the optimizer to elide the bounds checking when creating each index. let _ = I::new(self.len()); self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] pub fn drain>(&mut self, range: R) -> impl Iterator { self.raw.drain(range) } #[inline] pub fn drain_enumerated>( &mut self, range: R, ) -> impl Iterator { let begin = match range.start_bound() { std::ops::Bound::Included(i) => *i, std::ops::Bound::Excluded(i) => i.checked_add(1).unwrap(), std::ops::Bound::Unbounded => 0, }; self.raw.drain(range).enumerate().map(move |(n, t)| (I::new(begin + n), t)) } #[inline] pub fn shrink_to_fit(&mut self) { self.raw.shrink_to_fit() } #[inline] pub fn truncate(&mut self, a: usize) { self.raw.truncate(a) } /// 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`. /// /// Returns a reference to the `elem` entry. #[inline] pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) -> &mut T { let min_new_len = elem.index() + 1; if self.len() < min_new_len { self.raw.resize_with(min_new_len, fill_value); } &mut self[elem] } #[inline] pub fn resize(&mut self, new_len: usize, value: T) where T: Clone, { 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); } #[inline] pub fn append(&mut self, other: &mut Self) { self.raw.append(&mut other.raw); } } /// `IndexVec` is often used as a map, so it provides some map-like APIs. impl IndexVec> { #[inline] pub fn insert(&mut self, index: I, value: T) -> Option { self.ensure_contains_elem(index, || None).replace(value) } #[inline] pub fn get_or_insert_with(&mut self, index: I, value: impl FnOnce() -> T) -> &mut T { self.ensure_contains_elem(index, || None).get_or_insert_with(value) } #[inline] pub fn remove(&mut self, index: I) -> Option { self.get_mut(index)?.take() } #[inline] pub fn contains(&self, index: I) -> bool { self.get(index).and_then(Option::as_ref).is_some() } } impl fmt::Debug for IndexVec { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.raw, fmt) } } impl Deref for IndexVec { type Target = IndexSlice; #[inline] fn deref(&self) -> &Self::Target { self.as_slice() } } impl DerefMut for IndexVec { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() } } impl Borrow> for IndexVec { fn borrow(&self) -> &IndexSlice { self } } impl BorrowMut> for IndexVec { fn borrow_mut(&mut self) -> &mut IndexSlice { self } } impl Extend for IndexVec { #[inline] fn extend>(&mut self, iter: J) { self.raw.extend(iter); } #[inline] #[cfg(feature = "nightly")] fn extend_one(&mut self, item: T) { self.raw.push(item); } #[inline] #[cfg(feature = "nightly")] fn extend_reserve(&mut self, additional: usize) { self.raw.reserve(additional); } } impl FromIterator for IndexVec { #[inline] fn from_iter(iter: J) -> Self where J: IntoIterator, { IndexVec::from_raw(Vec::from_iter(iter)) } } impl IntoIterator for IndexVec { type Item = T; type IntoIter = vec::IntoIter; #[inline] fn into_iter(self) -> vec::IntoIter { self.raw.into_iter() } } impl<'a, I: Idx, T> IntoIterator for &'a IndexVec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; #[inline] fn into_iter(self) -> slice::Iter<'a, T> { self.iter() } } impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; #[inline] fn into_iter(self) -> slice::IterMut<'a, T> { self.iter_mut() } } impl Default for IndexVec { #[inline] fn default() -> Self { IndexVec::new() } } impl From<[T; N]> for IndexVec { #[inline] fn from(array: [T; N]) -> Self { IndexVec::from_raw(array.into()) } } #[cfg(feature = "nightly")] impl> Encodable for IndexVec { fn encode(&self, s: &mut S) { Encodable::encode(&self.raw, s); } } #[cfg(feature = "nightly")] impl> Decodable for IndexVec { fn decode(d: &mut D) -> Self { IndexVec::from_raw(Vec::::decode(d)) } } // Whether `IndexVec` is `Send` depends only on the data, // not the phantom data. unsafe impl Send for IndexVec where T: Send {} #[cfg(test)] mod tests;