mirror of
https://github.com/openharmony/third_party_rust_rust-smallvec.git
synced 2026-07-21 01:55:25 -04:00
Merge pull request #7 from servo/stuff
Make SmallVec::drop sound and other stuff
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
//! Small vectors in various sizes. These store a certain number of elements inline and fall back
|
||||
//! to the heap for larger allocations.
|
||||
|
||||
use std::mem::zeroed as i;
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::iter::{IntoIterator, FromIterator};
|
||||
@@ -14,7 +13,8 @@ use std::ops;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
// Generic code for all small vectors
|
||||
use SmallVecData::{Inline, Heap};
|
||||
|
||||
|
||||
pub trait VecLike<T>:
|
||||
ops::Index<usize, Output=T> +
|
||||
@@ -52,8 +52,6 @@ unsafe fn deallocate<T>(ptr: *mut T, capacity: usize) {
|
||||
}
|
||||
|
||||
pub struct SmallVecMoveIterator<'a, T: 'a> {
|
||||
allocation: Option<*mut T>,
|
||||
cap: usize,
|
||||
iter: slice::IterMut<'a,T>,
|
||||
}
|
||||
|
||||
@@ -66,8 +64,7 @@ impl<'a, T: 'a> Iterator for SmallVecMoveIterator<'a,T> {
|
||||
None => None,
|
||||
Some(reference) => {
|
||||
unsafe {
|
||||
// Zero out the values as we go so they don't get double-freed.
|
||||
Some(mem::replace(reference, mem::zeroed()))
|
||||
Some(ptr::read(reference))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,22 +75,144 @@ impl<'a, T: 'a> Drop for SmallVecMoveIterator<'a,T> {
|
||||
fn drop(&mut self) {
|
||||
// Destroy the remaining elements.
|
||||
for _ in self.by_ref() {}
|
||||
}
|
||||
}
|
||||
|
||||
match self.allocation {
|
||||
None => {}
|
||||
Some(allocation) => {
|
||||
unsafe {
|
||||
deallocate(allocation, self.cap)
|
||||
}
|
||||
enum SmallVecData<A: Array> {
|
||||
Inline { array: A },
|
||||
Heap { ptr: *mut A::Item, capacity: usize },
|
||||
}
|
||||
|
||||
|
||||
pub struct SmallVec<A: Array> {
|
||||
len: usize,
|
||||
data: SmallVecData<A>,
|
||||
}
|
||||
|
||||
impl<A: Array> SmallVec<A> {
|
||||
unsafe fn set_len(&mut self, new_len: usize) {
|
||||
self.len = new_len
|
||||
}
|
||||
|
||||
pub fn inline_size(&self) -> usize {
|
||||
A::size()
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
pub fn capacity(&self) -> usize {
|
||||
match self.data {
|
||||
Inline { .. } => A::size(),
|
||||
Heap { capacity, .. } => capacity,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spilled(&self) -> bool {
|
||||
match self.data {
|
||||
Inline { .. } => false,
|
||||
Heap { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// NB: For efficiency reasons (avoiding making a second copy of the inline elements), this
|
||||
/// actually clears out the original array instead of moving it.
|
||||
/// FIXME: Rename this to `drain`? It’s more like `Vec::drain` than `Vec::into_iter`.
|
||||
pub fn into_iter<'a>(&'a mut self) -> SmallVecMoveIterator<'a, A::Item> {
|
||||
unsafe {
|
||||
self.set_len(0);
|
||||
SmallVecMoveIterator {
|
||||
iter: self.iter_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: A::Item) {
|
||||
let cap = self.capacity();
|
||||
if self.len == cap {
|
||||
self.grow(cmp::max(cap * 2, 1))
|
||||
}
|
||||
unsafe {
|
||||
let end = self.as_mut_ptr().offset(self.len as isize);
|
||||
ptr::write(end, value);
|
||||
let len = self.len;
|
||||
self.set_len(len + 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_all_move<V: IntoIterator<Item=A::Item>>(&mut self, other: V) {
|
||||
for value in other {
|
||||
self.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<A::Item> {
|
||||
if self.len == 0 {
|
||||
return None
|
||||
}
|
||||
let last_index = self.len - 1;
|
||||
if (last_index as isize) < 0 {
|
||||
panic!("overflow")
|
||||
}
|
||||
unsafe {
|
||||
let end_ptr = self.as_mut_ptr().offset(last_index as isize);
|
||||
let value = ptr::replace(end_ptr, mem::uninitialized());
|
||||
self.set_len(last_index);
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, new_cap: usize) {
|
||||
let mut vec: Vec<A::Item> = Vec::with_capacity(new_cap);
|
||||
let new_alloc = vec.as_mut_ptr();
|
||||
unsafe {
|
||||
mem::forget(vec);
|
||||
ptr::copy_nonoverlapping(self.as_ptr(), new_alloc, self.len);
|
||||
|
||||
match self.data {
|
||||
Inline { .. } => {}
|
||||
Heap { ptr, capacity } => deallocate(ptr, capacity),
|
||||
}
|
||||
ptr::write(&mut self.data, Heap {
|
||||
ptr: new_alloc,
|
||||
capacity: new_cap,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> ops::Deref for SmallVec<A> {
|
||||
type Target = [A::Item];
|
||||
#[inline]
|
||||
fn deref(&self) -> &[A::Item] {
|
||||
let ptr: *const _ = match self.data {
|
||||
Inline { ref array } => array.ptr(),
|
||||
Heap { ptr, .. } => ptr,
|
||||
};
|
||||
unsafe {
|
||||
slice::from_raw_parts(ptr, self.len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> ops::DerefMut for SmallVec<A> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut [A::Item] {
|
||||
let ptr = match self.data {
|
||||
Inline { ref mut array } => array.ptr_mut(),
|
||||
Heap { ptr, .. } => ptr,
|
||||
};
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(ptr, self.len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_index {
|
||||
($name: ident, $index_type: ty, $output_type: ty) => {
|
||||
impl<T> ops::Index<$index_type> for $name<T> {
|
||||
($index_type: ty, $output_type: ty) => {
|
||||
impl<A: Array> ops::Index<$index_type> for SmallVec<A> {
|
||||
type Output = $output_type;
|
||||
#[inline]
|
||||
fn index(&self, index: $index_type) -> &$output_type {
|
||||
@@ -101,7 +220,7 @@ macro_rules! impl_index {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::IndexMut<$index_type> for $name<T> {
|
||||
impl<A: Array> ops::IndexMut<$index_type> for SmallVec<A> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: $index_type) -> &mut $output_type {
|
||||
&mut (&mut **self)[index]
|
||||
@@ -110,283 +229,147 @@ macro_rules! impl_index {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! def_small_vector(
|
||||
($name:ident, $size:expr) => (
|
||||
pub struct $name<T> {
|
||||
len: usize,
|
||||
cap: usize,
|
||||
ptr: *const T,
|
||||
data: [T; $size],
|
||||
impl_index!(usize, A::Item);
|
||||
impl_index!(ops::Range<usize>, [A::Item]);
|
||||
impl_index!(ops::RangeFrom<usize>, [A::Item]);
|
||||
impl_index!(ops::RangeTo<usize>, [A::Item]);
|
||||
impl_index!(ops::RangeFull, [A::Item]);
|
||||
|
||||
|
||||
impl<A: Array> VecLike<A::Item> for SmallVec<A> {
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
SmallVec::len(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push(&mut self, value: A::Item) {
|
||||
SmallVec::push(self, value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> FromIterator<A::Item> for SmallVec<A> {
|
||||
fn from_iter<I: IntoIterator<Item=A::Item>>(iterable: I) -> SmallVec<A> {
|
||||
let mut v = SmallVec::new();
|
||||
v.extend(iterable);
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> SmallVec<A> {
|
||||
pub fn extend<I: IntoIterator<Item=A::Item>>(&mut self, iterable: I) {
|
||||
let iter = iterable.into_iter();
|
||||
let (lower_size_bound, _) = iter.size_hint();
|
||||
|
||||
let target_len = self.len + lower_size_bound;
|
||||
|
||||
if target_len > self.capacity() {
|
||||
self.grow(target_len);
|
||||
}
|
||||
|
||||
impl<T> $name<T> {
|
||||
unsafe fn set_len(&mut self, new_len: usize) {
|
||||
self.len = new_len
|
||||
}
|
||||
unsafe fn set_cap(&mut self, new_cap: usize) {
|
||||
self.cap = new_cap
|
||||
}
|
||||
fn data(&self, index: usize) -> *const T {
|
||||
let ptr: *const T = &self.data[index];
|
||||
ptr
|
||||
}
|
||||
unsafe fn ptr(&self) -> *const T {
|
||||
self.ptr
|
||||
}
|
||||
unsafe fn mut_ptr(&mut self) -> *mut T {
|
||||
self.ptr as *mut T
|
||||
}
|
||||
unsafe fn set_ptr(&mut self, new_ptr: *mut T) {
|
||||
self.ptr = new_ptr as *const T
|
||||
}
|
||||
for elem in iter {
|
||||
self.push(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline_size(&self) -> usize {
|
||||
$size
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
pub fn cap(&self) -> usize {
|
||||
self.cap
|
||||
}
|
||||
impl<A: Array> fmt::Debug for SmallVec<A> where A::Item: fmt::Debug {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", &**self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spilled(&self) -> bool {
|
||||
self.cap() > self.inline_size()
|
||||
}
|
||||
|
||||
pub fn begin(&self) -> *const T {
|
||||
unsafe {
|
||||
if self.spilled() {
|
||||
self.ptr()
|
||||
} else {
|
||||
self.data(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn begin_mut(&mut self) -> *mut T {
|
||||
self.begin() as *mut T
|
||||
}
|
||||
|
||||
pub fn end(&self) -> *const T {
|
||||
unsafe {
|
||||
self.begin().offset(self.len() as isize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn end_mut(&mut self) -> *mut T {
|
||||
self.end() as *mut T
|
||||
}
|
||||
|
||||
/// NB: For efficiency reasons (avoiding making a second copy of the inline elements), this
|
||||
/// actually clears out the original array instead of moving it.
|
||||
pub fn into_iter<'a>(&'a mut self) -> SmallVecMoveIterator<'a,T> {
|
||||
unsafe {
|
||||
let ptr_opt = if self.spilled() {
|
||||
Some(self.mut_ptr())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let cap = self.cap();
|
||||
let inline_size = self.inline_size();
|
||||
self.set_cap(inline_size);
|
||||
self.set_len(0);
|
||||
let iter = self.iter_mut();
|
||||
SmallVecMoveIterator {
|
||||
allocation: ptr_opt,
|
||||
cap: cap,
|
||||
iter: iter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: T) {
|
||||
let cap = self.cap();
|
||||
if self.len() == cap {
|
||||
self.grow(cmp::max(cap * 2, 1))
|
||||
}
|
||||
let end = self.end_mut();
|
||||
unsafe {
|
||||
ptr::write(end, value);
|
||||
let len = self.len();
|
||||
self.set_len(len + 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_all_move<V: IntoIterator<Item=T>>(&mut self, other: V) {
|
||||
for value in other {
|
||||
self.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
if self.len() == 0 {
|
||||
return None
|
||||
}
|
||||
let last_index = self.len() - 1;
|
||||
if (last_index as isize) < 0 {
|
||||
panic!("overflow")
|
||||
}
|
||||
unsafe {
|
||||
let end_ptr = self.begin_mut().offset(last_index as isize);
|
||||
let value = ptr::replace(end_ptr, mem::uninitialized());
|
||||
self.set_len(last_index);
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, new_cap: usize) {
|
||||
let mut vec: Vec<T> = Vec::with_capacity(new_cap);
|
||||
let new_alloc = vec.as_mut_ptr();
|
||||
unsafe {
|
||||
mem::forget(vec);
|
||||
ptr::copy_nonoverlapping(self.begin(), new_alloc, self.len());
|
||||
|
||||
if self.spilled() {
|
||||
deallocate(self.mut_ptr(), self.cap())
|
||||
} else {
|
||||
ptr::write_bytes(self.begin_mut(), 0, self.len())
|
||||
}
|
||||
|
||||
self.set_ptr(new_alloc);
|
||||
self.set_cap(new_cap)
|
||||
}
|
||||
impl<A: Array> SmallVec<A> {
|
||||
#[inline]
|
||||
pub fn new() -> SmallVec<A> {
|
||||
unsafe {
|
||||
SmallVec {
|
||||
len: 0,
|
||||
data: Inline { array: mem::zeroed() },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Deref for $name<T> {
|
||||
type Target = [T];
|
||||
#[inline]
|
||||
fn deref(&self) -> &[T] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self.begin(), self.len())
|
||||
impl<A: Array> Drop for SmallVec<A> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = self.as_ptr();
|
||||
for i in 0 .. self.len {
|
||||
ptr::read(ptr.offset(i as isize));
|
||||
}
|
||||
|
||||
match self.data {
|
||||
Inline { .. } => {
|
||||
// Inhibit the array destructor.
|
||||
ptr::write(&mut self.data, Heap {
|
||||
ptr: ptr::null_mut(),
|
||||
capacity: 0,
|
||||
});
|
||||
}
|
||||
Heap { ptr, capacity } => deallocate(ptr, capacity),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::DerefMut for $name<T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self.begin_mut(), self.len())
|
||||
}
|
||||
}
|
||||
impl<A: Array> Clone for SmallVec<A> where A::Item: Clone {
|
||||
fn clone(&self) -> SmallVec<A> {
|
||||
let mut new_vector = SmallVec::new();
|
||||
for element in self.iter() {
|
||||
new_vector.push((*element).clone())
|
||||
}
|
||||
new_vector
|
||||
}
|
||||
}
|
||||
|
||||
impl_index!($name, usize, T);
|
||||
impl_index!($name, ops::Range<usize>, [T]);
|
||||
impl_index!($name, ops::RangeFrom<usize>, [T]);
|
||||
impl_index!($name, ops::RangeTo<usize>, [T]);
|
||||
impl_index!($name, ops::RangeFull, [T]);
|
||||
unsafe impl<A: Array> Send for SmallVec<A> where A::Item: Send {}
|
||||
|
||||
impl<T> VecLike<T> for $name<T> {
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
$name::len(self)
|
||||
// TODO: Remove these and its users.
|
||||
|
||||
/// Deprecated alias to ease transition from an earlier version.
|
||||
pub type SmallVec1<T> = SmallVec<[T; 1]>;
|
||||
|
||||
/// Deprecated alias to ease transition from an earlier version.
|
||||
pub type SmallVec2<T> = SmallVec<[T; 2]>;
|
||||
|
||||
/// Deprecated alias to ease transition from an earlier version.
|
||||
pub type SmallVec4<T> = SmallVec<[T; 4]>;
|
||||
|
||||
/// Deprecated alias to ease transition from an earlier version.
|
||||
pub type SmallVec8<T> = SmallVec<[T; 8]>;
|
||||
|
||||
/// Deprecated alias to ease transition from an earlier version.
|
||||
pub type SmallVec16<T> = SmallVec<[T; 16]>;
|
||||
|
||||
/// Deprecated alias to ease transition from an earlier version.
|
||||
pub type SmallVec24<T> = SmallVec<[T; 24]>;
|
||||
|
||||
/// Deprecated alias to ease transition from an earlier version.
|
||||
pub type SmallVec32<T> = SmallVec<[T; 32]>;
|
||||
|
||||
|
||||
pub trait Array {
|
||||
type Item;
|
||||
fn size() -> usize;
|
||||
fn ptr(&self) -> *const Self::Item;
|
||||
fn ptr_mut(&mut self) -> *mut Self::Item;
|
||||
}
|
||||
|
||||
macro_rules! impl_array(
|
||||
($($size:expr),+) => {
|
||||
$(
|
||||
impl<T> Array for [T; $size] {
|
||||
type Item = T;
|
||||
fn size() -> usize { $size }
|
||||
fn ptr(&self) -> *const T { &self[0] }
|
||||
fn ptr_mut(&mut self) -> *mut T { &mut self[0] }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push(&mut self, value: T) {
|
||||
$name::push(self, value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromIterator<T> for $name<T> {
|
||||
fn from_iter<I: IntoIterator<Item=T>>(iterable: I) -> $name<T> {
|
||||
let mut v = $name::new();
|
||||
|
||||
let iter = iterable.into_iter();
|
||||
let (lower_size_bound, _) = iter.size_hint();
|
||||
|
||||
if lower_size_bound > v.cap() {
|
||||
v.grow(lower_size_bound);
|
||||
}
|
||||
|
||||
for elem in iter {
|
||||
v.push(elem);
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> $name<T> {
|
||||
pub fn extend<I: Iterator<Item=T>>(&mut self, iter: I) {
|
||||
let (lower_size_bound, _) = iter.size_hint();
|
||||
|
||||
let target_len = self.len() + lower_size_bound;
|
||||
|
||||
if target_len > self.cap() {
|
||||
self.grow(target_len);
|
||||
}
|
||||
|
||||
for elem in iter {
|
||||
self.push(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for $name<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", &**self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> $name<T> {
|
||||
#[inline]
|
||||
pub fn new() -> $name<T> {
|
||||
unsafe {
|
||||
$name {
|
||||
len: 0,
|
||||
cap: $size,
|
||||
ptr: ptr::null(),
|
||||
data: mem::zeroed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for $name<T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.spilled() {
|
||||
return
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr = self.mut_ptr();
|
||||
for i in 0 .. self.len() {
|
||||
*ptr.offset(i as isize) = mem::uninitialized();
|
||||
}
|
||||
|
||||
deallocate(self.mut_ptr(), self.cap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for $name<T> {
|
||||
fn clone(&self) -> $name<T> {
|
||||
let mut new_vector = $name::new();
|
||||
for element in self.iter() {
|
||||
new_vector.push((*element).clone())
|
||||
}
|
||||
new_vector
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for $name<T> {}
|
||||
)
|
||||
)+
|
||||
}
|
||||
);
|
||||
|
||||
def_small_vector!(SmallVec1, 1);
|
||||
def_small_vector!(SmallVec2, 2);
|
||||
def_small_vector!(SmallVec4, 4);
|
||||
def_small_vector!(SmallVec8, 8);
|
||||
def_small_vector!(SmallVec16, 16);
|
||||
def_small_vector!(SmallVec24, 24);
|
||||
def_small_vector!(SmallVec32, 32);
|
||||
impl_array!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32);
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
@@ -446,4 +429,16 @@ pub mod tests {
|
||||
"shave".to_owned(),
|
||||
][..]);
|
||||
}
|
||||
|
||||
/// https://github.com/servo/rust-smallvec/issues/4
|
||||
#[test]
|
||||
fn issue_4() {
|
||||
SmallVec2::<Box<u32>>::new();
|
||||
}
|
||||
|
||||
/// https://github.com/servo/rust-smallvec/issues/5
|
||||
#[test]
|
||||
fn issue_5() {
|
||||
assert!(Some(SmallVec2::<&u32>::new()).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user