1
Fork 0

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
This commit is contained in:
bors 2021-03-22 06:45:33 +00:00
commit 2b8fbe6b0b
2 changed files with 30 additions and 18 deletions

View file

@ -105,6 +105,10 @@ impl Buffer {
crate fn is_for_html(&self) -> bool { crate fn is_for_html(&self) -> bool {
self.for_html self.for_html
} }
crate fn reserve(&mut self, additional: usize) {
self.buffer.reserve(additional)
}
} }
/// Wrapper struct for properly emitting a function or method declaration. /// Wrapper struct for properly emitting a function or method declaration.

View file

@ -1009,18 +1009,25 @@ fn render_assoc_item(
href(did, cx.cache()).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor) href(did, cx.cache()).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
} }
}; };
let mut header_len = format!( let tcx = cx.tcx();
"{}{}{}{}{}{:#}fn {}{:#}", let vis = meth.visibility.print_with_space(tcx, meth.def_id, cx.cache()).to_string();
meth.visibility.print_with_space(cx.tcx(), meth.def_id, cx.cache()), let constness = header.constness.print_with_space();
header.constness.print_with_space(), let asyncness = header.asyncness.print_with_space();
header.asyncness.print_with_space(), let unsafety = header.unsafety.print_with_space();
header.unsafety.print_with_space(), let defaultness = print_default_space(meth.is_default());
print_default_space(meth.is_default()), let abi = print_abi_with_space(header.abi).to_string();
print_abi_with_space(header.abi), // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
name, let generics_len = format!("{:#}", g.print(cx.cache())).len();
g.print(cx.cache()) let mut header_len = "fn ".len()
) + vis.len()
.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 { let (indent, end_newline) = if parent == ItemType::Trait {
header_len += 4; header_len += 4;
(4, false) (4, false)
@ -1028,17 +1035,18 @@ fn render_assoc_item(
(0, true) (0, true)
}; };
render_attributes(w, meth, false); render_attributes(w, meth, false);
w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
write!( write!(
w, w,
"{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\ "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
{generics}{decl}{spotlight}{where_clause}", {generics}{decl}{spotlight}{where_clause}",
if parent == ItemType::Trait { " " } else { "" }, if parent == ItemType::Trait { " " } else { "" },
meth.visibility.print_with_space(cx.tcx(), meth.def_id, cx.cache()), vis,
header.constness.print_with_space(), constness,
header.asyncness.print_with_space(), asyncness,
header.unsafety.print_with_space(), unsafety,
print_default_space(meth.is_default()), defaultness,
print_abi_with_space(header.abi), abi,
href = href, href = href,
name = name, name = name,
generics = g.print(cx.cache()), generics = g.print(cx.cache()),