1 | use core::alloc::LayoutError;
|
2 | use core::mem::{self, ManuallyDrop, MaybeUninit};
|
3 | use core::ops::Drop;
|
4 | use core::ptr::{self, NonNull};
|
5 | use core::slice;
|
6 | use core::{cmp, fmt};
|
7 |
|
8 | use super::{
|
9 | alloc::{Allocator, Global, Layout},
|
10 | assume,
|
11 | boxed::Box,
|
12 | };
|
13 |
|
14 | #[cfg (not(no_global_oom_handling))]
|
15 | use super::alloc::handle_alloc_error;
|
16 |
|
17 | /// The error type for `try_reserve` methods.
|
18 | #[derive (Clone, PartialEq, Eq, Debug)]
|
19 | pub struct TryReserveError {
|
20 | kind: TryReserveErrorKind,
|
21 | }
|
22 |
|
23 | impl TryReserveError {
|
24 | /// Details about the allocation that caused the error
|
25 | pub fn kind(&self) -> TryReserveErrorKind {
|
26 | self.kind.clone()
|
27 | }
|
28 | }
|
29 |
|
30 | /// Details of the allocation that caused a `TryReserveError`
|
31 | #[derive (Clone, PartialEq, Eq, Debug)]
|
32 | pub enum TryReserveErrorKind {
|
33 | /// Error due to the computed capacity exceeding the collection's maximum
|
34 | /// (usually `isize::MAX` bytes).
|
35 | CapacityOverflow,
|
36 |
|
37 | /// The memory allocator returned an error
|
38 | AllocError {
|
39 | /// The layout of allocation request that failed
|
40 | layout: Layout,
|
41 |
|
42 | #[doc (hidden)]
|
43 | non_exhaustive: (),
|
44 | },
|
45 | }
|
46 |
|
47 | use TryReserveErrorKind::*;
|
48 |
|
49 | impl From<TryReserveErrorKind> for TryReserveError {
|
50 | #[inline (always)]
|
51 | fn from(kind: TryReserveErrorKind) -> Self {
|
52 | Self { kind }
|
53 | }
|
54 | }
|
55 |
|
56 | impl From<LayoutError> for TryReserveErrorKind {
|
57 | /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
|
58 | #[inline (always)]
|
59 | fn from(_: LayoutError) -> Self {
|
60 | TryReserveErrorKind::CapacityOverflow
|
61 | }
|
62 | }
|
63 |
|
64 | impl fmt::Display for TryReserveError {
|
65 | fn fmt(
|
66 | &self,
|
67 | fmt: &mut core::fmt::Formatter<'_>,
|
68 | ) -> core::result::Result<(), core::fmt::Error> {
|
69 | fmt.write_str(data:"memory allocation failed" )?;
|
70 | let reason: &'static str = match self.kind {
|
71 | TryReserveErrorKind::CapacityOverflow => {
|
72 | " because the computed capacity exceeded the collection's maximum"
|
73 | }
|
74 | TryReserveErrorKind::AllocError { .. } => {
|
75 | " because the memory allocator returned an error"
|
76 | }
|
77 | };
|
78 | fmt.write_str(data:reason)
|
79 | }
|
80 | }
|
81 |
|
82 | #[cfg (feature = "std" )]
|
83 | impl std::error::Error for TryReserveError {}
|
84 |
|
85 | #[cfg (not(no_global_oom_handling))]
|
86 | enum AllocInit {
|
87 | /// The contents of the new memory are uninitialized.
|
88 | Uninitialized,
|
89 | /// The new memory is guaranteed to be zeroed.
|
90 | Zeroed,
|
91 | }
|
92 |
|
93 | /// A low-level utility for more ergonomically allocating, reallocating, and deallocating
|
94 | /// a buffer of memory on the heap without having to worry about all the corner cases
|
95 | /// involved. This type is excellent for building your own data structures like Vec and VecDeque.
|
96 | /// In particular:
|
97 | ///
|
98 | /// * Produces `NonNull::dangling()` on zero-sized types.
|
99 | /// * Produces `NonNull::dangling()` on zero-length allocations.
|
100 | /// * Avoids freeing `NonNull::dangling()`.
|
101 | /// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics).
|
102 | /// * Guards against 32-bit systems allocating more than isize::MAX bytes.
|
103 | /// * Guards against overflowing your length.
|
104 | /// * Calls `handle_alloc_error` for fallible allocations.
|
105 | /// * Contains a `ptr::NonNull` and thus endows the user with all related benefits.
|
106 | /// * Uses the excess returned from the allocator to use the largest available capacity.
|
107 | ///
|
108 | /// This type does not in anyway inspect the memory that it manages. When dropped it *will*
|
109 | /// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec`
|
110 | /// to handle the actual things *stored* inside of a `RawVec`.
|
111 | ///
|
112 | /// Note that the excess of a zero-sized types is always infinite, so `capacity()` always returns
|
113 | /// `usize::MAX`. This means that you need to be careful when round-tripping this type with a
|
114 | /// `Box<[T]>`, since `capacity()` won't yield the length.
|
115 | #[allow (missing_debug_implementations)]
|
116 | pub(crate) struct RawVec<T, A: Allocator = Global> {
|
117 | ptr: NonNull<T>,
|
118 | cap: usize,
|
119 | alloc: A,
|
120 | }
|
121 |
|
122 | // Safety: RawVec owns both T and A, so sending is safe if
|
123 | // sending is safe for T and A.
|
124 | unsafe impl<T, A: Allocator> Send for RawVec<T, A>
|
125 | where
|
126 | T: Send,
|
127 | A: Send,
|
128 | {
|
129 | }
|
130 |
|
131 | // Safety: RawVec owns both T and A, so sharing is safe if
|
132 | // sharing is safe for T and A.
|
133 | unsafe impl<T, A: Allocator> Sync for RawVec<T, A>
|
134 | where
|
135 | T: Sync,
|
136 | A: Sync,
|
137 | {
|
138 | }
|
139 |
|
140 | impl<T> RawVec<T, Global> {
|
141 | /// Creates the biggest possible `RawVec` (on the system heap)
|
142 | /// without allocating. If `T` has positive size, then this makes a
|
143 | /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a
|
144 | /// `RawVec` with capacity `usize::MAX`. Useful for implementing
|
145 | /// delayed allocation.
|
146 | #[must_use ]
|
147 | pub const fn new() -> Self {
|
148 | Self::new_in(Global)
|
149 | }
|
150 |
|
151 | /// Creates a `RawVec` (on the system heap) with exactly the
|
152 | /// capacity and alignment requirements for a `[T; capacity]`. This is
|
153 | /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is
|
154 | /// zero-sized. Note that if `T` is zero-sized this means you will
|
155 | /// *not* get a `RawVec` with the requested capacity.
|
156 | ///
|
157 | /// # Panics
|
158 | ///
|
159 | /// Panics if the requested capacity exceeds `isize::MAX` bytes.
|
160 | ///
|
161 | /// # Aborts
|
162 | ///
|
163 | /// Aborts on OOM.
|
164 | #[cfg (not(no_global_oom_handling))]
|
165 | #[must_use ]
|
166 | #[inline (always)]
|
167 | pub fn with_capacity(capacity: usize) -> Self {
|
168 | Self::with_capacity_in(capacity, Global)
|
169 | }
|
170 |
|
171 | /// Like `with_capacity`, but guarantees the buffer is zeroed.
|
172 | #[cfg (not(no_global_oom_handling))]
|
173 | #[must_use ]
|
174 | #[inline (always)]
|
175 | pub fn with_capacity_zeroed(capacity: usize) -> Self {
|
176 | Self::with_capacity_zeroed_in(capacity, Global)
|
177 | }
|
178 | }
|
179 |
|
180 | impl<T, A: Allocator> RawVec<T, A> {
|
181 | // Tiny Vecs are dumb. Skip to:
|
182 | // - 8 if the element size is 1, because any heap allocators is likely
|
183 | // to round up a request of less than 8 bytes to at least 8 bytes.
|
184 | // - 4 if elements are moderate-sized (<= 1 KiB).
|
185 | // - 1 otherwise, to avoid wasting too much space for very short Vecs.
|
186 | pub(crate) const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
|
187 | 8
|
188 | } else if mem::size_of::<T>() <= 1024 {
|
189 | 4
|
190 | } else {
|
191 | 1
|
192 | };
|
193 |
|
194 | /// Like `new`, but parameterized over the choice of allocator for
|
195 | /// the returned `RawVec`.
|
196 | #[inline (always)]
|
197 | pub const fn new_in(alloc: A) -> Self {
|
198 | // `cap: 0` means "unallocated". zero-sized types are ignored.
|
199 | Self {
|
200 | ptr: NonNull::dangling(),
|
201 | cap: 0,
|
202 | alloc,
|
203 | }
|
204 | }
|
205 |
|
206 | /// Like `with_capacity`, but parameterized over the choice of
|
207 | /// allocator for the returned `RawVec`.
|
208 | #[cfg (not(no_global_oom_handling))]
|
209 | #[inline (always)]
|
210 | pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
|
211 | Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
|
212 | }
|
213 |
|
214 | /// Like `with_capacity_zeroed`, but parameterized over the choice
|
215 | /// of allocator for the returned `RawVec`.
|
216 | #[cfg (not(no_global_oom_handling))]
|
217 | #[inline (always)]
|
218 | pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
|
219 | Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
|
220 | }
|
221 |
|
222 | /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
|
223 | ///
|
224 | /// Note that this will correctly reconstitute any `cap` changes
|
225 | /// that may have been performed. (See description of type for details.)
|
226 | ///
|
227 | /// # Safety
|
228 | ///
|
229 | /// * `len` must be greater than or equal to the most recently requested capacity, and
|
230 | /// * `len` must be less than or equal to `self.capacity()`.
|
231 | ///
|
232 | /// Note, that the requested capacity and `self.capacity()` could differ, as
|
233 | /// an allocator could overallocate and return a greater memory block than requested.
|
234 | #[inline (always)]
|
235 | pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> {
|
236 | // Sanity-check one half of the safety requirement (we cannot check the other half).
|
237 | debug_assert!(
|
238 | len <= self.capacity(),
|
239 | "`len` must be smaller than or equal to `self.capacity()`"
|
240 | );
|
241 |
|
242 | let me = ManuallyDrop::new(self);
|
243 | unsafe {
|
244 | let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
|
245 | Box::<[MaybeUninit<T>], A>::from_raw_in(slice, ptr::read(&me.alloc))
|
246 | }
|
247 | }
|
248 |
|
249 | #[cfg (not(no_global_oom_handling))]
|
250 | #[inline (always)]
|
251 | fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
|
252 | // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
|
253 | if mem::size_of::<T>() == 0 || capacity == 0 {
|
254 | Self::new_in(alloc)
|
255 | } else {
|
256 | // We avoid `unwrap_or_else` here because it bloats the amount of
|
257 | // LLVM IR generated.
|
258 | let layout = match Layout::array::<T>(capacity) {
|
259 | Ok(layout) => layout,
|
260 | Err(_) => capacity_overflow(),
|
261 | };
|
262 | match alloc_guard(layout.size()) {
|
263 | Ok(_) => {}
|
264 | Err(_) => capacity_overflow(),
|
265 | }
|
266 | let result = match init {
|
267 | AllocInit::Uninitialized => alloc.allocate(layout),
|
268 | AllocInit::Zeroed => alloc.allocate_zeroed(layout),
|
269 | };
|
270 | let ptr = match result {
|
271 | Ok(ptr) => ptr,
|
272 | Err(_) => handle_alloc_error(layout),
|
273 | };
|
274 |
|
275 | // Allocators currently return a `NonNull<[u8]>` whose length
|
276 | // matches the size requested. If that ever changes, the capacity
|
277 | // here should change to `ptr.len() / mem::size_of::<T>()`.
|
278 | Self {
|
279 | ptr: unsafe { NonNull::new_unchecked(ptr.cast().as_ptr()) },
|
280 | cap: capacity,
|
281 | alloc,
|
282 | }
|
283 | }
|
284 | }
|
285 |
|
286 | /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
|
287 | ///
|
288 | /// # Safety
|
289 | ///
|
290 | /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
|
291 | /// `capacity`.
|
292 | /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
|
293 | /// systems). ZST vectors may have a capacity up to `usize::MAX`.
|
294 | /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
|
295 | /// guaranteed.
|
296 | #[inline (always)]
|
297 | pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
|
298 | Self {
|
299 | ptr: unsafe { NonNull::new_unchecked(ptr) },
|
300 | cap: capacity,
|
301 | alloc,
|
302 | }
|
303 | }
|
304 |
|
305 | /// Gets a raw pointer to the start of the allocation. Note that this is
|
306 | /// `NonNull::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
|
307 | /// be careful.
|
308 | #[inline (always)]
|
309 | pub fn ptr(&self) -> *mut T {
|
310 | self.ptr.as_ptr()
|
311 | }
|
312 |
|
313 | /// Gets the capacity of the allocation.
|
314 | ///
|
315 | /// This will always be `usize::MAX` if `T` is zero-sized.
|
316 | #[inline (always)]
|
317 | pub fn capacity(&self) -> usize {
|
318 | if mem::size_of::<T>() == 0 {
|
319 | usize::MAX
|
320 | } else {
|
321 | self.cap
|
322 | }
|
323 | }
|
324 |
|
325 | /// Returns a shared reference to the allocator backing this `RawVec`.
|
326 | #[inline (always)]
|
327 | pub fn allocator(&self) -> &A {
|
328 | &self.alloc
|
329 | }
|
330 |
|
331 | #[inline (always)]
|
332 | fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
|
333 | if mem::size_of::<T>() == 0 || self.cap == 0 {
|
334 | None
|
335 | } else {
|
336 | // We have an allocated chunk of memory, so we can bypass runtime
|
337 | // checks to get our current layout.
|
338 | unsafe {
|
339 | let layout = Layout::array::<T>(self.cap).unwrap_unchecked();
|
340 | Some((self.ptr.cast(), layout))
|
341 | }
|
342 | }
|
343 | }
|
344 |
|
345 | /// Ensures that the buffer contains at least enough space to hold `len +
|
346 | /// additional` elements. If it doesn't already have enough capacity, will
|
347 | /// reallocate enough space plus comfortable slack space to get amortized
|
348 | /// *O*(1) behavior. Will limit this behavior if it would needlessly cause
|
349 | /// itself to panic.
|
350 | ///
|
351 | /// If `len` exceeds `self.capacity()`, this may fail to actually allocate
|
352 | /// the requested space. This is not really unsafe, but the unsafe
|
353 | /// code *you* write that relies on the behavior of this function may break.
|
354 | ///
|
355 | /// This is ideal for implementing a bulk-push operation like `extend`.
|
356 | ///
|
357 | /// # Panics
|
358 | ///
|
359 | /// Panics if the new capacity exceeds `isize::MAX` bytes.
|
360 | ///
|
361 | /// # Aborts
|
362 | ///
|
363 | /// Aborts on OOM.
|
364 | #[cfg (not(no_global_oom_handling))]
|
365 | #[inline (always)]
|
366 | pub fn reserve(&mut self, len: usize, additional: usize) {
|
367 | // Callers expect this function to be very cheap when there is already sufficient capacity.
|
368 | // Therefore, we move all the resizing and error-handling logic from grow_amortized and
|
369 | // handle_reserve behind a call, while making sure that this function is likely to be
|
370 | // inlined as just a comparison and a call if the comparison fails.
|
371 | #[cold ]
|
372 | #[inline (always)]
|
373 | fn do_reserve_and_handle<T, A: Allocator>(
|
374 | slf: &mut RawVec<T, A>,
|
375 | len: usize,
|
376 | additional: usize,
|
377 | ) {
|
378 | handle_reserve(slf.grow_amortized(len, additional));
|
379 | }
|
380 |
|
381 | if self.needs_to_grow(len, additional) {
|
382 | do_reserve_and_handle(self, len, additional);
|
383 | }
|
384 | }
|
385 |
|
386 | /// A specialized version of `reserve()` used only by the hot and
|
387 | /// oft-instantiated `Vec::push()`, which does its own capacity check.
|
388 | #[cfg (not(no_global_oom_handling))]
|
389 | #[inline (always)]
|
390 | pub fn reserve_for_push(&mut self, len: usize) {
|
391 | handle_reserve(self.grow_amortized(len, 1));
|
392 | }
|
393 |
|
394 | /// The same as `reserve`, but returns on errors instead of panicking or aborting.
|
395 | #[inline (always)]
|
396 | pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
397 | if self.needs_to_grow(len, additional) {
|
398 | self.grow_amortized(len, additional)
|
399 | } else {
|
400 | Ok(())
|
401 | }
|
402 | }
|
403 |
|
404 | /// Ensures that the buffer contains at least enough space to hold `len +
|
405 | /// additional` elements. If it doesn't already, will reallocate the
|
406 | /// minimum possible amount of memory necessary. Generally this will be
|
407 | /// exactly the amount of memory necessary, but in principle the allocator
|
408 | /// is free to give back more than we asked for.
|
409 | ///
|
410 | /// If `len` exceeds `self.capacity()`, this may fail to actually allocate
|
411 | /// the requested space. This is not really unsafe, but the unsafe code
|
412 | /// *you* write that relies on the behavior of this function may break.
|
413 | ///
|
414 | /// # Panics
|
415 | ///
|
416 | /// Panics if the new capacity exceeds `isize::MAX` bytes.
|
417 | ///
|
418 | /// # Aborts
|
419 | ///
|
420 | /// Aborts on OOM.
|
421 | #[cfg (not(no_global_oom_handling))]
|
422 | #[inline (always)]
|
423 | pub fn reserve_exact(&mut self, len: usize, additional: usize) {
|
424 | handle_reserve(self.try_reserve_exact(len, additional));
|
425 | }
|
426 |
|
427 | /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
|
428 | #[inline (always)]
|
429 | pub fn try_reserve_exact(
|
430 | &mut self,
|
431 | len: usize,
|
432 | additional: usize,
|
433 | ) -> Result<(), TryReserveError> {
|
434 | if self.needs_to_grow(len, additional) {
|
435 | self.grow_exact(len, additional)
|
436 | } else {
|
437 | Ok(())
|
438 | }
|
439 | }
|
440 |
|
441 | /// Shrinks the buffer down to the specified capacity. If the given amount
|
442 | /// is 0, actually completely deallocates.
|
443 | ///
|
444 | /// # Panics
|
445 | ///
|
446 | /// Panics if the given amount is *larger* than the current capacity.
|
447 | ///
|
448 | /// # Aborts
|
449 | ///
|
450 | /// Aborts on OOM.
|
451 | #[cfg (not(no_global_oom_handling))]
|
452 | #[inline (always)]
|
453 | pub fn shrink_to_fit(&mut self, cap: usize) {
|
454 | handle_reserve(self.shrink(cap));
|
455 | }
|
456 | }
|
457 |
|
458 | impl<T, A: Allocator> RawVec<T, A> {
|
459 | /// Returns if the buffer needs to grow to fulfill the needed extra capacity.
|
460 | /// Mainly used to make inlining reserve-calls possible without inlining `grow`.
|
461 | #[inline (always)]
|
462 | fn needs_to_grow(&self, len: usize, additional: usize) -> bool {
|
463 | additional > self.capacity().wrapping_sub(len)
|
464 | }
|
465 |
|
466 | #[inline (always)]
|
467 | fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
|
468 | // Allocators currently return a `NonNull<[u8]>` whose length matches
|
469 | // the size requested. If that ever changes, the capacity here should
|
470 | // change to `ptr.len() / mem::size_of::<T>()`.
|
471 | self.ptr = unsafe { NonNull::new_unchecked(ptr.cast().as_ptr()) };
|
472 | self.cap = cap;
|
473 | }
|
474 |
|
475 | // This method is usually instantiated many times. So we want it to be as
|
476 | // small as possible, to improve compile times. But we also want as much of
|
477 | // its contents to be statically computable as possible, to make the
|
478 | // generated code run faster. Therefore, this method is carefully written
|
479 | // so that all of the code that depends on `T` is within it, while as much
|
480 | // of the code that doesn't depend on `T` as possible is in functions that
|
481 | // are non-generic over `T`.
|
482 | #[inline (always)]
|
483 | fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
484 | // This is ensured by the calling contexts.
|
485 | debug_assert!(additional > 0);
|
486 |
|
487 | if mem::size_of::<T>() == 0 {
|
488 | // Since we return a capacity of `usize::MAX` when `elem_size` is
|
489 | // 0, getting to here necessarily means the `RawVec` is overfull.
|
490 | return Err(CapacityOverflow.into());
|
491 | }
|
492 |
|
493 | // Nothing we can really do about these checks, sadly.
|
494 | let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
|
495 |
|
496 | // This guarantees exponential growth. The doubling cannot overflow
|
497 | // because `cap <= isize::MAX` and the type of `cap` is `usize`.
|
498 | let cap = cmp::max(self.cap * 2, required_cap);
|
499 | let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap);
|
500 |
|
501 | let new_layout = Layout::array::<T>(cap);
|
502 |
|
503 | // `finish_grow` is non-generic over `T`.
|
504 | let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
|
505 | self.set_ptr_and_cap(ptr, cap);
|
506 | Ok(())
|
507 | }
|
508 |
|
509 | // The constraints on this method are much the same as those on
|
510 | // `grow_amortized`, but this method is usually instantiated less often so
|
511 | // it's less critical.
|
512 | #[inline (always)]
|
513 | fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
514 | if mem::size_of::<T>() == 0 {
|
515 | // Since we return a capacity of `usize::MAX` when the type size is
|
516 | // 0, getting to here necessarily means the `RawVec` is overfull.
|
517 | return Err(CapacityOverflow.into());
|
518 | }
|
519 |
|
520 | let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
|
521 | let new_layout = Layout::array::<T>(cap);
|
522 |
|
523 | // `finish_grow` is non-generic over `T`.
|
524 | let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
|
525 | self.set_ptr_and_cap(ptr, cap);
|
526 | Ok(())
|
527 | }
|
528 |
|
529 | #[cfg (not(no_global_oom_handling))]
|
530 | #[inline (always)]
|
531 | fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
|
532 | assert!(
|
533 | cap <= self.capacity(),
|
534 | "Tried to shrink to a larger capacity"
|
535 | );
|
536 |
|
537 | let (ptr, layout) = if let Some(mem) = self.current_memory() {
|
538 | mem
|
539 | } else {
|
540 | return Ok(());
|
541 | };
|
542 |
|
543 | let ptr = unsafe {
|
544 | // `Layout::array` cannot overflow here because it would have
|
545 | // overflowed earlier when capacity was larger.
|
546 | let new_layout = Layout::array::<T>(cap).unwrap_unchecked();
|
547 | self.alloc
|
548 | .shrink(ptr, layout, new_layout)
|
549 | .map_err(|_| AllocError {
|
550 | layout: new_layout,
|
551 | non_exhaustive: (),
|
552 | })?
|
553 | };
|
554 | self.set_ptr_and_cap(ptr, cap);
|
555 | Ok(())
|
556 | }
|
557 | }
|
558 |
|
559 | // This function is outside `RawVec` to minimize compile times. See the comment
|
560 | // above `RawVec::grow_amortized` for details. (The `A` parameter isn't
|
561 | // significant, because the number of different `A` types seen in practice is
|
562 | // much smaller than the number of `T` types.)
|
563 | #[inline (always)]
|
564 | fn finish_grow<A>(
|
565 | new_layout: Result<Layout, LayoutError>,
|
566 | current_memory: Option<(NonNull<u8>, Layout)>,
|
567 | alloc: &mut A,
|
568 | ) -> Result<NonNull<[u8]>, TryReserveError>
|
569 | where
|
570 | A: Allocator,
|
571 | {
|
572 | // Check for the error here to minimize the size of `RawVec::grow_*`.
|
573 | let new_layout = new_layout.map_err(|_| CapacityOverflow)?;
|
574 |
|
575 | alloc_guard(new_layout.size())?;
|
576 |
|
577 | let memory = if let Some((ptr, old_layout)) = current_memory {
|
578 | debug_assert_eq!(old_layout.align(), new_layout.align());
|
579 | unsafe {
|
580 | // The allocator checks for alignment equality
|
581 | assume(old_layout.align() == new_layout.align());
|
582 | alloc.grow(ptr, old_layout, new_layout)
|
583 | }
|
584 | } else {
|
585 | alloc.allocate(new_layout)
|
586 | };
|
587 |
|
588 | memory.map_err(|_| {
|
589 | AllocError {
|
590 | layout: new_layout,
|
591 | non_exhaustive: (),
|
592 | }
|
593 | .into()
|
594 | })
|
595 | }
|
596 |
|
597 | impl<T, A: Allocator> Drop for RawVec<T, A> {
|
598 | /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
|
599 | #[inline (always)]
|
600 | fn drop(&mut self) {
|
601 | if let Some((ptr: NonNull, layout: Layout)) = self.current_memory() {
|
602 | unsafe { self.alloc.deallocate(ptr, layout) }
|
603 | }
|
604 | }
|
605 | }
|
606 |
|
607 | // Central function for reserve error handling.
|
608 | #[cfg (not(no_global_oom_handling))]
|
609 | #[inline (always)]
|
610 | fn handle_reserve(result: Result<(), TryReserveError>) {
|
611 | match result.map_err(|e: TryReserveError| e.kind()) {
|
612 | Err(CapacityOverflow) => capacity_overflow(),
|
613 | Err(AllocError { layout: Layout, .. }) => handle_alloc_error(layout),
|
614 | Ok(()) => { /* yay */ }
|
615 | }
|
616 | }
|
617 |
|
618 | // We need to guarantee the following:
|
619 | // * We don't ever allocate `> isize::MAX` byte-size objects.
|
620 | // * We don't overflow `usize::MAX` and actually allocate too little.
|
621 | //
|
622 | // On 64-bit we just need to check for overflow since trying to allocate
|
623 | // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add
|
624 | // an extra guard for this in case we're running on a platform which can use
|
625 | // all 4GB in user-space, e.g., PAE or x32.
|
626 |
|
627 | #[inline (always)]
|
628 | fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
|
629 | if usize::BITS < 64 && alloc_size > isize::MAX as usize {
|
630 | Err(CapacityOverflow.into())
|
631 | } else {
|
632 | Ok(())
|
633 | }
|
634 | }
|
635 |
|
636 | // One central function responsible for reporting capacity overflows. This'll
|
637 | // ensure that the code generation related to these panics is minimal as there's
|
638 | // only one location which panics rather than a bunch throughout the module.
|
639 | #[cfg (not(no_global_oom_handling))]
|
640 | fn capacity_overflow() -> ! {
|
641 | panic!("capacity overflow" );
|
642 | }
|
643 | |