Make the CodeWriter more efficient
This commit is contained in:
parent
08fef95969
commit
315d79ff2b
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Razor.Chunks.Generators;
|
using Microsoft.AspNet.Razor.Chunks.Generators;
|
||||||
|
|
@ -15,6 +16,19 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
{
|
{
|
||||||
private const string InstanceMethodFormat = "{0}.{1}";
|
private const string InstanceMethodFormat = "{0}.{1}";
|
||||||
|
|
||||||
|
private static readonly char[] CStyleStringLiteralEscapeChars = new char[]
|
||||||
|
{
|
||||||
|
'\r',
|
||||||
|
'\t',
|
||||||
|
'\"',
|
||||||
|
'\'',
|
||||||
|
'\\',
|
||||||
|
'\0',
|
||||||
|
'\n',
|
||||||
|
'\u2028',
|
||||||
|
'\u2029',
|
||||||
|
};
|
||||||
|
|
||||||
public CSharpCodeWriter()
|
public CSharpCodeWriter()
|
||||||
{
|
{
|
||||||
LineMappingManager = new LineMappingManager();
|
LineMappingManager = new LineMappingManager();
|
||||||
|
|
@ -195,8 +209,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
file = location.FilePath;
|
file = location.FilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(LastWrite) &&
|
if (Builder.Length >= NewLine.Length && !IsAfterNewLine)
|
||||||
!LastWrite.EndsWith(NewLine, StringComparison.Ordinal))
|
|
||||||
{
|
{
|
||||||
WriteLine();
|
WriteLine();
|
||||||
}
|
}
|
||||||
|
|
@ -445,18 +458,23 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
{
|
{
|
||||||
Write("@\"");
|
Write("@\"");
|
||||||
|
|
||||||
foreach (char c in literal)
|
// We need to find the index of each '"' (double-quote) to escape it.
|
||||||
|
var start = 0;
|
||||||
|
int end;
|
||||||
|
while ((end = literal.IndexOf('\"', start)) > -1)
|
||||||
{
|
{
|
||||||
if (c == '\"')
|
Write(literal, start, end - start);
|
||||||
{
|
|
||||||
Write("\"\"");
|
Write("\"\"");
|
||||||
}
|
|
||||||
else
|
start = end + 1;
|
||||||
{
|
|
||||||
Write(c.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.Assert(end == -1); // We've hit all of the double-quotes.
|
||||||
|
|
||||||
|
// Write the remainder after the last double-quote.
|
||||||
|
Write(literal, start, literal.Length - start);
|
||||||
|
|
||||||
Write("\"");
|
Write("\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -464,9 +482,15 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
{
|
{
|
||||||
// From CSharpCodeGenerator.QuoteSnippetStringCStyle in CodeDOM
|
// From CSharpCodeGenerator.QuoteSnippetStringCStyle in CodeDOM
|
||||||
Write("\"");
|
Write("\"");
|
||||||
for (int i = 0; i < literal.Length; i++)
|
|
||||||
|
// We need to find the index of each escapable character to escape it.
|
||||||
|
var start = 0;
|
||||||
|
int end;
|
||||||
|
while ((end = literal.IndexOfAny(CStyleStringLiteralEscapeChars, start)) > -1)
|
||||||
{
|
{
|
||||||
switch (literal[i])
|
Write(literal, start, end - start);
|
||||||
|
|
||||||
|
switch (literal[end])
|
||||||
{
|
{
|
||||||
case '\r':
|
case '\r':
|
||||||
Write("\\r");
|
Write("\\r");
|
||||||
|
|
@ -492,13 +516,21 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
case '\u2028':
|
case '\u2028':
|
||||||
case '\u2029':
|
case '\u2029':
|
||||||
Write("\\u");
|
Write("\\u");
|
||||||
Write(((int)literal[i]).ToString("X4", CultureInfo.InvariantCulture));
|
Write(((int)literal[end]).ToString("X4", CultureInfo.InvariantCulture));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Write(literal[i].ToString());
|
Debug.Assert(false, "Unknown escape character.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start = end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.Assert(end == -1); // We've hit all of chars that need escaping.
|
||||||
|
|
||||||
|
// Write the remainder after the last escaped char.
|
||||||
|
Write(literal, start, literal.Length - start);
|
||||||
|
|
||||||
Write("\"");
|
Write("\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,9 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
|
|
||||||
private void TryAutoSpace(string spaceCharacter)
|
private void TryAutoSpace(string spaceCharacter)
|
||||||
{
|
{
|
||||||
if (_autoSpace && _writer.LastWrite.Length > 0 && !Char.IsWhiteSpace(_writer.LastWrite.Last()))
|
if (_autoSpace &&
|
||||||
|
_writer.Builder.Length > 0 &&
|
||||||
|
!char.IsWhiteSpace(_writer.Builder[_writer.Builder.Length - 1]))
|
||||||
{
|
{
|
||||||
_writer.Write(spaceCharacter);
|
_writer.Write(spaceCharacter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
|
|
@ -10,32 +9,21 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
public class CodeWriter : IDisposable
|
public class CodeWriter : IDisposable
|
||||||
{
|
{
|
||||||
private static readonly char[] NewLineCharacters = new char[] { '\r', '\n' };
|
private static readonly char[] NewLineCharacters = new char[] { '\r', '\n' };
|
||||||
private readonly StringWriter _writer = new StringWriter();
|
|
||||||
private bool _newLine;
|
|
||||||
private string _cache = string.Empty;
|
private string _cache = string.Empty;
|
||||||
private bool _dirty = false;
|
private bool _dirty;
|
||||||
|
|
||||||
private int _absoluteIndex;
|
private int _absoluteIndex;
|
||||||
private int _currentLineIndex;
|
private int _currentLineIndex;
|
||||||
private int _currentLineCharacterIndex;
|
private int _currentLineCharacterIndex;
|
||||||
|
|
||||||
public StringBuilder Builder => _writer.GetStringBuilder();
|
public StringBuilder Builder { get; } = new StringBuilder();
|
||||||
|
|
||||||
public string LastWrite { get; private set; }
|
|
||||||
|
|
||||||
public int CurrentIndent { get; private set; }
|
public int CurrentIndent { get; private set; }
|
||||||
|
|
||||||
public string NewLine
|
public bool IsAfterNewLine { get; private set; }
|
||||||
{
|
|
||||||
get
|
public string NewLine { get; set; } = Environment.NewLine;
|
||||||
{
|
|
||||||
return _writer.NewLine;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_writer.NewLine = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter ResetIndent()
|
public CodeWriter ResetIndent()
|
||||||
{
|
{
|
||||||
|
|
@ -65,16 +53,15 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
|
|
||||||
public CodeWriter Indent(int size)
|
public CodeWriter Indent(int size)
|
||||||
{
|
{
|
||||||
if (_newLine)
|
if (IsAfterNewLine)
|
||||||
{
|
{
|
||||||
_writer.Write(new string(' ', size));
|
Builder.Append(' ', size);
|
||||||
Flush();
|
|
||||||
|
|
||||||
_currentLineCharacterIndex += size;
|
_currentLineCharacterIndex += size;
|
||||||
_absoluteIndex += size;
|
_absoluteIndex += size;
|
||||||
|
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
_newLine = false;
|
IsAfterNewLine = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -82,35 +69,42 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
|
|
||||||
public CodeWriter Write(string data)
|
public CodeWriter Write(string data)
|
||||||
{
|
{
|
||||||
Indent(CurrentIndent);
|
if (data == null)
|
||||||
|
|
||||||
_writer.Write(data);
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
LastWrite = data;
|
|
||||||
_dirty = true;
|
|
||||||
_newLine = false;
|
|
||||||
|
|
||||||
if (data == null || data.Length == 0)
|
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_absoluteIndex += data.Length;
|
return Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CodeWriter Write(string data, int index, int count)
|
||||||
|
{
|
||||||
|
if (data == null || count == 0)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Indent(CurrentIndent);
|
||||||
|
|
||||||
|
Builder.Append(data, index, count);
|
||||||
|
|
||||||
|
_dirty = true;
|
||||||
|
IsAfterNewLine = false;
|
||||||
|
|
||||||
|
_absoluteIndex += count;
|
||||||
|
|
||||||
// The data string might contain a partial newline where the previously
|
// The data string might contain a partial newline where the previously
|
||||||
// written string has part of the newline.
|
// written string has part of the newline.
|
||||||
var i = 0;
|
var i = index;
|
||||||
int? trailingPartStart = null;
|
int? trailingPartStart = null;
|
||||||
var builder = _writer.GetStringBuilder();
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
// Check the last character of the previous write operation.
|
// Check the last character of the previous write operation.
|
||||||
builder.Length - data.Length - 1 >= 0 &&
|
Builder.Length - count - 1 >= 0 &&
|
||||||
builder[builder.Length - data.Length - 1] == '\r' &&
|
Builder[Builder.Length - count - 1] == '\r' &&
|
||||||
|
|
||||||
// Check the first character of the current write operation.
|
// Check the first character of the current write operation.
|
||||||
builder[builder.Length - data.Length] == '\n')
|
Builder[Builder.Length - count] == '\n')
|
||||||
{
|
{
|
||||||
// This is newline that's spread across two writes. Skip the first character of the
|
// This is newline that's spread across two writes. Skip the first character of the
|
||||||
// current write operation.
|
// current write operation.
|
||||||
|
|
@ -133,7 +127,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
|
|
||||||
// We might have stopped at a \r, so check if it's followed by \n and then advance the index to
|
// We might have stopped at a \r, so check if it's followed by \n and then advance the index to
|
||||||
// start the next search after it.
|
// start the next search after it.
|
||||||
if (data.Length > i &&
|
if (count > i &&
|
||||||
data[i - 1] == '\r' &&
|
data[i - 1] == '\r' &&
|
||||||
data[i] == '\n')
|
data[i] == '\n')
|
||||||
{
|
{
|
||||||
|
|
@ -147,12 +141,12 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
if (trailingPartStart == null)
|
if (trailingPartStart == null)
|
||||||
{
|
{
|
||||||
// No newlines, just add the length of the data buffer
|
// No newlines, just add the length of the data buffer
|
||||||
_currentLineCharacterIndex += data.Length;
|
_currentLineCharacterIndex += count;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Newlines found, add the trailing part of 'data'
|
// Newlines found, add the trailing part of 'data'
|
||||||
_currentLineCharacterIndex += (data.Length - trailingPartStart.Value);
|
_currentLineCharacterIndex += (count - trailingPartStart.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -160,17 +154,14 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
|
|
||||||
public CodeWriter WriteLine()
|
public CodeWriter WriteLine()
|
||||||
{
|
{
|
||||||
LastWrite = _writer.NewLine;
|
Builder.Append(NewLine);
|
||||||
|
|
||||||
_writer.WriteLine();
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
_currentLineIndex++;
|
_currentLineIndex++;
|
||||||
_currentLineCharacterIndex = 0;
|
_currentLineCharacterIndex = 0;
|
||||||
_absoluteIndex += _writer.NewLine.Length;
|
_absoluteIndex += NewLine.Length;
|
||||||
|
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
_newLine = true;
|
IsAfterNewLine = true;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -180,18 +171,11 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
return Write(data).WriteLine();
|
return Write(data).WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeWriter Flush()
|
|
||||||
{
|
|
||||||
_writer.Flush();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GenerateCode()
|
public string GenerateCode()
|
||||||
{
|
{
|
||||||
if (_dirty)
|
if (_dirty)
|
||||||
{
|
{
|
||||||
_cache = _writer.ToString();
|
_cache = Builder.ToString();
|
||||||
_dirty = false;
|
_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,7 +191,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
_writer.Dispose();
|
Builder.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue