From 876142417cd03ee0838d2fc83ddac83c06748ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Wed, 9 Mar 2022 17:10:34 +0100 Subject: [PATCH 1/3] Optimize ascii::escape_default by using a digit LUT --- library/core/src/ascii.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index 532208e41afa2..20f2dd13d8fb4 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -98,15 +98,23 @@ pub fn escape_default(c: u8) -> EscapeDefault { b'\'' => ([b'\\', b'\'', 0, 0], 2), b'"' => ([b'\\', b'"', 0, 0], 2), b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1), - _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), + _ => { + let (b1, b2) = hexify(c); + ([b'\\', b'x', b1, b2], 4) + } }; return EscapeDefault { range: 0..len, data }; - fn hexify(b: u8) -> u8 { - match b { - 0..=9 => b'0' + b, - _ => b'a' + b - 10, + #[inline] + fn hexify(b: u8) -> (u8, u8) { + let hex_digits: &[u8; 16] = b"0123456789abcdef"; + // SAFETY: For all n: u8, n >> 4 < 16 and n & 0xf < 16 + unsafe { + ( + *hex_digits.get_unchecked((b >> 4) as usize), + *hex_digits.get_unchecked((b & 0xf) as usize), + ) } } } From 7f4f4fc34c5f404042e200c26ffb0395278d2cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Wed, 9 Mar 2022 22:21:35 +0100 Subject: [PATCH 2/3] Use indexing instead of .get_unchecked() for LUT lookup Based on @paolobarbolini's tip that the unsafe block was unnecessary in this case. Not much left of `hexify()` after this, so seemed clearer to just inline it. --- library/core/src/ascii.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index 20f2dd13d8fb4..6acaf7e8b89a5 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -99,24 +99,12 @@ pub fn escape_default(c: u8) -> EscapeDefault { b'"' => ([b'\\', b'"', 0, 0], 2), b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1), _ => { - let (b1, b2) = hexify(c); - ([b'\\', b'x', b1, b2], 4) + let hex_digits: &[u8; 16] = b"0123456789abcdef"; + ([b'\\', b'x', hex_digits[(c >> 4) as usize], hex_digits[(c & 0xf) as usize]], 4) } }; return EscapeDefault { range: 0..len, data }; - - #[inline] - fn hexify(b: u8) -> (u8, u8) { - let hex_digits: &[u8; 16] = b"0123456789abcdef"; - // SAFETY: For all n: u8, n >> 4 < 16 and n & 0xf < 16 - unsafe { - ( - *hex_digits.get_unchecked((b >> 4) as usize), - *hex_digits.get_unchecked((b & 0xf) as usize), - ) - } - } } #[stable(feature = "rust1", since = "1.0.0")] From c62ab422d06410772e364c61741376e10b39fff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Thu, 10 Mar 2022 15:35:22 +0100 Subject: [PATCH 3/3] Inline ::next --- library/core/src/ascii.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index 6acaf7e8b89a5..8a4cb78cc7f92 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -110,6 +110,8 @@ pub fn escape_default(c: u8) -> EscapeDefault { #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for EscapeDefault { type Item = u8; + + #[inline] fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i as usize]) }