Auto merge of #95643 - WaffleLapkin:ptr_convenience, r=joshtriplett
Add convenience byte offset/check align functions to pointers This PR adds the following APIs: ```rust impl *const T { // feature gates `pointer_byte_offsets` and `const_pointer_byte_offsets pub const unsafe fn byte_offset(self, count: isize) -> Self; pub const fn wrapping_byte_offset(self, count: isize) -> Self; pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize; pub const unsafe fn byte_add(self, count: usize) -> Self; pub const unsafe fn byte_sub(self, count: usize) -> Self; pub const fn wrapping_byte_add(self, count: usize) -> Self; pub const fn wrapping_byte_sub(self, count: usize) -> Self; // feature gate `pointer_is_aligned` pub fn is_aligned(self) -> bool where T: Sized; pub fn is_aligned_to(self, align: usize) -> bool; } // ... and the same for` *mut T` ``` Note that all functions except `is_aligned` do **not** require `T: Sized` as their pointee-sized-offset counterparts. cc `@oli-obk` (you may want to check that I've correctly placed `const`s) cc `@RalfJung`
This commit is contained in:
commit
d8a3fc4d71
@ -455,6 +455,26 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
|
|||||||
unsafe { intrinsics::offset(self, count) }
|
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::<u8>().offset(count).cast::<()>() };
|
||||||
|
from_raw_parts::<T>(this, metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
///
|
///
|
||||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||||
@ -517,6 +537,24 @@ pub const fn wrapping_offset(self, count: isize) -> *const T
|
|||||||
unsafe { intrinsics::arith_offset(self, count) }
|
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::<T>(self.cast::<u8>().wrapping_offset(count).cast::<()>(), metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the distance between two pointers. The returned value is in
|
/// Calculates the distance between two pointers. The returned value is in
|
||||||
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
|
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
|
||||||
///
|
///
|
||||||
@ -611,6 +649,23 @@ pub const fn wrapping_offset(self, count: isize) -> *const T
|
|||||||
unsafe { intrinsics::ptr_offset_from(self, origin) }
|
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::<u8>().offset_from(origin.cast::<u8>()) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the distance between two pointers, *where it's known that
|
/// Calculates the distance between two pointers, *where it's known that
|
||||||
/// `self` is equal to or greater than `origin`*. The returned value is in
|
/// `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::<T>()`.
|
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||||
@ -813,6 +868,26 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
|
|||||||
unsafe { self.offset(count as isize) }
|
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::<u8>().add(count).cast::<()>() };
|
||||||
|
from_raw_parts::<T>(this, metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer (convenience for
|
/// Calculates the offset from a pointer (convenience for
|
||||||
/// `.offset((count as isize).wrapping_neg())`).
|
/// `.offset((count as isize).wrapping_neg())`).
|
||||||
///
|
///
|
||||||
@ -877,6 +952,27 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
|
|||||||
unsafe { self.offset((count as isize).wrapping_neg()) }
|
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::<u8>().sub(count).cast::<()>() };
|
||||||
|
from_raw_parts::<T>(this, metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
/// (convenience for `.wrapping_offset(count as isize)`)
|
/// (convenience for `.wrapping_offset(count as isize)`)
|
||||||
///
|
///
|
||||||
@ -939,6 +1035,24 @@ pub const fn wrapping_add(self, count: usize) -> Self
|
|||||||
self.wrapping_offset(count as isize)
|
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::<T>(self.cast::<u8>().wrapping_add(count).cast::<()>(), metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
/// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
|
/// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
|
||||||
///
|
///
|
||||||
@ -1001,6 +1115,24 @@ pub const fn wrapping_sub(self, count: usize) -> Self
|
|||||||
self.wrapping_offset((count as isize).wrapping_neg())
|
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::<T>(self.cast::<u8>().wrapping_sub(count).cast::<()>(), metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads the value from `self` without moving it. This leaves the
|
/// Reads the value from `self` without moving it. This leaves the
|
||||||
/// memory in `self` unchanged.
|
/// memory in `self` unchanged.
|
||||||
///
|
///
|
||||||
@ -1154,12 +1286,46 @@ const fn ctfe_impl<T>(_: *const T, _: usize) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY:
|
// 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.
|
// 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.
|
// 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) }
|
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::<T>())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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::<u8>().addr() % align == 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> *const [T] {
|
impl<T> *const [T] {
|
||||||
|
@ -467,6 +467,26 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
|
|||||||
unsafe { intrinsics::offset(self, count) as *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::<u8>().offset(count).cast::<()>() };
|
||||||
|
from_raw_parts_mut::<T>(this, metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||||
/// offset of `3 * size_of::<T>()` bytes.
|
/// offset of `3 * size_of::<T>()` bytes.
|
||||||
@ -528,6 +548,27 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
|
|||||||
unsafe { intrinsics::arith_offset(self, count) as *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::<T>(
|
||||||
|
self.cast::<u8>().wrapping_offset(count).cast::<()>(),
|
||||||
|
metadata(self),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `None` if the pointer is null, or else returns a unique reference to
|
/// 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`]
|
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`]
|
||||||
/// must be used instead.
|
/// must be used instead.
|
||||||
@ -787,6 +828,23 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
|
|||||||
unsafe { (self as *const T).offset_from(origin) }
|
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::<u8>().offset_from(origin.cast::<u8>()) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the distance between two pointers, *where it's known that
|
/// Calculates the distance between two pointers, *where it's known that
|
||||||
/// `self` is equal to or greater than `origin`*. The returned value is in
|
/// `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::<T>()`.
|
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||||
@ -922,6 +980,26 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
|
|||||||
unsafe { self.offset(count as isize) }
|
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::<u8>().add(count).cast::<()>() };
|
||||||
|
from_raw_parts_mut::<T>(this, metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer (convenience for
|
/// Calculates the offset from a pointer (convenience for
|
||||||
/// `.offset((count as isize).wrapping_neg())`).
|
/// `.offset((count as isize).wrapping_neg())`).
|
||||||
///
|
///
|
||||||
@ -986,6 +1064,27 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
|
|||||||
unsafe { self.offset((count as isize).wrapping_neg()) }
|
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::<u8>().sub(count).cast::<()>() };
|
||||||
|
from_raw_parts_mut::<T>(this, metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
/// (convenience for `.wrapping_offset(count as isize)`)
|
/// (convenience for `.wrapping_offset(count as isize)`)
|
||||||
///
|
///
|
||||||
@ -1048,6 +1147,24 @@ pub const fn wrapping_add(self, count: usize) -> Self
|
|||||||
self.wrapping_offset(count as isize)
|
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::<T>(self.cast::<u8>().wrapping_add(count).cast::<()>(), metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
/// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
|
/// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
|
||||||
///
|
///
|
||||||
@ -1110,6 +1227,24 @@ pub const fn wrapping_sub(self, count: usize) -> Self
|
|||||||
self.wrapping_offset((count as isize).wrapping_neg())
|
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::<T>(self.cast::<u8>().wrapping_sub(count).cast::<()>(), metadata(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads the value from `self` without moving it. This leaves the
|
/// Reads the value from `self` without moving it. This leaves the
|
||||||
/// memory in `self` unchanged.
|
/// memory in `self` unchanged.
|
||||||
///
|
///
|
||||||
@ -1420,12 +1555,46 @@ const fn ctfe_impl<T>(_: *mut T, _: usize) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY:
|
// 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.
|
// 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.
|
// 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) }
|
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::<T>())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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::<u8>().addr() % align == 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> *mut [T] {
|
impl<T> *mut [T] {
|
||||||
|
Loading…
Reference in New Issue
Block a user