mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-04 05:44:50 +00:00
Optimized away the expensive StringBuilder.Remove(0, 1) in CodeInlineParser
This commit is contained in:
@@ -1,47 +1,47 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Parsers.Inlines
|
||||
{
|
||||
/// <summary>
|
||||
/// An inline parser for a <see cref="CodeInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Parsers.InlineParser" />
|
||||
public class CodeInlineParser : InlineParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CodeInlineParser"/> class.
|
||||
/// </summary>
|
||||
public CodeInlineParser()
|
||||
{
|
||||
OpeningCharacters = new[] { '`' };
|
||||
}
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
var match = slice.CurrentChar;
|
||||
if (slice.PeekCharExtra(-1) == match)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var startPosition = slice.Start;
|
||||
|
||||
int openSticks = 0;
|
||||
int closeSticks = 0;
|
||||
|
||||
// Match the opened sticks
|
||||
char c = slice.CurrentChar;
|
||||
while (c == match)
|
||||
{
|
||||
openSticks++;
|
||||
c = slice.NextChar();
|
||||
}
|
||||
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Parsers.Inlines
|
||||
{
|
||||
/// <summary>
|
||||
/// An inline parser for a <see cref="CodeInline"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Parsers.InlineParser" />
|
||||
public class CodeInlineParser : InlineParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CodeInlineParser"/> class.
|
||||
/// </summary>
|
||||
public CodeInlineParser()
|
||||
{
|
||||
OpeningCharacters = new[] { '`' };
|
||||
}
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
var match = slice.CurrentChar;
|
||||
if (slice.PeekCharExtra(-1) == match)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var startPosition = slice.Start;
|
||||
|
||||
int openSticks = 0;
|
||||
int closeSticks = 0;
|
||||
|
||||
// Match the opened sticks
|
||||
char c = slice.CurrentChar;
|
||||
while (c == match)
|
||||
{
|
||||
openSticks++;
|
||||
c = slice.NextChar();
|
||||
}
|
||||
|
||||
var builder = processor.StringBuilders.Get();
|
||||
|
||||
// A backtick string is a string of one or more backtick characters (`) that is neither preceded nor followed by a backtick.
|
||||
@@ -53,71 +53,76 @@ namespace Markdig.Parsers.Inlines
|
||||
// 2. If the resulting string both begins AND ends with a space character, but does not consist entirely
|
||||
// of space characters, a single space character is removed from the front and back.
|
||||
// This allows you to include code that begins or ends with backtick characters, which must be separated by
|
||||
// whitespace from the opening or closing backtick strings.
|
||||
|
||||
bool allSpace = true;
|
||||
|
||||
while (c != '\0')
|
||||
{
|
||||
// Transform '\n' into a single space
|
||||
if (c == '\n')
|
||||
{
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
// whitespace from the opening or closing backtick strings.
|
||||
|
||||
bool allSpace = true;
|
||||
|
||||
while (c != '\0')
|
||||
{
|
||||
// Transform '\n' into a single space
|
||||
if (c == '\n')
|
||||
{
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
if (c == match)
|
||||
{
|
||||
do
|
||||
{
|
||||
closeSticks++;
|
||||
c = slice.NextChar();
|
||||
do
|
||||
{
|
||||
closeSticks++;
|
||||
c = slice.NextChar();
|
||||
}
|
||||
while (c == match);
|
||||
|
||||
if (openSticks == closeSticks)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
allSpace = false;
|
||||
builder.Append(match, closeSticks);
|
||||
if (openSticks == closeSticks)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
allSpace = false;
|
||||
builder.Append(match, closeSticks);
|
||||
closeSticks = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(c);
|
||||
if (c != ' ')
|
||||
{
|
||||
allSpace = false;
|
||||
}
|
||||
}
|
||||
c = slice.NextChar();
|
||||
}
|
||||
}
|
||||
|
||||
bool isMatching = false;
|
||||
if (closeSticks == openSticks)
|
||||
{
|
||||
// Remove one space from front and back if the string is not all spaces
|
||||
if (!allSpace && builder.Length > 2 && builder[0] == ' ' && builder[builder.Length - 1] == ' ')
|
||||
{
|
||||
builder.Length--;
|
||||
builder.Remove(0, 1); // More expensive, alternative is to have a double-pass algorithm
|
||||
}
|
||||
|
||||
processor.Inline = new CodeInline()
|
||||
{
|
||||
Delimiter = match,
|
||||
Content = builder.ToString(),
|
||||
Span = new SourceSpan(processor.GetSourcePosition(startPosition, out int line, out int column), processor.GetSourcePosition(slice.Start - 1)),
|
||||
Line = line,
|
||||
Column = column
|
||||
};
|
||||
isMatching = true;
|
||||
}
|
||||
|
||||
// Release the builder if not used
|
||||
processor.StringBuilders.Release(builder);
|
||||
return isMatching;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isMatching = false;
|
||||
if (closeSticks == openSticks)
|
||||
{
|
||||
string content;
|
||||
|
||||
// Remove one space from front and back if the string is not all spaces
|
||||
if (!allSpace && builder.Length > 2 && builder[0] == ' ' && builder[builder.Length - 1] == ' ')
|
||||
{
|
||||
content = builder.ToString(1, builder.Length - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
content = builder.ToString();
|
||||
}
|
||||
|
||||
processor.Inline = new CodeInline()
|
||||
{
|
||||
Delimiter = match,
|
||||
Content = content,
|
||||
Span = new SourceSpan(processor.GetSourcePosition(startPosition, out int line, out int column), processor.GetSourcePosition(slice.Start - 1)),
|
||||
Line = line,
|
||||
Column = column
|
||||
};
|
||||
isMatching = true;
|
||||
}
|
||||
|
||||
// Release the builder if not used
|
||||
processor.StringBuilders.Release(builder);
|
||||
return isMatching;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user