diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 028adc796e526..f26fdc74ce161 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -455,6 +455,26 @@ impl *const T { unsafe { intrinsics::offset(self, count) } } + /// Calculates the offset from a pointer in bytes. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset][pointer::offset] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_offset(self, count: isize) -> Self { + // SAFETY: the caller must uphold the safety contract for `offset`. + let this = unsafe { self.cast::().offset(count).cast::<()>() }; + from_raw_parts::(this, metadata(self)) + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -517,6 +537,24 @@ impl *const T { unsafe { intrinsics::arith_offset(self, count) } } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_offset][pointer::wrapping_offset] on it. See that method + /// for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const fn wrapping_byte_offset(self, count: isize) -> Self { + from_raw_parts::(self.cast::().wrapping_offset(count).cast::<()>(), metadata(self)) + } + /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes divided by `mem::size_of::()`. /// @@ -611,6 +649,23 @@ impl *const T { unsafe { intrinsics::ptr_offset_from(self, origin) } } + /// Calculates the distance between two pointers. The returned value is in + /// units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset_from][pointer::offset_from] on it. See that method for + /// documentation and safety requirements. + /// + /// For non-`Sized` pointees this operation considers only the data pointers, + /// ignoring the metadata. + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { + // SAFETY: the caller must uphold the safety contract for `offset_from`. + unsafe { self.cast::().offset_from(origin.cast::()) } + } + /// Calculates the distance between two pointers, *where it's known that /// `self` is equal to or greater than `origin`*. The returned value is in /// units of T: the distance in bytes is divided by `mem::size_of::()`. @@ -813,6 +868,26 @@ impl *const T { unsafe { self.offset(count as isize) } } + /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [add][pointer::add] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_add(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `add`. + let this = unsafe { self.cast::().add(count).cast::<()>() }; + from_raw_parts::(this, metadata(self)) + } + /// Calculates the offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// @@ -877,6 +952,27 @@ impl *const T { unsafe { self.offset((count as isize).wrapping_neg()) } } + /// Calculates the offset from a pointer in bytes (convenience for + /// `.byte_offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [sub][pointer::sub] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_sub(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `sub`. + let this = unsafe { self.cast::().sub(count).cast::<()>() }; + from_raw_parts::(this, metadata(self)) + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset(count as isize)`) /// @@ -939,6 +1035,24 @@ impl *const T { self.wrapping_offset(count as isize) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_add][pointer::wrapping_add] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const fn wrapping_byte_add(self, count: usize) -> Self { + from_raw_parts::(self.cast::().wrapping_add(count).cast::<()>(), metadata(self)) + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) /// @@ -1001,6 +1115,24 @@ impl *const T { self.wrapping_offset((count as isize).wrapping_neg()) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_sub][pointer::wrapping_sub] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const fn wrapping_byte_sub(self, count: usize) -> Self { + from_raw_parts::(self.cast::().wrapping_sub(count).cast::<()>(), metadata(self)) + } + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// @@ -1154,12 +1286,46 @@ impl *const T { } // SAFETY: - // It is permisseble for `align_offset` to always return `usize::MAX`, + // It is permissible for `align_offset` to always return `usize::MAX`, // algorithm correctness can not depend on `align_offset` returning non-max values. // // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can. unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) } } + + /// Returns whether the pointer is properly aligned for `T`. + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] + pub fn is_aligned(self) -> bool + where + T: Sized, + { + self.is_aligned_to(core::mem::align_of::()) + } + + /// Returns whether the pointer is aligned to `align`. + /// + /// For non-`Sized` pointees this operation considers only the data pointer, + /// ignoring the metadata. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two (this includes 0). + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] + pub fn is_aligned_to(self, align: usize) -> bool { + if !align.is_power_of_two() { + panic!("is_aligned_to: align is not a power-of-two"); + } + + // SAFETY: `is_power_of_two()` will return `false` for zero. + unsafe { core::intrinsics::assume(align != 0) }; + + // Cast is needed for `T: !Sized` + self.cast::().addr() % align == 0 + } } impl *const [T] { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 1a32dd62dfd55..37cf2ef4bfbb5 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -467,6 +467,26 @@ impl *mut T { unsafe { intrinsics::offset(self, count) as *mut T } } + /// Calculates the offset from a pointer in bytes. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset][pointer::offset] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_offset(self, count: isize) -> Self { + // SAFETY: the caller must uphold the safety contract for `offset`. + let this = unsafe { self.cast::().offset(count).cast::<()>() }; + from_raw_parts_mut::(this, metadata(self)) + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -528,6 +548,27 @@ impl *mut T { unsafe { intrinsics::arith_offset(self, count) as *mut T } } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_offset][pointer::wrapping_offset] on it. See that method + /// for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const fn wrapping_byte_offset(self, count: isize) -> Self { + from_raw_parts_mut::( + self.cast::().wrapping_offset(count).cast::<()>(), + metadata(self), + ) + } + /// Returns `None` if the pointer is null, or else returns a unique reference to /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`] /// must be used instead. @@ -787,6 +828,23 @@ impl *mut T { unsafe { (self as *const T).offset_from(origin) } } + /// Calculates the distance between two pointers. The returned value is in + /// units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset_from][pointer::offset_from] on it. See that method for + /// documentation and safety requirements. + /// + /// For non-`Sized` pointees this operation considers only the data pointers, + /// ignoring the metadata. + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { + // SAFETY: the caller must uphold the safety contract for `offset_from`. + unsafe { self.cast::().offset_from(origin.cast::()) } + } + /// Calculates the distance between two pointers, *where it's known that /// `self` is equal to or greater than `origin`*. The returned value is in /// units of T: the distance in bytes is divided by `mem::size_of::()`. @@ -922,6 +980,26 @@ impl *mut T { unsafe { self.offset(count as isize) } } + /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [add][pointer::add] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_add(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `add`. + let this = unsafe { self.cast::().add(count).cast::<()>() }; + from_raw_parts_mut::(this, metadata(self)) + } + /// Calculates the offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// @@ -986,6 +1064,27 @@ impl *mut T { unsafe { self.offset((count as isize).wrapping_neg()) } } + /// Calculates the offset from a pointer in bytes (convenience for + /// `.byte_offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [sub][pointer::sub] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const unsafe fn byte_sub(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `sub`. + let this = unsafe { self.cast::().sub(count).cast::<()>() }; + from_raw_parts_mut::(this, metadata(self)) + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset(count as isize)`) /// @@ -1048,6 +1147,24 @@ impl *mut T { self.wrapping_offset(count as isize) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_add][pointer::wrapping_add] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const fn wrapping_byte_add(self, count: usize) -> Self { + from_raw_parts_mut::(self.cast::().wrapping_add(count).cast::<()>(), metadata(self)) + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) /// @@ -1110,6 +1227,24 @@ impl *mut T { self.wrapping_offset((count as isize).wrapping_neg()) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_sub][pointer::wrapping_sub] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + pub const fn wrapping_byte_sub(self, count: usize) -> Self { + from_raw_parts_mut::(self.cast::().wrapping_sub(count).cast::<()>(), metadata(self)) + } + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// @@ -1420,12 +1555,46 @@ impl *mut T { } // SAFETY: - // It is permisseble for `align_offset` to always return `usize::MAX`, + // It is permissible for `align_offset` to always return `usize::MAX`, // algorithm correctness can not depend on `align_offset` returning non-max values. // // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can. unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) } } + + /// Returns whether the pointer is properly aligned for `T`. + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] + pub fn is_aligned(self) -> bool + where + T: Sized, + { + self.is_aligned_to(core::mem::align_of::()) + } + + /// Returns whether the pointer is aligned to `align`. + /// + /// For non-`Sized` pointees this operation considers only the data pointer, + /// ignoring the metadata. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two (this includes 0). + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] + pub fn is_aligned_to(self, align: usize) -> bool { + if !align.is_power_of_two() { + panic!("is_aligned_to: align is not a power-of-two"); + } + + // SAFETY: `is_power_of_two()` will return `false` for zero. + unsafe { core::intrinsics::assume(align != 0) }; + + // Cast is needed for `T: !Sized` + self.cast::().addr() % align == 0 + } } impl *mut [T] {