Eliminate extra List<RazorError> copies

Changing to IReadOnlyList since we always want to support indexing.
Replacing ToArray() with non-linq when needed, and with a static
EmptyArray when not needed.

Eliminates 50mb of list copies.
This commit is contained in:
Ryan Nowak 2016-01-14 14:54:47 -08:00
parent 9c6e5f714a
commit 6a4a9544a1
11 changed files with 28 additions and 19 deletions

View File

@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Razor.Parser
return new CSharpTokenizer(source); return new CSharpTokenizer(source);
} }
protected override CSharpSymbol CreateSymbol(SourceLocation location, string content, CSharpSymbolType type, IEnumerable<RazorError> errors) protected override CSharpSymbol CreateSymbol(SourceLocation location, string content, CSharpSymbolType type, IReadOnlyList<RazorError> errors)
{ {
return new CSharpSymbol(location, content, type, errors); return new CSharpSymbol(location, content, type, errors);
} }

View File

@ -129,7 +129,7 @@ namespace Microsoft.AspNet.Razor.Parser
} }
} }
protected override HtmlSymbol CreateSymbol(SourceLocation location, string content, HtmlSymbolType type, IEnumerable<RazorError> errors) protected override HtmlSymbol CreateSymbol(SourceLocation location, string content, HtmlSymbolType type, IReadOnlyList<RazorError> errors)
{ {
return new HtmlSymbol(location, content, type, errors); return new HtmlSymbol(location, content, type, errors);
} }

View File

@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Razor.Parser
public virtual Tuple<TSymbol, TSymbol> SplitSymbol(TSymbol symbol, int splitAt, TSymbolType leftType) public virtual Tuple<TSymbol, TSymbol> SplitSymbol(TSymbol symbol, int splitAt, TSymbolType leftType)
{ {
var left = CreateSymbol(symbol.Start, symbol.Content.Substring(0, splitAt), leftType, Enumerable.Empty<RazorError>()); var left = CreateSymbol(symbol.Start, symbol.Content.Substring(0, splitAt), leftType, RazorError.EmptyArray);
TSymbol right = null; TSymbol right = null;
if (splitAt < symbol.Content.Length) if (splitAt < symbol.Content.Length)
{ {
@ -107,6 +107,6 @@ namespace Microsoft.AspNet.Razor.Parser
return type == KnownSymbolType.Unknown || !Equals(GetKnownSymbolType(type), GetKnownSymbolType(KnownSymbolType.Unknown)); return type == KnownSymbolType.Unknown || !Equals(GetKnownSymbolType(type), GetKnownSymbolType(KnownSymbolType.Unknown));
} }
protected abstract TSymbol CreateSymbol(SourceLocation location, string content, TSymbolType type, IEnumerable<RazorError> errors); protected abstract TSymbol CreateSymbol(SourceLocation location, string content, TSymbolType type, IReadOnlyList<RazorError> errors);
} }
} }

View File

@ -9,6 +9,8 @@ namespace Microsoft.AspNet.Razor
{ {
public class RazorError : IEquatable<RazorError> public class RazorError : IEquatable<RazorError>
{ {
internal static readonly RazorError[] EmptyArray = new RazorError[0];
internal const int DefaultErrorLength = 1; internal const int DefaultErrorLength = 1;
/// <summary> /// <summary>

View File

@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer
get { return CSharpSymbolType.RazorCommentStar; } get { return CSharpSymbolType.RazorCommentStar; }
} }
protected override CSharpSymbol CreateSymbol(SourceLocation start, string content, CSharpSymbolType type, IEnumerable<RazorError> errors) protected override CSharpSymbol CreateSymbol(SourceLocation start, string content, CSharpSymbolType type, IReadOnlyList<RazorError> errors)
{ {
return new CSharpSymbol(start, content, type, errors); return new CSharpSymbol(start, content, type, errors);
} }

View File

@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer
} }
} }
protected override HtmlSymbol CreateSymbol(SourceLocation start, string content, HtmlSymbolType type, IEnumerable<RazorError> errors) protected override HtmlSymbol CreateSymbol(SourceLocation start, string content, HtmlSymbolType type, IReadOnlyList<RazorError> errors)
{ {
return new HtmlSymbol(start, content, type, errors); return new HtmlSymbol(start, content, type, errors);
} }

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
{ {
// Helper constructor // Helper constructor
public CSharpSymbol(int offset, int line, int column, string content, CSharpSymbolType type) public CSharpSymbol(int offset, int line, int column, string content, CSharpSymbolType type)
: this(new SourceLocation(offset, line, column), content, type, Enumerable.Empty<RazorError>()) : this(new SourceLocation(offset, line, column), content, type, RazorError.EmptyArray)
{ {
if (content == null) if (content == null)
{ {
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
} }
public CSharpSymbol(SourceLocation start, string content, CSharpSymbolType type) public CSharpSymbol(SourceLocation start, string content, CSharpSymbolType type)
: this(start, content, type, Enumerable.Empty<RazorError>()) : this(start, content, type, RazorError.EmptyArray)
{ {
if (content == null) if (content == null)
{ {
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
int column, int column,
string content, string content,
CSharpSymbolType type, CSharpSymbolType type,
IEnumerable<RazorError> errors) IReadOnlyList<RazorError> errors)
: base(new SourceLocation(offset, line, column), content, type, errors) : base(new SourceLocation(offset, line, column), content, type, errors)
{ {
if (content == null) if (content == null)
@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
SourceLocation start, SourceLocation start,
string content, string content,
CSharpSymbolType type, CSharpSymbolType type,
IEnumerable<RazorError> errors) IReadOnlyList<RazorError> errors)
: base(start, content, type, errors) : base(start, content, type, errors)
{ {
if (content == null) if (content == null)

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
{ {
// Helper constructor // Helper constructor
public HtmlSymbol(int offset, int line, int column, string content, HtmlSymbolType type) public HtmlSymbol(int offset, int line, int column, string content, HtmlSymbolType type)
: this(new SourceLocation(offset, line, column), content, type, Enumerable.Empty<RazorError>()) : this(new SourceLocation(offset, line, column), content, type, RazorError.EmptyArray)
{ {
if (content == null) if (content == null)
{ {
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
} }
public HtmlSymbol(SourceLocation start, string content, HtmlSymbolType type) public HtmlSymbol(SourceLocation start, string content, HtmlSymbolType type)
: base(start, content, type, Enumerable.Empty<RazorError>()) : base(start, content, type, RazorError.EmptyArray)
{ {
if (content == null) if (content == null)
{ {
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
int column, int column,
string content, string content,
HtmlSymbolType type, HtmlSymbolType type,
IEnumerable<RazorError> errors) IReadOnlyList<RazorError> errors)
: base(new SourceLocation(offset, line, column), content, type, errors) : base(new SourceLocation(offset, line, column), content, type, errors)
{ {
if (content == null) if (content == null)
@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
SourceLocation start, SourceLocation start,
string content, string content,
HtmlSymbolType type, HtmlSymbolType type,
IEnumerable<RazorError> errors) IReadOnlyList<RazorError> errors)
: base(start, content, type, errors) : base(start, content, type, errors)
{ {
if (content == null) if (content == null)

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
SourceLocation start, SourceLocation start,
string content, string content,
TType type, TType type,
IEnumerable<RazorError> errors) IReadOnlyList<RazorError> errors)
{ {
if (content == null) if (content == null)
{ {
@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
public string Content { get; } public string Content { get; }
public IEnumerable<RazorError> Errors { get; } public IReadOnlyList<RazorError> Errors { get; }
public TType Type { get; } public TType Type { get; }

View File

@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer
CurrentState = StartState; CurrentState = StartState;
} }
protected abstract TSymbol CreateSymbol(SourceLocation start, string content, TSymbolType type, IEnumerable<RazorError> errors); protected abstract TSymbol CreateSymbol(SourceLocation start, string content, TSymbolType type, IReadOnlyList<RazorError> errors);
protected TSymbol Single(TSymbolType type) protected TSymbol Single(TSymbolType type)
{ {
@ -115,7 +115,14 @@ namespace Microsoft.AspNet.Razor.Tokenizer
TSymbol sym = null; TSymbol sym = null;
if (HaveContent) if (HaveContent)
{ {
sym = CreateSymbol(start, Buffer.ToString(), type, CurrentErrors.ToArray()); // Perf: Don't allocate a new errors array unless necessary.
var errors = CurrentErrors.Count == 0 ? RazorError.EmptyArray : new RazorError[CurrentErrors.Count];
for (var i = 0; i < CurrentErrors.Count; i++)
{
errors[i] = CurrentErrors[i];
}
sym = CreateSymbol(start, Buffer.ToString(), type, errors);
} }
StartSymbol(); StartSymbol();
return sym; return sym;

View File

@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Razor.Test.Tokenizer
SourceLocation start, SourceLocation start,
string content, string content,
CSharpSymbolType type, CSharpSymbolType type,
IEnumerable<RazorError> errors) IReadOnlyList<RazorError> errors)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }