diff options
| author | Nicholas Nethercote <n.nethercote@gmail.com> | 2021-11-26 13:39:05 +1100 |
|---|---|---|
| committer | Nicholas Nethercote <n.nethercote@gmail.com> | 2021-11-26 19:30:35 +1100 |
| commit | f3bda74d363a060ade5e5caeb654ba59bfed51a4 (patch) | |
| tree | 8a4b9f1307eb89a2d34a967447d341b6d28f0211 | |
| parent | 026edbb4ef85ef3d38876548a771b7c72c87803f (diff) | |
| download | rust-f3bda74d363a060ade5e5caeb654ba59bfed51a4.tar.gz rust-f3bda74d363a060ade5e5caeb654ba59bfed51a4.zip | |
Optimize `Layout::array`.
The current implementation is much more conservative than it needs to
be, because it's dealing with the size and alignment of a given `T`,
which are more restricted than an arbitrary `Layout`.
For example, imagine a struct with a `u32` and a `u4`. You can safely
create a `Layout { size_: 5, align_: 4 }` by hand, but
`Layout::new::<T>` will give `Layout { size_: 8, align_: 4}`, where the
size already has padding that accounts for the alignment. (And the
existing `debug_assert_eq!` in `Layout::array` already demonstrates that
no additional padding is required.)
| -rw-r--r-- | library/core/src/alloc/layout.rs | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index a9abb8d2d59..9df0b5c5519 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -405,9 +405,17 @@ impl Layout { #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn array<T>(n: usize) -> Result<Self, LayoutError> { - let (layout, offset) = Layout::new::<T>().repeat(n)?; - debug_assert_eq!(offset, mem::size_of::<T>()); - Ok(layout.pad_to_align()) + let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?; + + // SAFETY: + // - Size: `array_size` cannot be too big because `size_of::<T>()` must + // be a multiple of `align_of::<T>()`. Therefore, `array_size` + // rounded up to the nearest multiple of `align_of::<T>()` is just + // `array_size`. And `array_size` cannot be too big because it was + // just checked by the `checked_mul()`. + // - Alignment: `align_of::<T>()` will always give an acceptable + // (non-zero, power of two) alignment. + Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) }) } } |
