Rollup merge of #68978 - ecstatic-morse:const-int-pow, r=oli-obk
Make integer exponentiation methods unstably const cc #53718 This makes the following inherent methods on integer primitives into unstable `const fn`: - `pow` - `checked_pow` - `wrapping_pow` - `overflowing_pow` - `saturating_pow` - `next_power_of_two` - `checked_next_power_of_two` - `wrapping_next_power_of_two` Only two changes were made to the implementation of these methods. First, I had to switch from the `?` operator, which is not yet implemented in a const context, to a `try_opt` macro. Second, `next_power_of_two` was using `ops::Add::add` (see the first commit) to "get overflow checks", so I switched to `#[rustc_inherit_overflow_checks]`. I'm not quite sure why the attribute wasn't used in the first place.
This commit is contained in:
commit
d96951f554
@ -73,11 +73,14 @@
|
||||
#![feature(const_ascii_ctype_on_intrinsics)]
|
||||
#![feature(const_alloc_layout)]
|
||||
#![feature(const_if_match)]
|
||||
#![feature(const_loop)]
|
||||
#![feature(const_checked_int_methods)]
|
||||
#![feature(const_euclidean_int_methods)]
|
||||
#![feature(const_overflowing_int_methods)]
|
||||
#![feature(const_saturating_int_methods)]
|
||||
#![feature(const_int_unchecked_arith)]
|
||||
#![feature(const_int_pow)]
|
||||
#![feature(constctlz)]
|
||||
#![feature(const_panic)]
|
||||
#![feature(const_fn_union)]
|
||||
#![feature(const_generics)]
|
||||
|
@ -8,9 +8,18 @@ use crate::convert::Infallible;
|
||||
use crate::fmt;
|
||||
use crate::intrinsics;
|
||||
use crate::mem;
|
||||
use crate::ops;
|
||||
use crate::str::FromStr;
|
||||
|
||||
// Used because the `?` operator is not allowed in a const context.
|
||||
macro_rules! try_opt {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Some(x) => x,
|
||||
None => return None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_nonzero_fmt {
|
||||
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
|
||||
$(
|
||||
@ -993,26 +1002,27 @@ $EndFeature, "
|
||||
```"),
|
||||
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
|
||||
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
|
||||
let mut base = self;
|
||||
let mut acc: Self = 1;
|
||||
|
||||
while exp > 1 {
|
||||
if (exp & 1) == 1 {
|
||||
acc = acc.checked_mul(base)?;
|
||||
acc = try_opt!(acc.checked_mul(base));
|
||||
}
|
||||
exp /= 2;
|
||||
base = base.checked_mul(base)?;
|
||||
base = try_opt!(base.checked_mul(base));
|
||||
}
|
||||
|
||||
// Deal with the final bit of the exponent separately, since
|
||||
// squaring the base afterwards is not necessary and may cause a
|
||||
// needless overflow.
|
||||
if exp == 1 {
|
||||
acc = acc.checked_mul(base)?;
|
||||
acc = try_opt!(acc.checked_mul(base));
|
||||
}
|
||||
|
||||
Some(acc)
|
||||
@ -1180,10 +1190,11 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT
|
||||
$EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn saturating_pow(self, exp: u32) -> Self {
|
||||
pub const fn saturating_pow(self, exp: u32) -> Self {
|
||||
match self.checked_pow(exp) {
|
||||
Some(x) => x,
|
||||
None if self < 0 && exp % 2 == 1 => Self::min_value(),
|
||||
@ -1523,10 +1534,11 @@ assert_eq!(3i8.wrapping_pow(6), -39);",
|
||||
$EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||
let mut base = self;
|
||||
let mut acc: Self = 1;
|
||||
|
||||
@ -1900,10 +1912,11 @@ assert_eq!(3i8.overflowing_pow(5), (-13, true));",
|
||||
$EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
|
||||
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
|
||||
let mut base = self;
|
||||
let mut acc: Self = 1;
|
||||
let mut overflown = false;
|
||||
@ -1949,11 +1962,12 @@ assert_eq!(x.pow(5), 32);",
|
||||
$EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub fn pow(self, mut exp: u32) -> Self {
|
||||
pub const fn pow(self, mut exp: u32) -> Self {
|
||||
let mut base = self;
|
||||
let mut acc = 1;
|
||||
|
||||
@ -3119,26 +3133,27 @@ Basic usage:
|
||||
assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
|
||||
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
|
||||
let mut base = self;
|
||||
let mut acc: Self = 1;
|
||||
|
||||
while exp > 1 {
|
||||
if (exp & 1) == 1 {
|
||||
acc = acc.checked_mul(base)?;
|
||||
acc = try_opt!(acc.checked_mul(base));
|
||||
}
|
||||
exp /= 2;
|
||||
base = base.checked_mul(base)?;
|
||||
base = try_opt!(base.checked_mul(base));
|
||||
}
|
||||
|
||||
// Deal with the final bit of the exponent separately, since
|
||||
// squaring the base afterwards is not necessary and may cause a
|
||||
// needless overflow.
|
||||
if exp == 1 {
|
||||
acc = acc.checked_mul(base)?;
|
||||
acc = try_opt!(acc.checked_mul(base));
|
||||
}
|
||||
|
||||
Some(acc)
|
||||
@ -3234,10 +3249,11 @@ assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT
|
||||
$EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn saturating_pow(self, exp: u32) -> Self {
|
||||
pub const fn saturating_pow(self, exp: u32) -> Self {
|
||||
match self.checked_pow(exp) {
|
||||
Some(x) => x,
|
||||
None => Self::max_value(),
|
||||
@ -3527,10 +3543,11 @@ Basic usage:
|
||||
assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||
let mut base = self;
|
||||
let mut acc: Self = 1;
|
||||
|
||||
@ -3853,10 +3870,11 @@ Basic usage:
|
||||
assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "no_panic_pow", since = "1.34.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
|
||||
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
|
||||
let mut base = self;
|
||||
let mut acc: Self = 1;
|
||||
let mut overflown = false;
|
||||
@ -3899,11 +3917,12 @@ Basic usage:
|
||||
", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub fn pow(self, mut exp: u32) -> Self {
|
||||
pub const fn pow(self, mut exp: u32) -> Self {
|
||||
let mut base = self;
|
||||
let mut acc = 1;
|
||||
|
||||
@ -4014,7 +4033,8 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
|
||||
// overflow cases it instead ends up returning the maximum value
|
||||
// of the type, and can return 0 for 0.
|
||||
#[inline]
|
||||
fn one_less_than_next_power_of_two(self) -> Self {
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
const fn one_less_than_next_power_of_two(self) -> Self {
|
||||
if self <= 1 { return 0; }
|
||||
|
||||
let p = self - 1;
|
||||
@ -4042,10 +4062,11 @@ Basic usage:
|
||||
assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
|
||||
```"),
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
#[inline]
|
||||
pub fn next_power_of_two(self) -> Self {
|
||||
// Call the trait to get overflow checks
|
||||
ops::Add::add(self.one_less_than_next_power_of_two(), 1)
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn next_power_of_two(self) -> Self {
|
||||
self.one_less_than_next_power_of_two() + 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -4067,7 +4088,8 @@ $EndFeature, "
|
||||
```"),
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn checked_next_power_of_two(self) -> Option<Self> {
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
pub const fn checked_next_power_of_two(self) -> Option<Self> {
|
||||
self.one_less_than_next_power_of_two().checked_add(1)
|
||||
}
|
||||
}
|
||||
@ -4091,7 +4113,8 @@ $EndFeature, "
|
||||
```"),
|
||||
#[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
|
||||
reason = "needs decision on wrapping behaviour")]
|
||||
pub fn wrapping_next_power_of_two(self) -> Self {
|
||||
#[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
|
||||
pub const fn wrapping_next_power_of_two(self) -> Self {
|
||||
self.one_less_than_next_power_of_two().wrapping_add(1)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,48 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(const_int_pow)]
|
||||
#![feature(wrapping_next_power_of_two)]
|
||||
|
||||
const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two();
|
||||
const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two();
|
||||
const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two();
|
||||
|
||||
const POW: u8 = 3u8.pow(5);
|
||||
|
||||
const CHECKED_POW_OK: Option<u8> = 3u8.checked_pow(5);
|
||||
const CHECKED_POW_OVERFLOW: Option<u8> = 3u8.checked_pow(6);
|
||||
|
||||
const WRAPPING_POW: u8 = 3u8.wrapping_pow(6);
|
||||
const OVERFLOWING_POW: (u8, bool) = 3u8.overflowing_pow(6);
|
||||
const SATURATING_POW: u8 = 3u8.saturating_pow(6);
|
||||
|
||||
const NEXT_POWER_OF_TWO: u32 = 3u32.next_power_of_two();
|
||||
|
||||
const CHECKED_NEXT_POWER_OF_TWO_OK: Option<u32> = 3u32.checked_next_power_of_two();
|
||||
const CHECKED_NEXT_POWER_OF_TWO_OVERFLOW: Option<u32> =
|
||||
u32::max_value().checked_next_power_of_two();
|
||||
|
||||
const WRAPPING_NEXT_POWER_OF_TWO: u32 =
|
||||
u32::max_value().wrapping_next_power_of_two();
|
||||
|
||||
fn main() {
|
||||
assert!(!IS_POWER_OF_TWO_A);
|
||||
assert!(IS_POWER_OF_TWO_B);
|
||||
assert!(!IS_POWER_OF_TWO_C);
|
||||
|
||||
assert_eq!(POW, 243);
|
||||
|
||||
assert_eq!(CHECKED_POW_OK, Some(243));
|
||||
assert_eq!(CHECKED_POW_OVERFLOW, None);
|
||||
|
||||
assert_eq!(WRAPPING_POW, 217);
|
||||
assert_eq!(OVERFLOWING_POW, (217, true));
|
||||
assert_eq!(SATURATING_POW, u8::max_value());
|
||||
|
||||
assert_eq!(NEXT_POWER_OF_TWO, 4);
|
||||
|
||||
assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OK, Some(4));
|
||||
assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OVERFLOW, None);
|
||||
|
||||
assert_eq!(WRAPPING_NEXT_POWER_OF_TWO, 0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user