1057b8d25SMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT 2057b8d25SMiguel Ojeda 3753dece8SMiguel Ojeda #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")] 4753dece8SMiguel Ojeda 5753dece8SMiguel Ojeda use core::alloc::LayoutError; 6753dece8SMiguel Ojeda use core::cmp; 7753dece8SMiguel Ojeda use core::intrinsics; 83ed03f4dSMiguel Ojeda use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; 9753dece8SMiguel Ojeda use core::ptr::{self, NonNull, Unique}; 10753dece8SMiguel Ojeda use core::slice; 11753dece8SMiguel Ojeda 12753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 13753dece8SMiguel Ojeda use crate::alloc::handle_alloc_error; 14753dece8SMiguel Ojeda use crate::alloc::{Allocator, Global, Layout}; 15753dece8SMiguel Ojeda use crate::boxed::Box; 16753dece8SMiguel Ojeda use crate::collections::TryReserveError; 17753dece8SMiguel Ojeda use crate::collections::TryReserveErrorKind::*; 18753dece8SMiguel Ojeda 19753dece8SMiguel Ojeda #[cfg(test)] 20753dece8SMiguel Ojeda mod tests; 21753dece8SMiguel Ojeda 22753dece8SMiguel Ojeda enum AllocInit { 23753dece8SMiguel Ojeda /// The contents of the new memory are uninitialized. 24753dece8SMiguel Ojeda Uninitialized, 25753dece8SMiguel Ojeda /// The new memory is guaranteed to be zeroed. 2651d3a25aSMiguel Ojeda #[allow(dead_code)] 27753dece8SMiguel Ojeda Zeroed, 28753dece8SMiguel Ojeda } 29753dece8SMiguel Ojeda 30753dece8SMiguel Ojeda /// A low-level utility for more ergonomically allocating, reallocating, and deallocating 31753dece8SMiguel Ojeda /// a buffer of memory on the heap without having to worry about all the corner cases 32753dece8SMiguel Ojeda /// involved. This type is excellent for building your own data structures like Vec and VecDeque. 33753dece8SMiguel Ojeda /// In particular: 34753dece8SMiguel Ojeda /// 35753dece8SMiguel Ojeda /// * Produces `Unique::dangling()` on zero-sized types. 36753dece8SMiguel Ojeda /// * Produces `Unique::dangling()` on zero-length allocations. 37753dece8SMiguel Ojeda /// * Avoids freeing `Unique::dangling()`. 38753dece8SMiguel Ojeda /// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). 39753dece8SMiguel Ojeda /// * Guards against 32-bit systems allocating more than isize::MAX bytes. 40753dece8SMiguel Ojeda /// * Guards against overflowing your length. 41753dece8SMiguel Ojeda /// * Calls `handle_alloc_error` for fallible allocations. 42753dece8SMiguel Ojeda /// * Contains a `ptr::Unique` and thus endows the user with all related benefits. 43753dece8SMiguel Ojeda /// * Uses the excess returned from the allocator to use the largest available capacity. 44753dece8SMiguel Ojeda /// 45753dece8SMiguel Ojeda /// This type does not in anyway inspect the memory that it manages. When dropped it *will* 46753dece8SMiguel Ojeda /// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec` 47753dece8SMiguel Ojeda /// to handle the actual things *stored* inside of a `RawVec`. 48753dece8SMiguel Ojeda /// 49753dece8SMiguel Ojeda /// Note that the excess of a zero-sized types is always infinite, so `capacity()` always returns 50753dece8SMiguel Ojeda /// `usize::MAX`. This means that you need to be careful when round-tripping this type with a 51753dece8SMiguel Ojeda /// `Box<[T]>`, since `capacity()` won't yield the length. 52753dece8SMiguel Ojeda #[allow(missing_debug_implementations)] 53753dece8SMiguel Ojeda pub(crate) struct RawVec<T, A: Allocator = Global> { 54753dece8SMiguel Ojeda ptr: Unique<T>, 55753dece8SMiguel Ojeda cap: usize, 56753dece8SMiguel Ojeda alloc: A, 57753dece8SMiguel Ojeda } 58753dece8SMiguel Ojeda 59753dece8SMiguel Ojeda impl<T> RawVec<T, Global> { 60753dece8SMiguel Ojeda /// HACK(Centril): This exists because stable `const fn` can only call stable `const fn`, so 61753dece8SMiguel Ojeda /// they cannot call `Self::new()`. 62753dece8SMiguel Ojeda /// 63753dece8SMiguel Ojeda /// If you change `RawVec<T>::new` or dependencies, please take care to not introduce anything 64753dece8SMiguel Ojeda /// that would truly const-call something unstable. 65753dece8SMiguel Ojeda pub const NEW: Self = Self::new(); 66753dece8SMiguel Ojeda 67753dece8SMiguel Ojeda /// Creates the biggest possible `RawVec` (on the system heap) 68753dece8SMiguel Ojeda /// without allocating. If `T` has positive size, then this makes a 69753dece8SMiguel Ojeda /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a 70753dece8SMiguel Ojeda /// `RawVec` with capacity `usize::MAX`. Useful for implementing 71753dece8SMiguel Ojeda /// delayed allocation. 72753dece8SMiguel Ojeda #[must_use] 73753dece8SMiguel Ojeda pub const fn new() -> Self { 74753dece8SMiguel Ojeda Self::new_in(Global) 75753dece8SMiguel Ojeda } 76753dece8SMiguel Ojeda 77753dece8SMiguel Ojeda /// Creates a `RawVec` (on the system heap) with exactly the 78753dece8SMiguel Ojeda /// capacity and alignment requirements for a `[T; capacity]`. This is 79753dece8SMiguel Ojeda /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is 80753dece8SMiguel Ojeda /// zero-sized. Note that if `T` is zero-sized this means you will 81753dece8SMiguel Ojeda /// *not* get a `RawVec` with the requested capacity. 82753dece8SMiguel Ojeda /// 83753dece8SMiguel Ojeda /// # Panics 84753dece8SMiguel Ojeda /// 85753dece8SMiguel Ojeda /// Panics if the requested capacity exceeds `isize::MAX` bytes. 86753dece8SMiguel Ojeda /// 87753dece8SMiguel Ojeda /// # Aborts 88753dece8SMiguel Ojeda /// 89753dece8SMiguel Ojeda /// Aborts on OOM. 90753dece8SMiguel Ojeda #[cfg(not(any(no_global_oom_handling, test)))] 91753dece8SMiguel Ojeda #[must_use] 92753dece8SMiguel Ojeda #[inline] 93753dece8SMiguel Ojeda pub fn with_capacity(capacity: usize) -> Self { 94753dece8SMiguel Ojeda Self::with_capacity_in(capacity, Global) 95753dece8SMiguel Ojeda } 96753dece8SMiguel Ojeda 97753dece8SMiguel Ojeda /// Like `with_capacity`, but guarantees the buffer is zeroed. 98753dece8SMiguel Ojeda #[cfg(not(any(no_global_oom_handling, test)))] 99753dece8SMiguel Ojeda #[must_use] 100753dece8SMiguel Ojeda #[inline] 101753dece8SMiguel Ojeda pub fn with_capacity_zeroed(capacity: usize) -> Self { 102753dece8SMiguel Ojeda Self::with_capacity_zeroed_in(capacity, Global) 103753dece8SMiguel Ojeda } 104753dece8SMiguel Ojeda } 105753dece8SMiguel Ojeda 106753dece8SMiguel Ojeda impl<T, A: Allocator> RawVec<T, A> { 107753dece8SMiguel Ojeda // Tiny Vecs are dumb. Skip to: 108753dece8SMiguel Ojeda // - 8 if the element size is 1, because any heap allocators is likely 109753dece8SMiguel Ojeda // to round up a request of less than 8 bytes to at least 8 bytes. 110753dece8SMiguel Ojeda // - 4 if elements are moderate-sized (<= 1 KiB). 111753dece8SMiguel Ojeda // - 1 otherwise, to avoid wasting too much space for very short Vecs. 112753dece8SMiguel Ojeda pub(crate) const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 { 113753dece8SMiguel Ojeda 8 114753dece8SMiguel Ojeda } else if mem::size_of::<T>() <= 1024 { 115753dece8SMiguel Ojeda 4 116753dece8SMiguel Ojeda } else { 117753dece8SMiguel Ojeda 1 118753dece8SMiguel Ojeda }; 119753dece8SMiguel Ojeda 120753dece8SMiguel Ojeda /// Like `new`, but parameterized over the choice of allocator for 121753dece8SMiguel Ojeda /// the returned `RawVec`. 122753dece8SMiguel Ojeda pub const fn new_in(alloc: A) -> Self { 123753dece8SMiguel Ojeda // `cap: 0` means "unallocated". zero-sized types are ignored. 124753dece8SMiguel Ojeda Self { ptr: Unique::dangling(), cap: 0, alloc } 125753dece8SMiguel Ojeda } 126753dece8SMiguel Ojeda 127753dece8SMiguel Ojeda /// Like `with_capacity`, but parameterized over the choice of 128753dece8SMiguel Ojeda /// allocator for the returned `RawVec`. 129753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 130753dece8SMiguel Ojeda #[inline] 131753dece8SMiguel Ojeda pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { 132753dece8SMiguel Ojeda Self::allocate_in(capacity, AllocInit::Uninitialized, alloc) 133753dece8SMiguel Ojeda } 134753dece8SMiguel Ojeda 13551d3a25aSMiguel Ojeda /// Like `try_with_capacity`, but parameterized over the choice of 13651d3a25aSMiguel Ojeda /// allocator for the returned `RawVec`. 13751d3a25aSMiguel Ojeda #[inline] 13851d3a25aSMiguel Ojeda pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> { 13951d3a25aSMiguel Ojeda Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc) 14051d3a25aSMiguel Ojeda } 14151d3a25aSMiguel Ojeda 142753dece8SMiguel Ojeda /// Like `with_capacity_zeroed`, but parameterized over the choice 143753dece8SMiguel Ojeda /// of allocator for the returned `RawVec`. 144753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 145753dece8SMiguel Ojeda #[inline] 146753dece8SMiguel Ojeda pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { 147753dece8SMiguel Ojeda Self::allocate_in(capacity, AllocInit::Zeroed, alloc) 148753dece8SMiguel Ojeda } 149753dece8SMiguel Ojeda 150753dece8SMiguel Ojeda /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`. 151753dece8SMiguel Ojeda /// 152753dece8SMiguel Ojeda /// Note that this will correctly reconstitute any `cap` changes 153753dece8SMiguel Ojeda /// that may have been performed. (See description of type for details.) 154753dece8SMiguel Ojeda /// 155753dece8SMiguel Ojeda /// # Safety 156753dece8SMiguel Ojeda /// 157753dece8SMiguel Ojeda /// * `len` must be greater than or equal to the most recently requested capacity, and 158753dece8SMiguel Ojeda /// * `len` must be less than or equal to `self.capacity()`. 159753dece8SMiguel Ojeda /// 160753dece8SMiguel Ojeda /// Note, that the requested capacity and `self.capacity()` could differ, as 161753dece8SMiguel Ojeda /// an allocator could overallocate and return a greater memory block than requested. 162753dece8SMiguel Ojeda pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> { 163753dece8SMiguel Ojeda // Sanity-check one half of the safety requirement (we cannot check the other half). 164753dece8SMiguel Ojeda debug_assert!( 165753dece8SMiguel Ojeda len <= self.capacity(), 166753dece8SMiguel Ojeda "`len` must be smaller than or equal to `self.capacity()`" 167753dece8SMiguel Ojeda ); 168753dece8SMiguel Ojeda 169753dece8SMiguel Ojeda let me = ManuallyDrop::new(self); 170753dece8SMiguel Ojeda unsafe { 171753dece8SMiguel Ojeda let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len); 172753dece8SMiguel Ojeda Box::from_raw_in(slice, ptr::read(&me.alloc)) 173753dece8SMiguel Ojeda } 174753dece8SMiguel Ojeda } 175753dece8SMiguel Ojeda 176753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 177753dece8SMiguel Ojeda fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { 178753dece8SMiguel Ojeda // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. 1793ed03f4dSMiguel Ojeda if T::IS_ZST || capacity == 0 { 180753dece8SMiguel Ojeda Self::new_in(alloc) 181753dece8SMiguel Ojeda } else { 182753dece8SMiguel Ojeda // We avoid `unwrap_or_else` here because it bloats the amount of 183753dece8SMiguel Ojeda // LLVM IR generated. 184753dece8SMiguel Ojeda let layout = match Layout::array::<T>(capacity) { 185753dece8SMiguel Ojeda Ok(layout) => layout, 186753dece8SMiguel Ojeda Err(_) => capacity_overflow(), 187753dece8SMiguel Ojeda }; 188753dece8SMiguel Ojeda match alloc_guard(layout.size()) { 189753dece8SMiguel Ojeda Ok(_) => {} 190753dece8SMiguel Ojeda Err(_) => capacity_overflow(), 191753dece8SMiguel Ojeda } 192753dece8SMiguel Ojeda let result = match init { 193753dece8SMiguel Ojeda AllocInit::Uninitialized => alloc.allocate(layout), 194753dece8SMiguel Ojeda AllocInit::Zeroed => alloc.allocate_zeroed(layout), 195753dece8SMiguel Ojeda }; 196753dece8SMiguel Ojeda let ptr = match result { 197753dece8SMiguel Ojeda Ok(ptr) => ptr, 198753dece8SMiguel Ojeda Err(_) => handle_alloc_error(layout), 199753dece8SMiguel Ojeda }; 200753dece8SMiguel Ojeda 201753dece8SMiguel Ojeda // Allocators currently return a `NonNull<[u8]>` whose length 202753dece8SMiguel Ojeda // matches the size requested. If that ever changes, the capacity 203753dece8SMiguel Ojeda // here should change to `ptr.len() / mem::size_of::<T>()`. 204753dece8SMiguel Ojeda Self { 205753dece8SMiguel Ojeda ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }, 206753dece8SMiguel Ojeda cap: capacity, 207753dece8SMiguel Ojeda alloc, 208753dece8SMiguel Ojeda } 209753dece8SMiguel Ojeda } 210753dece8SMiguel Ojeda } 211753dece8SMiguel Ojeda 21251d3a25aSMiguel Ojeda fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> { 21351d3a25aSMiguel Ojeda // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. 2143ed03f4dSMiguel Ojeda if T::IS_ZST || capacity == 0 { 21551d3a25aSMiguel Ojeda return Ok(Self::new_in(alloc)); 21651d3a25aSMiguel Ojeda } 21751d3a25aSMiguel Ojeda 21851d3a25aSMiguel Ojeda let layout = Layout::array::<T>(capacity).map_err(|_| CapacityOverflow)?; 21951d3a25aSMiguel Ojeda alloc_guard(layout.size())?; 22051d3a25aSMiguel Ojeda let result = match init { 22151d3a25aSMiguel Ojeda AllocInit::Uninitialized => alloc.allocate(layout), 22251d3a25aSMiguel Ojeda AllocInit::Zeroed => alloc.allocate_zeroed(layout), 22351d3a25aSMiguel Ojeda }; 22451d3a25aSMiguel Ojeda let ptr = result.map_err(|_| AllocError { layout, non_exhaustive: () })?; 22551d3a25aSMiguel Ojeda 22651d3a25aSMiguel Ojeda // Allocators currently return a `NonNull<[u8]>` whose length 22751d3a25aSMiguel Ojeda // matches the size requested. If that ever changes, the capacity 22851d3a25aSMiguel Ojeda // here should change to `ptr.len() / mem::size_of::<T>()`. 22951d3a25aSMiguel Ojeda Ok(Self { 23051d3a25aSMiguel Ojeda ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }, 23151d3a25aSMiguel Ojeda cap: capacity, 23251d3a25aSMiguel Ojeda alloc, 23351d3a25aSMiguel Ojeda }) 23451d3a25aSMiguel Ojeda } 23551d3a25aSMiguel Ojeda 236753dece8SMiguel Ojeda /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. 237753dece8SMiguel Ojeda /// 238753dece8SMiguel Ojeda /// # Safety 239753dece8SMiguel Ojeda /// 240753dece8SMiguel Ojeda /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given 241753dece8SMiguel Ojeda /// `capacity`. 242753dece8SMiguel Ojeda /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit 243753dece8SMiguel Ojeda /// systems). ZST vectors may have a capacity up to `usize::MAX`. 244753dece8SMiguel Ojeda /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is 245753dece8SMiguel Ojeda /// guaranteed. 246753dece8SMiguel Ojeda #[inline] 247753dece8SMiguel Ojeda pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { 248753dece8SMiguel Ojeda Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc } 249753dece8SMiguel Ojeda } 250753dece8SMiguel Ojeda 251753dece8SMiguel Ojeda /// Gets a raw pointer to the start of the allocation. Note that this is 252753dece8SMiguel Ojeda /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must 253753dece8SMiguel Ojeda /// be careful. 254753dece8SMiguel Ojeda #[inline] 255753dece8SMiguel Ojeda pub fn ptr(&self) -> *mut T { 256753dece8SMiguel Ojeda self.ptr.as_ptr() 257753dece8SMiguel Ojeda } 258753dece8SMiguel Ojeda 259753dece8SMiguel Ojeda /// Gets the capacity of the allocation. 260753dece8SMiguel Ojeda /// 261753dece8SMiguel Ojeda /// This will always be `usize::MAX` if `T` is zero-sized. 262753dece8SMiguel Ojeda #[inline(always)] 263753dece8SMiguel Ojeda pub fn capacity(&self) -> usize { 2643ed03f4dSMiguel Ojeda if T::IS_ZST { usize::MAX } else { self.cap } 265753dece8SMiguel Ojeda } 266753dece8SMiguel Ojeda 267753dece8SMiguel Ojeda /// Returns a shared reference to the allocator backing this `RawVec`. 268753dece8SMiguel Ojeda pub fn allocator(&self) -> &A { 269753dece8SMiguel Ojeda &self.alloc 270753dece8SMiguel Ojeda } 271753dece8SMiguel Ojeda 272753dece8SMiguel Ojeda fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> { 2733ed03f4dSMiguel Ojeda if T::IS_ZST || self.cap == 0 { 274753dece8SMiguel Ojeda None 275753dece8SMiguel Ojeda } else { 276*89eed1abSMiguel Ojeda // We could use Layout::array here which ensures the absence of isize and usize overflows 277*89eed1abSMiguel Ojeda // and could hypothetically handle differences between stride and size, but this memory 278*89eed1abSMiguel Ojeda // has already been allocated so we know it can't overflow and currently rust does not 279*89eed1abSMiguel Ojeda // support such types. So we can do better by skipping some checks and avoid an unwrap. 280*89eed1abSMiguel Ojeda let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) }; 281753dece8SMiguel Ojeda unsafe { 282*89eed1abSMiguel Ojeda let align = mem::align_of::<T>(); 283*89eed1abSMiguel Ojeda let size = mem::size_of::<T>().unchecked_mul(self.cap); 284*89eed1abSMiguel Ojeda let layout = Layout::from_size_align_unchecked(size, align); 285753dece8SMiguel Ojeda Some((self.ptr.cast().into(), layout)) 286753dece8SMiguel Ojeda } 287753dece8SMiguel Ojeda } 288753dece8SMiguel Ojeda } 289753dece8SMiguel Ojeda 290753dece8SMiguel Ojeda /// Ensures that the buffer contains at least enough space to hold `len + 291753dece8SMiguel Ojeda /// additional` elements. If it doesn't already have enough capacity, will 292753dece8SMiguel Ojeda /// reallocate enough space plus comfortable slack space to get amortized 293753dece8SMiguel Ojeda /// *O*(1) behavior. Will limit this behavior if it would needlessly cause 294753dece8SMiguel Ojeda /// itself to panic. 295753dece8SMiguel Ojeda /// 296753dece8SMiguel Ojeda /// If `len` exceeds `self.capacity()`, this may fail to actually allocate 297753dece8SMiguel Ojeda /// the requested space. This is not really unsafe, but the unsafe 298753dece8SMiguel Ojeda /// code *you* write that relies on the behavior of this function may break. 299753dece8SMiguel Ojeda /// 300753dece8SMiguel Ojeda /// This is ideal for implementing a bulk-push operation like `extend`. 301753dece8SMiguel Ojeda /// 302753dece8SMiguel Ojeda /// # Panics 303753dece8SMiguel Ojeda /// 304753dece8SMiguel Ojeda /// Panics if the new capacity exceeds `isize::MAX` bytes. 305753dece8SMiguel Ojeda /// 306753dece8SMiguel Ojeda /// # Aborts 307753dece8SMiguel Ojeda /// 308753dece8SMiguel Ojeda /// Aborts on OOM. 309753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 310753dece8SMiguel Ojeda #[inline] 311753dece8SMiguel Ojeda pub fn reserve(&mut self, len: usize, additional: usize) { 312753dece8SMiguel Ojeda // Callers expect this function to be very cheap when there is already sufficient capacity. 313753dece8SMiguel Ojeda // Therefore, we move all the resizing and error-handling logic from grow_amortized and 314753dece8SMiguel Ojeda // handle_reserve behind a call, while making sure that this function is likely to be 315753dece8SMiguel Ojeda // inlined as just a comparison and a call if the comparison fails. 316753dece8SMiguel Ojeda #[cold] 317753dece8SMiguel Ojeda fn do_reserve_and_handle<T, A: Allocator>( 318753dece8SMiguel Ojeda slf: &mut RawVec<T, A>, 319753dece8SMiguel Ojeda len: usize, 320753dece8SMiguel Ojeda additional: usize, 321753dece8SMiguel Ojeda ) { 322753dece8SMiguel Ojeda handle_reserve(slf.grow_amortized(len, additional)); 323753dece8SMiguel Ojeda } 324753dece8SMiguel Ojeda 325753dece8SMiguel Ojeda if self.needs_to_grow(len, additional) { 326753dece8SMiguel Ojeda do_reserve_and_handle(self, len, additional); 327753dece8SMiguel Ojeda } 328753dece8SMiguel Ojeda } 329753dece8SMiguel Ojeda 330753dece8SMiguel Ojeda /// A specialized version of `reserve()` used only by the hot and 331753dece8SMiguel Ojeda /// oft-instantiated `Vec::push()`, which does its own capacity check. 332753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 333753dece8SMiguel Ojeda #[inline(never)] 334753dece8SMiguel Ojeda pub fn reserve_for_push(&mut self, len: usize) { 335753dece8SMiguel Ojeda handle_reserve(self.grow_amortized(len, 1)); 336753dece8SMiguel Ojeda } 337753dece8SMiguel Ojeda 338753dece8SMiguel Ojeda /// The same as `reserve`, but returns on errors instead of panicking or aborting. 339753dece8SMiguel Ojeda pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { 340753dece8SMiguel Ojeda if self.needs_to_grow(len, additional) { 341753dece8SMiguel Ojeda self.grow_amortized(len, additional) 342753dece8SMiguel Ojeda } else { 343753dece8SMiguel Ojeda Ok(()) 344753dece8SMiguel Ojeda } 345753dece8SMiguel Ojeda } 346753dece8SMiguel Ojeda 347057b8d25SMiguel Ojeda /// The same as `reserve_for_push`, but returns on errors instead of panicking or aborting. 348057b8d25SMiguel Ojeda #[inline(never)] 349057b8d25SMiguel Ojeda pub fn try_reserve_for_push(&mut self, len: usize) -> Result<(), TryReserveError> { 350057b8d25SMiguel Ojeda self.grow_amortized(len, 1) 351057b8d25SMiguel Ojeda } 352057b8d25SMiguel Ojeda 353753dece8SMiguel Ojeda /// Ensures that the buffer contains at least enough space to hold `len + 354753dece8SMiguel Ojeda /// additional` elements. If it doesn't already, will reallocate the 355753dece8SMiguel Ojeda /// minimum possible amount of memory necessary. Generally this will be 356753dece8SMiguel Ojeda /// exactly the amount of memory necessary, but in principle the allocator 357753dece8SMiguel Ojeda /// is free to give back more than we asked for. 358753dece8SMiguel Ojeda /// 359753dece8SMiguel Ojeda /// If `len` exceeds `self.capacity()`, this may fail to actually allocate 360753dece8SMiguel Ojeda /// the requested space. This is not really unsafe, but the unsafe code 361753dece8SMiguel Ojeda /// *you* write that relies on the behavior of this function may break. 362753dece8SMiguel Ojeda /// 363753dece8SMiguel Ojeda /// # Panics 364753dece8SMiguel Ojeda /// 365753dece8SMiguel Ojeda /// Panics if the new capacity exceeds `isize::MAX` bytes. 366753dece8SMiguel Ojeda /// 367753dece8SMiguel Ojeda /// # Aborts 368753dece8SMiguel Ojeda /// 369753dece8SMiguel Ojeda /// Aborts on OOM. 370753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 371753dece8SMiguel Ojeda pub fn reserve_exact(&mut self, len: usize, additional: usize) { 372753dece8SMiguel Ojeda handle_reserve(self.try_reserve_exact(len, additional)); 373753dece8SMiguel Ojeda } 374753dece8SMiguel Ojeda 375753dece8SMiguel Ojeda /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. 376753dece8SMiguel Ojeda pub fn try_reserve_exact( 377753dece8SMiguel Ojeda &mut self, 378753dece8SMiguel Ojeda len: usize, 379753dece8SMiguel Ojeda additional: usize, 380753dece8SMiguel Ojeda ) -> Result<(), TryReserveError> { 381753dece8SMiguel Ojeda if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) } 382753dece8SMiguel Ojeda } 383753dece8SMiguel Ojeda 384753dece8SMiguel Ojeda /// Shrinks the buffer down to the specified capacity. If the given amount 385753dece8SMiguel Ojeda /// is 0, actually completely deallocates. 386753dece8SMiguel Ojeda /// 387753dece8SMiguel Ojeda /// # Panics 388753dece8SMiguel Ojeda /// 389753dece8SMiguel Ojeda /// Panics if the given amount is *larger* than the current capacity. 390753dece8SMiguel Ojeda /// 391753dece8SMiguel Ojeda /// # Aborts 392753dece8SMiguel Ojeda /// 393753dece8SMiguel Ojeda /// Aborts on OOM. 394753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 395753dece8SMiguel Ojeda pub fn shrink_to_fit(&mut self, cap: usize) { 396753dece8SMiguel Ojeda handle_reserve(self.shrink(cap)); 397753dece8SMiguel Ojeda } 398753dece8SMiguel Ojeda } 399753dece8SMiguel Ojeda 400753dece8SMiguel Ojeda impl<T, A: Allocator> RawVec<T, A> { 401753dece8SMiguel Ojeda /// Returns if the buffer needs to grow to fulfill the needed extra capacity. 402753dece8SMiguel Ojeda /// Mainly used to make inlining reserve-calls possible without inlining `grow`. 403753dece8SMiguel Ojeda fn needs_to_grow(&self, len: usize, additional: usize) -> bool { 404753dece8SMiguel Ojeda additional > self.capacity().wrapping_sub(len) 405753dece8SMiguel Ojeda } 406753dece8SMiguel Ojeda 407753dece8SMiguel Ojeda fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { 408753dece8SMiguel Ojeda // Allocators currently return a `NonNull<[u8]>` whose length matches 409753dece8SMiguel Ojeda // the size requested. If that ever changes, the capacity here should 410753dece8SMiguel Ojeda // change to `ptr.len() / mem::size_of::<T>()`. 411753dece8SMiguel Ojeda self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }; 412753dece8SMiguel Ojeda self.cap = cap; 413753dece8SMiguel Ojeda } 414753dece8SMiguel Ojeda 415753dece8SMiguel Ojeda // This method is usually instantiated many times. So we want it to be as 416753dece8SMiguel Ojeda // small as possible, to improve compile times. But we also want as much of 417753dece8SMiguel Ojeda // its contents to be statically computable as possible, to make the 418753dece8SMiguel Ojeda // generated code run faster. Therefore, this method is carefully written 419753dece8SMiguel Ojeda // so that all of the code that depends on `T` is within it, while as much 420753dece8SMiguel Ojeda // of the code that doesn't depend on `T` as possible is in functions that 421753dece8SMiguel Ojeda // are non-generic over `T`. 422753dece8SMiguel Ojeda fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { 423753dece8SMiguel Ojeda // This is ensured by the calling contexts. 424753dece8SMiguel Ojeda debug_assert!(additional > 0); 425753dece8SMiguel Ojeda 4263ed03f4dSMiguel Ojeda if T::IS_ZST { 427753dece8SMiguel Ojeda // Since we return a capacity of `usize::MAX` when `elem_size` is 428753dece8SMiguel Ojeda // 0, getting to here necessarily means the `RawVec` is overfull. 429753dece8SMiguel Ojeda return Err(CapacityOverflow.into()); 430753dece8SMiguel Ojeda } 431753dece8SMiguel Ojeda 432753dece8SMiguel Ojeda // Nothing we can really do about these checks, sadly. 433753dece8SMiguel Ojeda let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; 434753dece8SMiguel Ojeda 435753dece8SMiguel Ojeda // This guarantees exponential growth. The doubling cannot overflow 436753dece8SMiguel Ojeda // because `cap <= isize::MAX` and the type of `cap` is `usize`. 437753dece8SMiguel Ojeda let cap = cmp::max(self.cap * 2, required_cap); 438753dece8SMiguel Ojeda let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap); 439753dece8SMiguel Ojeda 440753dece8SMiguel Ojeda let new_layout = Layout::array::<T>(cap); 441753dece8SMiguel Ojeda 442753dece8SMiguel Ojeda // `finish_grow` is non-generic over `T`. 443753dece8SMiguel Ojeda let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; 444753dece8SMiguel Ojeda self.set_ptr_and_cap(ptr, cap); 445753dece8SMiguel Ojeda Ok(()) 446753dece8SMiguel Ojeda } 447753dece8SMiguel Ojeda 448753dece8SMiguel Ojeda // The constraints on this method are much the same as those on 449753dece8SMiguel Ojeda // `grow_amortized`, but this method is usually instantiated less often so 450753dece8SMiguel Ojeda // it's less critical. 451753dece8SMiguel Ojeda fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { 4523ed03f4dSMiguel Ojeda if T::IS_ZST { 453753dece8SMiguel Ojeda // Since we return a capacity of `usize::MAX` when the type size is 454753dece8SMiguel Ojeda // 0, getting to here necessarily means the `RawVec` is overfull. 455753dece8SMiguel Ojeda return Err(CapacityOverflow.into()); 456753dece8SMiguel Ojeda } 457753dece8SMiguel Ojeda 458753dece8SMiguel Ojeda let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; 459753dece8SMiguel Ojeda let new_layout = Layout::array::<T>(cap); 460753dece8SMiguel Ojeda 461753dece8SMiguel Ojeda // `finish_grow` is non-generic over `T`. 462753dece8SMiguel Ojeda let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; 463753dece8SMiguel Ojeda self.set_ptr_and_cap(ptr, cap); 464753dece8SMiguel Ojeda Ok(()) 465753dece8SMiguel Ojeda } 466753dece8SMiguel Ojeda 4673ed03f4dSMiguel Ojeda #[cfg(not(no_global_oom_handling))] 468753dece8SMiguel Ojeda fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { 469753dece8SMiguel Ojeda assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity"); 470753dece8SMiguel Ojeda 471753dece8SMiguel Ojeda let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; 472*89eed1abSMiguel Ojeda // See current_memory() why this assert is here 473*89eed1abSMiguel Ojeda let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) }; 474753dece8SMiguel Ojeda let ptr = unsafe { 475753dece8SMiguel Ojeda // `Layout::array` cannot overflow here because it would have 476753dece8SMiguel Ojeda // overflowed earlier when capacity was larger. 477*89eed1abSMiguel Ojeda let new_size = mem::size_of::<T>().unchecked_mul(cap); 478*89eed1abSMiguel Ojeda let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); 479753dece8SMiguel Ojeda self.alloc 480753dece8SMiguel Ojeda .shrink(ptr, layout, new_layout) 481753dece8SMiguel Ojeda .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? 482753dece8SMiguel Ojeda }; 483753dece8SMiguel Ojeda self.set_ptr_and_cap(ptr, cap); 484753dece8SMiguel Ojeda Ok(()) 485753dece8SMiguel Ojeda } 486753dece8SMiguel Ojeda } 487753dece8SMiguel Ojeda 488753dece8SMiguel Ojeda // This function is outside `RawVec` to minimize compile times. See the comment 489753dece8SMiguel Ojeda // above `RawVec::grow_amortized` for details. (The `A` parameter isn't 490753dece8SMiguel Ojeda // significant, because the number of different `A` types seen in practice is 491753dece8SMiguel Ojeda // much smaller than the number of `T` types.) 492753dece8SMiguel Ojeda #[inline(never)] 493753dece8SMiguel Ojeda fn finish_grow<A>( 494753dece8SMiguel Ojeda new_layout: Result<Layout, LayoutError>, 495753dece8SMiguel Ojeda current_memory: Option<(NonNull<u8>, Layout)>, 496753dece8SMiguel Ojeda alloc: &mut A, 497753dece8SMiguel Ojeda ) -> Result<NonNull<[u8]>, TryReserveError> 498753dece8SMiguel Ojeda where 499753dece8SMiguel Ojeda A: Allocator, 500753dece8SMiguel Ojeda { 501753dece8SMiguel Ojeda // Check for the error here to minimize the size of `RawVec::grow_*`. 502753dece8SMiguel Ojeda let new_layout = new_layout.map_err(|_| CapacityOverflow)?; 503753dece8SMiguel Ojeda 504753dece8SMiguel Ojeda alloc_guard(new_layout.size())?; 505753dece8SMiguel Ojeda 506753dece8SMiguel Ojeda let memory = if let Some((ptr, old_layout)) = current_memory { 507753dece8SMiguel Ojeda debug_assert_eq!(old_layout.align(), new_layout.align()); 508753dece8SMiguel Ojeda unsafe { 509753dece8SMiguel Ojeda // The allocator checks for alignment equality 510753dece8SMiguel Ojeda intrinsics::assume(old_layout.align() == new_layout.align()); 511753dece8SMiguel Ojeda alloc.grow(ptr, old_layout, new_layout) 512753dece8SMiguel Ojeda } 513753dece8SMiguel Ojeda } else { 514753dece8SMiguel Ojeda alloc.allocate(new_layout) 515753dece8SMiguel Ojeda }; 516753dece8SMiguel Ojeda 517753dece8SMiguel Ojeda memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) 518753dece8SMiguel Ojeda } 519753dece8SMiguel Ojeda 520753dece8SMiguel Ojeda unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> { 521753dece8SMiguel Ojeda /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. 522753dece8SMiguel Ojeda fn drop(&mut self) { 523753dece8SMiguel Ojeda if let Some((ptr, layout)) = self.current_memory() { 524753dece8SMiguel Ojeda unsafe { self.alloc.deallocate(ptr, layout) } 525753dece8SMiguel Ojeda } 526753dece8SMiguel Ojeda } 527753dece8SMiguel Ojeda } 528753dece8SMiguel Ojeda 529753dece8SMiguel Ojeda // Central function for reserve error handling. 530753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 531753dece8SMiguel Ojeda #[inline] 532753dece8SMiguel Ojeda fn handle_reserve(result: Result<(), TryReserveError>) { 533753dece8SMiguel Ojeda match result.map_err(|e| e.kind()) { 534753dece8SMiguel Ojeda Err(CapacityOverflow) => capacity_overflow(), 535753dece8SMiguel Ojeda Err(AllocError { layout, .. }) => handle_alloc_error(layout), 536753dece8SMiguel Ojeda Ok(()) => { /* yay */ } 537753dece8SMiguel Ojeda } 538753dece8SMiguel Ojeda } 539753dece8SMiguel Ojeda 540753dece8SMiguel Ojeda // We need to guarantee the following: 541753dece8SMiguel Ojeda // * We don't ever allocate `> isize::MAX` byte-size objects. 542753dece8SMiguel Ojeda // * We don't overflow `usize::MAX` and actually allocate too little. 543753dece8SMiguel Ojeda // 544753dece8SMiguel Ojeda // On 64-bit we just need to check for overflow since trying to allocate 545753dece8SMiguel Ojeda // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add 546753dece8SMiguel Ojeda // an extra guard for this in case we're running on a platform which can use 547753dece8SMiguel Ojeda // all 4GB in user-space, e.g., PAE or x32. 548753dece8SMiguel Ojeda 549753dece8SMiguel Ojeda #[inline] 550753dece8SMiguel Ojeda fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { 551753dece8SMiguel Ojeda if usize::BITS < 64 && alloc_size > isize::MAX as usize { 552753dece8SMiguel Ojeda Err(CapacityOverflow.into()) 553753dece8SMiguel Ojeda } else { 554753dece8SMiguel Ojeda Ok(()) 555753dece8SMiguel Ojeda } 556753dece8SMiguel Ojeda } 557753dece8SMiguel Ojeda 558753dece8SMiguel Ojeda // One central function responsible for reporting capacity overflows. This'll 559753dece8SMiguel Ojeda // ensure that the code generation related to these panics is minimal as there's 560753dece8SMiguel Ojeda // only one location which panics rather than a bunch throughout the module. 561753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 562753dece8SMiguel Ojeda fn capacity_overflow() -> ! { 563753dece8SMiguel Ojeda panic!("capacity overflow"); 564753dece8SMiguel Ojeda } 565