Merge pull request #22877 from dotnet/dev/toddgrun/MorePerfOptimizations
Dev/toddgrun/more perf optimizations
This commit is contained in:
commit
073cd0aa40
|
|
@ -554,13 +554,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
return Transition(CSharpTokenizerState.Data, EndToken(SyntaxKind.StringLiteral));
|
||||
}
|
||||
|
||||
private StateResult QuotedCharacterLiteral() => QuotedLiteral('\'', SyntaxKind.CharacterLiteral);
|
||||
private StateResult QuotedCharacterLiteral() => QuotedLiteral('\'', IsEndQuotedCharacterLiteral, SyntaxKind.CharacterLiteral);
|
||||
|
||||
private StateResult QuotedStringLiteral() => QuotedLiteral('\"', SyntaxKind.StringLiteral);
|
||||
private StateResult QuotedStringLiteral() => QuotedLiteral('\"', IsEndQuotedStringLiteral, SyntaxKind.StringLiteral);
|
||||
|
||||
private StateResult QuotedLiteral(char quote, SyntaxKind literalType)
|
||||
private Func<char, bool> IsEndQuotedCharacterLiteral = (c) => c == '\\' || c == '\'' || ParserHelpers.IsNewLine(c);
|
||||
private Func<char, bool> IsEndQuotedStringLiteral = (c) => c == '\\' || c == '\"' || ParserHelpers.IsNewLine(c);
|
||||
|
||||
private StateResult QuotedLiteral(char quote, Func<char, bool> isEndQuotedLiteral, SyntaxKind literalType)
|
||||
{
|
||||
TakeUntil(c => c == '\\' || c == quote || ParserHelpers.IsNewLine(c));
|
||||
TakeUntil(isEndQuotedLiteral);
|
||||
if (CurrentCharacter == '\\')
|
||||
{
|
||||
TakeCurrent(); // Take the '\'
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
private readonly IList<TextLine> _lines;
|
||||
private readonly string _filePath;
|
||||
private TextLine _currentLine;
|
||||
private TextLine _endLine;
|
||||
|
||||
public LineTrackingStringBuffer(string content, string filePath)
|
||||
: this(content.ToCharArray(), filePath)
|
||||
|
|
@ -22,17 +21,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
|
||||
public LineTrackingStringBuffer(char[] content, string filePath)
|
||||
{
|
||||
_endLine = new TextLine(0, 0);
|
||||
_lines = new List<TextLine>() { _endLine };
|
||||
_lines = new List<TextLine>();
|
||||
|
||||
Append(content);
|
||||
BuildTextLines(content);
|
||||
|
||||
_filePath = filePath;
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return _endLine.End; }
|
||||
get { return _lines[_lines.Count - 1].End; }
|
||||
}
|
||||
|
||||
public SourceLocation EndLocation
|
||||
|
|
@ -43,7 +41,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
public CharacterReference CharAt(int absoluteIndex)
|
||||
{
|
||||
var line = FindLine(absoluteIndex);
|
||||
if (line == null)
|
||||
if (line.IsDefault)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(absoluteIndex));
|
||||
}
|
||||
|
|
@ -51,38 +49,38 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
return new CharacterReference(line.Content[idx], new SourceLocation(_filePath, absoluteIndex, line.Index, idx));
|
||||
}
|
||||
|
||||
private void Append(char[] content)
|
||||
private void BuildTextLines(char[] content)
|
||||
{
|
||||
string lineText;
|
||||
var lineStart = 0;
|
||||
|
||||
for (int i = 0; i < content.Length; i++)
|
||||
{
|
||||
AppendCore(content[i]);
|
||||
|
||||
// \r on it's own: Start a new line, otherwise wait for \n
|
||||
// Other Newline: Start a new line
|
||||
if ((content[i] == '\r' && (i + 1 == content.Length || content[i + 1] != '\n')) || (content[i] != '\r' && ParserHelpers.IsNewLine(content[i])))
|
||||
if (ParserHelpers.IsNewLine(content[i]))
|
||||
{
|
||||
PushNewLine();
|
||||
// \r on it's own: Start a new line, otherwise wait for \n
|
||||
// Other Newline: Start a new line
|
||||
if (content[i] == '\r' && i + 1 < content.Length && content[i + 1] == '\n')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
lineText = new string(content, lineStart, (i - lineStart) + 1); // +1 to include the current char
|
||||
_lines.Add(new TextLine(lineStart, _lines.Count, lineText));
|
||||
|
||||
lineStart = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PushNewLine()
|
||||
{
|
||||
_endLine = new TextLine(_endLine.End, _endLine.Index + 1);
|
||||
_lines.Add(_endLine);
|
||||
}
|
||||
|
||||
private void AppendCore(char chr)
|
||||
{
|
||||
Debug.Assert(_lines.Count > 0);
|
||||
_lines[_lines.Count - 1].Content.Append(chr);
|
||||
lineText = new string(content, lineStart, content.Length - lineStart); // no +1 as content.Length points past the last char already
|
||||
_lines.Add(new TextLine(lineStart, _lines.Count, lineText));
|
||||
}
|
||||
|
||||
private TextLine FindLine(int absoluteIndex)
|
||||
{
|
||||
TextLine selected = null;
|
||||
TextLine selected;
|
||||
|
||||
if (_currentLine == null)
|
||||
if (_currentLine.IsDefault)
|
||||
{
|
||||
// Scan from line 0
|
||||
selected = ScanLines(absoluteIndex, 0, _lines.Count);
|
||||
|
|
@ -104,6 +102,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
selected = ScanLines(absoluteIndex, _currentLine.Index, _lines.Count);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = default;
|
||||
}
|
||||
}
|
||||
else if (absoluteIndex < _currentLine.Start)
|
||||
{
|
||||
|
|
@ -122,6 +124,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
selected = ScanLines(absoluteIndex, 0, _currentLine.Index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = default;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -129,7 +135,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
selected = _currentLine;
|
||||
}
|
||||
|
||||
Debug.Assert(selected == null || selected.Contains(absoluteIndex));
|
||||
Debug.Assert(selected.IsDefault || selected.Contains(absoluteIndex));
|
||||
_currentLine = selected;
|
||||
return selected;
|
||||
}
|
||||
|
|
@ -159,7 +165,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return default;
|
||||
}
|
||||
|
||||
internal struct CharacterReference
|
||||
|
|
@ -175,28 +181,26 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
public SourceLocation Location { get; }
|
||||
}
|
||||
|
||||
private class TextLine
|
||||
private struct TextLine
|
||||
{
|
||||
private StringBuilder _content = new StringBuilder();
|
||||
|
||||
public TextLine(int start, int index)
|
||||
public TextLine(int start, int index, string content)
|
||||
{
|
||||
Start = start;
|
||||
Index = index;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public StringBuilder Content
|
||||
{
|
||||
get { return _content; }
|
||||
}
|
||||
public string Content { get; }
|
||||
|
||||
public bool IsDefault => Content == null;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return Content.Length; }
|
||||
}
|
||||
|
||||
public int Start { get; set; }
|
||||
public int Index { get; set; }
|
||||
public int Start { get; }
|
||||
public int Index { get; }
|
||||
|
||||
public int End
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,25 +16,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
private readonly TokenizerView<TTokenizer> _tokenizer;
|
||||
private SyntaxListBuilder<SyntaxToken>? _tokenBuilder;
|
||||
|
||||
// Following four high traffic methods cached as using method groups would cause allocation on every invocation.
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingToken = (token) =>
|
||||
{
|
||||
return token.Kind == SyntaxKind.Whitespace;
|
||||
};
|
||||
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingTokenIncludingNewLines = (token) =>
|
||||
{
|
||||
return IsSpacingToken(token) || token.Kind == SyntaxKind.NewLine;
|
||||
};
|
||||
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingTokenIncludingComments = (token) =>
|
||||
{
|
||||
return IsSpacingToken(token) || token.Kind == SyntaxKind.CSharpComment;
|
||||
};
|
||||
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingTokenIncludingNewLinesAndComments = (token) =>
|
||||
{
|
||||
return IsSpacingTokenIncludingNewLines(token) || token.Kind == SyntaxKind.CSharpComment;
|
||||
// Following four high traffic methods cached as using method groups would cause allocation on every invocation.
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingToken = (token) =>
|
||||
{
|
||||
return token.Kind == SyntaxKind.Whitespace;
|
||||
};
|
||||
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingTokenIncludingNewLines = (token) =>
|
||||
{
|
||||
return IsSpacingToken(token) || token.Kind == SyntaxKind.NewLine;
|
||||
};
|
||||
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingTokenIncludingComments = (token) =>
|
||||
{
|
||||
return IsSpacingToken(token) || token.Kind == SyntaxKind.CSharpComment;
|
||||
};
|
||||
|
||||
protected static readonly Func<SyntaxToken, bool> IsSpacingTokenIncludingNewLinesAndComments = (token) =>
|
||||
{
|
||||
return IsSpacingTokenIncludingNewLines(token) || token.Kind == SyntaxKind.CSharpComment;
|
||||
};
|
||||
|
||||
protected TokenizerBackedParser(LanguageCharacteristics<TTokenizer> language, ParserContext context)
|
||||
|
|
@ -224,7 +224,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
|
||||
protected internal bool NextIs(SyntaxKind type)
|
||||
{
|
||||
return NextIs(token => token != null && type == token.Kind);
|
||||
// Duplicated logic with NextIs(Func...) to prevent allocation
|
||||
var cur = CurrentToken;
|
||||
var result = false;
|
||||
if (NextToken())
|
||||
{
|
||||
result = (type == CurrentToken.Kind);
|
||||
PutCurrentBack();
|
||||
}
|
||||
|
||||
PutBack(cur);
|
||||
EnsureCurrent();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected internal bool NextIs(params SyntaxKind[] types)
|
||||
|
|
@ -235,21 +247,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
protected internal bool NextIs(Func<SyntaxToken, bool> condition)
|
||||
{
|
||||
var cur = CurrentToken;
|
||||
var result = false;
|
||||
if (NextToken())
|
||||
{
|
||||
var result = condition(CurrentToken);
|
||||
result = condition(CurrentToken);
|
||||
PutCurrentBack();
|
||||
PutBack(cur);
|
||||
EnsureCurrent();
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
PutBack(cur);
|
||||
EnsureCurrent();
|
||||
}
|
||||
|
||||
return false;
|
||||
PutBack(cur);
|
||||
EnsureCurrent();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected internal bool Was(SyntaxKind type)
|
||||
|
|
@ -289,11 +297,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
|||
|
||||
protected internal IReadOnlyList<SyntaxToken> ReadWhile(Func<SyntaxToken, bool> condition)
|
||||
{
|
||||
if (!EnsureCurrent() || !condition(CurrentToken))
|
||||
{
|
||||
return Array.Empty<SyntaxToken>();
|
||||
}
|
||||
|
||||
if (!EnsureCurrent() || !condition(CurrentToken))
|
||||
{
|
||||
return Array.Empty<SyntaxToken>();
|
||||
}
|
||||
|
||||
var result = new List<SyntaxToken>();
|
||||
do
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue