/// <summary> /// Specialized constructor for creating a ThroughChildren iterator at a node path. Basically, we create an iterator at the parent /// then queue up the remaining siblings for next evals in iter state. That allows us to start at a path and not miss the siblings /// </summary> /// <param name="nodeParent"></param> /// <param name="nodePath"></param> /// <param name="traversalParameters"></param> /// <param name="getChildrenMethodOverride"></param> /// <param name="getParentMethodOverride"></param> private TreeIter(TTreeNode nodeParent, TreeNodePath nodePath, TreeTraversalParameters <TTreeNode> traversalParameters, GetTreeNodeChildren <TTreeNode> getChildrenMethodOverride = null, GetTreeNodeParent <TTreeNode> getParentMethodOverride = null) { this.TraversalParameters = traversalParameters; //int finalIndex = nodePath.Last(); //TTreeNode currentTarget = this.State.GetChildrenMethod(nodeParent).ElementAt(finalIndex); this.State = new TreeIterState <TTreeNode>(nodeParent, traversalParameters, nodePath); this.State.ProcessNextEvaluations(nodePath.Last()); }
/// <summary> /// Creates a customizable tree iterator /// </summary> /// <param name="start">The starting point</param> /// <param name="traversalParameters">The custom parameters used to control the traversal</param> /// <returns>The iterator that was created</returns> public static TreeIter <TTreeNode> CreateIterator(TTreeNode start, TreeTraversalParameters <TTreeNode> traversalParameters) { if (start == null) { return(TreeIter <TTreeNode> .End); } return(new TreeIter <TTreeNode>(start, traversalParameters)); }
public static TreeIter <TTreeNode> IteratorAt(TTreeNode root, TreeNodePath nodePath, Predicate <TTreeNode> predicate = null, eTraversalFlowDirection flowDirection = DefaultTraversalFlowDirection, eTraversalStrategy strategy = DefaultTraversalStrategy, bool includeSelf = true, LevelRestriction depthLimits = null, GetTreeNodeChildren <TTreeNode> getChildrenMethodOverride = null, GetTreeNodeParent <TTreeNode> getParentMethodOverride = null) { var traversalParams = new TreeTraversalParameters <TTreeNode>(root, flowDirection, strategy, getChildrenMethodOverride, getParentMethodOverride) { Predicate = predicate, DepthLimits = depthLimits, }; var iter = TreeIter <TTreeNode> .CreateIteratorAtNodePath(root, nodePath, traversalParams); return(FinalizeAndReturnIter(iter, includeSelf, traversalParams.Predicate, start: false)); }
internal TreeIterState(TTreeNode node, TreeTraversalParameters <TTreeNode> traversalParameters, TreeNodePath nodePath = null) { m_traversalParameters = traversalParameters; this.Target = node; this.CurrentNumberOfEvaluations = 0; if (nodePath != null) { this.TargetPath = nodePath; } else { this.TargetPath = new TreeNodePath(); } }
/// <summary> /// Iterate over all the nodes of a particaulr type /// </summary> /// <typeparam name="T">Tree node type</typeparam> /// <param name="root">The tree's root node</param> /// <param name="start">The starting point</param> /// <param name="predicate">The predicate</param> /// <param name="flowDirection">The direction the traversal flows through the tree</param> /// <param name="strategy">The traversal strategy</param> /// <param name="includeSelf">Should the start node be included</param> /// <param name="canTypeBeAncestor">Can the type be derivitive of the passed in type, or must it be an exact match (default is true)</param> /// <param name="depthLimits">Depth limits</param> /// <param name="getChildrenMethodOverride">The override to the default GetTreeNodeChildren method specified in <see cref="TreeTraversal{TTreeNode}"/>.SetupDefaults, or null to use the default</param> /// <param name="getParentMethodOverride">The override to the default GetTreeNodeParents method specified in <see cref="TreeTraversal{TTreeNode}"/>.SetupDefaults, or null to use the default</param> /// <returns></returns> public static TreeIter <TTreeNode> IterateOverNodesOfType <T> (TTreeNode root, TTreeNode start, Predicate <T> predicate = null, eTraversalFlowDirection flowDirection = DefaultTraversalFlowDirection, eTraversalStrategy strategy = DefaultTraversalStrategy, bool includeSelf = true, bool canTypeBeAncestor = true, LevelRestriction depthLimits = null, GetTreeNodeChildren <TTreeNode> getChildrenMethodOverride = null, GetTreeNodeParent <TTreeNode> getParentMethodOverride = null) where T : class { var traversalParams = new TreeTraversalParameters <TTreeNode>(root ?? FindRoot(start, getParentMethodOverride), flowDirection, strategy, getChildrenMethodOverride, getParentMethodOverride) { TypeMatching = new TypeEval(typeof(T), canTypeBeAncestor), PruneAfterFirstFind = false, DepthLimits = depthLimits, }; if (predicate != null) { traversalParams.Predicate = (_obj) => predicate(_obj as T); } var iter = CreateIterator(start, traversalParams); return(FinalizeAndReturnIter(iter, includeSelf, traversalParams.Predicate)); }
/// <summary> /// Specialty constructor for creating iter from a root node /// </summary> /// <param name="start">The root node</param> /// <param name="traversalParameters">The parameters to the tree traversal</param> /// <param name="getChildrenMethodOverride">An override to the default GetChildren method</param> /// <param name="getParentMethodOverride">An override to the default GetParent method</param> internal TreeIter(TTreeNode start, TreeTraversalParameters <TTreeNode> traversalParameters) { this.TraversalParameters = traversalParameters; // We want our paths to be root-centric so if start is not root (and there is a root listed) // then we need to give ourselves a starter path from root TreeNodePath pathFromRoot = null; if (traversalParameters.Root != null && start != traversalParameters.Root) { var treePath = new Stack <int>(); TTreeNode target = start; while (target != null && target != traversalParameters.Root) { var parent = this.TraversalParameters.GetParentMethod(target); if (parent == null) { break; } // To path in this way, we must gurantee that the children we get are indexable // thus this will throw if they are not of IList var children = this.TraversalParameters.GetChildrenMethod.Invoke(parent); if (children is IList listChild) { treePath.Push(listChild.IndexOf(target)); } else { treePath.Push(children.Count(_ => _ != target)); } target = parent; } pathFromRoot = new TreeNodePath(treePath); } this.State = new TreeIterState <TTreeNode>(start, traversalParameters, pathFromRoot); this.State.ProcessNextEvaluations(); }
/// <summary> /// Basic constructor /// </summary> internal TreeIter(TreeIterState <TTreeNode> state, TreeTraversalParameters <TTreeNode> traversalParameters) { this.State = state; this.TraversalParameters = traversalParameters; }
internal static TreeIter <TTreeNode> CreateIteratorAtNodePath(TTreeNode root, TreeNodePath nodePath, TreeTraversalParameters <TTreeNode> traversalParameters, GetTreeNodeChildren <TTreeNode> getChildrenMethodOverride = null, GetTreeNodeParent <TTreeNode> getParentMethodOverride = null) { // If the node path is empty, then we're creating one from the root if (nodePath.Count == 0) { return(new TreeIter <TTreeNode>(root, traversalParameters)); } if (traversalParameters.FlowDirection == eTraversalFlowDirection.ThroughParents) { // Why is this not supported Debug.Fail("Node pathing through parents is not supported"); } else if (traversalParameters.FlowDirection == eTraversalFlowDirection.ThroughChildren) { // Otherwise we are creating an iterator for the node's parent, but with the next evaluations stocked starting at the final nodepath piece, // then we can just increment by one. This enables us to use the siblings to the indicated start node. TTreeNode parentNode = TreeTraversal <TTreeNode> .ParentNodeFromPath(root, nodePath); if (parentNode == null) { return(End); } var justBeforeIter = new TreeIter <TTreeNode>(parentNode, nodePath, traversalParameters, getChildrenMethodOverride, getParentMethodOverride); return(++justBeforeIter); } else if (traversalParameters.FlowDirection == eTraversalFlowDirection.ReversedThroughChildren) { Debug.Fail("Node pathing through parents is not supported"); } return(End); }
/// <summary> /// Creates a customizable tree iterator /// </summary> /// <param name="startNode">The node of the tree to start at, or null to start at the root</param> /// <param name="traversalParameters">The custom parameters used to control the traversal</param> /// <returns>The iterator that was created</returns> public TreeIter <TTreeNode> CreateIterator(TTreeNode startNode, TreeTraversalParameters <TTreeNode> traversalParameters) { traversalParameters.Root = this.Root; traversalParameters.SetGetChildrenGetParentOverrideMethods(this.GetChildrenOverride, this.GetParentOverride); return(TreeTraversal <TTreeNode> .CreateIterator(startNode ?? this.Root, traversalParameters)); }
/// <summary> /// Creates a customizable tree iterator /// </summary> /// <param name="traversalParameters">The custom parameters used to control the traversal</param> /// <returns>The iterator that was created</returns> public TreeIter <TTreeNode> CreateIterator(TreeTraversalParameters <TTreeNode> traversalParameters) { return(this.CreateIterator(this.Root, traversalParameters)); }