Skip to content

Commit c8c91f7

Browse files
committed
Add convenience functions to pointers
The functions added: - {*const T,*mut T}::{wrapping_,}byte_{offset,add,sub} - {*const T,*mut T}::{byte_offset_from,is_aligned,is_aligned_to}
1 parent 3a08bd7 commit c8c91f7

File tree

2 files changed

+320
-2
lines changed

2 files changed

+320
-2
lines changed

library/core/src/ptr/const_ptr.rs

+160-1
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,25 @@ impl<T: ?Sized> *const T {
455455
unsafe { intrinsics::offset(self, count) }
456456
}
457457

458+
/// Calculates the offset from a pointer in bytes.
459+
///
460+
/// `count` is in units of **bytes**.
461+
///
462+
/// This is purely a convenience for casting to a `u8` pointer and
463+
/// using [offset][pointer::offset] on it. See that method for documentation
464+
/// and safety requirements.
465+
#[must_use]
466+
#[inline(always)]
467+
#[unstable(feature = "pointer_byte_offsets", issue = "none")]
468+
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")]
469+
pub const unsafe fn byte_offset(self, count: isize) -> Self
470+
where
471+
T: Sized,
472+
{
473+
// SAFETY: the caller must uphold the safety contract for `offset`.
474+
unsafe { self.cast::<u8>().offset(count).cast::<T>() }
475+
}
476+
458477
/// Calculates the offset from a pointer using wrapping arithmetic.
459478
///
460479
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@@ -517,6 +536,24 @@ impl<T: ?Sized> *const T {
517536
unsafe { intrinsics::arith_offset(self, count) }
518537
}
519538

539+
/// Calculates the offset from a pointer in bytes using wrapping arithmetic.
540+
///
541+
/// `count` is in units of **bytes**.
542+
///
543+
/// This is purely a convenience for casting to a `u8` pointer and
544+
/// using [wrapping_offset][pointer::wrapping_offset] on it. See that method
545+
/// for documentation.
546+
#[must_use]
547+
#[inline(always)]
548+
#[unstable(feature = "pointer_byte_offsets", issue = "none")]
549+
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")]
550+
pub const fn wrapping_byte_offset(self, count: isize) -> Self
551+
where
552+
T: Sized,
553+
{
554+
self.cast::<u8>().wrapping_offset(count).cast::<T>()
555+
}
556+
520557
/// Calculates the distance between two pointers. The returned value is in
521558
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
522559
///
@@ -611,6 +648,23 @@ impl<T: ?Sized> *const T {
611648
unsafe { intrinsics::ptr_offset_from(self, origin) }
612649
}
613650

651+
/// Calculates the distance between two pointers. The returned value is in
652+
/// units of **bytes**.
653+
///
654+
/// This is purely a convenience for casting to a `u8` pointer and
655+
/// using [offset_from][pointer::offset_from] on it. See that method for
656+
/// documentation and safety requirements.
657+
#[inline(always)]
658+
#[unstable(feature = "pointer_byte_offsets", issue = "none")]
659+
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")]
660+
pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize
661+
where
662+
T: Sized,
663+
{
664+
// SAFETY: the caller must uphold the safety contract for `offset_from`.
665+
unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) }
666+
}
667+
614668
/// Calculates the distance between two pointers, *where it's known that
615669
/// `self` is equal to or greater than `origin`*. The returned value is in
616670
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
@@ -813,6 +867,25 @@ impl<T: ?Sized> *const T {
813867
unsafe { self.offset(count as isize) }
814868
}
815869

870+
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
871+
///
872+
/// `count` is in units of bytes.
873+
///
874+
/// This is purely a convenience for casting to a `u8` pointer and
875+
/// using [add][pointer::add] on it. See that method for documentation
876+
/// and safety requirements.
877+
#[must_use]
878+
#[inline(always)]
879+
#[unstable(feature = "pointer_byte_offsets", issue = "none")]
880+
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")]
881+
pub const unsafe fn byte_add(self, count: usize) -> Self
882+
where
883+
T: Sized,
884+
{
885+
// SAFETY: the caller must uphold the safety contract for `add`.
886+
unsafe { self.cast::<u8>().add(count).cast::<T>() }
887+
}
888+
816889
/// Calculates the offset from a pointer (convenience for
817890
/// `.offset((count as isize).wrapping_neg())`).
818891
///
@@ -877,6 +950,26 @@ impl<T: ?Sized> *const T {
877950
unsafe { self.offset((count as isize).wrapping_neg()) }
878951
}
879952

953+
/// Calculates the offset from a pointer in bytes (convenience for
954+
/// `.byte_offset((count as isize).wrapping_neg())`).
955+
///
956+
/// `count` is in units of bytes.
957+
///
958+
/// This is purely a convenience for casting to a `u8` pointer and
959+
/// using [sub][pointer::sub] on it. See that method for documentation
960+
/// and safety requirements.
961+
#[must_use]
962+
#[inline(always)]
963+
#[unstable(feature = "pointer_byte_offsets", issue = "none")]
964+
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")]
965+
pub const unsafe fn byte_sub(self, count: usize) -> Self
966+
where
967+
T: Sized,
968+
{
969+
// SAFETY: the caller must uphold the safety contract for `sub`.
970+
unsafe { self.cast::<u8>().sub(count).cast::<T>() }
971+
}
972+
880973
/// Calculates the offset from a pointer using wrapping arithmetic.
881974
/// (convenience for `.wrapping_offset(count as isize)`)
882975
///
@@ -939,6 +1032,24 @@ impl<T: ?Sized> *const T {
9391032
self.wrapping_offset(count as isize)
9401033
}
9411034

1035+
/// Calculates the offset from a pointer in bytes using wrapping arithmetic.
1036+
/// (convenience for `.wrapping_byte_offset(count as isize)`)
1037+
///
1038+
/// `count` is in units of bytes.
1039+
///
1040+
/// This is purely a convenience for casting to a `u8` pointer and
1041+
/// using [wrapping_add][pointer::wrapping_add] on it. See that method for documentation.
1042+
#[must_use]
1043+
#[inline(always)]
1044+
#[unstable(feature = "pointer_byte_offsets", issue = "none")]
1045+
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")]
1046+
pub const fn wrapping_byte_add(self, count: usize) -> Self
1047+
where
1048+
T: Sized,
1049+
{
1050+
self.cast::<u8>().wrapping_add(count).cast::<T>()
1051+
}
1052+
9421053
/// Calculates the offset from a pointer using wrapping arithmetic.
9431054
/// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
9441055
///
@@ -1001,6 +1112,24 @@ impl<T: ?Sized> *const T {
10011112
self.wrapping_offset((count as isize).wrapping_neg())
10021113
}
10031114

1115+
/// Calculates the offset from a pointer in bytes using wrapping arithmetic.
1116+
/// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
1117+
///
1118+
/// `count` is in units of bytes.
1119+
///
1120+
/// This is purely a convenience for casting to a `u8` pointer and
1121+
/// using [wrapping_sub][pointer::wrapping_sub] on it. See that method for documentation.
1122+
#[must_use]
1123+
#[inline(always)]
1124+
#[unstable(feature = "pointer_byte_offsets", issue = "none")]
1125+
#[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")]
1126+
pub const fn wrapping_byte_sub(self, count: usize) -> Self
1127+
where
1128+
T: Sized,
1129+
{
1130+
self.cast::<u8>().wrapping_sub(count).cast::<T>()
1131+
}
1132+
10041133
/// Reads the value from `self` without moving it. This leaves the
10051134
/// memory in `self` unchanged.
10061135
///
@@ -1154,12 +1283,42 @@ impl<T: ?Sized> *const T {
11541283
}
11551284

11561285
// SAFETY:
1157-
// It is permisseble for `align_offset` to always return `usize::MAX`,
1286+
// It is permissible for `align_offset` to always return `usize::MAX`,
11581287
// algorithm correctness can not depend on `align_offset` returning non-max values.
11591288
//
11601289
// As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
11611290
unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) }
11621291
}
1292+
1293+
/// Returns whether the pointer is properly aligned for `T`.
1294+
#[must_use]
1295+
#[inline]
1296+
#[unstable(feature = "pointer_is_aligned", issue = "none")]
1297+
pub fn is_aligned(self) -> bool
1298+
where
1299+
T: Sized,
1300+
{
1301+
self.addr() % core::mem::align_of::<T>() == 0
1302+
}
1303+
1304+
/// Returns whether the pointer is aligned to `align`.
1305+
///
1306+
/// # Panics
1307+
///
1308+
/// The function panics if `align` is not a power-of-two (this includes 0).
1309+
#[must_use]
1310+
#[inline]
1311+
#[unstable(feature = "pointer_is_aligned", issue = "none")]
1312+
pub fn is_aligned_to(self, align: usize) -> bool
1313+
where
1314+
T: Sized,
1315+
{
1316+
if !align.is_power_of_two() {
1317+
panic!("is_aligned_to: align is not a power-of-two");
1318+
}
1319+
1320+
self.addr() % align == 0
1321+
}
11631322
}
11641323

11651324
impl<T> *const [T] {

0 commit comments

Comments
 (0)