Skip to content

Commit

Permalink
Merge pull request #288 from MihaZupan/rewrite-descendants-search
Browse files Browse the repository at this point in the history
Rewrite Descendants iteratively
  • Loading branch information
xoofx committed Jan 19, 2019
2 parents f8df3c8 + 95cbf0e commit e643203
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 147 deletions.
1 change: 1 addition & 0 deletions src/Markdig.Tests/Markdig.Tests.csproj
Expand Up @@ -58,6 +58,7 @@
</Compile>
<Compile Include="Specs\TestEmphasisPlus.cs" />
<Compile Include="TestEmphasisExtraOptions.cs" />
<Compile Include="TestDescendantsOrder.cs" />
<Compile Include="TestConfigureNewLine.cs" />
<Compile Include="TestHtmlAttributes.cs" />
<Compile Include="TestHtmlHelper.cs" />
Expand Down
85 changes: 85 additions & 0 deletions src/Markdig.Tests/TestDescendantsOrder.cs
@@ -0,0 +1,85 @@
using NUnit.Framework;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using System.Linq;
using System.Collections.Generic;

namespace Markdig.Tests
{
[TestFixture]
public class TestDescendantsOrder
{
[Test]
public void TestSchemas()
{
foreach (var markdown in TestParser.SpecsMarkdown)
{
AssertSameDescendantsOrder(markdown);
}
}

private void AssertSameDescendantsOrder(string markdown)
{
var syntaxTree = Markdown.Parse(markdown, new MarkdownPipelineBuilder().UseAdvancedExtensions().Build());

var descendants_legacy = Descendants_Legacy(syntaxTree).ToList();
var descendants_new = syntaxTree.Descendants().ToList();

Assert.AreEqual(descendants_legacy.Count, descendants_new.Count);

for (int i = 0; i < descendants_legacy.Count; i++)
{
Assert.AreSame(descendants_legacy[i], descendants_new[i]);
}
}

private static IEnumerable<MarkdownObject> Descendants_Legacy(MarkdownObject markdownObject)
{
// TODO: implement a recursiveless method

var block = markdownObject as ContainerBlock;
if (block != null)
{
foreach (var subBlock in block)
{
yield return subBlock;

foreach (var sub in Descendants_Legacy(subBlock))
{
yield return sub;
}

// Visit leaf block that have inlines
var leafBlock = subBlock as LeafBlock;
if (leafBlock?.Inline != null)
{
foreach (var subInline in Descendants_Legacy(leafBlock.Inline))
{
yield return subInline;
}
}
}
}
else
{
var inline = markdownObject as ContainerInline;
if (inline != null)
{
var child = inline.FirstChild;
while (child != null)
{
var next = child.NextSibling;
yield return child;

foreach (var sub in Descendants_Legacy(child))
{
yield return sub;
}

child = next;
}
}
}
}
}
}
16 changes: 16 additions & 0 deletions src/Markdig.Tests/TestParser.cs
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Markdig.Extensions.JiraLinks;
Expand Down Expand Up @@ -155,5 +156,20 @@ private static string Compact(string html)
html = html.Normalize(NormalizationForm.FormKD);
return html;
}

public static readonly string[] SpecsMarkdown;
static TestParser()
{
string assemblyDir = Path.GetDirectoryName(typeof(TestParser).Assembly.Location);
string specsDir = Path.GetFullPath(Path.Combine(assemblyDir, "../../Specs"));

var files = Directory.GetFiles(specsDir).Where(file => file.EndsWith(".md", StringComparison.Ordinal)).ToList();
SpecsMarkdown = new string[files.Count];

for (int i = 0; i < files.Count; i++)
{
SpecsMarkdown[i] = File.ReadAllText(files[i]);
}
}
}
}
45 changes: 28 additions & 17 deletions src/Markdig/Syntax/Inlines/ContainerInline.cs
Expand Up @@ -94,25 +94,36 @@ public bool ContainsChild(Inline childToFind)
/// <returns>An enumeration of T</returns>
public IEnumerable<T> FindDescendants<T>() where T : Inline
{
var child = FirstChild;
while (child != null)
{
var next = child.NextSibling;
// Fast-path an empty container to avoid allocating a Stack
if (LastChild == null) yield break;

if (child is T)
{
yield return (T)child;
}
Stack<Inline> stack = new Stack<Inline>();

if (child is ContainerInline)
{
foreach (var subChild in ((ContainerInline) child).FindDescendants<T>())
{
yield return subChild;
}
}

child = next;
var child = LastChild;
while (child != null)
{
stack.Push(child);
child = child.PreviousSibling;
}

while (stack.Count > 0)
{
child = stack.Pop();

if (child is T childT)
{
yield return childT;
}

if (child is ContainerInline containerInline)
{
child = containerInline.LastChild;
while (child != null)
{
stack.Push(child);
child = child.PreviousSibling;
}
}
}
}

Expand Down

0 comments on commit e643203

Please sign in to comment.