1*057b8d25SMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT 2*057b8d25SMiguel 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; 8753dece8SMiguel Ojeda use core::mem::{self, ManuallyDrop, MaybeUninit}; 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 #[cfg(not(no_global_oom_handling))] 24753dece8SMiguel Ojeda enum AllocInit { 25753dece8SMiguel Ojeda /// The contents of the new memory are uninitialized. 26753dece8SMiguel Ojeda Uninitialized, 27753dece8SMiguel Ojeda /// The new memory is guaranteed to be zeroed. 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 136753dece8SMiguel Ojeda /// Like `with_capacity_zeroed`, but parameterized over the choice 137753dece8SMiguel Ojeda /// of allocator for the returned `RawVec`. 138753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 139753dece8SMiguel Ojeda #[inline] 140753dece8SMiguel Ojeda pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { 141753dece8SMiguel Ojeda Self::allocate_in(capacity, AllocInit::Zeroed, alloc) 142753dece8SMiguel Ojeda } 143753dece8SMiguel Ojeda 144753dece8SMiguel Ojeda /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`. 145753dece8SMiguel Ojeda /// 146753dece8SMiguel Ojeda /// Note that this will correctly reconstitute any `cap` changes 147753dece8SMiguel Ojeda /// that may have been performed. (See description of type for details.) 148753dece8SMiguel Ojeda /// 149753dece8SMiguel Ojeda /// # Safety 150753dece8SMiguel Ojeda /// 151753dece8SMiguel Ojeda /// * `len` must be greater than or equal to the most recently requested capacity, and 152753dece8SMiguel Ojeda /// * `len` must be less than or equal to `self.capacity()`. 153753dece8SMiguel Ojeda /// 154753dece8SMiguel Ojeda /// Note, that the requested capacity and `self.capacity()` could differ, as 155753dece8SMiguel Ojeda /// an allocator could overallocate and return a greater memory block than requested. 156753dece8SMiguel Ojeda pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> { 157753dece8SMiguel Ojeda // Sanity-check one half of the safety requirement (we cannot check the other half). 158753dece8SMiguel Ojeda debug_assert!( 159753dece8SMiguel Ojeda len <= self.capacity(), 160753dece8SMiguel Ojeda "`len` must be smaller than or equal to `self.capacity()`" 161753dece8SMiguel Ojeda ); 162753dece8SMiguel Ojeda 163753dece8SMiguel Ojeda let me = ManuallyDrop::new(self); 164753dece8SMiguel Ojeda unsafe { 165753dece8SMiguel Ojeda let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len); 166753dece8SMiguel Ojeda Box::from_raw_in(slice, ptr::read(&me.alloc)) 167753dece8SMiguel Ojeda } 168753dece8SMiguel Ojeda } 169753dece8SMiguel Ojeda 170753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 171753dece8SMiguel Ojeda fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { 172753dece8SMiguel Ojeda // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. 173753dece8SMiguel Ojeda if mem::size_of::<T>() == 0 || capacity == 0 { 174753dece8SMiguel Ojeda Self::new_in(alloc) 175753dece8SMiguel Ojeda } else { 176753dece8SMiguel Ojeda // We avoid `unwrap_or_else` here because it bloats the amount of 177753dece8SMiguel Ojeda // LLVM IR generated. 178753dece8SMiguel Ojeda let layout = match Layout::array::<T>(capacity) { 179753dece8SMiguel Ojeda Ok(layout) => layout, 180753dece8SMiguel Ojeda Err(_) => capacity_overflow(), 181753dece8SMiguel Ojeda }; 182753dece8SMiguel Ojeda match alloc_guard(layout.size()) { 183753dece8SMiguel Ojeda Ok(_) => {} 184753dece8SMiguel Ojeda Err(_) => capacity_overflow(), 185753dece8SMiguel Ojeda } 186753dece8SMiguel Ojeda let result = match init { 187753dece8SMiguel Ojeda AllocInit::Uninitialized => alloc.allocate(layout), 188753dece8SMiguel Ojeda AllocInit::Zeroed => alloc.allocate_zeroed(layout), 189753dece8SMiguel Ojeda }; 190753dece8SMiguel Ojeda let ptr = match result { 191753dece8SMiguel Ojeda Ok(ptr) => ptr, 192753dece8SMiguel Ojeda Err(_) => handle_alloc_error(layout), 193753dece8SMiguel Ojeda }; 194753dece8SMiguel Ojeda 195753dece8SMiguel Ojeda // Allocators currently return a `NonNull<[u8]>` whose length 196753dece8SMiguel Ojeda // matches the size requested. If that ever changes, the capacity 197753dece8SMiguel Ojeda // here should change to `ptr.len() / mem::size_of::<T>()`. 198753dece8SMiguel Ojeda Self { 199753dece8SMiguel Ojeda ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }, 200753dece8SMiguel Ojeda cap: capacity, 201753dece8SMiguel Ojeda alloc, 202753dece8SMiguel Ojeda } 203753dece8SMiguel Ojeda } 204753dece8SMiguel Ojeda } 205753dece8SMiguel Ojeda 206753dece8SMiguel Ojeda /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. 207753dece8SMiguel Ojeda /// 208753dece8SMiguel Ojeda /// # Safety 209753dece8SMiguel Ojeda /// 210753dece8SMiguel Ojeda /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given 211753dece8SMiguel Ojeda /// `capacity`. 212753dece8SMiguel Ojeda /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit 213753dece8SMiguel Ojeda /// systems). ZST vectors may have a capacity up to `usize::MAX`. 214753dece8SMiguel Ojeda /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is 215753dece8SMiguel Ojeda /// guaranteed. 216753dece8SMiguel Ojeda #[inline] 217753dece8SMiguel Ojeda pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { 218753dece8SMiguel Ojeda Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc } 219753dece8SMiguel Ojeda } 220753dece8SMiguel Ojeda 221753dece8SMiguel Ojeda /// Gets a raw pointer to the start of the allocation. Note that this is 222753dece8SMiguel Ojeda /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must 223753dece8SMiguel Ojeda /// be careful. 224753dece8SMiguel Ojeda #[inline] 225753dece8SMiguel Ojeda pub fn ptr(&self) -> *mut T { 226753dece8SMiguel Ojeda self.ptr.as_ptr() 227753dece8SMiguel Ojeda } 228753dece8SMiguel Ojeda 229753dece8SMiguel Ojeda /// Gets the capacity of the allocation. 230753dece8SMiguel Ojeda /// 231753dece8SMiguel Ojeda /// This will always be `usize::MAX` if `T` is zero-sized. 232753dece8SMiguel Ojeda #[inline(always)] 233753dece8SMiguel Ojeda pub fn capacity(&self) -> usize { 234753dece8SMiguel Ojeda if mem::size_of::<T>() == 0 { usize::MAX } else { self.cap } 235753dece8SMiguel Ojeda } 236753dece8SMiguel Ojeda 237753dece8SMiguel Ojeda /// Returns a shared reference to the allocator backing this `RawVec`. 238753dece8SMiguel Ojeda pub fn allocator(&self) -> &A { 239753dece8SMiguel Ojeda &self.alloc 240753dece8SMiguel Ojeda } 241753dece8SMiguel Ojeda 242753dece8SMiguel Ojeda fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> { 243753dece8SMiguel Ojeda if mem::size_of::<T>() == 0 || self.cap == 0 { 244753dece8SMiguel Ojeda None 245753dece8SMiguel Ojeda } else { 246753dece8SMiguel Ojeda // We have an allocated chunk of memory, so we can bypass runtime 247753dece8SMiguel Ojeda // checks to get our current layout. 248753dece8SMiguel Ojeda unsafe { 249753dece8SMiguel Ojeda let layout = Layout::array::<T>(self.cap).unwrap_unchecked(); 250753dece8SMiguel Ojeda Some((self.ptr.cast().into(), layout)) 251753dece8SMiguel Ojeda } 252753dece8SMiguel Ojeda } 253753dece8SMiguel Ojeda } 254753dece8SMiguel Ojeda 255753dece8SMiguel Ojeda /// Ensures that the buffer contains at least enough space to hold `len + 256753dece8SMiguel Ojeda /// additional` elements. If it doesn't already have enough capacity, will 257753dece8SMiguel Ojeda /// reallocate enough space plus comfortable slack space to get amortized 258753dece8SMiguel Ojeda /// *O*(1) behavior. Will limit this behavior if it would needlessly cause 259753dece8SMiguel Ojeda /// itself to panic. 260753dece8SMiguel Ojeda /// 261753dece8SMiguel Ojeda /// If `len` exceeds `self.capacity()`, this may fail to actually allocate 262753dece8SMiguel Ojeda /// the requested space. This is not really unsafe, but the unsafe 263753dece8SMiguel Ojeda /// code *you* write that relies on the behavior of this function may break. 264753dece8SMiguel Ojeda /// 265753dece8SMiguel Ojeda /// This is ideal for implementing a bulk-push operation like `extend`. 266753dece8SMiguel Ojeda /// 267753dece8SMiguel Ojeda /// # Panics 268753dece8SMiguel Ojeda /// 269753dece8SMiguel Ojeda /// Panics if the new capacity exceeds `isize::MAX` bytes. 270753dece8SMiguel Ojeda /// 271753dece8SMiguel Ojeda /// # Aborts 272753dece8SMiguel Ojeda /// 273753dece8SMiguel Ojeda /// Aborts on OOM. 274753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 275753dece8SMiguel Ojeda #[inline] 276753dece8SMiguel Ojeda pub fn reserve(&mut self, len: usize, additional: usize) { 277753dece8SMiguel Ojeda // Callers expect this function to be very cheap when there is already sufficient capacity. 278753dece8SMiguel Ojeda // Therefore, we move all the resizing and error-handling logic from grow_amortized and 279753dece8SMiguel Ojeda // handle_reserve behind a call, while making sure that this function is likely to be 280753dece8SMiguel Ojeda // inlined as just a comparison and a call if the comparison fails. 281753dece8SMiguel Ojeda #[cold] 282753dece8SMiguel Ojeda fn do_reserve_and_handle<T, A: Allocator>( 283753dece8SMiguel Ojeda slf: &mut RawVec<T, A>, 284753dece8SMiguel Ojeda len: usize, 285753dece8SMiguel Ojeda additional: usize, 286753dece8SMiguel Ojeda ) { 287753dece8SMiguel Ojeda handle_reserve(slf.grow_amortized(len, additional)); 288753dece8SMiguel Ojeda } 289753dece8SMiguel Ojeda 290753dece8SMiguel Ojeda if self.needs_to_grow(len, additional) { 291753dece8SMiguel Ojeda do_reserve_and_handle(self, len, additional); 292753dece8SMiguel Ojeda } 293753dece8SMiguel Ojeda } 294753dece8SMiguel Ojeda 295753dece8SMiguel Ojeda /// A specialized version of `reserve()` used only by the hot and 296753dece8SMiguel Ojeda /// oft-instantiated `Vec::push()`, which does its own capacity check. 297753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 298753dece8SMiguel Ojeda #[inline(never)] 299753dece8SMiguel Ojeda pub fn reserve_for_push(&mut self, len: usize) { 300753dece8SMiguel Ojeda handle_reserve(self.grow_amortized(len, 1)); 301753dece8SMiguel Ojeda } 302753dece8SMiguel Ojeda 303753dece8SMiguel Ojeda /// The same as `reserve`, but returns on errors instead of panicking or aborting. 304753dece8SMiguel Ojeda pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { 305753dece8SMiguel Ojeda if self.needs_to_grow(len, additional) { 306753dece8SMiguel Ojeda self.grow_amortized(len, additional) 307753dece8SMiguel Ojeda } else { 308753dece8SMiguel Ojeda Ok(()) 309753dece8SMiguel Ojeda } 310753dece8SMiguel Ojeda } 311753dece8SMiguel Ojeda 312*057b8d25SMiguel Ojeda /// The same as `reserve_for_push`, but returns on errors instead of panicking or aborting. 313*057b8d25SMiguel Ojeda #[inline(never)] 314*057b8d25SMiguel Ojeda pub fn try_reserve_for_push(&mut self, len: usize) -> Result<(), TryReserveError> { 315*057b8d25SMiguel Ojeda self.grow_amortized(len, 1) 316*057b8d25SMiguel Ojeda } 317*057b8d25SMiguel Ojeda 318753dece8SMiguel Ojeda /// Ensures that the buffer contains at least enough space to hold `len + 319753dece8SMiguel Ojeda /// additional` elements. If it doesn't already, will reallocate the 320753dece8SMiguel Ojeda /// minimum possible amount of memory necessary. Generally this will be 321753dece8SMiguel Ojeda /// exactly the amount of memory necessary, but in principle the allocator 322753dece8SMiguel Ojeda /// is free to give back more than we asked for. 323753dece8SMiguel Ojeda /// 324753dece8SMiguel Ojeda /// If `len` exceeds `self.capacity()`, this may fail to actually allocate 325753dece8SMiguel Ojeda /// the requested space. This is not really unsafe, but the unsafe code 326753dece8SMiguel Ojeda /// *you* write that relies on the behavior of this function may break. 327753dece8SMiguel Ojeda /// 328753dece8SMiguel Ojeda /// # Panics 329753dece8SMiguel Ojeda /// 330753dece8SMiguel Ojeda /// Panics if the new capacity exceeds `isize::MAX` bytes. 331753dece8SMiguel Ojeda /// 332753dece8SMiguel Ojeda /// # Aborts 333753dece8SMiguel Ojeda /// 334753dece8SMiguel Ojeda /// Aborts on OOM. 335753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 336753dece8SMiguel Ojeda pub fn reserve_exact(&mut self, len: usize, additional: usize) { 337753dece8SMiguel Ojeda handle_reserve(self.try_reserve_exact(len, additional)); 338753dece8SMiguel Ojeda } 339753dece8SMiguel Ojeda 340753dece8SMiguel Ojeda /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. 341753dece8SMiguel Ojeda pub fn try_reserve_exact( 342753dece8SMiguel Ojeda &mut self, 343753dece8SMiguel Ojeda len: usize, 344753dece8SMiguel Ojeda additional: usize, 345753dece8SMiguel Ojeda ) -> Result<(), TryReserveError> { 346753dece8SMiguel Ojeda if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) } 347753dece8SMiguel Ojeda } 348753dece8SMiguel Ojeda 349753dece8SMiguel Ojeda /// Shrinks the buffer down to the specified capacity. If the given amount 350753dece8SMiguel Ojeda /// is 0, actually completely deallocates. 351753dece8SMiguel Ojeda /// 352753dece8SMiguel Ojeda /// # Panics 353753dece8SMiguel Ojeda /// 354753dece8SMiguel Ojeda /// Panics if the given amount is *larger* than the current capacity. 355753dece8SMiguel Ojeda /// 356753dece8SMiguel Ojeda /// # Aborts 357753dece8SMiguel Ojeda /// 358753dece8SMiguel Ojeda /// Aborts on OOM. 359753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 360753dece8SMiguel Ojeda pub fn shrink_to_fit(&mut self, cap: usize) { 361753dece8SMiguel Ojeda handle_reserve(self.shrink(cap)); 362753dece8SMiguel Ojeda } 363753dece8SMiguel Ojeda } 364753dece8SMiguel Ojeda 365753dece8SMiguel Ojeda impl<T, A: Allocator> RawVec<T, A> { 366753dece8SMiguel Ojeda /// Returns if the buffer needs to grow to fulfill the needed extra capacity. 367753dece8SMiguel Ojeda /// Mainly used to make inlining reserve-calls possible without inlining `grow`. 368753dece8SMiguel Ojeda fn needs_to_grow(&self, len: usize, additional: usize) -> bool { 369753dece8SMiguel Ojeda additional > self.capacity().wrapping_sub(len) 370753dece8SMiguel Ojeda } 371753dece8SMiguel Ojeda 372753dece8SMiguel Ojeda fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { 373753dece8SMiguel Ojeda // Allocators currently return a `NonNull<[u8]>` whose length matches 374753dece8SMiguel Ojeda // the size requested. If that ever changes, the capacity here should 375753dece8SMiguel Ojeda // change to `ptr.len() / mem::size_of::<T>()`. 376753dece8SMiguel Ojeda self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }; 377753dece8SMiguel Ojeda self.cap = cap; 378753dece8SMiguel Ojeda } 379753dece8SMiguel Ojeda 380753dece8SMiguel Ojeda // This method is usually instantiated many times. So we want it to be as 381753dece8SMiguel Ojeda // small as possible, to improve compile times. But we also want as much of 382753dece8SMiguel Ojeda // its contents to be statically computable as possible, to make the 383753dece8SMiguel Ojeda // generated code run faster. Therefore, this method is carefully written 384753dece8SMiguel Ojeda // so that all of the code that depends on `T` is within it, while as much 385753dece8SMiguel Ojeda // of the code that doesn't depend on `T` as possible is in functions that 386753dece8SMiguel Ojeda // are non-generic over `T`. 387753dece8SMiguel Ojeda fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { 388753dece8SMiguel Ojeda // This is ensured by the calling contexts. 389753dece8SMiguel Ojeda debug_assert!(additional > 0); 390753dece8SMiguel Ojeda 391753dece8SMiguel Ojeda if mem::size_of::<T>() == 0 { 392753dece8SMiguel Ojeda // Since we return a capacity of `usize::MAX` when `elem_size` is 393753dece8SMiguel Ojeda // 0, getting to here necessarily means the `RawVec` is overfull. 394753dece8SMiguel Ojeda return Err(CapacityOverflow.into()); 395753dece8SMiguel Ojeda } 396753dece8SMiguel Ojeda 397753dece8SMiguel Ojeda // Nothing we can really do about these checks, sadly. 398753dece8SMiguel Ojeda let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; 399753dece8SMiguel Ojeda 400753dece8SMiguel Ojeda // This guarantees exponential growth. The doubling cannot overflow 401753dece8SMiguel Ojeda // because `cap <= isize::MAX` and the type of `cap` is `usize`. 402753dece8SMiguel Ojeda let cap = cmp::max(self.cap * 2, required_cap); 403753dece8SMiguel Ojeda let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap); 404753dece8SMiguel Ojeda 405753dece8SMiguel Ojeda let new_layout = Layout::array::<T>(cap); 406753dece8SMiguel Ojeda 407753dece8SMiguel Ojeda // `finish_grow` is non-generic over `T`. 408753dece8SMiguel Ojeda let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; 409753dece8SMiguel Ojeda self.set_ptr_and_cap(ptr, cap); 410753dece8SMiguel Ojeda Ok(()) 411753dece8SMiguel Ojeda } 412753dece8SMiguel Ojeda 413753dece8SMiguel Ojeda // The constraints on this method are much the same as those on 414753dece8SMiguel Ojeda // `grow_amortized`, but this method is usually instantiated less often so 415753dece8SMiguel Ojeda // it's less critical. 416753dece8SMiguel Ojeda fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { 417753dece8SMiguel Ojeda if mem::size_of::<T>() == 0 { 418753dece8SMiguel Ojeda // Since we return a capacity of `usize::MAX` when the type size is 419753dece8SMiguel Ojeda // 0, getting to here necessarily means the `RawVec` is overfull. 420753dece8SMiguel Ojeda return Err(CapacityOverflow.into()); 421753dece8SMiguel Ojeda } 422753dece8SMiguel Ojeda 423753dece8SMiguel Ojeda let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; 424753dece8SMiguel Ojeda let new_layout = Layout::array::<T>(cap); 425753dece8SMiguel Ojeda 426753dece8SMiguel Ojeda // `finish_grow` is non-generic over `T`. 427753dece8SMiguel Ojeda let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; 428753dece8SMiguel Ojeda self.set_ptr_and_cap(ptr, cap); 429753dece8SMiguel Ojeda Ok(()) 430753dece8SMiguel Ojeda } 431753dece8SMiguel Ojeda 432*057b8d25SMiguel Ojeda #[allow(dead_code)] 433753dece8SMiguel Ojeda fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { 434753dece8SMiguel Ojeda assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity"); 435753dece8SMiguel Ojeda 436753dece8SMiguel Ojeda let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; 437753dece8SMiguel Ojeda 438753dece8SMiguel Ojeda let ptr = unsafe { 439753dece8SMiguel Ojeda // `Layout::array` cannot overflow here because it would have 440753dece8SMiguel Ojeda // overflowed earlier when capacity was larger. 441753dece8SMiguel Ojeda let new_layout = Layout::array::<T>(cap).unwrap_unchecked(); 442753dece8SMiguel Ojeda self.alloc 443753dece8SMiguel Ojeda .shrink(ptr, layout, new_layout) 444753dece8SMiguel Ojeda .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? 445753dece8SMiguel Ojeda }; 446753dece8SMiguel Ojeda self.set_ptr_and_cap(ptr, cap); 447753dece8SMiguel Ojeda Ok(()) 448753dece8SMiguel Ojeda } 449753dece8SMiguel Ojeda } 450753dece8SMiguel Ojeda 451753dece8SMiguel Ojeda // This function is outside `RawVec` to minimize compile times. See the comment 452753dece8SMiguel Ojeda // above `RawVec::grow_amortized` for details. (The `A` parameter isn't 453753dece8SMiguel Ojeda // significant, because the number of different `A` types seen in practice is 454753dece8SMiguel Ojeda // much smaller than the number of `T` types.) 455753dece8SMiguel Ojeda #[inline(never)] 456753dece8SMiguel Ojeda fn finish_grow<A>( 457753dece8SMiguel Ojeda new_layout: Result<Layout, LayoutError>, 458753dece8SMiguel Ojeda current_memory: Option<(NonNull<u8>, Layout)>, 459753dece8SMiguel Ojeda alloc: &mut A, 460753dece8SMiguel Ojeda ) -> Result<NonNull<[u8]>, TryReserveError> 461753dece8SMiguel Ojeda where 462753dece8SMiguel Ojeda A: Allocator, 463753dece8SMiguel Ojeda { 464753dece8SMiguel Ojeda // Check for the error here to minimize the size of `RawVec::grow_*`. 465753dece8SMiguel Ojeda let new_layout = new_layout.map_err(|_| CapacityOverflow)?; 466753dece8SMiguel Ojeda 467753dece8SMiguel Ojeda alloc_guard(new_layout.size())?; 468753dece8SMiguel Ojeda 469753dece8SMiguel Ojeda let memory = if let Some((ptr, old_layout)) = current_memory { 470753dece8SMiguel Ojeda debug_assert_eq!(old_layout.align(), new_layout.align()); 471753dece8SMiguel Ojeda unsafe { 472753dece8SMiguel Ojeda // The allocator checks for alignment equality 473753dece8SMiguel Ojeda intrinsics::assume(old_layout.align() == new_layout.align()); 474753dece8SMiguel Ojeda alloc.grow(ptr, old_layout, new_layout) 475753dece8SMiguel Ojeda } 476753dece8SMiguel Ojeda } else { 477753dece8SMiguel Ojeda alloc.allocate(new_layout) 478753dece8SMiguel Ojeda }; 479753dece8SMiguel Ojeda 480753dece8SMiguel Ojeda memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) 481753dece8SMiguel Ojeda } 482753dece8SMiguel Ojeda 483753dece8SMiguel Ojeda unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> { 484753dece8SMiguel Ojeda /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. 485753dece8SMiguel Ojeda fn drop(&mut self) { 486753dece8SMiguel Ojeda if let Some((ptr, layout)) = self.current_memory() { 487753dece8SMiguel Ojeda unsafe { self.alloc.deallocate(ptr, layout) } 488753dece8SMiguel Ojeda } 489753dece8SMiguel Ojeda } 490753dece8SMiguel Ojeda } 491753dece8SMiguel Ojeda 492753dece8SMiguel Ojeda // Central function for reserve error handling. 493753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 494753dece8SMiguel Ojeda #[inline] 495753dece8SMiguel Ojeda fn handle_reserve(result: Result<(), TryReserveError>) { 496753dece8SMiguel Ojeda match result.map_err(|e| e.kind()) { 497753dece8SMiguel Ojeda Err(CapacityOverflow) => capacity_overflow(), 498753dece8SMiguel Ojeda Err(AllocError { layout, .. }) => handle_alloc_error(layout), 499753dece8SMiguel Ojeda Ok(()) => { /* yay */ } 500753dece8SMiguel Ojeda } 501753dece8SMiguel Ojeda } 502753dece8SMiguel Ojeda 503753dece8SMiguel Ojeda // We need to guarantee the following: 504753dece8SMiguel Ojeda // * We don't ever allocate `> isize::MAX` byte-size objects. 505753dece8SMiguel Ojeda // * We don't overflow `usize::MAX` and actually allocate too little. 506753dece8SMiguel Ojeda // 507753dece8SMiguel Ojeda // On 64-bit we just need to check for overflow since trying to allocate 508753dece8SMiguel Ojeda // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add 509753dece8SMiguel Ojeda // an extra guard for this in case we're running on a platform which can use 510753dece8SMiguel Ojeda // all 4GB in user-space, e.g., PAE or x32. 511753dece8SMiguel Ojeda 512753dece8SMiguel Ojeda #[inline] 513753dece8SMiguel Ojeda fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { 514753dece8SMiguel Ojeda if usize::BITS < 64 && alloc_size > isize::MAX as usize { 515753dece8SMiguel Ojeda Err(CapacityOverflow.into()) 516753dece8SMiguel Ojeda } else { 517753dece8SMiguel Ojeda Ok(()) 518753dece8SMiguel Ojeda } 519753dece8SMiguel Ojeda } 520753dece8SMiguel Ojeda 521753dece8SMiguel Ojeda // One central function responsible for reporting capacity overflows. This'll 522753dece8SMiguel Ojeda // ensure that the code generation related to these panics is minimal as there's 523753dece8SMiguel Ojeda // only one location which panics rather than a bunch throughout the module. 524753dece8SMiguel Ojeda #[cfg(not(no_global_oom_handling))] 525753dece8SMiguel Ojeda fn capacity_overflow() -> ! { 526753dece8SMiguel Ojeda panic!("capacity overflow"); 527753dece8SMiguel Ojeda } 528