]> git.lizzy.rs Git - rust.git/commitdiff
Avoid allocating when parsing \u{...} literals.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 18 Apr 2018 04:09:27 +0000 (14:09 +1000)
committerNicholas Nethercote <nnethercote@mozilla.com>
Wed, 18 Apr 2018 23:17:40 +0000 (09:17 +1000)
`char_lit` uses an allocation in order to ignore '_' chars in \u{...}
literals. This patch changes it to not do that by processing the chars
more directly.

This improves various rustc-perf benchmark measurements by up to 6%,
particularly regex, futures, clap, coercions, hyper, and encoding.

src/libsyntax/parse/mod.rs

index ff63c9a5c6d539ac1614011b5096a6aff631cc53..0397c3297db0a2e832295b1369432791c9bf123f 100644 (file)
@@ -271,8 +271,16 @@ pub fn char_lit(lit: &str, diag: Option<(Span, &Handler)>) -> (char, isize) {
         'u' => {
             assert_eq!(lit.as_bytes()[2], b'{');
             let idx = lit.find('}').unwrap();
-            let s = &lit[3..idx].chars().filter(|&c| c != '_').collect::<String>();
-            let v = u32::from_str_radix(&s, 16).unwrap();
+
+            // All digits and '_' are ascii, so treat each byte as a char.
+            let mut v: u32 = 0;
+            for c in lit[3..idx].bytes() {
+                let c = char::from(c);
+                if c != '_' {
+                    let x = c.to_digit(16).unwrap();
+                    v = v.checked_mul(16).unwrap().checked_add(x).unwrap();
+                }
+            }
             let c = char::from_u32(v).unwrap_or_else(|| {
                 if let Some((span, diag)) = diag {
                     let mut diag = diag.struct_span_err(span, "invalid unicode character escape");