Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add u8::parse_ascii_digit method #83447

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,74 @@ impl u8 {
pub fn escape_ascii(&self) -> ascii::EscapeDefault {
ascii::escape_default(*self)
}

/// Converts a value to a digit in the given radix.
///
/// A 'radix' here is sometimes also called a 'base'. A radix of two
/// indicates a binary number, a radix of ten, decimal, and a radix of
/// sixteen, hexadecimal, to give some common values. Arbitrary
/// radices are supported.
///
/// 'Digit' is defined to be only the following ASCII characters:
///
/// * `0-9`
/// * `a-z`
/// * `A-Z`
///
/// # Errors
///
/// Returns `None` if the value does not refer to a digit in the given radix.
///
/// # Panics
///
/// Panics if given a radix larger than 36.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(byte_parse_ascii_digit)]
/// assert_eq!(b'1'.parse_ascii_digit(10), Some(1));
/// assert_eq!(b'f'.parse_ascii_digit(16), Some(15));
/// ```
///
/// Passing a non-digit results in failure:
///
/// ```
/// #![feature(byte_parse_ascii_digit)]
/// assert_eq!(b'f'.parse_ascii_digit(10), None);
/// assert_eq!(b'z'.parse_ascii_digit(16), None);
/// ```
///
/// Passing a large radix, causing a panic:
///
/// ```should_panic
/// #![feature(byte_parse_ascii_digit)]
/// // this panics
/// b'1'.parse_ascii_digit(37);
/// ```
#[unstable(feature = "byte_parse_ascii_digit", issue = "83447")]
#[inline]
pub fn parse_ascii_digit(&self, radix: u32) -> Option<u32> {
assert!(radix <= 36, "parse_ascii_digit: radix is too high (maximum 36)");
// the code is split up here to improve execution speed for cases where
// the `radix` is constant and 10 or smaller
let val = if intrinsics::likely(radix <= 10) {
// If not a digit, a number greater than radix will be created.
self.wrapping_sub(b'0')
} else {
match self {
b'0'..=b'9' => self - b'0',
b'a'..=b'z' => self - b'a' + 10,
b'A'..=b'Z' => self - b'A' + 10,
_ => return None,
}
};
let val: u32 = val.into();

if val < radix { Some(val) } else { None }
}
}

#[lang = "u16"]
Expand Down
17 changes: 17 additions & 0 deletions library/core/tests/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,23 @@ fn test_is_ascii_control() {
);
}

#[cfg(not(bootstrap))]
#[test]
fn test_to_digit() {
assert_eq!(b'0'.parse_ascii_digit(10), Some(0));
assert_eq!(b'1'.parse_ascii_digit(2), Some(1));
assert_eq!(b'2'.parse_ascii_digit(3), Some(2));
assert_eq!(b'9'.parse_ascii_digit(10), Some(9));
assert_eq!(b'a'.parse_ascii_digit(16), Some(10));
assert_eq!(b'A'.parse_ascii_digit(16), Some(10));
assert_eq!(b'b'.parse_ascii_digit(16), Some(11));
assert_eq!(b'B'.parse_ascii_digit(16), Some(11));
assert_eq!(b'z'.parse_ascii_digit(36), Some(35));
assert_eq!(b'Z'.parse_ascii_digit(36), Some(35));
assert_eq!(b' '.parse_ascii_digit(10), None);
assert_eq!(b'$'.parse_ascii_digit(36), None);
}

// `is_ascii` does a good amount of pointer manipulation and has
// alignment-dependent computation. This is all sanity-checked via
// `debug_assert!`s, so we test various sizes/alignments thoroughly versus an
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#![feature(step_trait_ext)]
#![feature(str_internals)]
#![feature(test)]
#![cfg_attr(not(bootstrap), feature(byte_parse_ascii_digit))]
#![feature(trusted_len)]
#![feature(try_trait)]
#![feature(slice_internals)]
Expand Down