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