@@ -970,12 +970,14 @@ pub enum FpCategory {
970970
971971#[ doc( hidden) ]
972972trait FromStrRadixHelper : PartialOrd + Copy {
973- fn min_value ( ) -> Self ;
974- fn max_value ( ) -> Self ;
973+ const MIN : Self ;
975974 fn from_u32 ( u : u32 ) -> Self ;
976975 fn checked_mul ( & self , other : u32 ) -> Option < Self > ;
977976 fn checked_sub ( & self , other : u32 ) -> Option < Self > ;
978977 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 ;
979981}
980982
981983macro_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 }
993995
994996macro_rules! doit {
995997 ( $( $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 ;
1000999 #[ inline]
10011000 fn from_u32( u: u32 ) -> Self { u as Self }
10021001 #[ inline]
@@ -1011,6 +1010,27 @@ macro_rules! doit {
10111010 fn checked_add( & self , other: u32 ) -> Option <Self > {
10121011 Self :: checked_add( * self , other as Self )
10131012 }
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+ }
10141034 } ) * )
10151035}
10161036doit ! { 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
10291049 return Err ( PIE { kind : Empty } ) ;
10301050 }
10311051
1032- let is_signed_ty = T :: from_u32 ( 0 ) > T :: min_value ( ) ;
1052+ let is_signed_ty = T :: from_u32 ( 0 ) > T :: MIN ;
10331053
10341054 // all valid digits are ascii, so we will just iterate over the utf8 bytes
10351055 // 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
10471067 } ;
10481068
10491069 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+ }
10651085 }
10661086 } 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+
10681090 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) ?;
10811096 }
10821097 }
10831098 Ok ( result)
0 commit comments