Skip to content

Commit

Permalink
optimize char::to_digit and assert radix is at least 2
Browse files Browse the repository at this point in the history
  • Loading branch information
programmerjake committed Nov 6, 2024
1 parent 116fc31 commit 58e383c
Showing 1 changed file with 31 additions and 13 deletions.
44 changes: 31 additions & 13 deletions library/core/src/char/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ impl char {
///
/// # Panics
///
/// Panics if given a radix larger than 36.
/// Panics if given a radix smaller than 2 or larger than 36.
///
/// # Examples
///
Expand All @@ -319,6 +319,13 @@ impl char {
/// // this panics
/// '1'.is_digit(37);
/// ```
///
/// Passing a small radix, causing a panic:
///
/// ```should_panic
/// // this panics
/// '1'.is_digit(1);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_char_classify", issue = "132241")]
#[inline]
Expand All @@ -345,7 +352,7 @@ impl char {
///
/// # Panics
///
/// Panics if given a radix larger than 36.
/// Panics if given a radix smaller than 2 or larger than 36.
///
/// # Examples
///
Expand All @@ -369,24 +376,35 @@ impl char {
/// // this panics
/// let _ = '1'.to_digit(37);
/// ```
/// Passing a small radix, causing a panic:
///
/// ```should_panic
/// // this panics
/// let _ = '1'.to_digit(1);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_digit(self, radix: u32) -> Option<u32> {
// If not a digit, a number greater than radix will be created.
let mut digit = (self as u32).wrapping_sub('0' as u32);
if radix > 10 {
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
if digit < 10 {
return Some(digit);
}
// Force the 6th bit to be set to ensure ascii is lower case.
digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10);
}
assert!(
radix >= 2 && radix <= 36,
"to_digit: invalid radix -- radix must be in the range 2 to 36 inclusive"
);
// check radix to remove letter handling code when radix is a known constant
let value = if self > '9' && radix > 10 {
// convert ASCII letters to lowercase
let lower = self as u32 | 0x20;
// convert an ASCII letter to the corresponding value,
// non-letters convert to values > 36
lower.wrapping_sub('a' as u32).saturating_add(10)
} else {
// convert digit to value, non-digits wrap to values > 36
(self as u32).wrapping_sub('0' as u32)
};
// FIXME(const-hack): once then_some is const fn, use it here
if digit < radix { Some(digit) } else { None }
if value < radix { Some(value) } else { None }
}

/// Returns an iterator that yields the hexadecimal Unicode escape of a
Expand Down

0 comments on commit 58e383c

Please sign in to comment.