Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4d1c7d9

Browse files
committedNov 7, 2024
optimize char::to_digit and assert radix is at least 2
approved by t-libs: rust-lang/libs-team#475 (comment)
1 parent 28f7e7b commit 4d1c7d9

File tree

1 file changed

+31
-13
lines changed

1 file changed

+31
-13
lines changed
 

‎core/src/char/methods.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ impl char {
301301
///
302302
/// # Panics
303303
///
304-
/// Panics if given a radix larger than 36.
304+
/// Panics if given a radix smaller than 2 or larger than 36.
305305
///
306306
/// # Examples
307307
///
@@ -319,6 +319,13 @@ impl char {
319319
/// // this panics
320320
/// '1'.is_digit(37);
321321
/// ```
322+
///
323+
/// Passing a small radix, causing a panic:
324+
///
325+
/// ```should_panic
326+
/// // this panics
327+
/// '1'.is_digit(1);
328+
/// ```
322329
#[stable(feature = "rust1", since = "1.0.0")]
323330
#[rustc_const_unstable(feature = "const_char_classify", issue = "132241")]
324331
#[inline]
@@ -345,7 +352,7 @@ impl char {
345352
///
346353
/// # Panics
347354
///
348-
/// Panics if given a radix larger than 36.
355+
/// Panics if given a radix smaller than 2 or larger than 36.
349356
///
350357
/// # Examples
351358
///
@@ -369,24 +376,35 @@ impl char {
369376
/// // this panics
370377
/// let _ = '1'.to_digit(37);
371378
/// ```
379+
/// Passing a small radix, causing a panic:
380+
///
381+
/// ```should_panic
382+
/// // this panics
383+
/// let _ = '1'.to_digit(1);
384+
/// ```
372385
#[stable(feature = "rust1", since = "1.0.0")]
373386
#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
374387
#[must_use = "this returns the result of the operation, \
375388
without modifying the original"]
376389
#[inline]
377390
pub const fn to_digit(self, radix: u32) -> Option<u32> {
378-
// If not a digit, a number greater than radix will be created.
379-
let mut digit = (self as u32).wrapping_sub('0' as u32);
380-
if radix > 10 {
381-
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
382-
if digit < 10 {
383-
return Some(digit);
384-
}
385-
// Force the 6th bit to be set to ensure ascii is lower case.
386-
digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10);
387-
}
391+
assert!(
392+
radix >= 2 && radix <= 36,
393+
"to_digit: invalid radix -- radix must be in the range 2 to 36 inclusive"
394+
);
395+
// check radix to remove letter handling code when radix is a known constant
396+
let value = if self > '9' && radix > 10 {
397+
// convert ASCII letters to lowercase
398+
let lower = self as u32 | 0x20;
399+
// convert an ASCII letter to the corresponding value,
400+
// non-letters convert to values > 36
401+
lower.wrapping_sub('a' as u32) as u64 + 10
402+
} else {
403+
// convert digit to value, non-digits wrap to values > 36
404+
(self as u32).wrapping_sub('0' as u32) as u64
405+
};
388406
// FIXME(const-hack): once then_some is const fn, use it here
389-
if digit < radix { Some(digit) } else { None }
407+
if value < radix as u64 { Some(value as u32) } else { None }
390408
}
391409

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

0 commit comments

Comments
 (0)
Failed to load comments.