Use AttrVec
in more places.
In some places we use `Vec<Attribute>` and some places we use `ThinVec<Attribute>` (a.k.a. `AttrVec`). This results in various points where we have to convert between `Vec` and `ThinVec`. This commit changes the places that use `Vec<Attribute>` to use `AttrVec`. A lot of this is mechanical and boring, but there are some interesting parts: - It adds a few new methods to `ThinVec`. - It implements `MapInPlace` for `ThinVec`, and introduces a macro to avoid the repetition of this trait for `Vec`, `SmallVec`, and `ThinVec`. Overall, it makes the code a little nicer, and has little effect on performance. But it is a precursor to removing `rustc_data_structures::thin_vec::ThinVec` and replacing it with `thin_vec::ThinVec`, which is implemented more efficiently.
This commit is contained in:
parent
650bff80a6
commit
619b8abaa6
49 changed files with 352 additions and 392 deletions
|
@ -1,3 +1,4 @@
|
|||
use crate::thin_vec::ThinVec;
|
||||
use smallvec::{Array, SmallVec};
|
||||
use std::ptr;
|
||||
|
||||
|
@ -15,94 +16,64 @@ pub trait MapInPlace<T>: Sized {
|
|||
I: IntoIterator<Item = T>;
|
||||
}
|
||||
|
||||
impl<T> MapInPlace<T> for Vec<T> {
|
||||
fn flat_map_in_place<F, I>(&mut self, mut f: F)
|
||||
where
|
||||
F: FnMut(T) -> I,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut read_i = 0;
|
||||
let mut write_i = 0;
|
||||
unsafe {
|
||||
let mut old_len = self.len();
|
||||
self.set_len(0); // make sure we just leak elements in case of panic
|
||||
// The implementation of this method is syntactically identical for all the
|
||||
// different vector types.
|
||||
macro_rules! flat_map_in_place {
|
||||
() => {
|
||||
fn flat_map_in_place<F, I>(&mut self, mut f: F)
|
||||
where
|
||||
F: FnMut(T) -> I,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut read_i = 0;
|
||||
let mut write_i = 0;
|
||||
unsafe {
|
||||
let mut old_len = self.len();
|
||||
self.set_len(0); // make sure we just leak elements in case of panic
|
||||
|
||||
while read_i < old_len {
|
||||
// move the read_i'th item out of the vector and map it
|
||||
// to an iterator
|
||||
let e = ptr::read(self.as_ptr().add(read_i));
|
||||
let iter = f(e).into_iter();
|
||||
read_i += 1;
|
||||
while read_i < old_len {
|
||||
// move the read_i'th item out of the vector and map it
|
||||
// to an iterator
|
||||
let e = ptr::read(self.as_ptr().add(read_i));
|
||||
let iter = f(e).into_iter();
|
||||
read_i += 1;
|
||||
|
||||
for e in iter {
|
||||
if write_i < read_i {
|
||||
ptr::write(self.as_mut_ptr().add(write_i), e);
|
||||
write_i += 1;
|
||||
} else {
|
||||
// If this is reached we ran out of space
|
||||
// in the middle of the vector.
|
||||
// However, the vector is in a valid state here,
|
||||
// so we just do a somewhat inefficient insert.
|
||||
self.set_len(old_len);
|
||||
self.insert(write_i, e);
|
||||
for e in iter {
|
||||
if write_i < read_i {
|
||||
ptr::write(self.as_mut_ptr().add(write_i), e);
|
||||
write_i += 1;
|
||||
} else {
|
||||
// If this is reached we ran out of space
|
||||
// in the middle of the vector.
|
||||
// However, the vector is in a valid state here,
|
||||
// so we just do a somewhat inefficient insert.
|
||||
self.set_len(old_len);
|
||||
self.insert(write_i, e);
|
||||
|
||||
old_len = self.len();
|
||||
self.set_len(0);
|
||||
old_len = self.len();
|
||||
self.set_len(0);
|
||||
|
||||
read_i += 1;
|
||||
write_i += 1;
|
||||
read_i += 1;
|
||||
write_i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write_i tracks the number of actually written new items.
|
||||
self.set_len(write_i);
|
||||
// write_i tracks the number of actually written new items.
|
||||
self.set_len(write_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<T> MapInPlace<T> for Vec<T> {
|
||||
flat_map_in_place!();
|
||||
}
|
||||
|
||||
impl<T, A: Array<Item = T>> MapInPlace<T> for SmallVec<A> {
|
||||
fn flat_map_in_place<F, I>(&mut self, mut f: F)
|
||||
where
|
||||
F: FnMut(T) -> I,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut read_i = 0;
|
||||
let mut write_i = 0;
|
||||
unsafe {
|
||||
let mut old_len = self.len();
|
||||
self.set_len(0); // make sure we just leak elements in case of panic
|
||||
|
||||
while read_i < old_len {
|
||||
// move the read_i'th item out of the vector and map it
|
||||
// to an iterator
|
||||
let e = ptr::read(self.as_ptr().add(read_i));
|
||||
let iter = f(e).into_iter();
|
||||
read_i += 1;
|
||||
|
||||
for e in iter {
|
||||
if write_i < read_i {
|
||||
ptr::write(self.as_mut_ptr().add(write_i), e);
|
||||
write_i += 1;
|
||||
} else {
|
||||
// If this is reached we ran out of space
|
||||
// in the middle of the vector.
|
||||
// However, the vector is in a valid state here,
|
||||
// so we just do a somewhat inefficient insert.
|
||||
self.set_len(old_len);
|
||||
self.insert(write_i, e);
|
||||
|
||||
old_len = self.len();
|
||||
self.set_len(0);
|
||||
|
||||
read_i += 1;
|
||||
write_i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write_i tracks the number of actually written new items.
|
||||
self.set_len(write_i);
|
||||
}
|
||||
}
|
||||
flat_map_in_place!();
|
||||
}
|
||||
|
||||
impl<T> MapInPlace<T> for ThinVec<T> {
|
||||
flat_map_in_place!();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,51 @@ impl<T> ThinVec<T> {
|
|||
ThinVec(None) => *self = vec![item].into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: if `set_len(0)` is called on a non-empty `ThinVec`, it will
|
||||
/// remain in the `Some` form. This is required for some code sequences
|
||||
/// (such as the one in `flat_map_in_place`) that call `set_len(0)` before
|
||||
/// an operation that might panic, and then call `set_len(n)` again
|
||||
/// afterwards.
|
||||
pub unsafe fn set_len(&mut self, new_len: usize) {
|
||||
match *self {
|
||||
ThinVec(None) => {
|
||||
// A prerequisite of `Vec::set_len` is that `new_len` must be
|
||||
// less than or equal to capacity(). The same applies here.
|
||||
if new_len != 0 {
|
||||
panic!("unsafe ThinVec::set_len({})", new_len);
|
||||
}
|
||||
}
|
||||
ThinVec(Some(ref mut vec)) => vec.set_len(new_len),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, index: usize, value: T) {
|
||||
match *self {
|
||||
ThinVec(None) => {
|
||||
if index == 0 {
|
||||
*self = vec![value].into();
|
||||
} else {
|
||||
panic!("invalid ThinVec::insert");
|
||||
}
|
||||
}
|
||||
ThinVec(Some(ref mut vec)) => vec.insert(index, value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, index: usize) -> T {
|
||||
match self {
|
||||
ThinVec(None) => panic!("invalid ThinVec::remove"),
|
||||
ThinVec(Some(vec)) => vec.remove(index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
match self {
|
||||
ThinVec(None) => &[],
|
||||
ThinVec(Some(vec)) => vec.as_slice(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<T>> for ThinVec<T> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue