Skip to content

Commit

Permalink
Auto merge of #96946 - WaffleLapkin:ptr_mask, r=scottmcm
Browse files Browse the repository at this point in the history
Add pointer masking convenience functions

This PR adds the following public API:
```rust
impl<T: ?Sized> *const T {
    fn mask(self, mask: usize) -> *const T;
}

impl<T: ?Sized> *mut T {
    fn mask(self, mask: usize) -> *const T;
}

// mod intrinsics
fn mask<T>(ptr: *const T, mask: usize) -> *const T
```
This is equivalent to `ptr.map_addr(|a| a & mask)` but also uses a cool llvm intrinsic.

Proposed in rust-lang/rust#95643 (comment)

cc `@Gankra` `@scottmcm` `@RalfJung`

r? rust-lang/libs-api
  • Loading branch information
bors committed Aug 28, 2022
2 parents ada17f4 + 5e5c59e commit 098f1b4
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 0 deletions.
11 changes: 11 additions & 0 deletions core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,17 @@ extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;

/// Masks out bits of the pointer according to a mask.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// Consider using [`pointer::mask`] instead.
#[cfg(not(bootstrap))]
pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;

/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
/// a size of `count` * `size_of::<T>()` and an alignment of
/// `min_align_of::<T>()`
Expand Down
15 changes: 15 additions & 0 deletions core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,21 @@ impl<T: ?Sized> *const T {
from_raw_parts::<T>(self.cast::<u8>().wrapping_offset(count).cast::<()>(), metadata(self))
}

/// Masks out bits of the pointer according to a mask.
///
/// This is convenience for `ptr.map_addr(|a| a & mask)`.
///
/// For non-`Sized` pointees this operation changes only the data pointer,
/// leaving the metadata untouched.
#[cfg(not(bootstrap))]
#[unstable(feature = "ptr_mask", issue = "98290")]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[inline(always)]
pub fn mask(self, mask: usize) -> *const T {
let this = intrinsics::ptr_mask(self.cast::<()>(), mask);
from_raw_parts::<T>(this, 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::<T>()`.
///
Expand Down
15 changes: 15 additions & 0 deletions core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,21 @@ impl<T: ?Sized> *mut T {
)
}

/// Masks out bits of the pointer according to a mask.
///
/// This is convenience for `ptr.map_addr(|a| a & mask)`.
///
/// For non-`Sized` pointees this operation changes only the data pointer,
/// leaving the metadata untouched.
#[cfg(not(bootstrap))]
#[unstable(feature = "ptr_mask", issue = "98290")]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[inline(always)]
pub fn mask(self, mask: usize) -> *mut T {
let this = intrinsics::ptr_mask(self.cast::<()>(), mask) as *mut ();
from_raw_parts_mut::<T>(this, 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.
Expand Down

0 comments on commit 098f1b4

Please sign in to comment.