about summary refs log tree commit diff
path: root/src/librustdoc/html
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-03-22 06:45:33 +0000
committerbors <bors@rust-lang.org>2021-03-22 06:45:33 +0000
commit2b8fbe6b0b6db7960828bd2c9a50e52c9a5d0aef (patch)
tree92d9b94cd437e9e7ca01080b10e87d0475444cfb /src/librustdoc/html
parent142c831861ba5a995fd9de99198e7f6074b6b400 (diff)
parent1e6d8495ba63255407ebea058f2194b65ccc307d (diff)
downloadrust-2b8fbe6b0b6db7960828bd2c9a50e52c9a5d0aef.tar.gz
rust-2b8fbe6b0b6db7960828bd2c9a50e52c9a5d0aef.zip
Auto merge of #82855 - jyn514:no-temporaries, r=GuillaumeGomez
Avoid temporary allocations in `render_assoc_item`

`render_assoc_item` came up as very hot in a profile of rustdoc on
`bevy`.  This avoids some temporary allocations just to calculate the
length of the header.

This should be a strict improvement, since all string formatting was
done twice before.

cc #82845
Diffstat (limited to 'src/librustdoc/html')
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs44
2 files changed, 30 insertions, 18 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index bea0e75832c..60106f3b7ae 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -105,6 +105,10 @@ impl Buffer {
     crate fn is_for_html(&self) -> bool {
         self.for_html
     }
+
+    crate fn reserve(&mut self, additional: usize) {
+        self.buffer.reserve(additional)
+    }
 }
 
 /// Wrapper struct for properly emitting a function or method declaration.
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 66c47f14655..128eac8cb0a 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1009,18 +1009,25 @@ fn render_assoc_item(
                 href(did, cx.cache()).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
             }
         };
-        let mut header_len = format!(
-            "{}{}{}{}{}{:#}fn {}{:#}",
-            meth.visibility.print_with_space(cx.tcx(), meth.def_id, cx.cache()),
-            header.constness.print_with_space(),
-            header.asyncness.print_with_space(),
-            header.unsafety.print_with_space(),
-            print_default_space(meth.is_default()),
-            print_abi_with_space(header.abi),
-            name,
-            g.print(cx.cache())
-        )
-        .len();
+        let tcx = cx.tcx();
+        let vis = meth.visibility.print_with_space(tcx, meth.def_id, cx.cache()).to_string();
+        let constness = header.constness.print_with_space();
+        let asyncness = header.asyncness.print_with_space();
+        let unsafety = header.unsafety.print_with_space();
+        let defaultness = print_default_space(meth.is_default());
+        let abi = print_abi_with_space(header.abi).to_string();
+        // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
+        let generics_len = format!("{:#}", g.print(cx.cache())).len();
+        let mut header_len = "fn ".len()
+            + vis.len()
+            + constness.len()
+            + asyncness.len()
+            + unsafety.len()
+            + defaultness.len()
+            + abi.len()
+            + name.as_str().len()
+            + generics_len;
+
         let (indent, end_newline) = if parent == ItemType::Trait {
             header_len += 4;
             (4, false)
@@ -1028,17 +1035,18 @@ fn render_assoc_item(
             (0, true)
         };
         render_attributes(w, meth, false);
+        w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
         write!(
             w,
             "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
              {generics}{decl}{spotlight}{where_clause}",
             if parent == ItemType::Trait { "    " } else { "" },
-            meth.visibility.print_with_space(cx.tcx(), meth.def_id, cx.cache()),
-            header.constness.print_with_space(),
-            header.asyncness.print_with_space(),
-            header.unsafety.print_with_space(),
-            print_default_space(meth.is_default()),
-            print_abi_with_space(header.abi),
+            vis,
+            constness,
+            asyncness,
+            unsafety,
+            defaultness,
+            abi,
             href = href,
             name = name,
             generics = g.print(cx.cache()),