/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lexical-util-1.0.7/src/digit.rs
Line | Count | Source |
1 | | //! Utilities to process digits. |
2 | | //! |
3 | | //! This both contains routines to convert to and from digits, |
4 | | //! as well as iterate over digits while skipping digit separators. |
5 | | |
6 | | // CONST FNS |
7 | | // --------- |
8 | | |
9 | | // These are optimized functions for when the radix is known at compile-time, |
10 | | // which is **most** of our cases. There are cases where for code generation, |
11 | | // using a runtime algorithm is preferable. |
12 | | |
13 | | /// Unchecked, highly optimized algorithm to convert a char to a digit. |
14 | | /// This only works if the input character is known to be a valid digit. |
15 | | #[inline(always)] |
16 | 30.9k | pub const fn char_to_valid_digit_const(c: u8, radix: u32) -> u32 { |
17 | 30.9k | if radix <= 10 { |
18 | | // Optimize for small radixes. |
19 | 30.9k | (c.wrapping_sub(b'0')) as u32 |
20 | | } else { |
21 | | // Fallback, still decently fast. |
22 | 0 | let digit = match c { |
23 | 0 | b'0'..=b'9' => c - b'0', |
24 | 0 | b'A'..=b'Z' => c - b'A' + 10, |
25 | 0 | b'a'..=b'z' => c - b'a' + 10, |
26 | 0 | _ => 0xFF, |
27 | | }; |
28 | 0 | digit as u32 |
29 | | } |
30 | 30.9k | } |
31 | | |
32 | | /// Convert a character to a digit with a radix known at compile time. |
33 | | /// |
34 | | /// This optimizes for cases where radix is <= 10, and uses a decent, |
35 | | /// match-based fallback algorithm. |
36 | | #[inline(always)] |
37 | 30.0k | pub const fn char_to_digit_const(c: u8, radix: u32) -> Option<u32> { |
38 | 30.0k | let digit = char_to_valid_digit_const(c, radix); |
39 | 30.0k | if digit < radix { |
40 | 29.3k | Some(digit) |
41 | | } else { |
42 | 686 | None |
43 | | } |
44 | 30.0k | } |
45 | | |
46 | | /// Determine if a character is a digit with a radix known at compile time. |
47 | | #[inline(always)] |
48 | 0 | pub const fn char_is_digit_const(c: u8, radix: u32) -> bool { |
49 | 0 | char_to_digit_const(c, radix).is_some() |
50 | 0 | } |
51 | | |
52 | | /// Convert a digit to a character with a radix known at compile time. |
53 | | /// |
54 | | /// This optimizes for cases where radix is <= 10, and uses a decent, |
55 | | /// match-based fallback algorithm. |
56 | | #[inline(always)] |
57 | | #[cfg(any(feature = "parse-floats", feature = "write-floats", feature = "write-integers"))] |
58 | 0 | pub const fn digit_to_char_const(digit: u32, radix: u32) -> u8 { |
59 | 0 | if radix <= 10 || digit < 10 { |
60 | | // Can short-circuit if we know the radix is small at compile time. |
61 | 0 | digit as u8 + b'0' |
62 | | } else { |
63 | 0 | digit as u8 + b'A' - 10 |
64 | | } |
65 | 0 | } |
66 | | |
67 | | // NON-CONST |
68 | | // --------- |
69 | | |
70 | | // These are less optimized functions for when the radix is not known at |
71 | | // compile-time, which is a few (but important) cases. These generally have |
72 | | // improved compiler optimization passes when generics are used more sparingly. |
73 | | |
74 | | /// Convert a character to a digit. |
75 | | #[inline(always)] |
76 | | #[cfg(any(feature = "parse-floats", feature = "parse-integers"))] |
77 | 0 | pub const fn char_to_digit(c: u8, radix: u32) -> Option<u32> { |
78 | | // Fallback, still decently fast. |
79 | 0 | let digit = match c { |
80 | 0 | b'0'..=b'9' => c - b'0', |
81 | 0 | b'A'..=b'Z' => c - b'A' + 10, |
82 | 0 | b'a'..=b'z' => c - b'a' + 10, |
83 | 0 | _ => 0xFF, |
84 | | } as u32; |
85 | 0 | if digit < radix { |
86 | 0 | Some(digit) |
87 | | } else { |
88 | 0 | None |
89 | | } |
90 | 0 | } |
91 | | |
92 | | /// Determine if a character is a digit. |
93 | | #[inline(always)] |
94 | | #[cfg(any(feature = "parse-floats", feature = "parse-integers"))] |
95 | 0 | pub const fn char_is_digit(c: u8, radix: u32) -> bool { |
96 | 0 | char_to_digit(c, radix).is_some() |
97 | 0 | } |
98 | | |
99 | | /// Convert a digit to a character. This uses a pre-computed table to avoid |
100 | | /// branching. |
101 | | /// |
102 | | /// # Panics |
103 | | /// |
104 | | /// Panics if `digit >= 36`. |
105 | | #[inline(always)] |
106 | | #[cfg(any(feature = "write-floats", feature = "write-integers"))] |
107 | | pub fn digit_to_char(digit: u32) -> u8 { |
108 | | const TABLE: [u8; 36] = [ |
109 | | b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', |
110 | | b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', |
111 | | b'U', b'V', b'W', b'X', b'Y', b'Z', |
112 | | ]; |
113 | | debug_assert!(digit < 36, "digit_to_char() invalid character."); |
114 | | TABLE[digit as usize] |
115 | | } |