diff --git a/Source/SvgExtentions.cs b/Source/SvgExtentions.cs index 4f24735e010921d8d6c280a720bf67bd1d48a8ee..74354c06bd9d0b91cb2975c9ed9e0b284315ee7f 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); } }