Skip to content

Commit fc24178

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 2395dba commit fc24178

File tree

3 files changed

+46
-205
lines changed

3 files changed

+46
-205
lines changed

library/core/src/num/int_macros.rs

Lines changed: 20 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,23 +1786,10 @@ macro_rules! int_impl {
17861786
without modifying the original"]
17871787
#[inline]
17881788
#[track_caller]
1789-
pub const fn strict_pow(self, mut exp: u32) -> Self {
1790-
if exp == 0 {
1791-
return 1;
1792-
}
1793-
let mut base = self;
1794-
let mut acc: Self = 1;
1795-
1796-
loop {
1797-
if (exp & 1) == 1 {
1798-
acc = acc.strict_mul(base);
1799-
// since exp!=0, finally the exp must be 1.
1800-
if exp == 1 {
1801-
return acc;
1802-
}
1803-
}
1804-
exp /= 2;
1805-
base = base.strict_mul(base);
1789+
pub const fn strict_pow(self, exp: u32) -> Self {
1790+
match self.checked_pow(exp) {
1791+
Some(x) => x,
1792+
None => overflow_panic::pow(),
18061793
}
18071794
}
18081795

@@ -2397,43 +2384,9 @@ macro_rules! int_impl {
23972384
#[must_use = "this returns the result of the operation, \
23982385
without modifying the original"]
23992386
#[inline]
2400-
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
2401-
if exp == 0 {
2402-
return 1;
2403-
}
2404-
let mut base = self;
2405-
let mut acc: Self = 1;
2406-
2407-
if intrinsics::is_val_statically_known(exp) {
2408-
while exp > 1 {
2409-
if (exp & 1) == 1 {
2410-
acc = acc.wrapping_mul(base);
2411-
}
2412-
exp /= 2;
2413-
base = base.wrapping_mul(base);
2414-
}
2415-
2416-
// since exp!=0, finally the exp must be 1.
2417-
// Deal with the final bit of the exponent separately, since
2418-
// squaring the base afterwards is not necessary.
2419-
acc.wrapping_mul(base)
2420-
} else {
2421-
// This is faster than the above when the exponent is not known
2422-
// at compile time. We can't use the same code for the constant
2423-
// exponent case because LLVM is currently unable to unroll
2424-
// this loop.
2425-
loop {
2426-
if (exp & 1) == 1 {
2427-
acc = acc.wrapping_mul(base);
2428-
// since exp!=0, finally the exp must be 1.
2429-
if exp == 1 {
2430-
return acc;
2431-
}
2432-
}
2433-
exp /= 2;
2434-
base = base.wrapping_mul(base);
2435-
}
2436-
}
2387+
pub const fn wrapping_pow(self, exp: u32) -> Self {
2388+
let (a, _) = self.overflowing_pow(exp);
2389+
a
24372390
}
24382391

24392392
/// Calculates `self` + `rhs`.
@@ -2991,29 +2944,26 @@ macro_rules! int_impl {
29912944
#[inline]
29922945
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
29932946
if exp == 0 {
2994-
return (1,false);
2947+
return (1, false);
29952948
}
2949+
29962950
let mut base = self;
29972951
let mut acc: Self = 1;
2998-
let mut overflown = false;
2999-
// Scratch space for storing results of overflowing_mul.
3000-
let mut r;
2952+
let mut overflow = false;
2953+
let mut tmp_overflow;
30012954

30022955
loop {
30032956
if (exp & 1) == 1 {
3004-
r = acc.overflowing_mul(base);
2957+
(acc, tmp_overflow) = acc.overflowing_mul(base);
2958+
overflow |= tmp_overflow;
30052959
// since exp!=0, finally the exp must be 1.
30062960
if exp == 1 {
3007-
r.1 |= overflown;
3008-
return r;
2961+
return (acc, overflow);
30092962
}
3010-
acc = r.0;
3011-
overflown |= r.1;
30122963
}
30132964
exp /= 2;
3014-
r = base.overflowing_mul(base);
3015-
base = r.0;
3016-
overflown |= r.1;
2965+
(base, tmp_overflow) = base.overflowing_mul(base);
2966+
overflow |= tmp_overflow;
30172967
}
30182968
}
30192969

@@ -3033,43 +2983,11 @@ macro_rules! int_impl {
30332983
without modifying the original"]
30342984
#[inline]
30352985
#[rustc_inherit_overflow_checks]
3036-
pub const fn pow(self, mut exp: u32) -> Self {
3037-
if exp == 0 {
3038-
return 1;
3039-
}
3040-
let mut base = self;
3041-
let mut acc = 1;
3042-
3043-
if intrinsics::is_val_statically_known(exp) {
3044-
while exp > 1 {
3045-
if (exp & 1) == 1 {
3046-
acc = acc * base;
3047-
}
3048-
exp /= 2;
3049-
base = base * base;
3050-
}
3051-
3052-
// since exp!=0, finally the exp must be 1.
3053-
// Deal with the final bit of the exponent separately, since
3054-
// squaring the base afterwards is not necessary and may cause a
3055-
// needless overflow.
3056-
acc * base
2986+
pub const fn pow(self, exp: u32) -> Self {
2987+
if intrinsics::overflow_checks() {
2988+
self.strict_pow(exp)
30572989
} else {
3058-
// This is faster than the above when the exponent is not known
3059-
// at compile time. We can't use the same code for the constant
3060-
// exponent case because LLVM is currently unable to unroll
3061-
// this loop.
3062-
loop {
3063-
if (exp & 1) == 1 {
3064-
acc = acc * base;
3065-
// since exp!=0, finally the exp must be 1.
3066-
if exp == 1 {
3067-
return acc;
3068-
}
3069-
}
3070-
exp /= 2;
3071-
base = base * base;
3072-
}
2990+
self.wrapping_pow(exp)
30732991
}
30742992
}
30752993

library/core/src/num/overflow_panic.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ pub(super) const fn rem() -> ! {
3232
panic!("attempt to calculate the remainder with overflow")
3333
}
3434

35+
#[cold]
36+
#[track_caller]
37+
pub(super) const fn pow() -> ! {
38+
panic!("attempt to calculate the power with overflow")
39+
}
40+
3541
#[cold]
3642
#[track_caller]
3743
pub(super) const fn neg() -> ! {

library/core/src/num/uint_macros.rs

Lines changed: 20 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,23 +2131,10 @@ macro_rules! uint_impl {
21312131
without modifying the original"]
21322132
#[inline]
21332133
#[track_caller]
2134-
pub const fn strict_pow(self, mut exp: u32) -> Self {
2135-
if exp == 0 {
2136-
return 1;
2137-
}
2138-
let mut base = self;
2139-
let mut acc: Self = 1;
2140-
2141-
loop {
2142-
if (exp & 1) == 1 {
2143-
acc = acc.strict_mul(base);
2144-
// since exp!=0, finally the exp must be 1.
2145-
if exp == 1 {
2146-
return acc;
2147-
}
2148-
}
2149-
exp /= 2;
2150-
base = base.strict_mul(base);
2134+
pub const fn strict_pow(self, exp: u32) -> Self {
2135+
match self.checked_pow(exp) {
2136+
None => overflow_panic::pow(),
2137+
Some(a) => a,
21512138
}
21522139
}
21532140

@@ -2609,43 +2596,9 @@ macro_rules! uint_impl {
26092596
#[must_use = "this returns the result of the operation, \
26102597
without modifying the original"]
26112598
#[inline]
2612-
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
2613-
if exp == 0 {
2614-
return 1;
2615-
}
2616-
let mut base = self;
2617-
let mut acc: Self = 1;
2618-
2619-
if intrinsics::is_val_statically_known(exp) {
2620-
while exp > 1 {
2621-
if (exp & 1) == 1 {
2622-
acc = acc.wrapping_mul(base);
2623-
}
2624-
exp /= 2;
2625-
base = base.wrapping_mul(base);
2626-
}
2627-
2628-
// since exp!=0, finally the exp must be 1.
2629-
// Deal with the final bit of the exponent separately, since
2630-
// squaring the base afterwards is not necessary.
2631-
acc.wrapping_mul(base)
2632-
} else {
2633-
// This is faster than the above when the exponent is not known
2634-
// at compile time. We can't use the same code for the constant
2635-
// exponent case because LLVM is currently unable to unroll
2636-
// this loop.
2637-
loop {
2638-
if (exp & 1) == 1 {
2639-
acc = acc.wrapping_mul(base);
2640-
// since exp!=0, finally the exp must be 1.
2641-
if exp == 1 {
2642-
return acc;
2643-
}
2644-
}
2645-
exp /= 2;
2646-
base = base.wrapping_mul(base);
2647-
}
2648-
}
2599+
pub const fn wrapping_pow(self, exp: u32) -> Self {
2600+
let (a, _) = self.overflowing_pow(exp);
2601+
a
26492602
}
26502603

26512604
/// Calculates `self` + `rhs`.
@@ -3286,30 +3239,26 @@ macro_rules! uint_impl {
32863239
without modifying the original"]
32873240
#[inline]
32883241
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
3289-
if exp == 0{
3290-
return (1,false);
3242+
if exp == 0 {
3243+
return (1, false);
32913244
}
32923245
let mut base = self;
32933246
let mut acc: Self = 1;
3294-
let mut overflown = false;
3295-
// Scratch space for storing results of overflowing_mul.
3296-
let mut r;
3247+
let mut overflow = false;
3248+
let mut tmp_overflow;
32973249

32983250
loop {
32993251
if (exp & 1) == 1 {
3300-
r = acc.overflowing_mul(base);
3252+
(acc, tmp_overflow) = acc.overflowing_mul(base);
3253+
overflow |= tmp_overflow;
33013254
// since exp!=0, finally the exp must be 1.
33023255
if exp == 1 {
3303-
r.1 |= overflown;
3304-
return r;
3256+
return (acc, overflow);
33053257
}
3306-
acc = r.0;
3307-
overflown |= r.1;
33083258
}
33093259
exp /= 2;
3310-
r = base.overflowing_mul(base);
3311-
base = r.0;
3312-
overflown |= r.1;
3260+
(base, tmp_overflow) = base.overflowing_mul(base);
3261+
overflow |= tmp_overflow;
33133262
}
33143263
}
33153264

@@ -3327,43 +3276,11 @@ macro_rules! uint_impl {
33273276
without modifying the original"]
33283277
#[inline]
33293278
#[rustc_inherit_overflow_checks]
3330-
pub const fn pow(self, mut exp: u32) -> Self {
3331-
if exp == 0 {
3332-
return 1;
3333-
}
3334-
let mut base = self;
3335-
let mut acc = 1;
3336-
3337-
if intrinsics::is_val_statically_known(exp) {
3338-
while exp > 1 {
3339-
if (exp & 1) == 1 {
3340-
acc = acc * base;
3341-
}
3342-
exp /= 2;
3343-
base = base * base;
3344-
}
3345-
3346-
// since exp!=0, finally the exp must be 1.
3347-
// Deal with the final bit of the exponent separately, since
3348-
// squaring the base afterwards is not necessary and may cause a
3349-
// needless overflow.
3350-
acc * base
3279+
pub const fn pow(self, exp: u32) -> Self {
3280+
if intrinsics::overflow_checks() {
3281+
self.strict_pow(exp)
33513282
} else {
3352-
// This is faster than the above when the exponent is not known
3353-
// at compile time. We can't use the same code for the constant
3354-
// exponent case because LLVM is currently unable to unroll
3355-
// this loop.
3356-
loop {
3357-
if (exp & 1) == 1 {
3358-
acc = acc * base;
3359-
// since exp!=0, finally the exp must be 1.
3360-
if exp == 1 {
3361-
return acc;
3362-
}
3363-
}
3364-
exp /= 2;
3365-
base = base * base;
3366-
}
3283+
self.wrapping_pow(exp)
33673284
}
33683285
}
33693286

0 commit comments

Comments
 (0)