-
-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Checked/wrapping/strict/unbounded funnel shifts #161119
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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -568,11 +568,8 @@ macro_rules! uint_impl { | |
| if intrinsics::overflow_checks() { | ||
| assert!(n < Self::BITS, "attempt to funnel shift left with overflow"); | ||
| } | ||
| // SAFETY: `n` is wrapped to within range | ||
| unsafe { | ||
| let n = n & (Self::BITS - 1); | ||
| self.unchecked_funnel_shl(right, n) | ||
| } | ||
|
|
||
| self.wrapping_funnel_shl(right, n) | ||
| } | ||
|
|
||
| /// Performs a right funnel shift. | ||
|
|
@@ -639,10 +636,141 @@ macro_rules! uint_impl { | |
| if intrinsics::overflow_checks() { | ||
| assert!(n < Self::BITS, "attempt to funnel shift right with overflow"); | ||
| } | ||
|
|
||
| self.wrapping_funnel_shr(right, n) | ||
| } | ||
|
|
||
| /// Performs a left funnel shift. | ||
| /// | ||
| /// This function will return `None` if `n` is greater than or equal to the number of | ||
| /// bits in `self`, i.e., when [`funnel_shl`](Self::funnel_shl) might panic or wrap. | ||
|
Comment on lines
+644
to
+646
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add examples
Comment on lines
+645
to
+646
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use "would" rather than "might" because we guarantee it would do one of those two things. |
||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn checked_funnel_shl(self, right: Self, n: u32) -> Option<Self> { | ||
| if n < Self::BITS { | ||
| // SAFETY: just checked that `n` is in-range | ||
| Some(unsafe { self.unchecked_funnel_shl(right, n) }) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
|
|
||
| /// Performs a right funnel shift. | ||
| /// | ||
| /// This function will return `None` if `n` is greater than or equal to the number of | ||
| /// bits in `self`, i.e., when [`funnel_shr`](Self::funnel_shr) might panic or wrap. | ||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn checked_funnel_shr(self, right: Self, n: u32) -> Option<Self> { | ||
| if n < Self::BITS { | ||
| // SAFETY: just checked that `n` is in-range | ||
| Some(unsafe { self.unchecked_funnel_shr(right, n) }) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
|
|
||
| /// Performs a left funnel shift. | ||
| /// | ||
| /// This function shifts by `mask(n)`, where `mask` removes any high-order bits of `n` | ||
| /// that would cause the shift to exceed the bitwidth of the type. As a result, this | ||
| /// function never panics, unlike [`funnel_shl`](Self::funnel_shl). | ||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn wrapping_funnel_shl(self, right: Self, n: u32) -> Self { | ||
|
Comment on lines
+677
to
+686
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Include the "Beware that, unlike most other wrapping_* methods on integer" from (same for |
||
| let n = n & (Self::BITS - 1); | ||
| // SAFETY: `n` is wrapped to within range | ||
| unsafe { | ||
| let n = n & (Self::BITS - 1); | ||
| self.unchecked_funnel_shr(right, n) | ||
| unsafe { self.unchecked_funnel_shl(right, n) } | ||
| } | ||
|
|
||
| /// Performs a right funnel shift. | ||
| /// | ||
| /// This function shifts by `mask(n)`, where `mask` removes any high-order bits of `n` | ||
| /// that would cause the shift to exceed the bitwidth of the type. As a result, this | ||
| /// function never panics, unlike [`funnel_shr`](Self::funnel_shr). | ||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn wrapping_funnel_shr(self, right: Self, n: u32) -> Self { | ||
| let n = n & (Self::BITS - 1); | ||
| // SAFETY: `n` is wrapped to within range | ||
| unsafe { self.unchecked_funnel_shr(right, n) } | ||
| } | ||
|
|
||
| /// Performs a left funnel shift. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// This function will always panic if `n` is greater than or equal to the number of | ||
| /// bits in `self`, i.e., when [`funnel_shr`](Self::funnel_shr) might panic or wrap. | ||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn strict_funnel_shl(self, right: Self, n: u32) -> Self { | ||
| assert!(n < Self::BITS, "attempt to funnel shift left with overflow"); | ||
| // SAFETY: `n` is checked to be within range | ||
| unsafe { self.unchecked_funnel_shl(right, n) } | ||
| } | ||
|
|
||
| /// Performs a right funnel shift. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// This function will always panic if `n` is greater than or equal to the number of | ||
| /// bits in `self`, i.e., when [`funnel_shr`](Self::funnel_shr) might panic or wrap. | ||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn strict_funnel_shr(self, right: Self, n: u32) -> Self { | ||
|
Comment on lines
+725
to
+733
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.strict_shl |
||
| assert!(n < Self::BITS, "attempt to funnel shift right with overflow"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should probably go in the |
||
| // SAFETY: `n` is checked to be within range | ||
| unsafe { self.unchecked_funnel_shr(right, n) } | ||
| } | ||
|
|
||
| /// Performs a left funnel shift. | ||
| /// | ||
| /// This function will act like [`unbounded_shl`](Self::unbounded_shl) on a type with | ||
| /// twice the bitwidth of `Self` where the high-order half comes from `self` and the | ||
| /// low-order half comes from `right`, regardless of whether such a type exists, and | ||
| /// will return the high-order half of the result. | ||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn unbounded_funnel_shl(self, right: Self, n: u32) -> Self { | ||
| if let Some(r) = self.checked_funnel_shl(right, n) { | ||
| r | ||
| } else { | ||
| // This subtraction will never underflow. | ||
| right.unbounded_shl(n - Self::BITS) | ||
| } | ||
| } | ||
|
|
||
| /// Performs a right funnel shift. | ||
| /// | ||
| /// This function will act like [`unbounded_shr`](Self::unbounded_shr) on a type with | ||
| /// twice the bitwidth of `Self` where the high-order half comes from `self` and the | ||
| /// low-order half comes from `right`, regardless of whether such a type exists, and | ||
| /// will return the low-order half of the result. | ||
| #[rustc_const_unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[unstable(feature = "wrapping_funnel_shifts", issue = "161798")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| #[inline(always)] | ||
| pub const fn unbounded_funnel_shr(self, right: Self, n: u32) -> Self { | ||
| if let Some(r) = self.checked_funnel_shr(right, n) { | ||
| r | ||
| } else { | ||
| // This subtraction will never underflow. | ||
| self.unbounded_shr(n - Self::BITS) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -652,7 +780,7 @@ macro_rules! uint_impl { | |
| /// | ||
| /// This results in undefined behavior if `n` is greater than or equal to | ||
| #[doc = concat!("`", stringify!($SelfT) , "::BITS`,")] | ||
| /// i.e. when [`funnel_shl`](Self::funnel_shl) would panic. | ||
| /// i.e. when [`funnel_shl`](Self::funnel_shl) might panic or wrap. | ||
| /// | ||
| #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] | ||
| #[unstable(feature = "funnel_shifts", issue = "145686")] | ||
|
|
@@ -678,7 +806,7 @@ macro_rules! uint_impl { | |
| /// | ||
| /// This results in undefined behavior if `n` is greater than or equal to | ||
| #[doc = concat!("`", stringify!($SelfT) , "::BITS`,")] | ||
| /// i.e. when [`funnel_shr`](Self::funnel_shr) would panic. | ||
| /// i.e. when [`funnel_shr`](Self::funnel_shr) might panic or wrap. | ||
| /// | ||
| #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] | ||
| #[unstable(feature = "funnel_shifts", issue = "145686")] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -241,6 +241,28 @@ macro_rules! uint_module { | |
| let _ = <$T>::funnel_shr(A, B, $T::BITS); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic = "attempt to funnel shift left with overflow"] | ||
| fn test_strict_funnel_shl_overflow() { | ||
| let _ = <$T>::strict_funnel_shl(A, B, $T::BITS); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic = "attempt to funnel shift right with overflow"] | ||
| fn test_strict_funnel_shr_overflow() { | ||
| let _ = <$T>::strict_funnel_shr(A, B, $T::BITS); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_wrapping_funnel_shl_overflow() { | ||
| let _ = <$T>::wrapping_funnel_shl(A, B, $T::BITS); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_wrapping_funnel_shr_overflow() { | ||
| let _ = <$T>::wrapping_funnel_shr(A, B, $T::BITS); | ||
| } | ||
|
|
||
|
Comment on lines
+256
to
+265
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These aren't actually testing anything other than the fact that we don't panic? These methods should be tested in |
||
| #[test] | ||
| fn test_funnel_shifts_runtime() { | ||
| for i in 0..$T::BITS - 1 { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of the summary lines say "Performs a left/right funnel shift." Please update these to be a bit more similar to the
{checked,wrapping,strict,unbounded}_{shl,shr}.