Skip to content

Commit b2bf646

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 134130f commit b2bf646

File tree

2 files changed

+26
-103
lines changed

2 files changed

+26
-103
lines changed

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)