@@ -6,7 +6,6 @@ use crate::ascii;
66use crate :: hint;
77use crate :: intrinsics;
88use crate :: mem;
9- use crate :: ops:: { Add , Mul , Sub } ;
109use crate :: str:: FromStr ;
1110
1211// Used because the `?` operator is not allowed in a const context.
@@ -1386,144 +1385,218 @@ pub enum FpCategory {
13861385 Normal ,
13871386}
13881387
1389- #[ doc( hidden) ]
1390- trait FromStrRadixHelper :
1391- PartialOrd + Copy + Add < Output = Self > + Sub < Output = Self > + Mul < Output = Self >
1392- {
1393- const MIN : Self ;
1394- fn from_u32 ( u : u32 ) -> Self ;
1395- fn checked_mul ( & self , other : u32 ) -> Option < Self > ;
1396- fn checked_sub ( & self , other : u32 ) -> Option < Self > ;
1397- fn checked_add ( & self , other : u32 ) -> Option < Self > ;
1398- }
1399-
14001388macro_rules! from_str_radix_int_impl {
14011389 ( $( $t: ty) * ) => { $(
14021390 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
14031391 impl FromStr for $t {
14041392 type Err = ParseIntError ;
14051393 fn from_str( src: & str ) -> Result <Self , ParseIntError > {
1406- from_str_radix( src, 10 )
1394+ <$t> :: from_str_radix( src, 10 )
14071395 }
14081396 }
14091397 ) * }
14101398}
14111399from_str_radix_int_impl ! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
14121400
1413- macro_rules! impl_helper_for {
1414- ( $( $t: ty) * ) => ( $( impl FromStrRadixHelper for $t {
1415- const MIN : Self = Self :: MIN ;
1416- #[ inline]
1417- fn from_u32( u: u32 ) -> Self { u as Self }
1418- #[ inline]
1419- fn checked_mul( & self , other: u32 ) -> Option <Self > {
1420- Self :: checked_mul( * self , other as Self )
1421- }
1422- #[ inline]
1423- fn checked_sub( & self , other: u32 ) -> Option <Self > {
1424- Self :: checked_sub( * self , other as Self )
1425- }
1426- #[ inline]
1427- fn checked_add( & self , other: u32 ) -> Option <Self > {
1428- Self :: checked_add( * self , other as Self )
1429- }
1430- } ) * )
1431- }
1432- impl_helper_for ! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
1433-
14341401/// Determines if a string of text of that length of that radix could be guaranteed to be
14351402/// stored in the given type T.
14361403/// Note that if the radix is known to the compiler, it is just the check of digits.len that
14371404/// is done at runtime.
14381405#[ doc( hidden) ]
14391406#[ inline( always) ]
14401407#[ unstable( issue = "none" , feature = "std_internals" ) ]
1441- pub fn can_not_overflow < T > ( radix : u32 , is_signed_ty : bool , digits : & [ u8 ] ) -> bool {
1408+ pub const fn can_not_overflow < T > ( radix : u32 , is_signed_ty : bool , digits : & [ u8 ] ) -> bool {
14421409 radix <= 16 && digits. len ( ) <= mem:: size_of :: < T > ( ) * 2 - is_signed_ty as usize
14431410}
14441411
1445- fn from_str_radix < T : FromStrRadixHelper > ( src : & str , radix : u32 ) -> Result < T , ParseIntError > {
1446- use self :: IntErrorKind :: * ;
1447- use self :: ParseIntError as PIE ;
1412+ #[ track_caller]
1413+ const fn from_str_radix_panic_ct ( _radix : u32 ) -> ! {
1414+ panic ! ( "from_str_radix_int: must lie in the range `[2, 36]`" ) ;
1415+ }
14481416
1449- assert ! (
1450- ( 2 ..=36 ) . contains( & radix) ,
1451- "from_str_radix_int: must lie in the range `[2, 36]` - found {}" ,
1452- radix
1453- ) ;
1417+ #[ track_caller]
1418+ fn from_str_radix_panic_rt ( radix : u32 ) -> ! {
1419+ panic ! ( "from_str_radix_int: must lie in the range `[2, 36]` - found {}" , radix) ;
1420+ }
14541421
1455- if src. is_empty ( ) {
1456- return Err ( PIE { kind : Empty } ) ;
1422+ #[ cfg_attr( not( feature = "panic_immediate_abort" ) , inline( never) ) ]
1423+ #[ cfg_attr( feature = "panic_immediate_abort" , inline) ]
1424+ #[ cold]
1425+ #[ track_caller]
1426+ const fn from_str_radix_assert ( radix : u32 ) {
1427+ if 2 > radix || radix > 36 {
1428+ // The only difference between these two functions is their panic message.
1429+ intrinsics:: const_eval_select ( ( radix, ) , from_str_radix_panic_ct, from_str_radix_panic_rt) ;
14571430 }
1431+ }
14581432
1459- let is_signed_ty = T :: from_u32 ( 0 ) > T :: MIN ;
1460-
1461- // all valid digits are ascii, so we will just iterate over the utf8 bytes
1462- // and cast them to chars. .to_digit() will safely return None for anything
1463- // other than a valid ascii digit for the given radix, including the first-byte
1464- // of multi-byte sequences
1465- let src = src. as_bytes ( ) ;
1433+ macro_rules! from_str_radix {
1434+ ( $( $int_ty: ty) +) => { $(
1435+ impl $int_ty {
1436+ /// Converts a string slice in a given base to an integer.
1437+ ///
1438+ /// The string is expected to be an optional `+` sign
1439+ /// followed by digits.
1440+ /// Leading and trailing whitespace represent an error.
1441+ /// Digits are a subset of these characters, depending on `radix`:
1442+ ///
1443+ /// * `0-9`
1444+ /// * `a-z`
1445+ /// * `A-Z`
1446+ ///
1447+ /// # Panics
1448+ ///
1449+ /// This function panics if `radix` is not in the range from 2 to 36.
1450+ ///
1451+ /// # Examples
1452+ ///
1453+ /// Basic usage:
1454+ ///
1455+ /// ```
1456+ #[ doc = concat!( "assert_eq!(" , stringify!( $int_ty) , "::from_str_radix(\" A\" , 16), Ok(10));" ) ]
1457+ /// ```
1458+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1459+ #[ rustc_const_unstable( feature = "const_int_from_str" , issue = "59133" ) ]
1460+ pub const fn from_str_radix( src: & str , radix: u32 ) -> Result <$int_ty, ParseIntError > {
1461+ use self :: IntErrorKind :: * ;
1462+ use self :: ParseIntError as PIE ;
1463+
1464+ from_str_radix_assert( radix) ;
1465+
1466+ if src. is_empty( ) {
1467+ return Err ( PIE { kind: Empty } ) ;
1468+ }
14661469
1467- let ( is_positive, digits) = match src[ 0 ] {
1468- b'+' | b'-' if src[ 1 ..] . is_empty ( ) => {
1469- return Err ( PIE { kind : InvalidDigit } ) ;
1470- }
1471- b'+' => ( true , & src[ 1 ..] ) ,
1472- b'-' if is_signed_ty => ( false , & src[ 1 ..] ) ,
1473- _ => ( true , src) ,
1474- } ;
1470+ #[ allow( unused_comparisons) ]
1471+ let is_signed_ty = 0 > <$int_ty>:: MIN ;
1472+
1473+ // all valid digits are ascii, so we will just iterate over the utf8 bytes
1474+ // and cast them to chars. .to_digit() will safely return None for anything
1475+ // other than a valid ascii digit for the given radix, including the first-byte
1476+ // of multi-byte sequences
1477+ let src = src. as_bytes( ) ;
1478+
1479+ let ( is_positive, mut digits) = match src {
1480+ [ b'+' | b'-' ] => {
1481+ return Err ( PIE { kind: InvalidDigit } ) ;
1482+ }
1483+ [ b'+' , rest @ ..] => ( true , rest) ,
1484+ [ b'-' , rest @ ..] if is_signed_ty => ( false , rest) ,
1485+ _ => ( true , src) ,
1486+ } ;
1487+
1488+ let mut result = 0 ;
1489+
1490+ macro_rules! unwrap_or_PIE {
1491+ ( $option: expr, $kind: ident) => {
1492+ match $option {
1493+ Some ( value) => value,
1494+ None => return Err ( PIE { kind: $kind } ) ,
1495+ }
1496+ } ;
1497+ }
14751498
1476- let mut result = T :: from_u32 ( 0 ) ;
1477-
1478- if can_not_overflow :: < T > ( radix, is_signed_ty, digits) {
1479- // If the len of the str is short compared to the range of the type
1480- // we are parsing into, then we can be certain that an overflow will not occur.
1481- // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
1482- // above is a faster (conservative) approximation of this.
1483- //
1484- // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
1485- // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
1486- // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
1487- macro_rules! run_unchecked_loop {
1488- ( $unchecked_additive_op: expr) => {
1489- for & c in digits {
1490- result = result * T :: from_u32( radix) ;
1491- let x = ( c as char ) . to_digit( radix) . ok_or( PIE { kind: InvalidDigit } ) ?;
1492- result = $unchecked_additive_op( result, T :: from_u32( x) ) ;
1499+ if can_not_overflow:: <$int_ty>( radix, is_signed_ty, digits) {
1500+ // If the len of the str is short compared to the range of the type
1501+ // we are parsing into, then we can be certain that an overflow will not occur.
1502+ // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
1503+ // above is a faster (conservative) approximation of this.
1504+ //
1505+ // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
1506+ // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
1507+ // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
1508+ macro_rules! run_unchecked_loop {
1509+ ( $unchecked_additive_op: tt) => { {
1510+ while let [ c, rest @ ..] = digits {
1511+ result = result * ( radix as $int_ty) ;
1512+ let x = unwrap_or_PIE!( ( * c as char ) . to_digit( radix) , InvalidDigit ) ;
1513+ result = result $unchecked_additive_op ( x as $int_ty) ;
1514+ digits = rest;
1515+ }
1516+ } } ;
1517+ }
1518+ if is_positive {
1519+ run_unchecked_loop!( +)
1520+ } else {
1521+ run_unchecked_loop!( -)
1522+ } ;
1523+ } else {
1524+ macro_rules! run_checked_loop {
1525+ ( $checked_additive_op: ident, $overflow_err: ident) => { {
1526+ while let [ c, rest @ ..] = digits {
1527+ // When `radix` is passed in as a literal, rather than doing a slow `imul`
1528+ // the compiler can use shifts if `radix` can be expressed as a
1529+ // sum of powers of 2 (x*10 can be written as x*8 + x*2).
1530+ // When the compiler can't use these optimisations,
1531+ // the latency of the multiplication can be hidden by issuing it
1532+ // before the result is needed to improve performance on
1533+ // modern out-of-order CPU as multiplication here is slower
1534+ // than the other instructions, we can get the end result faster
1535+ // doing multiplication first and let the CPU spends other cycles
1536+ // doing other computation and get multiplication result later.
1537+ let mul = result. checked_mul( radix as $int_ty) ;
1538+ let x = unwrap_or_PIE!( ( * c as char ) . to_digit( radix) , InvalidDigit ) as $int_ty;
1539+ result = unwrap_or_PIE!( mul, $overflow_err) ;
1540+ result = unwrap_or_PIE!( <$int_ty>:: $checked_additive_op( result, x) , $overflow_err) ;
1541+ digits = rest;
1542+ }
1543+ } } ;
1544+ }
1545+ if is_positive {
1546+ run_checked_loop!( checked_add, PosOverflow )
1547+ } else {
1548+ run_checked_loop!( checked_sub, NegOverflow )
1549+ } ;
14931550 }
1494- } ;
1551+ Ok ( result)
1552+ }
14951553 }
1496- if is_positive {
1497- run_unchecked_loop ! ( <T as core:: ops:: Add >:: add)
1498- } else {
1499- run_unchecked_loop ! ( <T as core:: ops:: Sub >:: sub)
1500- } ;
1501- } else {
1502- macro_rules! run_checked_loop {
1503- ( $checked_additive_op: ident, $overflow_err: expr) => {
1504- for & c in digits {
1505- // When `radix` is passed in as a literal, rather than doing a slow `imul`
1506- // the compiler can use shifts if `radix` can be expressed as a
1507- // sum of powers of 2 (x*10 can be written as x*8 + x*2).
1508- // When the compiler can't use these optimisations,
1509- // the latency of the multiplication can be hidden by issuing it
1510- // before the result is needed to improve performance on
1511- // modern out-of-order CPU as multiplication here is slower
1512- // than the other instructions, we can get the end result faster
1513- // doing multiplication first and let the CPU spends other cycles
1514- // doing other computation and get multiplication result later.
1515- let mul = result. checked_mul( radix) ;
1516- let x = ( c as char ) . to_digit( radix) . ok_or( PIE { kind: InvalidDigit } ) ?;
1517- result = mul. ok_or_else( $overflow_err) ?;
1518- result = T :: $checked_additive_op( & result, x) . ok_or_else( $overflow_err) ?;
1519- }
1520- } ;
1554+ ) +}
1555+ }
1556+
1557+ from_str_radix ! { i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 }
1558+
1559+ // Re-use the relevant implementation of from_str_radix for isize and usize to avoid outputting two
1560+ // identical functions.
1561+ macro_rules! from_str_radix_size_impl {
1562+ ( $( $t: ident $size: ty) ,* ) => { $(
1563+ impl $size {
1564+ /// Converts a string slice in a given base to an integer.
1565+ ///
1566+ /// The string is expected to be an optional `+` sign
1567+ /// followed by digits.
1568+ /// Leading and trailing whitespace represent an error.
1569+ /// Digits are a subset of these characters, depending on `radix`:
1570+ ///
1571+ /// * `0-9`
1572+ /// * `a-z`
1573+ /// * `A-Z`
1574+ ///
1575+ /// # Panics
1576+ ///
1577+ /// This function panics if `radix` is not in the range from 2 to 36.
1578+ ///
1579+ /// # Examples
1580+ ///
1581+ /// Basic usage:
1582+ ///
1583+ /// ```
1584+ #[ doc = concat!( "assert_eq!(" , stringify!( $size) , "::from_str_radix(\" A\" , 16), Ok(10));" ) ]
1585+ /// ```
1586+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1587+ #[ rustc_const_unstable( feature = "const_int_from_str" , issue = "59133" ) ]
1588+ pub const fn from_str_radix( src: & str , radix: u32 ) -> Result <$size, ParseIntError > {
1589+ match <$t>:: from_str_radix( src, radix) {
1590+ Ok ( x) => Ok ( x as $size) ,
1591+ Err ( e) => Err ( e) ,
1592+ }
15211593 }
1522- if is_positive {
1523- run_checked_loop ! ( checked_add, || PIE { kind: PosOverflow } )
1524- } else {
1525- run_checked_loop ! ( checked_sub, || PIE { kind: NegOverflow } )
1526- } ;
1527- }
1528- Ok ( result)
1594+ } ) * }
15291595}
1596+
1597+ #[ cfg( target_pointer_width = "16" ) ]
1598+ from_str_radix_size_impl ! { i16 isize , u16 usize }
1599+ #[ cfg( target_pointer_width = "32" ) ]
1600+ from_str_radix_size_impl ! { i32 isize , u32 usize }
1601+ #[ cfg( target_pointer_width = "64" ) ]
1602+ from_str_radix_size_impl ! { i64 isize , u64 usize }
0 commit comments