Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122// SPDX-License-Identifier: GPL-2.0
//! Memory layout.//!//! Custom layout types extending or improving [`Layout`].
use core::{ alloc::Layout, marker::PhantomData, //};
/// Error when constructing an [`ArrayLayout`].pub struct LayoutError;
/// A layout for an array `[T; n]`.////// # Invariants////// - `len * size_of::<T>() <= isize::MAX`.pub struct ArrayLayout<T> { len: usize, _phantom: PhantomData<fn() -> T>,}
impl<T> Clone for ArrayLayout<T> { fn clone(&self) -> Self { *self }}impl<T> Copy for ArrayLayout<T> {}
const ISIZE_MAX: usize = isize::MAX as usize;
impl<T> ArrayLayout<T> { /// Creates a new layout for `[T; 0]`. pub const fn empty() -> Self { // INVARIANT: `0 * size_of::<T>() <= isize::MAX`. Self { len: 0, _phantom: PhantomData, } }
/// Creates a new layout for `[T; len]`. /// /// # Errors /// /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`. /// /// # Examples /// /// ``` /// # use kernel::alloc::layout::{ /// # ArrayLayout, /// # LayoutError, // /// # }; /// let layout = ArrayLayout::<i32>::new(15)?; /// assert_eq!(layout.len(), 15); /// /// // Errors because `len * size_of::<T>()` overflows. /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize); /// assert!(layout.is_err()); /// /// // Errors because `len * size_of::<i32>() > isize::MAX`, /// // even though `len < isize::MAX`. /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize / 2); /// assert!(layout.is_err()); /// /// # Ok::<(), Error>(()) /// ``` pub const fn new(len: usize) -> Result<Self, LayoutError> { match len.checked_mul(core::mem::size_of::<T>()) { Some(size) if size <= ISIZE_MAX => { // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. Ok(Self { len, _phantom: PhantomData, }) } _ => Err(LayoutError), } }
/// Creates a new layout for `[T; len]`. /// /// # Safety /// /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true. pub const unsafe fn new_unchecked(len: usize) -> Self { // INVARIANT: By the safety requirements of this function // `len * size_of::<T>() <= isize::MAX`. Self { len, _phantom: PhantomData, } }
/// Returns the number of array elements represented by this layout. pub const fn len(&self) -> usize { self.len }
/// Returns `true` when no array elements are represented by this layout. pub const fn is_empty(&self) -> bool { self.len == 0 }
/// Returns the size of the [`ArrayLayout`] in bytes. pub const fn size(&self) -> usize { self.len() * core::mem::size_of::<T>() }}
impl<T> From<ArrayLayout<T>> for Layout { fn from(value: ArrayLayout<T>) -> Self { let res = Layout::array::<T>(value.len); // SAFETY: By the type invariant of `ArrayLayout` we have // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. unsafe { res.unwrap_unchecked() } }}