Skip to content

Commit

Permalink
Use Cow in Token::String.
Browse files Browse the repository at this point in the history
`Printer::word` takes a `&str` and converts it into a `String`, which
causes an allocation. But that allocation is rarely necessary, because
`&str` is almost always a `&'static str` or a `String` that won't be
used again.

This commit changes `Token::String` so it holds a `Cow<'static, str>`
instead of a `String`, which avoids a lot of allocations.
  • Loading branch information
nnethercote committed Nov 29, 2018
1 parent deb9195 commit 787959c
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 88 deletions.
61 changes: 32 additions & 29 deletions src/librustc/hir/print.rs
Expand Up @@ -25,6 +25,7 @@ use hir;
use hir::{PatKind, GenericBound, TraitBoundModifier, RangeEnd};
use hir::{GenericParam, GenericParamKind, GenericArg};

use std::borrow::Cow;
use std::cell::Cell;
use std::io::{self, Write, Read};
use std::iter::Peekable;
Expand Down Expand Up @@ -209,7 +210,7 @@ pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
String::from_utf8(wr).unwrap()
}

pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String {
pub fn visibility_qualified<S: Into<Cow<'static, str>>>(vis: &hir::Visibility, w: S) -> String {
to_string(NO_ANN, |s| {
s.print_visibility(vis)?;
s.s.word(w)
Expand All @@ -226,12 +227,13 @@ impl<'a> State<'a> {
self.s.word(" ")
}

pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
pub fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) -> io::Result<()> {
self.s.word(w)?;
self.nbsp()
}

pub fn head(&mut self, w: &str) -> io::Result<()> {
pub fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) -> io::Result<()> {
let w = w.into();
// outer-box is consistent
self.cbox(indent_unit)?;
// head-box is inconsistent
Expand Down Expand Up @@ -303,7 +305,7 @@ impl<'a> State<'a> {
pub fn synth_comment(&mut self, text: String) -> io::Result<()> {
self.s.word("/*")?;
self.s.space()?;
self.s.word(&text[..])?;
self.s.word(text)?;
self.s.space()?;
self.s.word("*/")
}
Expand Down Expand Up @@ -468,7 +470,7 @@ impl<'a> State<'a> {
self.end() // end the outer fn box
}
hir::ForeignItemKind::Static(ref t, m) => {
self.head(&visibility_qualified(&item.vis, "static"))?;
self.head(visibility_qualified(&item.vis, "static"))?;
if m {
self.word_space("mut")?;
}
Expand All @@ -480,7 +482,7 @@ impl<'a> State<'a> {
self.end() // end the outer cbox
}
hir::ForeignItemKind::Type => {
self.head(&visibility_qualified(&item.vis, "type"))?;
self.head(visibility_qualified(&item.vis, "type"))?;
self.print_name(item.name)?;
self.s.word(";")?;
self.end()?; // end the head-ibox
Expand All @@ -495,7 +497,7 @@ impl<'a> State<'a> {
default: Option<hir::BodyId>,
vis: &hir::Visibility)
-> io::Result<()> {
self.s.word(&visibility_qualified(vis, ""))?;
self.s.word(visibility_qualified(vis, ""))?;
self.word_space("const")?;
self.print_ident(ident)?;
self.word_space(":")?;
Expand Down Expand Up @@ -534,7 +536,7 @@ impl<'a> State<'a> {
self.ann.pre(self, AnnNode::Item(item))?;
match item.node {
hir::ItemKind::ExternCrate(orig_name) => {
self.head(&visibility_qualified(&item.vis, "extern crate"))?;
self.head(visibility_qualified(&item.vis, "extern crate"))?;
if let Some(orig_name) = orig_name {
self.print_name(orig_name)?;
self.s.space()?;
Expand All @@ -547,7 +549,7 @@ impl<'a> State<'a> {
self.end()?; // end outer head-block
}
hir::ItemKind::Use(ref path, kind) => {
self.head(&visibility_qualified(&item.vis, "use"))?;
self.head(visibility_qualified(&item.vis, "use"))?;
self.print_path(path, false)?;

match kind {
Expand All @@ -566,7 +568,7 @@ impl<'a> State<'a> {
self.end()?; // end outer head-block
}
hir::ItemKind::Static(ref ty, m, expr) => {
self.head(&visibility_qualified(&item.vis, "static"))?;
self.head(visibility_qualified(&item.vis, "static"))?;
if m == hir::MutMutable {
self.word_space("mut")?;
}
Expand All @@ -582,7 +584,7 @@ impl<'a> State<'a> {
self.end()?; // end the outer cbox
}
hir::ItemKind::Const(ref ty, expr) => {
self.head(&visibility_qualified(&item.vis, "const"))?;
self.head(visibility_qualified(&item.vis, "const"))?;
self.print_name(item.name)?;
self.word_space(":")?;
self.print_type(&ty)?;
Expand All @@ -609,7 +611,7 @@ impl<'a> State<'a> {
self.ann.nested(self, Nested::Body(body))?;
}
hir::ItemKind::Mod(ref _mod) => {
self.head(&visibility_qualified(&item.vis, "mod"))?;
self.head(visibility_qualified(&item.vis, "mod"))?;
self.print_name(item.name)?;
self.nbsp()?;
self.bopen()?;
Expand All @@ -618,18 +620,18 @@ impl<'a> State<'a> {
}
hir::ItemKind::ForeignMod(ref nmod) => {
self.head("extern")?;
self.word_nbsp(&nmod.abi.to_string())?;
self.word_nbsp(nmod.abi.to_string())?;
self.bopen()?;
self.print_foreign_mod(nmod, &item.attrs)?;
self.bclose(item.span)?;
}
hir::ItemKind::GlobalAsm(ref ga) => {
self.head(&visibility_qualified(&item.vis, "global asm"))?;
self.s.word(&ga.asm.as_str())?;
self.head(visibility_qualified(&item.vis, "global asm"))?;
self.s.word(ga.asm.as_str().get())?;
self.end()?
}
hir::ItemKind::Ty(ref ty, ref generics) => {
self.head(&visibility_qualified(&item.vis, "type"))?;
self.head(visibility_qualified(&item.vis, "type"))?;
self.print_name(item.name)?;
self.print_generic_params(&generics.params)?;
self.end()?; // end the inner ibox
Expand All @@ -642,7 +644,7 @@ impl<'a> State<'a> {
self.end()?; // end the outer ibox
}
hir::ItemKind::Existential(ref exist) => {
self.head(&visibility_qualified(&item.vis, "existential type"))?;
self.head(visibility_qualified(&item.vis, "existential type"))?;
self.print_name(item.name)?;
self.print_generic_params(&exist.generics.params)?;
self.end()?; // end the inner ibox
Expand All @@ -668,11 +670,11 @@ impl<'a> State<'a> {
self.print_enum_def(enum_definition, params, item.name, item.span, &item.vis)?;
}
hir::ItemKind::Struct(ref struct_def, ref generics) => {
self.head(&visibility_qualified(&item.vis, "struct"))?;
self.head(visibility_qualified(&item.vis, "struct"))?;
self.print_struct(struct_def, generics, item.name, item.span, true)?;
}
hir::ItemKind::Union(ref struct_def, ref generics) => {
self.head(&visibility_qualified(&item.vis, "union"))?;
self.head(visibility_qualified(&item.vis, "union"))?;
self.print_struct(struct_def, generics, item.name, item.span, true)?;
}
hir::ItemKind::Impl(unsafety,
Expand Down Expand Up @@ -795,7 +797,7 @@ impl<'a> State<'a> {
span: syntax_pos::Span,
visibility: &hir::Visibility)
-> io::Result<()> {
self.head(&visibility_qualified(visibility, "enum"))?;
self.head(visibility_qualified(visibility, "enum"))?;
self.print_name(name)?;
self.print_generic_params(&generics.params)?;
self.print_where_clause(&generics.where_clause)?;
Expand Down Expand Up @@ -1587,14 +1589,14 @@ impl<'a> State<'a> {
}

pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
self.s.word(&i.to_string())
self.s.word(i.to_string())
}

pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
if ident.is_raw_guess() {
self.s.word(&format!("r#{}", ident.name))?;
self.s.word(format!("r#{}", ident.name))?;
} else {
self.s.word(&ident.as_str())?;
self.s.word(ident.as_str().get())?;
}
self.ann.post(self, AnnNode::Name(&ident.name))
}
Expand Down Expand Up @@ -2010,7 +2012,7 @@ impl<'a> State<'a> {
self.commasep(Inconsistent, &decl.inputs, |s, ty| {
s.ibox(indent_unit)?;
if let Some(arg_name) = arg_names.get(i) {
s.s.word(&arg_name.as_str())?;
s.s.word(arg_name.as_str().get())?;
s.s.word(":")?;
s.s.space()?;
} else if let Some(body_id) = body_id {
Expand Down Expand Up @@ -2073,7 +2075,8 @@ impl<'a> State<'a> {
}
}

pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::GenericBound]) -> io::Result<()> {
pub fn print_bounds(&mut self, prefix: &'static str, bounds: &[hir::GenericBound])
-> io::Result<()> {
if !bounds.is_empty() {
self.s.word(prefix)?;
let mut first = true;
Expand Down Expand Up @@ -2322,7 +2325,7 @@ impl<'a> State<'a> {
Some(Abi::Rust) => Ok(()),
Some(abi) => {
self.word_nbsp("extern")?;
self.word_nbsp(&abi.to_string())
self.word_nbsp(abi.to_string())
}
None => Ok(()),
}
Expand All @@ -2332,7 +2335,7 @@ impl<'a> State<'a> {
match opt_abi {
Some(abi) => {
self.word_nbsp("extern")?;
self.word_nbsp(&abi.to_string())
self.word_nbsp(abi.to_string())
}
None => Ok(()),
}
Expand All @@ -2342,7 +2345,7 @@ impl<'a> State<'a> {
header: hir::FnHeader,
vis: &hir::Visibility)
-> io::Result<()> {
self.s.word(&visibility_qualified(vis, ""))?;
self.s.word(visibility_qualified(vis, ""))?;

match header.constness {
hir::Constness::NotConst => {}
Expand All @@ -2358,7 +2361,7 @@ impl<'a> State<'a> {

if header.abi != Abi::Rust {
self.word_nbsp("extern")?;
self.word_nbsp(&header.abi.to_string())?;
self.word_nbsp(header.abi.to_string())?;
}

self.s.word("fn")
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_driver/pretty.rs
Expand Up @@ -530,7 +530,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
s.s.space()?;
s.s.word("as")?;
s.s.space()?;
s.s.word(&self.tables.get().expr_ty(expr).to_string())?;
s.s.word(self.tables.get().expr_ty(expr).to_string())?;
s.pclose()
}
_ => Ok(()),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check_unused.rs
Expand Up @@ -185,7 +185,7 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
Some(orig_name) => format!("use {} as {};", orig_name, item.name),
None => format!("use {};", item.name),
};
let replacement = visibility_qualified(&item.vis, &base_replacement);
let replacement = visibility_qualified(&item.vis, base_replacement);
tcx.struct_span_lint_node(lint, id, extern_crate.span, msg)
.span_suggestion_short_with_applicability(
extern_crate.span,
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/parser.rs
Expand Up @@ -2795,7 +2795,7 @@ impl<'a> Parser<'a> {
s.print_usize(float.trunc() as usize)?;
s.pclose()?;
s.s.word(".")?;
s.s.word(fstr.splitn(2, ".").last().unwrap())
s.s.word(fstr.splitn(2, ".").last().unwrap().to_string())
});
err.span_suggestion_with_applicability(
lo.to(self.prev_span),
Expand Down
12 changes: 9 additions & 3 deletions src/libsyntax/print/pp.rs
Expand Up @@ -147,6 +147,7 @@
use std::collections::VecDeque;
use std::fmt;
use std::io;
use std::borrow::Cow;

/// How to break. Described in more detail in the module docs.
#[derive(Clone, Copy, PartialEq)]
Expand All @@ -169,7 +170,10 @@ pub struct BeginToken {

#[derive(Clone)]
pub enum Token {
String(String, isize),
// In practice a string token contains either a `&'static str` or a
// `String`. `Cow` is overkill for this because we never modify the data,
// but it's more convenient than rolling our own more specialized type.
String(Cow<'static, str>, isize),
Break(BreakToken),
Begin(BeginToken),
End,
Expand Down Expand Up @@ -644,8 +648,10 @@ impl<'a> Printer<'a> {
self.pretty_print(Token::Eof)
}

pub fn word(&mut self, wrd: &str) -> io::Result<()> {
self.pretty_print(Token::String(wrd.to_string(), wrd.len() as isize))
pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) -> io::Result<()> {
let s = wrd.into();
let len = s.len() as isize;
self.pretty_print(Token::String(s, len))
}

fn spaces(&mut self, n: usize) -> io::Result<()> {
Expand Down

0 comments on commit 787959c

Please sign in to comment.