about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-11-14 14:14:40 +0000
committerbors <bors@rust-lang.org>2024-11-14 14:14:40 +0000
commitc82e0dff84f922274c3060f09b5ae78d5dbf5c49 (patch)
treef700f6c195c0743b24fb963c01e3720468fafef3
parenta4cedecc9ec76b46dcbb954750068c832cf2dd43 (diff)
parentaeffff8ecf84a0a49ee597fb41729f8de9972592 (diff)
downloadrust-c82e0dff84f922274c3060f09b5ae78d5dbf5c49.tar.gz
rust-c82e0dff84f922274c3060f09b5ae78d5dbf5c49.zip
Auto merge of #132709 - programmerjake:optimize-charto_digit, r=joshtriplett
optimize char::to_digit and assert radix is at least 2

approved by t-libs: https://github.com/rust-lang/libs-team/issues/475#issuecomment-2457858458

let me know if this needs an assembly test or similar.
-rw-r--r--library/core/src/char/methods.rs44
1 files changed, 31 insertions, 13 deletions
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 6e79e79c143..974e7baccf7 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -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
     ///
@@ -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]
@@ -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
     ///
@@ -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) as u64 + 10
+        } else {
+            // convert digit to value, non-digits wrap to values > 36
+            (self as u32).wrapping_sub('0' as u32) as u64
+        };
         // FIXME(const-hack): once then_some is const fn, use it here
-        if digit < radix { Some(digit) } else { None }
+        if value < radix as u64 { Some(value as u32) } else { None }
     }
 
     /// Returns an iterator that yields the hexadecimal Unicode escape of a