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);
}
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);
}

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);
}

View File

@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Razor.Parser
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;
if (splitAt < symbol.Content.Length)
{
@ -107,6 +107,6 @@ namespace Microsoft.AspNet.Razor.Parser
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>
{
internal static readonly RazorError[] EmptyArray = new RazorError[0];
internal const int DefaultErrorLength = 1;
/// <summary>

View File

@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer
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);
}

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);
}

View File

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

View File

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

View File

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

View File

@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer
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)
{
@ -115,7 +115,14 @@ namespace Microsoft.AspNet.Razor.Tokenizer
TSymbol sym = null;
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();
return sym;

View File

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