001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 The ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package org.conqat.lib.commons.visitor; 018 019import java.util.ArrayDeque; 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.Deque; 023import java.util.List; 024 025import org.conqat.lib.commons.collections.CollectionUtils; 026import org.conqat.lib.commons.collections.IdentityHashSet; 027import org.conqat.lib.commons.error.NeverThrownRuntimeException; 028 029/** 030 * Utility class for working with visitors. 031 */ 032public class VisitorUtils { 033 034 /** 035 * Visits all nodes of a tree in pre-order, i.e. a node is visited directly 036 * before its children. 037 * 038 * @param root 039 * the root of the tree. 040 * @param walker 041 * the walker user for traversing the tree. 042 * @param visitor 043 * the visitor used for visiting the nodes. 044 */ 045 public static <T, X1 extends Exception, X2 extends Exception> void visitAllPreOrder(T root, 046 ITreeWalker<T, X1> walker, IVisitor<T, X2> visitor) throws X1, X2 { 047 048 visitor.visit(root); 049 for (T child : walker.getChildren(root)) { 050 visitAllPreOrder(child, walker, visitor); 051 } 052 } 053 054 /** 055 * Visits all leaves of a tree, i.e. those nodes without children. 056 * 057 * @param root 058 * the root of the tree. 059 * @param walker 060 * the walker user for traversing the tree. 061 * @param visitor 062 * the visitor used for visiting the nodes. 063 */ 064 public static <T, X1 extends Exception, X2 extends Exception> void visitLeaves(T root, ITreeWalker<T, X1> walker, 065 IVisitor<T, X2> visitor) throws X1, X2 { 066 067 Collection<T> children = walker.getChildren(root); 068 if (children.isEmpty()) { 069 visitor.visit(root); 070 } else { 071 for (T child : children) { 072 visitLeaves(child, walker, visitor); 073 } 074 } 075 } 076 077 /** 078 * Visits all elements of a mesh in depth first order. It is made sure, that 079 * each reachable element is visited exactly once, where we use equality of 080 * references to determine elements that were seen before. 081 * 082 * Does not use recursive function calls to enable listing large graphs. 083 * 084 * @param start 085 * the element to start the traversal from. 086 * @param walker 087 * the walker user for traversing the mesh. 088 * @param visitor 089 * the visitor used for visiting the elements. 090 */ 091 public static <T, X1 extends Exception, X2 extends Exception> void visitAllDepthFirst(T start, 092 IMeshWalker<T, X1> walker, IVisitor<T, X2> visitor) throws X1, X2 { 093 IdentityHashSet<T> visitedNodes = new IdentityHashSet<T>(); 094 Deque<T> todoNodes = new ArrayDeque<>(); 095 todoNodes.addFirst(start); 096 while (!todoNodes.isEmpty()) { 097 T current = todoNodes.removeFirst(); 098 if (visitedNodes.contains(current)) { 099 continue; 100 } 101 visitor.visit(current); 102 visitedNodes.add(current); 103 for (T succ : CollectionUtils.reverse(walker.getAdjacentElements(current))) { 104 if (!visitedNodes.contains(succ)) { 105 todoNodes.addFirst(succ); 106 } 107 } 108 } 109 } 110 111 /** 112 * Lists all elements of a mesh in depth first order. It is made sure, that 113 * each reachable element is visited exactly once, where we use equality of 114 * references to determine elements that were seen before. 115 * 116 * @param start 117 * the element to start the traversal from. 118 * @param walker 119 * the walker user for traversing the mesh. 120 */ 121 public static <T, X extends Exception> List<T> listAllDepthFirst(T start, IMeshWalker<T, X> walker) throws X { 122 final List<T> list = new ArrayList<>(); 123 visitAllDepthFirst(start, walker, new IVisitor<T, NeverThrownRuntimeException>() { 124 125 @Override 126 public void visit(T element) throws NeverThrownRuntimeException { 127 list.add(element); 128 } 129 }); 130 return list; 131 } 132 133}