Skip to content

add exact bitshifts #144342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,57 @@ macro_rules! int_impl {
}
}

/// Exact shift left. Computes `self << rhs`, returning `None` if any bits disagreeing with
/// the resulting sign bit would be shifted out.
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
if rhs < self.leading_zeros().max(self.leading_ones()) {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shl(rhs) })
} else {
None
}
}

/// Unchecked exact shift left. Computes `self << rhs`, assuming bits disagreeing with the
/// resulting sign bit cannot be shifted out.
///
/// # Safety
///
/// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >=
/// self.leading_ones()` i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub unsafe fn exact_shl_unchecked(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
(
len: u32 = self.leading_zeros().max(self.leading_ones()),
rhs: u32 = rhs,
) => rhs < len,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shl(rhs) }
}

/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
/// larger than or equal to the number of bits in `self`.
///
Expand Down Expand Up @@ -1508,6 +1559,60 @@ macro_rules! int_impl {
}
}

/// Exact shift right. Computes `self >> rhs`, returning `None` if any non-zero bits would be
/// shifted out or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(129), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
if rhs <= self.trailing_zeros().max(<$SelfT>::BITS - 1) {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shr(rhs) })
} else {
None
}
}

/// Unchecked exact shift right. Computes `self >> rhs`, assuming non-zero bits cannot be
/// shifted out and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
#[doc = concat!(stringify!($SelfT), "::BITS`")]
/// i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub unsafe fn exact_shr_unchecked(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
(
len: u32 = self.trailing_zeros().max(<$SelfT>::BITS - 1),
rhs: u32 = rhs,
) => rhs <= len,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shr(rhs) }
}

/// Checked absolute value. Computes `self.abs()`, returning `None` if
/// `self == MIN`.
///
Expand Down
108 changes: 108 additions & 0 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,60 @@ macro_rules! uint_impl {
}
}

/// Exact shift left. Computes `self << rhs`, returning `None` if any non-zero bits would be
/// shifted out or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
if rhs <= self.leading_zeros().max(<$SelfT>::BITS - 1) {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shl(rhs) })
} else {
None
}
}

/// Unchecked exact shift left. Computes `self << rhs`, assuming non-zero bits cannot be
/// shifted out and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs > self.leading_zeros() || rhs >=
#[doc = concat!(stringify!($SelfT), "::BITS`")]
/// i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub unsafe fn exact_shl_unchecked(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
(
len: u32 = self.leading_zeros().max(<$SelfT>::BITS - 1),
rhs: u32 = rhs,
) => rhs <= len,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shl(rhs) }
}

/// Checked shift right. Computes `self >> rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
///
Expand Down Expand Up @@ -1821,6 +1875,60 @@ macro_rules! uint_impl {
}
}

/// Exact shift right. Computes `self >> rhs`, returning `None` if any non-zero bits would be
/// shifted out or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(129), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
if rhs <= self.trailing_zeros().max(<$SelfT>::BITS - 1) {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shr(rhs) })
} else {
None
}
}

/// Unchecked exact shift right. Computes `self >> rhs`, assuming non-zero bits cannot be
/// shifted out and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
#[doc = concat!(stringify!($SelfT), "::BITS`")]
/// i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub unsafe fn exact_shr_unchecked(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
(
len: u32 = self.trailing_zeros().max(<$SelfT>::BITS - 1),
rhs: u32 = rhs,
) => rhs <= len,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shr(rhs) }
}

/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
/// overflow occurred.
///
Expand Down
Loading