raw_parts

This commit is contained in:
missing 2022-08-19 11:52:34 -05:00
parent 672ea5b0bc
commit 1c6d8cdfa3
2 changed files with 75 additions and 13 deletions

View file

@ -1,6 +1,6 @@
//! # A [`Vec<T: ?Sized>`]
//!
//! A dynamic length collection of unsized elements, akin to [`std::vec::Vec`].
//! [`dyn_vec::Vec`], a dynamic length collection of unsized elements, akin to [`std::vec::Vec`].
//!
//! # Examples
//!
@ -115,6 +115,7 @@
//! ```
//!
//! [`Vec<T: ?Sized>`]: Vec
//! [`dyn_vec::Vec`]: Vec
//! [`Vec::push_unsize`]: Vec::push_unsize
//! [`Vec::unsize`]: Vec::unsize
//! [`Vec::extend_unsize`]: Vec::extend_unsize
@ -149,10 +150,10 @@ pub mod prelude {
use core::panic;
use std::{
alloc::{alloc, dealloc, Layout},
alloc::{alloc, dealloc, handle_alloc_error, Layout},
any::Any,
marker::PhantomData,
mem::{self, align_of, align_of_val, size_of, size_of_val},
mem::{self, align_of, align_of_val, size_of, size_of_val, ManuallyDrop},
ops::{Index, IndexMut},
ptr::{drop_in_place, NonNull},
slice,
@ -238,6 +239,52 @@ impl<T: ?Sized> Vec<T> {
Self::with_capacity_bytes(cap * (size_of::<U>() + size_of::<Extra<U>>()))
}
/// Decomposes the vector into its raw components.
///
/// Returns the pointer to the underlying alloctaion, the number of elements,
/// the size of the allocation in bytes, and the total size of all of the
/// vector's elements.
pub fn into_raw_parts(self) -> (*mut u8, usize, usize, usize) {
let mut this = ManuallyDrop::new(self);
(
this.as_mut_ptr(),
this.len(),
this.capacity(),
this.data_size(),
)
}
/// Reconstructs a vector from its raw components.
///
/// # Safety
/// - `ptr` must be non-null and point to an allocation with the proper
/// data layout, as documented in the crate-level docs.
/// - `len` must be less than or equal to the number of initialized
/// elements in the allocation.
/// - `capacity` must be equal to the size of the allocation in bytes.
/// - `data_size` must be equal to the number of bytes taken up by the
/// first `len` elements of the vector, including leading (but not trailing)
/// padding.
/// - The allocation must have been allocated with alignment equal to
/// `align_of::<*const T>()`
///
/// All of these conditions are upheld by the values returned from
/// `into_raw_parts`.
pub const unsafe fn from_raw_parts(
ptr: *mut u8,
len: usize,
capacity: usize,
data_size: usize,
) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr),
len,
capacity,
end_ptr: NonNull::new_unchecked(ptr.add(data_size)),
_phantom: PhantomData,
}
}
/// Appends an element to the end of the vector.
///
/// Only avaliable if `T: Sized`.
@ -245,8 +292,7 @@ impl<T: ?Sized> Vec<T> {
where
T: Sized,
{
unsafe { self.push_raw(&v) }
mem::forget(v);
unsafe { self.push_raw(&*ManuallyDrop::new(v)) }
}
/// Appends an (possibly unsized) boxed element to the end of the vector.
@ -323,16 +369,15 @@ impl<T: ?Sized> Vec<T> {
unsafe fn realloc(&mut self, size: usize) {
let layout = Layout::from_size_align_unchecked(size, align_of::<Extra<T>>()).pad_to_align();
let new_alloc = NonNull::new(alloc(layout)).unwrap_or_else(|| handle_alloc_error(layout));
if self.capacity == 0 {
// will panic if OOM
self.ptr = NonNull::new(alloc(layout)).unwrap();
self.ptr = new_alloc;
self.end_ptr = self.ptr;
} else {
// cannot use mem::realloc here
let new_alloc = NonNull::new(alloc(layout)).unwrap();
// data
let mut ptr = new_alloc.as_ptr();
for i in 0..self.len {
@ -445,7 +490,7 @@ impl<T: ?Sized> Vec<T> {
/// Returns the capacity, which is the size of the allocation in bytes.
///
/// Note the distinction from [`std::vec::Vec`], which returns how many elements it can hold.
/// Note the distinction from [`std::vec::Vec::capacity`], which returns how many *elements* it can hold.
pub const fn capacity(&self) -> usize {
self.capacity
}
@ -460,6 +505,23 @@ impl<T: ?Sized> Vec<T> {
self.ptr.as_ptr()
}
/// Returns a pointer to the end of the last element of the vector.
pub const fn as_end_ptr(&self) -> *const u8 {
self.end_ptr.as_ptr()
}
/// Returns a mutable pointer to the end of the last element of the vector.
pub fn as_end_ptr_mut(&mut self) -> *const u8 {
self.end_ptr.as_ptr()
}
/// Returns the size (in bytes) of the elements (and padding) of the vector.
///
/// Same as `self.as_end_ptr() as usize - self.as_ptr() as usize`.
pub fn data_size(&self) -> usize {
self.as_end_ptr() as usize - self.as_ptr() as usize
}
/// Iterates over the vector by-ref.
pub fn iter(&self) -> Iter<T> {
Iter::new(self)
@ -644,14 +706,14 @@ impl<T> Vec<[T]> {
impl Vec<dyn Any> {
/// Gets a reference to the element at then specified index, downcasting it to the specified type.
///
/// Same as `.get().map(|v| v.downcast()).flatten()`.
/// Same as `self.get(index).map(|v| v.downcast()).flatten()`.
pub fn downcast_get<T: Any>(&self, index: usize) -> Option<&T> {
self.get(index)?.downcast_ref()
}
/// Gets a mutable reference to the element at then specified index, downcasting it to the specified type.
///
/// Same as `.get_mut().map(|v| v.downcast_mut()).flatten()`.
/// Same as `self.get_mut(index).map(|v| v.downcast_mut()).flatten()`.
pub fn downcast_get_mut<T: Any>(&mut self, index: usize) -> Option<&mut T> {
self.get_mut(index)?.downcast_mut()
}
@ -660,7 +722,7 @@ impl Vec<dyn Any> {
///
/// If the element is not of type `T`, the element will not be popped.
///
/// Similiar to `.pop().map(|v| v.downcast()).flatten()`, but without an intermediate allocation.
/// Same as `self.pop().map(|v| v.downcast()).flatten()`, but without an intermediate allocation.
pub fn downcast_pop<T: Any>(&mut self) -> Option<T> {
unsafe {
let el = self.get_unchecked_mut(self.len.checked_sub(1)?);

View file

@ -223,7 +223,7 @@ fn stress_test() {
let mut len = 0;
let iterations = if cfg!(miri) { 1_000 } else { 1_000_000 };
let iterations = if cfg!(miri) { 100 } else { 1_000_000 };
for _ in 0..iterations {
if len == 0 || rng.gen_bool(0.7) {