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}