|
1 | 1 | #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
|
2 | 2 |
|
3 | 3 | use core::alloc::LayoutError;
|
4 |
| -use core::cmp; |
5 | 4 | use core::intrinsics;
|
6 | 5 | use core::mem::{self, ManuallyDrop, MaybeUninit};
|
7 | 6 | use core::ops::Drop;
|
@@ -386,13 +385,32 @@ impl<T, A: Allocator> RawVec<T, A> {
|
386 | 385 | return Err(CapacityOverflow.into());
|
387 | 386 | }
|
388 | 387 |
|
| 388 | + // Size of allocator's per-allocation overhead we expect |
| 389 | + // FIXME: maybe two pointers to be on the safe side? It could potentially |
| 390 | + // be platform-dependent. |
| 391 | + let alloc_overhead_size = mem::size_of::<usize>(); |
| 392 | + |
389 | 393 | // Nothing we can really do about these checks, sadly.
|
390 | 394 | let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
|
391 | 395 |
|
392 |
| - // This guarantees exponential growth. The doubling cannot overflow |
393 |
| - // because `cap <= isize::MAX` and the type of `cap` is `usize`. |
394 |
| - let cap = cmp::max(self.cap * 2, required_cap); |
395 |
| - let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap); |
| 396 | + let alloc_size = required_cap.checked_mul(mem::size_of::<T>()).ok_or(CapacityOverflow)?; |
| 397 | + // Add the overhead |
| 398 | + let alloc_size = alloc_size.checked_add(alloc_overhead_size).ok_or(CapacityOverflow)?; |
| 399 | + |
| 400 | + // Since memory allocators tend to use power of two sized bins, find the |
| 401 | + // bin size we will fall into. |
| 402 | + debug_assert!(alloc_size > 1); |
| 403 | + let bin_size = usize::MAX >> (alloc_size - 1).leading_zeros(); // + 1 skipped to prevent overflow |
| 404 | + |
| 405 | + // Leave some room for allocators that add fixed overhead (usually |
| 406 | + // one pointer-size) |
| 407 | + let aligned_alloc_size = bin_size.saturating_sub(alloc_overhead_size - 1) /* the +1 skipped from the previous line turned into -1 here */ ; |
| 408 | + |
| 409 | + // Align the capacity to fit the bin |
| 410 | + let cap = aligned_alloc_size / mem::size_of::<T>(); |
| 411 | + // Since we've added the overhead in `required_cap`, we shold never |
| 412 | + // end up with smaller cap after aligning |
| 413 | + debug_assert!(required_cap <= cap); |
396 | 414 |
|
397 | 415 | let new_layout = Layout::array::<T>(cap);
|
398 | 416 |
|
|
0 commit comments