From 5dc7e7bc253def977285f5d693b76fc041e7677a Mon Sep 17 00:00:00 2001 From: Ken in NH Date: Wed, 27 Feb 2019 13:48:19 -0500 Subject: [PATCH] Took SvgDocument exclusion out of ApplyRecursive and optimized traversals (#425) --- Source/SvgExtentions.cs | 50 ++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/Source/SvgExtentions.cs b/Source/SvgExtentions.cs index 4f24735..74354c0 100644 --- a/Source/SvgExtentions.cs +++ b/Source/SvgExtentions.cs @@ -78,28 +78,52 @@ namespace Svg public static void ApplyRecursive(this SvgElement elem, Action action) { - action(elem); - - if (!(elem is SvgDocument)) //don't apply action to subtree of documents + foreach (var e in elem + .Traverse(e => e.Children)) { - foreach (var element in elem.Children) - { - element.ApplyRecursive(action); - } + action(e); } } public static void ApplyRecursiveDepthFirst(this SvgElement elem, Action action) { - if (!(elem is SvgDocument)) //don't apply action to subtree of documents + foreach (var e in elem + .TraverseDepthFirst(e => e.Children)) { - foreach (var element in elem.Children) - { - element.ApplyRecursiveDepthFirst(action); - } + action(e); + } + } + + public static IEnumerable Traverse(this IEnumerable items, Func> childrenSelector) + { + if (childrenSelector == null) throw new ArgumentNullException(nameof(childrenSelector)); + + var itemQueue = new Queue(items); + while (itemQueue.Count > 0) + { + var current = itemQueue.Dequeue(); + yield return current; + foreach (var child in childrenSelector(current) ?? Enumerable.Empty()) itemQueue.Enqueue(child); } + } - action(elem); + public static IEnumerable Traverse(this T root, Func> childrenSelector) + => Enumerable.Repeat(root, 1).Traverse(childrenSelector); + + public static IEnumerable TraverseDepthFirst(this IEnumerable items, Func> childrenSelector) + { + if (childrenSelector == null) throw new ArgumentNullException(nameof(childrenSelector)); + var itemStack = new Stack(items ?? Enumerable.Empty()); + + while (itemStack.Count > 0) + { + var current = itemStack.Pop(); + yield return current; + foreach (var child in childrenSelector(current) ?? Enumerable.Empty()) itemStack.Push(child); + } } + + public static IEnumerable TraverseDepthFirst(this T root, Func> childrenSelector) + => Enumerable.Repeat(root, 1).TraverseDepthFirst(childrenSelector); } } -- GitLab