@@ -970,12 +970,14 @@ pub enum FpCategory {
970
970
971
971
#[ doc( hidden) ]
972
972
trait FromStrRadixHelper : PartialOrd + Copy {
973
- fn min_value ( ) -> Self ;
974
- fn max_value ( ) -> Self ;
973
+ const MIN : Self ;
975
974
fn from_u32 ( u : u32 ) -> Self ;
976
975
fn checked_mul ( & self , other : u32 ) -> Option < Self > ;
977
976
fn checked_sub ( & self , other : u32 ) -> Option < Self > ;
978
977
fn checked_add ( & self , other : u32 ) -> Option < Self > ;
978
+ unsafe fn unchecked_mul ( & self , other : u32 ) -> Self ;
979
+ unsafe fn unchecked_sub ( & self , other : u32 ) -> Self ;
980
+ unsafe fn unchecked_add ( & self , other : u32 ) -> Self ;
979
981
}
980
982
981
983
macro_rules! from_str_radix_int_impl {
@@ -993,10 +995,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
993
995
994
996
macro_rules! doit {
995
997
( $( $t: ty) * ) => ( $( impl FromStrRadixHelper for $t {
996
- #[ inline]
997
- fn min_value( ) -> Self { Self :: MIN }
998
- #[ inline]
999
- fn max_value( ) -> Self { Self :: MAX }
998
+ const MIN : Self = Self :: MIN ;
1000
999
#[ inline]
1001
1000
fn from_u32( u: u32 ) -> Self { u as Self }
1002
1001
#[ inline]
@@ -1011,6 +1010,27 @@ macro_rules! doit {
1011
1010
fn checked_add( & self , other: u32 ) -> Option <Self > {
1012
1011
Self :: checked_add( * self , other as Self )
1013
1012
}
1013
+ #[ inline]
1014
+ unsafe fn unchecked_mul( & self , other: u32 ) -> Self {
1015
+ // SAFETY: Conditions of `Self::unchecked_mul` must be upheld by the caller.
1016
+ unsafe {
1017
+ Self :: unchecked_mul( * self , other as Self )
1018
+ }
1019
+ }
1020
+ #[ inline]
1021
+ unsafe fn unchecked_sub( & self , other: u32 ) -> Self {
1022
+ // SAFETY: Conditions of `Self::unchecked_sub` must be upheld by the caller.
1023
+ unsafe {
1024
+ Self :: unchecked_sub( * self , other as Self )
1025
+ }
1026
+ }
1027
+ #[ inline]
1028
+ unsafe fn unchecked_add( & self , other: u32 ) -> Self {
1029
+ // SAFETY: Conditions of `Self::unchecked_add` must be upheld by the caller.
1030
+ unsafe {
1031
+ Self :: unchecked_add( * self , other as Self )
1032
+ }
1033
+ }
1014
1034
} ) * )
1015
1035
}
1016
1036
doit ! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
@@ -1029,7 +1049,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
1029
1049
return Err ( PIE { kind : Empty } ) ;
1030
1050
}
1031
1051
1032
- let is_signed_ty = T :: from_u32 ( 0 ) > T :: min_value ( ) ;
1052
+ let is_signed_ty = T :: from_u32 ( 0 ) > T :: MIN ;
1033
1053
1034
1054
// all valid digits are ascii, so we will just iterate over the utf8 bytes
1035
1055
// and cast them to chars. .to_digit() will safely return None for anything
@@ -1047,37 +1067,32 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
1047
1067
} ;
1048
1068
1049
1069
let mut result = T :: from_u32 ( 0 ) ;
1050
- if is_positive {
1051
- // The number is positive
1052
- for & c in digits {
1053
- let x = match ( c as char ) . to_digit ( radix ) {
1054
- Some ( x ) => x ,
1055
- None => return Err ( PIE { kind : InvalidDigit } ) ,
1056
- } ;
1057
- result = match result . checked_mul ( radix ) {
1058
- Some ( result ) => result ,
1059
- None => return Err ( PIE { kind : PosOverflow } ) ,
1060
- } ;
1061
- result = match result. checked_add ( x ) {
1062
- Some ( result ) => result ,
1063
- None => return Err ( PIE { kind : PosOverflow } ) ,
1064
- } ;
1070
+
1071
+ if radix <= 16 && digits . len ( ) <= mem :: size_of :: < T > ( ) * 2 - is_signed_ty as usize {
1072
+ // SAFETY: Consider the highest radix of 16:
1073
+ // `u8::MAX` is `ff` (2 characters), `u16::MAX` is `ffff` (4 characters)
1074
+ // We can be sure that any src len of 2 would fit in a u8 so we don't need
1075
+ // to check for overflow.
1076
+ unsafe {
1077
+ let unchecked_additive_op =
1078
+ if is_positive { T :: unchecked_add } else { T :: unchecked_sub } ;
1079
+
1080
+ for & c in digits {
1081
+ result = result. unchecked_mul ( radix ) ;
1082
+ let x = ( c as char ) . to_digit ( radix ) . ok_or ( PIE { kind : InvalidDigit } ) ? ;
1083
+ result = unchecked_additive_op ( & result , x ) ;
1084
+ }
1065
1085
}
1066
1086
} else {
1067
- // The number is negative
1087
+ let additive_op = if is_positive { T :: checked_add } else { T :: checked_sub } ;
1088
+ let overflow_err = || PIE { kind : if is_positive { PosOverflow } else { NegOverflow } } ;
1089
+
1068
1090
for & c in digits {
1069
- let x = match ( c as char ) . to_digit ( radix) {
1070
- Some ( x) => x,
1071
- None => return Err ( PIE { kind : InvalidDigit } ) ,
1072
- } ;
1073
- result = match result. checked_mul ( radix) {
1074
- Some ( result) => result,
1075
- None => return Err ( PIE { kind : NegOverflow } ) ,
1076
- } ;
1077
- result = match result. checked_sub ( x) {
1078
- Some ( result) => result,
1079
- None => return Err ( PIE { kind : NegOverflow } ) ,
1080
- } ;
1091
+ let mul = result. checked_mul ( radix) ;
1092
+ let x = ( c as char ) . to_digit ( radix) . ok_or ( PIE { kind : InvalidDigit } ) ?;
1093
+ // multiply done early for performance reasons.
1094
+ result = mul. ok_or_else ( overflow_err) ?;
1095
+ result = additive_op ( & result, x) . ok_or_else ( overflow_err) ?;
1081
1096
}
1082
1097
}
1083
1098
Ok ( result)
0 commit comments