using System.Collections; using System; namespace GlitchyEngine.Collections { // TODO: TreeNode is very bare minimum // Destructor? // RemoveChild? // Remove in enumerator? public class TreeNode { public T Value; public Self Parent; public List Children = new .() ~ DeleteContainerAndItems!(_); public this() {} public this(T value) { Value = value; } public Self AddChild(T value) { for (var child in Children) { if(child.Value == value) return child; } Self newChild = new .(value); newChild.Parent = this; Children.Add(newChild); return newChild; } public bool RemoveChild(TreeNode value) { return Children.Remove(value); } public Self FindNode(T value) { if (Value == value) return this; for (var child in Children) { var childResult = child.FindNode(value); if (childResult != null) return childResult; } return null; } public static ref T operator ->(TreeNode node) { return ref node.Value; } public delegate void ElementFunc(TreeNode currentNode); public enum IterationMode { BreadthFirst, DepthFirst } public bool IsParentOf(TreeNode wantedChild) { return wantedChild.IsChildOf(this); } public bool IsChildOf(TreeNode wantedParent) { TreeNode currentParent = Parent; while (currentParent != null) { if (currentParent == wantedParent) return true; currentParent = currentParent.Parent; } return false; } public bool IsInSubtree(TreeNode subtree) { if (this == subtree) return true; return IsChildOf(subtree); } public void ForEach(ElementFunc func, IterationMode iterationMode = .DepthFirst) { if (iterationMode == .BreadthFirst) { ForEach_BreadthFirst(func); } else if (iterationMode == .DepthFirst) { ForEach_DepthFirst(func); } } public void ForEach_BreadthFirst(ElementFunc func) { Queue> nodes = scope .(); nodes.Add(this); while (!nodes.IsEmpty) { TreeNode node = nodes.PopFront(); func(node); for (var child in node.Children) { nodes.Add(child); } } } public void ForEach_DepthFirst(ElementFunc func) { List> nodes = scope .(); nodes.Add(this); while (!nodes.IsEmpty) { TreeNode node = nodes.PopBack(); func(node); for (var child in node.Children) { nodes.Add(child); } } } } static { public static mixin DeleteTreeAndChildren(TreeNode tree) where T : class, delete { InternalDeleteTreeAndChildren(tree); } private static void InternalDeleteTreeAndChildren(TreeNode tree) where T : class, delete { if (tree == null) return; for (var child in tree.Children) { InternalDeleteTreeAndChildren(child); } delete tree.Value; tree.Children.Clear(); delete tree; } } }