Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IndexSlice to go with IndexVec #109787

Merged
merged 1 commit into from
Mar 31, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 160 additions & 70 deletions compiler/rustc_index/src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::fmt;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut, RangeBounds};
use std::ops::{Deref, DerefMut, Index, IndexMut, RangeBounds};
use std::slice;
use std::vec;

Expand Down Expand Up @@ -52,15 +52,27 @@ impl Idx for u32 {
}

#[derive(Clone, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct IndexVec<I: Idx, T> {
pub raw: Vec<T>,
_marker: PhantomData<fn(&I)>,
}

#[derive(PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct IndexSlice<I: Idx, T> {
_marker: PhantomData<fn(&I)>,
pub raw: [T],
}

// 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 {}

// Whether `IndexSlice` is `Send` depends only on the data,
// not the phantom data.
unsafe impl<I: Idx, T> Send for IndexSlice<I, T> where T: Send {}

#[cfg(feature = "rustc_serialize")]
impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for IndexVec<I, T> {
fn encode(&self, s: &mut S) {
Expand Down Expand Up @@ -122,6 +134,16 @@ impl<I: Idx, T> IndexVec<I, T> {
Self::from_raw(indices.map(func).collect())
}

#[inline]
pub fn as_slice(&self) -> &IndexSlice<I, T> {
IndexSlice::from_raw(&self.raw)
}

#[inline]
pub fn as_mut_slice(&mut self) -> &mut IndexSlice<I, T> {
IndexSlice::from_raw_mut(&mut self.raw)
}

#[inline]
pub fn push(&mut self, d: T) -> I {
let idx = I::new(self.len());
Expand All @@ -135,32 +157,119 @@ impl<I: Idx, T> IndexVec<I, T> {
}

#[inline]
pub fn len(&self) -> usize {
self.raw.len()
pub fn into_iter(self) -> vec::IntoIter<T> {
self.raw.into_iter()
}

/// Gives the next index that will be assigned when `push` is
/// called.
#[inline]
pub fn next_index(&self) -> I {
I::new(self.len())
pub fn into_iter_enumerated(
self,
) -> impl DoubleEndedIterator<Item = (I, T)> + ExactSizeIterator {
self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t))
}

#[inline]
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
pub fn drain<'a, R: RangeBounds<usize>>(
&'a mut self,
range: R,
) -> impl Iterator<Item = T> + 'a {
self.raw.drain(range)
}

#[inline]
pub fn into_iter(self) -> vec::IntoIter<T> {
self.raw.into_iter()
pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, the diff is pretty bad because moving them to a different impl block mixes the order.

&'a mut self,
range: R,
) -> impl Iterator<Item = (I, T)> + 'a {
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 into_iter_enumerated(
self,
) -> impl DoubleEndedIterator<Item = (I, T)> + ExactSizeIterator {
self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t))
pub fn shrink_to_fit(&mut self) {
self.raw.shrink_to_fit()
}

#[inline]
pub fn truncate(&mut self, a: usize) {
self.raw.truncate(a)
}

pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
IndexVec { raw: self.raw, _marker: PhantomData }
}

/// 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_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> Deref for IndexVec<I, T> {
type Target = IndexSlice<I, T>;

#[inline]
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}

impl<I: Idx, T> DerefMut for IndexVec<I, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}

impl<I: Idx, T> IndexSlice<I, T> {
#[inline]
pub fn from_raw(raw: &[T]) -> &Self {
let ptr: *const [T] = raw;
// SAFETY: `IndexSlice` is `repr(transparent)` over a normal slice
unsafe { &*(ptr as *const Self) }
}

#[inline]
pub fn from_raw_mut(raw: &mut [T]) -> &mut Self {
let ptr: *mut [T] = raw;
// SAFETY: `IndexSlice` is `repr(transparent)` over a normal slice
unsafe { &mut *(ptr as *mut Self) }
}

#[inline]
pub fn len(&self) -> usize {
self.raw.len()
}

/// Gives the next index that will be assigned when `push` is called.
///
/// Manual bounds checks can be done using `idx < slice.next_index()`
/// (as opposed to `idx.index() < slice.len()`).
#[inline]
pub fn next_index(&self) -> I {
I::new(self.len())
}

#[inline]
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
}

#[inline]
Expand Down Expand Up @@ -194,47 +303,16 @@ impl<I: Idx, T> IndexVec<I, T> {
self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t))
}

#[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 {
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 last_index(&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())
Expand Down Expand Up @@ -274,28 +352,6 @@ impl<I: Idx, T> IndexVec<I, T> {
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 }
}

/// 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_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);
}
}

/// `IndexVec` is often used as a map, so it provides some map-like APIs.
Expand Down Expand Up @@ -336,7 +392,7 @@ impl<I: Idx, T: Ord> IndexVec<I, T> {
}
}

impl<I: Idx, T> Index<I> for IndexVec<I, T> {
impl<I: Idx, T> Index<I> for IndexSlice<I, T> {
type Output = T;

#[inline]
Expand All @@ -345,7 +401,7 @@ impl<I: Idx, T> Index<I> for IndexVec<I, T> {
}
}

impl<I: Idx, T> IndexMut<I> for IndexVec<I, T> {
impl<I: Idx, T> IndexMut<I> for IndexSlice<I, T> {
#[inline]
fn index_mut(&mut self, index: I) -> &mut T {
&mut self.raw[index.index()]
Expand All @@ -359,6 +415,20 @@ impl<I: Idx, T> Default for IndexVec<I, T> {
}
}

impl<I: Idx, T> Default for &IndexSlice<I, T> {
#[inline]
fn default() -> Self {
IndexSlice::from_raw(Default::default())
}
}

impl<I: Idx, T> Default for &mut IndexSlice<I, T> {
#[inline]
fn default() -> Self {
IndexSlice::from_raw_mut(Default::default())
}
}

impl<I: Idx, T> Extend<T> for IndexVec<I, T> {
#[inline]
fn extend<J: IntoIterator<Item = T>>(&mut self, iter: J) {
Expand Down Expand Up @@ -418,5 +488,25 @@ impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> {
}
}

impl<'a, I: Idx, T> IntoIterator for &'a IndexSlice<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 IndexSlice<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()
}
}

#[cfg(test)]
mod tests;