@@ -1035,6 +1035,11 @@ macro_rules! impl_helper_for {
1035
1035
}
1036
1036
impl_helper_for ! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
1037
1037
1038
+ #[ inline( always) ]
1039
+ pub ( crate ) fn can_not_overflow < T > ( radix : u32 , is_signed_ty : bool , digits : & [ u8 ] ) -> bool {
1040
+ radix <= 16 && digits. len ( ) <= mem:: size_of :: < T > ( ) * 2 - is_signed_ty as usize
1041
+ }
1042
+
1038
1043
fn from_str_radix < T : FromStrRadixHelper > ( src : & str , radix : u32 ) -> Result < T , ParseIntError > {
1039
1044
use self :: IntErrorKind :: * ;
1040
1045
use self :: ParseIntError as PIE ;
@@ -1068,7 +1073,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
1068
1073
1069
1074
let mut result = T :: from_u32 ( 0 ) ;
1070
1075
1071
- if radix <= 16 && digits . len ( ) <= mem :: size_of :: < T > ( ) * 2 - is_signed_ty as usize {
1076
+ if can_not_overflow :: < T > ( radix , is_signed_ty, digits ) {
1072
1077
// SAFETY: If the len of the str is short compared to the range of the type
1073
1078
// we are parsing into, then we can be certain that an overflow will not occur.
1074
1079
// This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
@@ -1093,9 +1098,9 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
1093
1098
run_unchecked_loop ! ( unchecked_sub)
1094
1099
} ;
1095
1100
}
1096
- } else {
1101
+ } else {
1097
1102
macro_rules! run_checked_loop {
1098
- ( $checked_additive_op: ident, $overflow_err: ident ) => {
1103
+ ( $checked_additive_op: ident, $overflow_err: expr ) => {
1099
1104
for & c in digits {
1100
1105
// When `radix` is passed in as a literal, rather than doing a slow `imul`
1101
1106
// the compiler can use shifts if `radix` can be expressed as a
@@ -1110,17 +1115,23 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
1110
1115
let mul = result. checked_mul( radix) ;
1111
1116
let x = ( c as char ) . to_digit( radix) . ok_or( PIE { kind: InvalidDigit } ) ?;
1112
1117
result = mul. ok_or_else( $overflow_err) ?;
1113
- result = T :: $checked_additive_op( & result, x) . ok_or_else( $overflow_err) ?;
1118
+ result = T :: $checked_additive_op( & result, x) . ok_or_else( $overflow_err) ?;
1114
1119
}
1115
- }
1120
+ } ;
1116
1121
}
1117
1122
if is_positive {
1118
- let overflow_err = || PIE { kind : PosOverflow } ;
1119
- run_checked_loop ! ( checked_add, overflow_err)
1123
+ run_checked_loop ! ( checked_add, || PIE { kind: PosOverflow } )
1120
1124
} else {
1121
- let overflow_err = || PIE { kind : NegOverflow } ;
1122
- run_checked_loop ! ( checked_sub, overflow_err)
1125
+ run_checked_loop ! ( checked_sub, || PIE { kind: NegOverflow } )
1123
1126
} ;
1124
1127
}
1125
1128
Ok ( result)
1126
1129
}
1130
+
1131
+ mod tests {
1132
+ #[ test]
1133
+ fn test_can_not_overflow ( ) {
1134
+ assert_eq ! ( can_not_overflow:: <i8 >( 10 , true , "99" . as_bytes( ) ) , true ) ;
1135
+ assert_eq ! ( can_not_overflow:: <i8 >( 10 , true , "129" . as_bytes( ) ) , false ) ;
1136
+ }
1137
+ }
0 commit comments