@@ -6,7 +6,6 @@ use crate::ascii;
6
6
use crate :: hint;
7
7
use crate :: intrinsics;
8
8
use crate :: mem;
9
- use crate :: ops:: { Add , Mul , Sub } ;
10
9
use crate :: str:: FromStr ;
11
10
12
11
// Used because the `?` operator is not allowed in a const context.
@@ -1386,144 +1385,218 @@ pub enum FpCategory {
1386
1385
Normal ,
1387
1386
}
1388
1387
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
-
1400
1388
macro_rules! from_str_radix_int_impl {
1401
1389
( $( $t: ty) * ) => { $(
1402
1390
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1403
1391
impl FromStr for $t {
1404
1392
type Err = ParseIntError ;
1405
1393
fn from_str( src: & str ) -> Result <Self , ParseIntError > {
1406
- from_str_radix( src, 10 )
1394
+ <$t> :: from_str_radix( src, 10 )
1407
1395
}
1408
1396
}
1409
1397
) * }
1410
1398
}
1411
1399
from_str_radix_int_impl ! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
1412
1400
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
-
1434
1401
/// Determines if a string of text of that length of that radix could be guaranteed to be
1435
1402
/// stored in the given type T.
1436
1403
/// Note that if the radix is known to the compiler, it is just the check of digits.len that
1437
1404
/// is done at runtime.
1438
1405
#[ doc( hidden) ]
1439
1406
#[ inline( always) ]
1440
1407
#[ 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 {
1442
1409
radix <= 16 && digits. len ( ) <= mem:: size_of :: < T > ( ) * 2 - is_signed_ty as usize
1443
1410
}
1444
1411
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
+ }
1448
1416
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
+ }
1454
1421
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) ;
1457
1430
}
1431
+ }
1458
1432
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
+ }
1466
1469
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
+ }
1475
1498
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
+ } ;
1493
1550
}
1494
- } ;
1551
+ Ok ( result)
1552
+ }
1495
1553
}
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
+ }
1521
1593
}
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
+ } ) * }
1529
1595
}
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