Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 8.0 and a few other perf improvements #751

Merged
merged 13 commits into from
Nov 25, 2023
Merged
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ jobs:
submodules: true
fetch-depth: 0

- name: Install .NET 6.0
- name: Install .NET 6.0, 7.0, and 8.0
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x'
dotnet-version: |
6.0.x
7.0.x
8.0.x

- name: Build, Test, Pack, Publish
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion src/Markdig.Tests/Markdig.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
3 changes: 3 additions & 0 deletions src/Markdig.Tests/TestYamlFrontMatterExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@ public DummyRenderer()
ObjectRenderers = new ObjectRendererCollection();
}

#pragma warning disable CS0067 // ObjectWriteBefore/ObjectWriteAfter is never used
public event Action<IMarkdownRenderer, MarkdownObject> ObjectWriteBefore;
public event Action<IMarkdownRenderer, MarkdownObject> ObjectWriteAfter;
#pragma warning restore CS0067

public ObjectRendererCollection ObjectRenderers { get; }
public object Render(MarkdownObject markdownObject)
{
Expand Down
29 changes: 17 additions & 12 deletions src/Markdig/Extensions/AutoIdentifiers/AutoIdentifierExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@ namespace Markdig.Extensions.AutoIdentifiers;
public class AutoIdentifierExtension : IMarkdownExtension
{
private const string AutoIdentifierKey = "AutoIdentifier";
private readonly AutoIdentifierOptions options;
private readonly StripRendererCache rendererCache = new StripRendererCache();

private static readonly StripRendererCache _rendererCache = new();

private readonly AutoIdentifierOptions _options;

/// <summary>
/// Initializes a new instance of the <see cref="AutoIdentifierExtension"/> class.
/// </summary>
/// <param name="options">The options.</param>
public AutoIdentifierExtension(AutoIdentifierOptions options)
{
this.options = options;
_options = options;
}

public void Setup(MarkdownPipelineBuilder pipeline)
Expand Down Expand Up @@ -68,7 +70,7 @@ private void HeadingBlockParser_Closed(BlockProcessor processor, Block block)
}

// If the AutoLink options is set, we register a LinkReferenceDefinition at the document level
if ((options & AutoIdentifierOptions.AutoLink) != 0)
if ((_options & AutoIdentifierOptions.AutoLink) != 0)
{
var headingLine = headingBlock.Lines.Lines[0];

Expand Down Expand Up @@ -157,16 +159,17 @@ private void HeadingBlock_ProcessInlinesEnd(InlineProcessor processor, Inline? i
}

// Use internally a HtmlRenderer to strip links from a heading
var stripRenderer = rendererCache.Get();
var stripRenderer = _rendererCache.Get();

stripRenderer.Render(headingBlock.Inline);
var headingText = stripRenderer.Writer.ToString()!;
rendererCache.Release(stripRenderer);
ReadOnlySpan<char> rawHeadingText = ((FastStringWriter)stripRenderer.Writer).AsSpan();

// Urilize the link
headingText = (options & AutoIdentifierOptions.GitHub) != 0
? LinkHelper.UrilizeAsGfm(headingText)
: LinkHelper.Urilize(headingText, (options & AutoIdentifierOptions.AllowOnlyAscii) != 0);
string headingText = (_options & AutoIdentifierOptions.GitHub) != 0
? LinkHelper.UrilizeAsGfm(rawHeadingText)
: LinkHelper.Urilize(rawHeadingText, (_options & AutoIdentifierOptions.AllowOnlyAscii) != 0);

_rendererCache.Release(stripRenderer);

// If the heading is empty, use the word "section" instead
var baseHeadingId = string.IsNullOrEmpty(headingText) ? "section" : headingText;
Expand Down Expand Up @@ -197,7 +200,7 @@ private sealed class StripRendererCache : ObjectCache<HtmlRenderer>
{
protected override HtmlRenderer NewInstance()
{
var headingWriter = new StringWriter();
var headingWriter = new FastStringWriter();
var stripRenderer = new HtmlRenderer(headingWriter)
{
// Set to false both to avoid having any HTML tags in the output
Expand All @@ -209,7 +212,9 @@ protected override HtmlRenderer NewInstance()

protected override void Reset(HtmlRenderer instance)
{
instance.Reset();
instance.ResetInternal();

((FastStringWriter)instance.Writer).Reset();
}
}
}
2 changes: 1 addition & 1 deletion src/Markdig/Helpers/BlockWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public BlockWrapper(Block block)

public bool Equals(BlockWrapper other) => ReferenceEquals(Block, other.Block);

public override bool Equals(object obj) => Block.Equals(obj);
public override bool Equals(object? obj) => Block.Equals(obj);

public override int GetHashCode() => Block.GetHashCode();
}
59 changes: 26 additions & 33 deletions src/Markdig/Helpers/CharHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ public static class CharHelper
{ 'I', 1 }, { 'V', 5 }, { 'X', 10 }
};

private static readonly char[] punctuationExceptions = { '−', '-', '†', '‡' };
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsPunctuationException(char c) =>
c is '−' or '-' or '†' or '‡';

public static void CheckOpenCloseDelimiter(char pc, char c, bool enableWithinWord, out bool canOpen, out bool canClose)
{
pc.CheckUnicodeCategory(out bool prevIsWhiteSpace, out bool prevIsPunctuation);
c.CheckUnicodeCategory(out bool nextIsWhiteSpace, out bool nextIsPunctuation);

var prevIsExcepted = prevIsPunctuation && punctuationExceptions.Contains(pc);
var nextIsExcepted = nextIsPunctuation && punctuationExceptions.Contains(c);
var prevIsExcepted = prevIsPunctuation && IsPunctuationException(pc);
var nextIsExcepted = nextIsPunctuation && IsPunctuationException(c);

// A left-flanking delimiter run is a delimiter run that is
// (1) not followed by Unicode whitespace, and either
Expand Down Expand Up @@ -126,19 +128,6 @@ public static bool IsAcrossTab(int column)
return (column & (TabSize - 1)) != 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains(this char[] charList, char c)
{
foreach (char ch in charList)
{
if (ch == c)
{
return true;
}
}
return false;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsWhitespace(this char c)
{
Expand Down Expand Up @@ -178,7 +167,7 @@ static bool IsWhitespaceRare(char c)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsControl(this char c)
{
return c < ' ' || char.IsControl(c);
return char.IsControl(c);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down Expand Up @@ -211,15 +200,17 @@ public static void CheckUnicodeCategory(this char c, out bool space, out bool pu
{
// A Unicode punctuation character is an ASCII punctuation character
// or anything in the general Unicode categories Pc, Pd, Pe, Pf, Pi, Po, or Ps.
const int PunctuationCategoryMask =
1 << (int)UnicodeCategory.ConnectorPunctuation |
1 << (int)UnicodeCategory.DashPunctuation |
1 << (int)UnicodeCategory.OpenPunctuation |
1 << (int)UnicodeCategory.ClosePunctuation |
1 << (int)UnicodeCategory.InitialQuotePunctuation |
1 << (int)UnicodeCategory.FinalQuotePunctuation |
1 << (int)UnicodeCategory.OtherPunctuation;

space = false;
UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory(c);
punctuation = category == UnicodeCategory.ConnectorPunctuation
|| category == UnicodeCategory.DashPunctuation
|| category == UnicodeCategory.OpenPunctuation
|| category == UnicodeCategory.ClosePunctuation
|| category == UnicodeCategory.InitialQuotePunctuation
|| category == UnicodeCategory.FinalQuotePunctuation
|| category == UnicodeCategory.OtherPunctuation;
punctuation = (PunctuationCategoryMask & (1 << (int)CharUnicodeInfo.GetUnicodeCategory(c))) != 0;
}
}

Expand All @@ -236,14 +227,16 @@ internal static bool IsSpaceOrPunctuation(this char c)
}
else
{
var category = CharUnicodeInfo.GetUnicodeCategory(c);
return category == UnicodeCategory.ConnectorPunctuation
|| category == UnicodeCategory.DashPunctuation
|| category == UnicodeCategory.OpenPunctuation
|| category == UnicodeCategory.ClosePunctuation
|| category == UnicodeCategory.InitialQuotePunctuation
|| category == UnicodeCategory.FinalQuotePunctuation
|| category == UnicodeCategory.OtherPunctuation;
const int PunctuationCategoryMask =
1 << (int)UnicodeCategory.ConnectorPunctuation |
1 << (int)UnicodeCategory.DashPunctuation |
1 << (int)UnicodeCategory.OpenPunctuation |
1 << (int)UnicodeCategory.ClosePunctuation |
1 << (int)UnicodeCategory.InitialQuotePunctuation |
1 << (int)UnicodeCategory.FinalQuotePunctuation |
1 << (int)UnicodeCategory.OtherPunctuation;

return (PunctuationCategoryMask & (1 << (int)CharUnicodeInfo.GetUnicodeCategory(c))) != 0;
}
}

Expand Down
Loading
Loading