Skip to content

Commit 2bcaa97

Browse files
committed
Add align_offset convenience method to NonNull
1 parent 4cc46df commit 2bcaa97

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

Diff for: library/core/src/ptr/non_null.rs

+60
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,66 @@ impl<T: ?Sized> NonNull<T> {
12221222
// SAFETY: the caller must uphold the safety contract for `swap`.
12231223
unsafe { ptr::swap(self.as_ptr(), with.as_ptr()) }
12241224
}
1225+
1226+
/// Computes the offset that needs to be applied to the pointer in order to make it aligned to
1227+
/// `align`.
1228+
///
1229+
/// If it is not possible to align the pointer, the implementation returns
1230+
/// `usize::MAX`. It is permissible for the implementation to *always*
1231+
/// return `usize::MAX`. Only your algorithm's performance can depend
1232+
/// on getting a usable offset here, not its correctness.
1233+
///
1234+
/// The offset is expressed in number of `T` elements, and not bytes.
1235+
///
1236+
/// There are no guarantees whatsoever that offsetting the pointer will not overflow or go
1237+
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
1238+
/// the returned offset is correct in all terms other than alignment.
1239+
///
1240+
/// # Panics
1241+
///
1242+
/// The function panics if `align` is not a power-of-two.
1243+
///
1244+
/// # Examples
1245+
///
1246+
/// Accessing adjacent `u8` as `u16`
1247+
///
1248+
/// ```
1249+
/// #![feature(non_null_convenience)]
1250+
/// use std::mem::align_of;
1251+
/// use std::ptr::NonNull;
1252+
///
1253+
/// # unsafe {
1254+
/// let x = [5_u8, 6, 7, 8, 9];
1255+
/// let ptr = NonNull::new(x.as_ptr() as *mut u8).unwrap();
1256+
/// let offset = ptr.align_offset(align_of::<u16>());
1257+
///
1258+
/// if offset < x.len() - 1 {
1259+
/// let u16_ptr = ptr.add(offset).cast::<u16>();
1260+
/// assert!(u16_ptr.read() == u16::from_ne_bytes([5, 6]) || u16_ptr.read() == u16::from_ne_bytes([6, 7]));
1261+
/// } else {
1262+
/// // while the pointer can be aligned via `offset`, it would point
1263+
/// // outside the allocation
1264+
/// }
1265+
/// # }
1266+
/// ```
1267+
#[unstable(feature = "non_null_convenience", issue = "117691")]
1268+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
1269+
//#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
1270+
#[must_use]
1271+
#[inline]
1272+
pub const fn align_offset(self, align: usize) -> usize
1273+
where
1274+
T: Sized,
1275+
{
1276+
if !align.is_power_of_two() {
1277+
panic!("align_offset: align is not a power-of-two");
1278+
}
1279+
1280+
{
1281+
// SAFETY: `align` has been checked to be a power of 2 above.
1282+
unsafe { ptr::align_offset(self.pointer, align) }
1283+
}
1284+
}
12251285
}
12261286

12271287
impl<T> NonNull<[T]> {

0 commit comments

Comments
 (0)