From bd4300d8cccbe827b5fa37270e7f8ba9bc03e86c Mon Sep 17 00:00:00 2001 From: Yves57 Date: Tue, 20 Dec 2016 21:45:31 +0100 Subject: [PATCH] Optimize HTML symbol content string allocation --- .../Legacy/CSharpTokenizer.cs | 5 +- .../Legacy/HtmlTokenizer.cs | 56 +++++++++++++++++++ .../Legacy/Tokenizer.cs | 7 ++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpTokenizer.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpTokenizer.cs index f7c1e08fbb..2f55429170 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpTokenizer.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpTokenizer.cs @@ -543,12 +543,13 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { CSharpKeyword keyword; var type = CSharpSymbolType.Identifier; - if (_keywords.TryGetValue(Buffer.ToString(), out keyword)) + var symbolContent = Buffer.ToString(); + if (_keywords.TryGetValue(symbolContent, out keyword)) { type = CSharpSymbolType.Keyword; } - symbol = new CSharpSymbol(CurrentStart, Buffer.ToString(), type) + symbol = new CSharpSymbol(CurrentStart, symbolContent, type) { Keyword = type == CSharpSymbolType.Keyword ? (CSharpKeyword?)keyword : null, }; diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlTokenizer.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlTokenizer.cs index 59260c421b..d736b18580 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlTokenizer.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlTokenizer.cs @@ -70,6 +70,62 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy } } + // Optimize memory allocation by returning constants for the most frequent cases + protected override string GetSymbolContent(HtmlSymbolType type) + { + var symbolLength = Buffer.Length; + + if (symbolLength == 1) + { + switch (type) + { + case HtmlSymbolType.OpenAngle: + return "<"; + case HtmlSymbolType.Bang: + return "!"; + case HtmlSymbolType.ForwardSlash: + return "/"; + case HtmlSymbolType.QuestionMark: + return "?"; + case HtmlSymbolType.LeftBracket: + return "["; + case HtmlSymbolType.CloseAngle: + return ">"; + case HtmlSymbolType.RightBracket: + return "]"; + case HtmlSymbolType.Equals: + return "="; + case HtmlSymbolType.DoubleQuote: + return "\""; + case HtmlSymbolType.SingleQuote: + return "'"; + case HtmlSymbolType.WhiteSpace: + if (Buffer[0] == ' ') + { + return " "; + } + if (Buffer[0] == '\t') + { + return "\t"; + } + break; + case HtmlSymbolType.NewLine: + if (Buffer[0] == '\n') + { + return "\n"; + } + break; + } + } + + if (symbolLength == 2 && type == HtmlSymbolType.NewLine) + { + return "\r\n"; + } + + return base.GetSymbolContent(type); + } + // http://dev.w3.org/html5/spec/Overview.html#data-state private StateResult Data() { diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/Tokenizer.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/Tokenizer.cs index c8c547b4f0..95fdced87d 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/Tokenizer.cs @@ -215,12 +215,17 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy errors[i] = CurrentErrors[i]; } - sym = CreateSymbol(start, Buffer.ToString(), type, errors); + sym = CreateSymbol(start, GetSymbolContent(type), type, errors); } StartSymbol(); return sym; } + protected virtual string GetSymbolContent(TSymbolType type) + { + return Buffer.ToString(); + } + protected bool TakeUntil(Func predicate) { // Take all the characters up to the end character