Skip to content

Commit c2fb0a3

Browse files
committed
refactor: Deduplicate pow implementations
`strict_pow` can be implemented in terms of `checked_pow`, `wrapping_pow` can be implemented in terms of `overflowing_pow`, and `pow` can be implemented in terms of `strict_pow` or `wrapping_pow`.
1 parent 943c02c commit c2fb0a3

5 files changed

Lines changed: 48 additions & 207 deletions

File tree

library/core/src/num/imp/overflow_panic.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ pub(in crate::num) const fn shl() -> ! {
5050
panic!("attempt to shift left with overflow")
5151
}
5252

53+
#[cold]
54+
#[track_caller]
55+
pub(in crate::num) const fn pow() -> ! {
56+
panic!("attempt to exponentiate with overflow")
57+
}
58+
5359
#[cold]
5460
#[track_caller]
5561
pub(in crate::num) const fn cast_integer() -> ! {

library/core/src/num/int_macros.rs

Lines changed: 20 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,23 +1891,10 @@ macro_rules! int_impl {
18911891
without modifying the original"]
18921892
#[inline]
18931893
#[track_caller]
1894-
pub const fn strict_pow(self, mut exp: u32) -> Self {
1895-
if exp == 0 {
1896-
return 1;
1897-
}
1898-
let mut base = self;
1899-
let mut acc: Self = 1;
1900-
1901-
loop {
1902-
if (exp & 1) == 1 {
1903-
acc = acc.strict_mul(base);
1904-
// since exp!=0, finally the exp must be 1.
1905-
if exp == 1 {
1906-
return acc;
1907-
}
1908-
}
1909-
exp /= 2;
1910-
base = base.strict_mul(base);
1894+
pub const fn strict_pow(self, exp: u32) -> Self {
1895+
match self.checked_pow(exp) {
1896+
Some(x) => x,
1897+
None => imp::overflow_panic::pow(),
19111898
}
19121899
}
19131900

@@ -2526,43 +2513,9 @@ macro_rules! int_impl {
25262513
#[must_use = "this returns the result of the operation, \
25272514
without modifying the original"]
25282515
#[inline]
2529-
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
2530-
if exp == 0 {
2531-
return 1;
2532-
}
2533-
let mut base = self;
2534-
let mut acc: Self = 1;
2535-
2536-
if intrinsics::is_val_statically_known(exp) {
2537-
while exp > 1 {
2538-
if (exp & 1) == 1 {
2539-
acc = acc.wrapping_mul(base);
2540-
}
2541-
exp /= 2;
2542-
base = base.wrapping_mul(base);
2543-
}
2544-
2545-
// since exp!=0, finally the exp must be 1.
2546-
// Deal with the final bit of the exponent separately, since
2547-
// squaring the base afterwards is not necessary.
2548-
acc.wrapping_mul(base)
2549-
} else {
2550-
// This is faster than the above when the exponent is not known
2551-
// at compile time. We can't use the same code for the constant
2552-
// exponent case because LLVM is currently unable to unroll
2553-
// this loop.
2554-
loop {
2555-
if (exp & 1) == 1 {
2556-
acc = acc.wrapping_mul(base);
2557-
// since exp!=0, finally the exp must be 1.
2558-
if exp == 1 {
2559-
return acc;
2560-
}
2561-
}
2562-
exp /= 2;
2563-
base = base.wrapping_mul(base);
2564-
}
2565-
}
2516+
pub const fn wrapping_pow(self, exp: u32) -> Self {
2517+
let (a, _) = self.overflowing_pow(exp);
2518+
a
25662519
}
25672520

25682521
/// Calculates `self` + `rhs`.
@@ -3128,29 +3081,26 @@ macro_rules! int_impl {
31283081
#[inline]
31293082
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
31303083
if exp == 0 {
3131-
return (1,false);
3084+
return (1, false);
31323085
}
3086+
31333087
let mut base = self;
31343088
let mut acc: Self = 1;
3135-
let mut overflown = false;
3136-
// Scratch space for storing results of overflowing_mul.
3137-
let mut r;
3089+
let mut overflow = false;
3090+
let mut tmp_overflow;
31383091

31393092
loop {
31403093
if (exp & 1) == 1 {
3141-
r = acc.overflowing_mul(base);
3094+
(acc, tmp_overflow) = acc.overflowing_mul(base);
3095+
overflow |= tmp_overflow;
31423096
// since exp!=0, finally the exp must be 1.
31433097
if exp == 1 {
3144-
r.1 |= overflown;
3145-
return r;
3098+
return (acc, overflow);
31463099
}
3147-
acc = r.0;
3148-
overflown |= r.1;
31493100
}
31503101
exp /= 2;
3151-
r = base.overflowing_mul(base);
3152-
base = r.0;
3153-
overflown |= r.1;
3102+
(base, tmp_overflow) = base.overflowing_mul(base);
3103+
overflow |= tmp_overflow;
31543104
}
31553105
}
31563106

@@ -3170,43 +3120,11 @@ macro_rules! int_impl {
31703120
without modifying the original"]
31713121
#[inline]
31723122
#[rustc_inherit_overflow_checks]
3173-
pub const fn pow(self, mut exp: u32) -> Self {
3174-
if exp == 0 {
3175-
return 1;
3176-
}
3177-
let mut base = self;
3178-
let mut acc = 1;
3179-
3180-
if intrinsics::is_val_statically_known(exp) {
3181-
while exp > 1 {
3182-
if (exp & 1) == 1 {
3183-
acc = acc * base;
3184-
}
3185-
exp /= 2;
3186-
base = base * base;
3187-
}
3188-
3189-
// since exp!=0, finally the exp must be 1.
3190-
// Deal with the final bit of the exponent separately, since
3191-
// squaring the base afterwards is not necessary and may cause a
3192-
// needless overflow.
3193-
acc * base
3123+
pub const fn pow(self, exp: u32) -> Self {
3124+
if intrinsics::overflow_checks() {
3125+
self.strict_pow(exp)
31943126
} else {
3195-
// This is faster than the above when the exponent is not known
3196-
// at compile time. We can't use the same code for the constant
3197-
// exponent case because LLVM is currently unable to unroll
3198-
// this loop.
3199-
loop {
3200-
if (exp & 1) == 1 {
3201-
acc = acc * base;
3202-
// since exp!=0, finally the exp must be 1.
3203-
if exp == 1 {
3204-
return acc;
3205-
}
3206-
}
3207-
exp /= 2;
3208-
base = base * base;
3209-
}
3127+
self.wrapping_pow(exp)
32103128
}
32113129
}
32123130

library/core/src/num/uint_macros.rs

Lines changed: 20 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,23 +2413,10 @@ macro_rules! uint_impl {
24132413
without modifying the original"]
24142414
#[inline]
24152415
#[track_caller]
2416-
pub const fn strict_pow(self, mut exp: u32) -> Self {
2417-
if exp == 0 {
2418-
return 1;
2419-
}
2420-
let mut base = self;
2421-
let mut acc: Self = 1;
2422-
2423-
loop {
2424-
if (exp & 1) == 1 {
2425-
acc = acc.strict_mul(base);
2426-
// since exp!=0, finally the exp must be 1.
2427-
if exp == 1 {
2428-
return acc;
2429-
}
2430-
}
2431-
exp /= 2;
2432-
base = base.strict_mul(base);
2416+
pub const fn strict_pow(self, exp: u32) -> Self {
2417+
match self.checked_pow(exp) {
2418+
None => imp::overflow_panic::pow(),
2419+
Some(a) => a,
24332420
}
24342421
}
24352422

@@ -2919,43 +2906,9 @@ macro_rules! uint_impl {
29192906
#[must_use = "this returns the result of the operation, \
29202907
without modifying the original"]
29212908
#[inline]
2922-
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
2923-
if exp == 0 {
2924-
return 1;
2925-
}
2926-
let mut base = self;
2927-
let mut acc: Self = 1;
2928-
2929-
if intrinsics::is_val_statically_known(exp) {
2930-
while exp > 1 {
2931-
if (exp & 1) == 1 {
2932-
acc = acc.wrapping_mul(base);
2933-
}
2934-
exp /= 2;
2935-
base = base.wrapping_mul(base);
2936-
}
2937-
2938-
// since exp!=0, finally the exp must be 1.
2939-
// Deal with the final bit of the exponent separately, since
2940-
// squaring the base afterwards is not necessary.
2941-
acc.wrapping_mul(base)
2942-
} else {
2943-
// This is faster than the above when the exponent is not known
2944-
// at compile time. We can't use the same code for the constant
2945-
// exponent case because LLVM is currently unable to unroll
2946-
// this loop.
2947-
loop {
2948-
if (exp & 1) == 1 {
2949-
acc = acc.wrapping_mul(base);
2950-
// since exp!=0, finally the exp must be 1.
2951-
if exp == 1 {
2952-
return acc;
2953-
}
2954-
}
2955-
exp /= 2;
2956-
base = base.wrapping_mul(base);
2957-
}
2958-
}
2909+
pub const fn wrapping_pow(self, exp: u32) -> Self {
2910+
let (a, _) = self.overflowing_pow(exp);
2911+
a
29592912
}
29602913

29612914
/// Calculates `self` + `rhs`.
@@ -3597,30 +3550,26 @@ macro_rules! uint_impl {
35973550
without modifying the original"]
35983551
#[inline]
35993552
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
3600-
if exp == 0{
3601-
return (1,false);
3553+
if exp == 0 {
3554+
return (1, false);
36023555
}
36033556
let mut base = self;
36043557
let mut acc: Self = 1;
3605-
let mut overflown = false;
3606-
// Scratch space for storing results of overflowing_mul.
3607-
let mut r;
3558+
let mut overflow = false;
3559+
let mut tmp_overflow;
36083560

36093561
loop {
36103562
if (exp & 1) == 1 {
3611-
r = acc.overflowing_mul(base);
3563+
(acc, tmp_overflow) = acc.overflowing_mul(base);
3564+
overflow |= tmp_overflow;
36123565
// since exp!=0, finally the exp must be 1.
36133566
if exp == 1 {
3614-
r.1 |= overflown;
3615-
return r;
3567+
return (acc, overflow);
36163568
}
3617-
acc = r.0;
3618-
overflown |= r.1;
36193569
}
36203570
exp /= 2;
3621-
r = base.overflowing_mul(base);
3622-
base = r.0;
3623-
overflown |= r.1;
3571+
(base, tmp_overflow) = base.overflowing_mul(base);
3572+
overflow |= tmp_overflow;
36243573
}
36253574
}
36263575

@@ -3638,43 +3587,11 @@ macro_rules! uint_impl {
36383587
without modifying the original"]
36393588
#[inline]
36403589
#[rustc_inherit_overflow_checks]
3641-
pub const fn pow(self, mut exp: u32) -> Self {
3642-
if exp == 0 {
3643-
return 1;
3644-
}
3645-
let mut base = self;
3646-
let mut acc = 1;
3647-
3648-
if intrinsics::is_val_statically_known(exp) {
3649-
while exp > 1 {
3650-
if (exp & 1) == 1 {
3651-
acc = acc * base;
3652-
}
3653-
exp /= 2;
3654-
base = base * base;
3655-
}
3656-
3657-
// since exp!=0, finally the exp must be 1.
3658-
// Deal with the final bit of the exponent separately, since
3659-
// squaring the base afterwards is not necessary and may cause a
3660-
// needless overflow.
3661-
acc * base
3590+
pub const fn pow(self, exp: u32) -> Self {
3591+
if intrinsics::overflow_checks() {
3592+
self.strict_pow(exp)
36623593
} else {
3663-
// This is faster than the above when the exponent is not known
3664-
// at compile time. We can't use the same code for the constant
3665-
// exponent case because LLVM is currently unable to unroll
3666-
// this loop.
3667-
loop {
3668-
if (exp & 1) == 1 {
3669-
acc = acc * base;
3670-
// since exp!=0, finally the exp must be 1.
3671-
if exp == 1 {
3672-
return acc;
3673-
}
3674-
}
3675-
exp /= 2;
3676-
base = base * base;
3677-
}
3594+
self.wrapping_pow(exp)
36783595
}
36793596
}
36803597

tests/ui/numbers-arithmetic/overflowing-pow-signed.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ run-fail
22
//@ regex-error-pattern: thread 'main'.*panicked
3-
//@ error-pattern: attempt to multiply with overflow
3+
//@ regex-error-pattern: attempt to exponentiate with overflow
44
//@ needs-subprocess
55
//@ compile-flags: -C debug-assertions
66

tests/ui/numbers-arithmetic/overflowing-pow-unsigned.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ run-fail
22
//@ regex-error-pattern: thread 'main'.*panicked
3-
//@ error-pattern: attempt to multiply with overflow
3+
//@ regex-error-pattern: attempt to exponentiate with overflow
44
//@ needs-subprocess
55
//@ compile-flags: -C debug-assertions
66

0 commit comments

Comments
 (0)