Skip to content

Commit 2b91cbe

Browse files
committedOct 12, 2022
Auto merge of rust-lang#102692 - nnethercote:TokenStreamBuilder, r=Aaron1011
Remove `TokenStreamBuilder` `TokenStreamBuilder` is used to combine multiple token streams. It can be removed, leaving the code a little simpler and a little faster. r? `@Aaron1011`
2 parents 7e8d64e + ed6f481 commit 2b91cbe

File tree

4 files changed

+118
-147
lines changed

4 files changed

+118
-147
lines changed
 

‎compiler/rustc_ast/src/tokenstream.rs

+45-72
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,12 @@ impl AttrTokenStream {
245245
// properly implemented - we always synthesize fake tokens,
246246
// so we never reach this code.
247247

248-
let mut builder = TokenStreamBuilder::new();
248+
let mut stream = TokenStream::default();
249249
for inner_attr in inner_attrs {
250-
builder.push(inner_attr.tokens());
250+
stream.push_stream(inner_attr.tokens());
251251
}
252-
builder.push(delim_tokens.clone());
253-
*tree = TokenTree::Delimited(*span, *delim, builder.build());
252+
stream.push_stream(delim_tokens.clone());
253+
*tree = TokenTree::Delimited(*span, *delim, stream);
254254
found = true;
255255
break;
256256
}
@@ -505,76 +505,49 @@ impl TokenStream {
505505

506506
self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
507507
}
508-
}
509508

510-
// 99.5%+ of the time we have 1 or 2 elements in this vector.
511-
#[derive(Clone)]
512-
pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>);
513-
514-
impl TokenStreamBuilder {
515-
pub fn new() -> TokenStreamBuilder {
516-
TokenStreamBuilder(SmallVec::new())
517-
}
518-
519-
pub fn push(&mut self, stream: TokenStream) {
520-
self.0.push(stream);
521-
}
522-
523-
pub fn build(self) -> TokenStream {
524-
let mut streams = self.0;
525-
match streams.len() {
526-
0 => TokenStream::default(),
527-
1 => streams.pop().unwrap(),
528-
_ => {
529-
// We will extend the first stream in `streams` with the
530-
// elements from the subsequent streams. This requires using
531-
// `make_mut()` on the first stream, and in practice this
532-
// doesn't cause cloning 99.9% of the time.
533-
//
534-
// One very common use case is when `streams` has two elements,
535-
// where the first stream has any number of elements within
536-
// (often 1, but sometimes many more) and the second stream has
537-
// a single element within.
538-
539-
// Determine how much the first stream will be extended.
540-
// Needed to avoid quadratic blow up from on-the-fly
541-
// reallocations (#57735).
542-
let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
543-
544-
// Get the first stream, which will become the result stream.
545-
// If it's `None`, create an empty stream.
546-
let mut iter = streams.into_iter();
547-
let mut res_stream_lrc = iter.next().unwrap().0;
548-
549-
// Append the subsequent elements to the result stream, after
550-
// reserving space for them.
551-
let res_vec_mut = Lrc::make_mut(&mut res_stream_lrc);
552-
res_vec_mut.reserve(num_appends);
553-
for stream in iter {
554-
let stream_iter = stream.0.iter().cloned();
555-
556-
// If (a) `res_mut_vec` is not empty and the last tree
557-
// within it is a token tree marked with `Joint`, and (b)
558-
// `stream` is not empty and the first tree within it is a
559-
// token tree, and (c) the two tokens can be glued
560-
// together...
561-
if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = res_vec_mut.last()
562-
&& let Some(TokenTree::Token(tok, spacing)) = stream.0.first()
563-
&& let Some(glued_tok) = last_tok.glue(&tok)
564-
{
565-
// ...then overwrite the last token tree in
566-
// `res_vec_mut` with the glued token, and skip the
567-
// first token tree from `stream`.
568-
*res_vec_mut.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
569-
res_vec_mut.extend(stream_iter.skip(1));
570-
} else {
571-
// Append all of `stream`.
572-
res_vec_mut.extend(stream_iter);
573-
}
574-
}
509+
// If `vec` is not empty, try to glue `tt` onto its last token. The return
510+
// value indicates if gluing took place.
511+
fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
512+
if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last()
513+
&& let TokenTree::Token(tok, spacing) = tt
514+
&& let Some(glued_tok) = last_tok.glue(&tok)
515+
{
516+
// ...then overwrite the last token tree in `vec` with the
517+
// glued token, and skip the first token tree from `stream`.
518+
*vec.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
519+
true
520+
} else {
521+
false
522+
}
523+
}
575524

576-
TokenStream(res_stream_lrc)
577-
}
525+
// Push `tt` onto the end of the stream, possibly gluing it to the last
526+
// token. Uses `make_mut` to maximize efficiency.
527+
pub fn push_tree(&mut self, tt: TokenTree) {
528+
let vec_mut = Lrc::make_mut(&mut self.0);
529+
530+
if Self::try_glue_to_last(vec_mut, &tt) {
531+
// nothing else to do
532+
} else {
533+
vec_mut.push(tt);
534+
}
535+
}
536+
537+
// Push `stream` onto the end of the stream, possibly gluing the first
538+
// token tree to the last token. (No other token trees will be glued.)
539+
// Uses `make_mut` to maximize efficiency.
540+
pub fn push_stream(&mut self, stream: TokenStream) {
541+
let vec_mut = Lrc::make_mut(&mut self.0);
542+
543+
let stream_iter = stream.0.iter().cloned();
544+
545+
if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) {
546+
// Now skip the first token tree from `stream`.
547+
vec_mut.extend(stream_iter.skip(1));
548+
} else {
549+
// Append all of `stream`.
550+
vec_mut.extend(stream_iter);
578551
}
579552
}
580553
}

‎compiler/rustc_expand/src/proc_macro_server.rs

+63-63
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::base::ExtCtxt;
2-
2+
use pm::bridge::{
3+
server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
4+
};
5+
use pm::{Delimiter, Level, LineColumn};
36
use rustc_ast as ast;
47
use rustc_ast::token;
58
use rustc_ast::tokenstream::{self, Spacing::*, TokenStream};
@@ -13,11 +16,7 @@ use rustc_session::parse::ParseSess;
1316
use rustc_span::def_id::CrateNum;
1417
use rustc_span::symbol::{self, sym, Symbol};
1518
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
16-
17-
use pm::bridge::{
18-
server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
19-
};
20-
use pm::{Delimiter, Level, LineColumn};
19+
use smallvec::{smallvec, SmallVec};
2120
use std::ops::Bound;
2221

2322
trait FromInternal<T> {
@@ -253,23 +252,57 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
253252
}
254253
}
255254

256-
impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>) {
257-
fn to_internal(self) -> TokenStream {
255+
// We use a `SmallVec` because the output size is always one or two `TokenTree`s.
256+
impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
257+
for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>)
258+
{
259+
fn to_internal(self) -> SmallVec<[tokenstream::TokenTree; 2]> {
258260
use rustc_ast::token::*;
259261

260262
let (tree, rustc) = self;
261-
let (ch, joint, span) = match tree {
262-
TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
263+
match tree {
264+
TokenTree::Punct(Punct { ch, joint, span }) => {
265+
let kind = match ch {
266+
b'=' => Eq,
267+
b'<' => Lt,
268+
b'>' => Gt,
269+
b'!' => Not,
270+
b'~' => Tilde,
271+
b'+' => BinOp(Plus),
272+
b'-' => BinOp(Minus),
273+
b'*' => BinOp(Star),
274+
b'/' => BinOp(Slash),
275+
b'%' => BinOp(Percent),
276+
b'^' => BinOp(Caret),
277+
b'&' => BinOp(And),
278+
b'|' => BinOp(Or),
279+
b'@' => At,
280+
b'.' => Dot,
281+
b',' => Comma,
282+
b';' => Semi,
283+
b':' => Colon,
284+
b'#' => Pound,
285+
b'$' => Dollar,
286+
b'?' => Question,
287+
b'\'' => SingleQuote,
288+
_ => unreachable!(),
289+
};
290+
smallvec![if joint {
291+
tokenstream::TokenTree::token_joint(kind, span)
292+
} else {
293+
tokenstream::TokenTree::token_alone(kind, span)
294+
}]
295+
}
263296
TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => {
264-
return tokenstream::TokenStream::delimited(
297+
smallvec![tokenstream::TokenTree::Delimited(
265298
tokenstream::DelimSpan { open, close },
266299
delimiter.to_internal(),
267300
stream.unwrap_or_default(),
268-
);
301+
)]
269302
}
270303
TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
271304
rustc.sess().symbol_gallery.insert(sym, span);
272-
return tokenstream::TokenStream::token_alone(Ident(sym, is_raw), span);
305+
smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)]
273306
}
274307
TokenTree::Literal(self::Literal {
275308
kind: self::LitKind::Integer,
@@ -282,7 +315,7 @@ impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rus
282315
let integer = TokenKind::lit(token::Integer, symbol, suffix);
283316
let a = tokenstream::TokenTree::token_alone(minus, span);
284317
let b = tokenstream::TokenTree::token_alone(integer, span);
285-
return [a, b].into_iter().collect();
318+
smallvec![a, b]
286319
}
287320
TokenTree::Literal(self::Literal {
288321
kind: self::LitKind::Float,
@@ -295,46 +328,14 @@ impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rus
295328
let float = TokenKind::lit(token::Float, symbol, suffix);
296329
let a = tokenstream::TokenTree::token_alone(minus, span);
297330
let b = tokenstream::TokenTree::token_alone(float, span);
298-
return [a, b].into_iter().collect();
331+
smallvec![a, b]
299332
}
300333
TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => {
301-
return tokenstream::TokenStream::token_alone(
334+
smallvec![tokenstream::TokenTree::token_alone(
302335
TokenKind::lit(kind.to_internal(), symbol, suffix),
303336
span,
304-
);
337+
)]
305338
}
306-
};
307-
308-
let kind = match ch {
309-
b'=' => Eq,
310-
b'<' => Lt,
311-
b'>' => Gt,
312-
b'!' => Not,
313-
b'~' => Tilde,
314-
b'+' => BinOp(Plus),
315-
b'-' => BinOp(Minus),
316-
b'*' => BinOp(Star),
317-
b'/' => BinOp(Slash),
318-
b'%' => BinOp(Percent),
319-
b'^' => BinOp(Caret),
320-
b'&' => BinOp(And),
321-
b'|' => BinOp(Or),
322-
b'@' => At,
323-
b'.' => Dot,
324-
b',' => Comma,
325-
b';' => Semi,
326-
b':' => Colon,
327-
b'#' => Pound,
328-
b'$' => Dollar,
329-
b'?' => Question,
330-
b'\'' => SingleQuote,
331-
_ => unreachable!(),
332-
};
333-
334-
if joint {
335-
tokenstream::TokenStream::token_joint(kind, span)
336-
} else {
337-
tokenstream::TokenStream::token_alone(kind, span)
338339
}
339340
}
340341
}
@@ -549,37 +550,35 @@ impl server::TokenStream for Rustc<'_, '_> {
549550
&mut self,
550551
tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
551552
) -> Self::TokenStream {
552-
(tree, &mut *self).to_internal()
553+
Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::<Vec<_>>())
553554
}
554555

555556
fn concat_trees(
556557
&mut self,
557558
base: Option<Self::TokenStream>,
558559
trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
559560
) -> Self::TokenStream {
560-
let mut builder = tokenstream::TokenStreamBuilder::new();
561-
if let Some(base) = base {
562-
builder.push(base);
563-
}
561+
let mut stream =
562+
if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
564563
for tree in trees {
565-
builder.push((tree, &mut *self).to_internal());
564+
for tt in (tree, &mut *self).to_internal() {
565+
stream.push_tree(tt);
566+
}
566567
}
567-
builder.build()
568+
stream
568569
}
569570

570571
fn concat_streams(
571572
&mut self,
572573
base: Option<Self::TokenStream>,
573574
streams: Vec<Self::TokenStream>,
574575
) -> Self::TokenStream {
575-
let mut builder = tokenstream::TokenStreamBuilder::new();
576-
if let Some(base) = base {
577-
builder.push(base);
576+
let mut stream =
577+
if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
578+
for s in streams {
579+
stream.push_stream(s);
578580
}
579-
for stream in streams {
580-
builder.push(stream);
581-
}
582-
builder.build()
581+
stream
583582
}
584583

585584
fn into_trees(
@@ -705,6 +704,7 @@ impl server::Span for Rustc<'_, '_> {
705704
fn source_text(&mut self, span: Self::Span) -> Option<String> {
706705
self.sess().source_map().span_to_snippet(span).ok()
707706
}
707+
708708
/// Saves the provided span into the metadata of
709709
/// *the crate we are currently compiling*, which must
710710
/// be a proc-macro crate. This id can be passed to

‎compiler/rustc_expand/src/tokenstream/tests.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::tests::string_to_stream;
22

33
use rustc_ast::token;
4-
use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder};
4+
use rustc_ast::tokenstream::{TokenStream, TokenTree};
55
use rustc_span::create_default_session_globals_then;
66
use rustc_span::{BytePos, Span, Symbol};
77

@@ -19,10 +19,9 @@ fn test_concat() {
1919
let test_res = string_to_ts("foo::bar::baz");
2020
let test_fst = string_to_ts("foo::bar");
2121
let test_snd = string_to_ts("::baz");
22-
let mut builder = TokenStreamBuilder::new();
23-
builder.push(test_fst);
24-
builder.push(test_snd);
25-
let eq_res = builder.build();
22+
let mut eq_res = TokenStream::default();
23+
eq_res.push_stream(test_fst);
24+
eq_res.push_stream(test_snd);
2625
assert_eq!(test_res.trees().count(), 5);
2726
assert_eq!(eq_res.trees().count(), 5);
2827
assert_eq!(test_res.eq_unspanned(&eq_res), true);
@@ -99,11 +98,10 @@ fn test_is_empty() {
9998
#[test]
10099
fn test_dotdotdot() {
101100
create_default_session_globals_then(|| {
102-
let mut builder = TokenStreamBuilder::new();
103-
builder.push(TokenStream::token_joint(token::Dot, sp(0, 1)));
104-
builder.push(TokenStream::token_joint(token::Dot, sp(1, 2)));
105-
builder.push(TokenStream::token_alone(token::Dot, sp(2, 3)));
106-
let stream = builder.build();
101+
let mut stream = TokenStream::default();
102+
stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1)));
103+
stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2)));
104+
stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3)));
107105
assert!(stream.eq_unspanned(&string_to_ts("...")));
108106
assert_eq!(stream.trees().count(), 1);
109107
})

‎library/proc_macro/src/bridge/client.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ pub(crate) use super::symbol::Symbol;
223223

224224
macro_rules! define_client_side {
225225
($($name:ident {
226-
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
226+
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
227227
}),* $(,)?) => {
228228
$(impl $name {
229-
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
229+
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
230230
Bridge::with(|bridge| {
231231
let mut buf = bridge.cached_buffer.take();
232232

0 commit comments

Comments
 (0)
Please sign in to comment.