From 1c6d8cdfa3b58b8bec8eb4282ded813ff7463b2d Mon Sep 17 00:00:00 2001 From: missing Date: Fri, 19 Aug 2022 11:52:34 -0500 Subject: [PATCH] raw_parts --- src/lib.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++-------- src/test.rs | 2 +- 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 82349f7..5e50837 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! # A [`Vec`] //! -//! 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`]: 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 Vec { Self::with_capacity_bytes(cap * (size_of::() + size_of::>())) } + /// 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 Vec { 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 Vec { unsafe fn realloc(&mut self, size: usize) { let layout = Layout::from_size_align_unchecked(size, align_of::>()).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 Vec { /// 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 Vec { 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 { Iter::new(self) @@ -644,14 +706,14 @@ impl Vec<[T]> { impl Vec { /// 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(&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(&mut self, index: usize) -> Option<&mut T> { self.get_mut(index)?.downcast_mut() } @@ -660,7 +722,7 @@ impl Vec { /// /// 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(&mut self) -> Option { unsafe { let el = self.get_unchecked_mut(self.len.checked_sub(1)?); diff --git a/src/test.rs b/src/test.rs index dadcb06..b814974 100644 --- a/src/test.rs +++ b/src/test.rs @@ -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) {