Skip to content

Commit f3bda74

Browse files
committed
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.)
1 parent 026edbb commit f3bda74

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

library/core/src/alloc/layout.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,17 @@ impl Layout {
405405
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
406406
#[inline]
407407
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
408-
let (layout, offset) = Layout::new::<T>().repeat(n)?;
409-
debug_assert_eq!(offset, mem::size_of::<T>());
410-
Ok(layout.pad_to_align())
408+
let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
409+
410+
// SAFETY:
411+
// - Size: `array_size` cannot be too big because `size_of::<T>()` must
412+
// be a multiple of `align_of::<T>()`. Therefore, `array_size`
413+
// rounded up to the nearest multiple of `align_of::<T>()` is just
414+
// `array_size`. And `array_size` cannot be too big because it was
415+
// just checked by the `checked_mul()`.
416+
// - Alignment: `align_of::<T>()` will always give an acceptable
417+
// (non-zero, power of two) alignment.
418+
Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
411419
}
412420
}
413421

0 commit comments

Comments
 (0)