From da5251fea337095d9cc7ebc175a2830e9ac0b443 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Wed, 24 Mar 2021 13:51:11 -0500 Subject: [PATCH 1/3] Add u8::to_digit and associated tests --- library/core/src/num/mod.rs | 65 +++++++++++++++++++++++++++++++++++++ library/core/tests/ascii.rs | 17 ++++++++++ library/core/tests/lib.rs | 1 + 3 files changed, 83 insertions(+) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 6032dc9a2d371..148b94a344bc1 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -687,6 +687,71 @@ 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: + /// + /// ``` + /// assert_eq!(b'1'.to_digit(10), Some(1)); + /// assert_eq!(b'f'.to_digit(16), Some(15)); + /// ``` + /// + /// Passing a non-digit results in failure: + /// + /// ``` + /// assert_eq!(b'f'.to_digit(10), None); + /// assert_eq!(b'z'.to_digit(16), None); + /// ``` + /// + /// Passing a large radix, causing a panic: + /// + /// ```should_panic + /// // this panics + /// b'1'.to_digit(37); + /// ``` + #[unstable(feature = "ascii_to_digit", issue = "none")] + #[inline] + pub fn to_digit(&self, radix: u32) -> Option { + assert!(radix <= 36, "to_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"] diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 66c25e449df2b..85ac8d28476b3 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -344,6 +344,23 @@ fn test_is_ascii_control() { ); } +#[cfg(not(bootstrap))] +#[test] +fn test_to_digit() { + assert_eq!(b'0'.to_digit(10), Some(0)); + assert_eq!(b'1'.to_digit(2), Some(1)); + assert_eq!(b'2'.to_digit(3), Some(2)); + assert_eq!(b'9'.to_digit(10), Some(9)); + assert_eq!(b'a'.to_digit(16), Some(10)); + assert_eq!(b'A'.to_digit(16), Some(10)); + assert_eq!(b'b'.to_digit(16), Some(11)); + assert_eq!(b'B'.to_digit(16), Some(11)); + assert_eq!(b'z'.to_digit(36), Some(35)); + assert_eq!(b'Z'.to_digit(36), Some(35)); + assert_eq!(b' '.to_digit(10), None); + assert_eq!(b'$'.to_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 diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index f6bfe67e1b12c..fc3f38009752c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -4,6 +4,7 @@ #![feature(array_methods)] #![feature(array_map)] #![feature(array_windows)] +#![cfg_attr(not(bootstrap), feature(ascii_to_digit))] #![feature(bool_to_option)] #![feature(bound_cloned)] #![feature(box_syntax)] From c416b7104a8e7ebab335ce4a8be9e389035d21a1 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Wed, 24 Mar 2021 16:54:31 -0500 Subject: [PATCH 2/3] Rename to to_ascii_digit_radix, add issue number --- library/core/src/num/mod.rs | 19 +++++++++++-------- library/core/tests/ascii.rs | 24 ++++++++++++------------ library/core/tests/lib.rs | 2 +- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 148b94a344bc1..93497341f2f64 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -714,27 +714,30 @@ impl u8 { /// Basic usage: /// /// ``` - /// assert_eq!(b'1'.to_digit(10), Some(1)); - /// assert_eq!(b'f'.to_digit(16), Some(15)); + /// #![feature(to_ascii_digit)] + /// assert_eq!(b'1'.to_ascii_digit_radix(10), Some(1)); + /// assert_eq!(b'f'.to_ascii_digit_radix(16), Some(15)); /// ``` /// /// Passing a non-digit results in failure: /// /// ``` - /// assert_eq!(b'f'.to_digit(10), None); - /// assert_eq!(b'z'.to_digit(16), None); + /// #![feature(to_ascii_digit)] + /// assert_eq!(b'f'.to_ascii_digit_radix(10), None); + /// assert_eq!(b'z'.to_ascii_digit_radix(16), None); /// ``` /// /// Passing a large radix, causing a panic: /// /// ```should_panic + /// #![feature(to_ascii_digit)] /// // this panics - /// b'1'.to_digit(37); + /// b'1'.to_ascii_digit_radix(37); /// ``` - #[unstable(feature = "ascii_to_digit", issue = "none")] + #[unstable(feature = "to_ascii_digit", issue = "83447")] #[inline] - pub fn to_digit(&self, radix: u32) -> Option { - assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); + pub fn to_ascii_digit_radix(&self, radix: u32) -> Option { + assert!(radix <= 36, "to_ascii_digit_radix: 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) { diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 85ac8d28476b3..577eda158f053 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -347,18 +347,18 @@ fn test_is_ascii_control() { #[cfg(not(bootstrap))] #[test] fn test_to_digit() { - assert_eq!(b'0'.to_digit(10), Some(0)); - assert_eq!(b'1'.to_digit(2), Some(1)); - assert_eq!(b'2'.to_digit(3), Some(2)); - assert_eq!(b'9'.to_digit(10), Some(9)); - assert_eq!(b'a'.to_digit(16), Some(10)); - assert_eq!(b'A'.to_digit(16), Some(10)); - assert_eq!(b'b'.to_digit(16), Some(11)); - assert_eq!(b'B'.to_digit(16), Some(11)); - assert_eq!(b'z'.to_digit(36), Some(35)); - assert_eq!(b'Z'.to_digit(36), Some(35)); - assert_eq!(b' '.to_digit(10), None); - assert_eq!(b'$'.to_digit(36), None); + assert_eq!(b'0'.to_ascii_digit_radix(10), Some(0)); + assert_eq!(b'1'.to_ascii_digit_radix(2), Some(1)); + assert_eq!(b'2'.to_ascii_digit_radix(3), Some(2)); + assert_eq!(b'9'.to_ascii_digit_radix(10), Some(9)); + assert_eq!(b'a'.to_ascii_digit_radix(16), Some(10)); + assert_eq!(b'A'.to_ascii_digit_radix(16), Some(10)); + assert_eq!(b'b'.to_ascii_digit_radix(16), Some(11)); + assert_eq!(b'B'.to_ascii_digit_radix(16), Some(11)); + assert_eq!(b'z'.to_ascii_digit_radix(36), Some(35)); + assert_eq!(b'Z'.to_ascii_digit_radix(36), Some(35)); + assert_eq!(b' '.to_ascii_digit_radix(10), None); + assert_eq!(b'$'.to_ascii_digit_radix(36), None); } // `is_ascii` does a good amount of pointer manipulation and has diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index fc3f38009752c..48de0c7c69021 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -4,7 +4,6 @@ #![feature(array_methods)] #![feature(array_map)] #![feature(array_windows)] -#![cfg_attr(not(bootstrap), feature(ascii_to_digit))] #![feature(bool_to_option)] #![feature(bound_cloned)] #![feature(box_syntax)] @@ -45,6 +44,7 @@ #![feature(step_trait_ext)] #![feature(str_internals)] #![feature(test)] +#![cfg_attr(not(bootstrap), feature(to_ascii_digit))] #![feature(trusted_len)] #![feature(try_trait)] #![feature(slice_internals)] From c1e214ac74e43b4197c1268a5078d06b00842f14 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Sun, 25 Apr 2021 13:21:12 -0500 Subject: [PATCH 3/3] Rename to parse_ascii_digit --- library/core/src/num/mod.rs | 22 +++++++++++----------- library/core/tests/ascii.rs | 24 ++++++++++++------------ library/core/tests/lib.rs | 2 +- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 93497341f2f64..cf53b29758ec0 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -714,30 +714,30 @@ impl u8 { /// Basic usage: /// /// ``` - /// #![feature(to_ascii_digit)] - /// assert_eq!(b'1'.to_ascii_digit_radix(10), Some(1)); - /// assert_eq!(b'f'.to_ascii_digit_radix(16), Some(15)); + /// #![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(to_ascii_digit)] - /// assert_eq!(b'f'.to_ascii_digit_radix(10), None); - /// assert_eq!(b'z'.to_ascii_digit_radix(16), None); + /// #![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(to_ascii_digit)] + /// #![feature(byte_parse_ascii_digit)] /// // this panics - /// b'1'.to_ascii_digit_radix(37); + /// b'1'.parse_ascii_digit(37); /// ``` - #[unstable(feature = "to_ascii_digit", issue = "83447")] + #[unstable(feature = "byte_parse_ascii_digit", issue = "83447")] #[inline] - pub fn to_ascii_digit_radix(&self, radix: u32) -> Option { - assert!(radix <= 36, "to_ascii_digit_radix: radix is too high (maximum 36)"); + pub fn parse_ascii_digit(&self, radix: u32) -> Option { + 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) { diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 577eda158f053..8c06848e0c2d2 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -347,18 +347,18 @@ fn test_is_ascii_control() { #[cfg(not(bootstrap))] #[test] fn test_to_digit() { - assert_eq!(b'0'.to_ascii_digit_radix(10), Some(0)); - assert_eq!(b'1'.to_ascii_digit_radix(2), Some(1)); - assert_eq!(b'2'.to_ascii_digit_radix(3), Some(2)); - assert_eq!(b'9'.to_ascii_digit_radix(10), Some(9)); - assert_eq!(b'a'.to_ascii_digit_radix(16), Some(10)); - assert_eq!(b'A'.to_ascii_digit_radix(16), Some(10)); - assert_eq!(b'b'.to_ascii_digit_radix(16), Some(11)); - assert_eq!(b'B'.to_ascii_digit_radix(16), Some(11)); - assert_eq!(b'z'.to_ascii_digit_radix(36), Some(35)); - assert_eq!(b'Z'.to_ascii_digit_radix(36), Some(35)); - assert_eq!(b' '.to_ascii_digit_radix(10), None); - assert_eq!(b'$'.to_ascii_digit_radix(36), None); + 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 diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 48de0c7c69021..4f1034f5586dd 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -44,7 +44,7 @@ #![feature(step_trait_ext)] #![feature(str_internals)] #![feature(test)] -#![cfg_attr(not(bootstrap), feature(to_ascii_digit))] +#![cfg_attr(not(bootstrap), feature(byte_parse_ascii_digit))] #![feature(trusted_len)] #![feature(try_trait)] #![feature(slice_internals)]