diff options
| author | Joshua Nelson <jyn514@gmail.com> | 2021-03-06 23:30:49 -0500 |
|---|---|---|
| committer | Joshua Nelson <jyn514@gmail.com> | 2021-03-07 10:18:06 -0500 |
| commit | 1e6d8495ba63255407ebea058f2194b65ccc307d (patch) | |
| tree | 9b3d0ede61c646a66783d8497fe51162b58287e8 | |
| parent | edeee915b1c52f97411e57ef6b1a8bd46548a37a (diff) | |
| download | rust-1e6d8495ba63255407ebea058f2194b65ccc307d.tar.gz rust-1e6d8495ba63255407ebea058f2194b65ccc307d.zip | |
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.
| -rw-r--r-- | src/librustdoc/html/format.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/html/render/mod.rs | 44 |
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 4e762a40f08..375cf1d0c8f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2999,18 +2999,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) @@ -3018,17 +3025,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()), |
