private void ProcessNextEvaluationsForReverseChildTraversal(List <TreeEvalItem <TTreeNode> > nextEvals) { TreeEvalItem <TTreeNode> nextEval = null; if (m_traversalParameters.ChildTraversalStrategy == eTraversalStrategy.BreadthFirst) { nextEval = this.ProcessNextEvaluationsForRBFS(this.Target, new TreeNodePath(this.TargetPath), this.CurrentDepthFromOrigin); // If the processing gives us nothing, then it's time to move up to the next if (nextEval == null) { var root = TreeTraversal <TTreeNode> .FindRoot(this.Target); if (root != null) { nextEval = this.GetLastLeafAtDepth(root, new TreeNodePath(), this.TargetPath.Count - 1); } } } else if (m_traversalParameters.ChildTraversalStrategy == eTraversalStrategy.DepthFirst) { var parent = m_traversalParameters.GetParentMethod(this.Target); if (parent == null) { return; } // Iterate over the children, saving the current one into toVisit until we reach // the target, that will give us the sibling before target TTreeNode toVisit = null; foreach (var child in m_traversalParameters.GetChildrenMethod(parent)) { if (child == this.Target) { break; } toVisit = child; } // If there are no siblings before target, then we need to move up to the parent if (toVisit == null) { TreeNodePath parentPath = this.TargetPath.CopyAndRemoveEnd(); nextEval = new TreeEvalItem <TTreeNode>(parent, parentPath); } else { // If there was an adjacent sibling, then we need to get the last leaf node of it, that is the next // evaluation. When that item gets evaluated, it will go through this same process which will lead // to any of it's siblings, andtheir last leaf, etc. etc. giving us a depth first search backwards nextEval = this.GetLastLeaf(toVisit, this.CurrentDepthFromOrigin, new TreeNodePath(this.TargetPath)); } } if (nextEval != null && this.IsUniqueInIteration(nextEval.Node)) { nextEvals.Add(nextEval); } }
private TreeEvalItem <TTreeNode> ProcessNextEvaluationsForRBFS(TTreeNode target, TreeNodePath path, int targetDepth) { if (target == null) { return(null); } var parent = m_traversalParameters.GetParentMethod(target); if (parent == null) { return(null); } TTreeNode nextClosestSibling = null; int nextClosestSiblingIndex = -1; int childIndex = 0; foreach (var sibling in m_traversalParameters.GetChildrenMethod(parent)) { if (sibling == target) { break; } nextClosestSiblingIndex = childIndex++; nextClosestSibling = sibling; } // No siblings, recurse to the parent/grandparent if (nextClosestSibling == null) { TreeEvalItem <TTreeNode> cousin = this.GetNextRBFSCousin(parent, path.CopyAndRemoveEnd(), targetDepth); if (cousin != null) { return(cousin); } // Looks like end of this depth... time to go forward and back to the end return(this.GetLastLeafAtDepth(m_traversalParameters.Root, new TreeNodePath(), this.CurrentDepthFromOrigin - 1)); } // There were some siblings, see if we can find our next target return(new TreeEvalItem <TTreeNode>(nextClosestSibling, path.CopyAndSwapEndForSibling(nextClosestSiblingIndex))); }
private TreeEvalItem <TTreeNode> GetNextRBFSCousin(TTreeNode curr, TreeNodePath path, int targetDepth) { // If we've gotten into an error state, or if we're attempting to go past root if (curr == null || curr == m_traversalParameters.Root) { return(null); } // Iterate over all siblings and build a stack of siblings for us to evaluate (popping will give us sibling closest to curr, instead of parent's index[0]) var parent = m_traversalParameters.GetParentMethod(curr); if (parent == null) { return(null); } var siblingStack = new Stack <IndexTrackedNode>(); int siblingIndex = 0; foreach (var sibling in m_traversalParameters.GetChildrenMethod(parent)) { if (sibling == curr) { break; } siblingStack.Push(new IndexTrackedNode(siblingIndex++, sibling)); } // Evaluate from closest to curr back to index zero, and call GetlastLeafAtDepth, if we find a cousin at the target depth // then that is the next BFS item to search while (siblingStack.Count > 0) { var next = siblingStack.Pop(); TreeEvalItem <TTreeNode> cousinLeaf = this.GetLastLeafAtDepth(next.Node, path.CopyAndSwapEndForSibling(next.Index), targetDepth); if (cousinLeaf != null) { return(cousinLeaf); } } // If no cousin is found, than recurse upwards, this will be evaluting parent as curr return(this.GetNextRBFSCousin(parent, path.CopyAndRemoveEnd(), targetDepth)); }
/// <summary> /// Determines the next action in iteration that should be taken. This is called *after* a node has been sucessfully processed, /// and determines what the next phase of iteration should be in regards to the next node. /// </summary> /// <returns></returns> private eNextTraversalMove DetermineNextAction() { TreeEvalItem <TTreeNode> next = this.State.PeekNext(); // If we are over our max number of allowed evaluations, or there is a termination path set, and we've already evaluted that, then it's time to quit. if (next == null || (this.TraversalParameters.HasEvaluationCap && this.State.CurrentNumberOfEvaluations >= this.TraversalParameters.MaxNumberOfEvaluations) || (this.TraversalParameters.TerminationNodePath != null && this.NodePath.Equals(this.TraversalParameters.TerminationNodePath))) { return(eNextTraversalMove.Quit); } // Make sure we're allowed to run our action if (!this.State.HasPendingEvalItems || (this.TraversalParameters.EnforcesLevelRestriction && !this.TraversalParameters.DepthLimits.Passes(next.DepthFromOrigin, true))) { return(eNextTraversalMove.PruneAndContinueSearching); } // Note: Evaluting type before predicate because some predicates are actually typed if (this.TraversalParameters.RequiresTypeMatching && !this.TraversalParameters.TypeMatching.Evaluate(next.Node.GetType())) { return(eNextTraversalMove.SkipAndContinueSearching); } if (this.TraversalParameters.HasPredicate && !this.TraversalParameters.Predicate(next.Node)) { return(eNextTraversalMove.SkipAndContinueSearching); } if (this.TraversalParameters.PruneAfterFirstFind) { return(eNextTraversalMove.ProcessAndPrune); } return(eNextTraversalMove.Process); }