Add a new special case to Parser::look_ahead.

This new special case is simpler than the old special case because it
only is used when `dist == 1`. But that's still enough to cover ~98% of
cases. This results in equivalent performance to the old special case,
and identical behaviour as the general case.
This commit is contained in:
Nicholas Nethercote 2024-07-12 13:20:24 +10:00
parent ebe1305b1e
commit 100f3fd133

View File

@ -1118,6 +1118,35 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
return looker(&self.token); return looker(&self.token);
} }
// Typically around 98% of the `dist > 0` cases have `dist == 1`, so we
// have a fast special case for that.
if dist == 1 {
// The index is zero because the tree cursor's index always points
// to the next token to be gotten.
match self.token_cursor.tree_cursor.look_ahead(0) {
Some(tree) => {
// Indexing stayed within the current token tree.
return match tree {
TokenTree::Token(token, _) => looker(token),
TokenTree::Delimited(dspan, _, delim, _) => {
looker(&Token::new(token::OpenDelim(*delim), dspan.open))
}
};
}
None => {
// The tree cursor lookahead went (one) past the end of the
// current token tree. Try to return a close delimiter.
if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
&& delim != Delimiter::Invisible
{
// We are not in the outermost token stream, so we have
// delimiters. Also, those delimiters are not skipped.
return looker(&Token::new(token::CloseDelim(delim), span.close));
}
}
}
}
// Just clone the token cursor and use `next`, skipping delimiters as // Just clone the token cursor and use `next`, skipping delimiters as
// necessary. Slow but simple. // necessary. Slow but simple.
let mut cursor = self.token_cursor.clone(); let mut cursor = self.token_cursor.clone();