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