/* * Copyright (c) 2012, Synflow * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the IETR/INSA of Rennes nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.graph.visit; import java.util.List; import java.util.ListIterator; import net.sf.orcc.graph.Edge; import net.sf.orcc.graph.GraphPackage; import net.sf.orcc.graph.Vertex; import org.eclipse.emf.ecore.EReference; /** * This class defines Depth-First Search (DFS) for a graph. * * @author Matthieu Wipliez * */ public class DFS extends Ordering { private boolean containsCycle = false; /** * current number. Starts at one. */ private int num = 1; private final EReference refEdges; private final EReference refVertex; /** * Creates a new DFS. This constructor only delegates to * <code>super(n)</code> and does not perform any visit. * * @param n * the expected number of vertices */ protected DFS(EReference refEdges, EReference refVertex, int n) { super(n); this.refEdges = refEdges; this.refVertex = refVertex; } /** * Initializes this DFS for a graph of <code>n</code> vertices. Does not * perform any kind of visit. * * @param n * the expected number of vertices */ public DFS(int n) { this(GraphPackage.Literals.VERTEX__OUTGOING, GraphPackage.Literals.EDGE__TARGET, n); } /** * Builds the list of vertices that can be reached from the given vertex * using depth-first search. Equivalent to <code>this(vertex, false)</code> * * @param vertex * a vertex * @see {@link #DFS(Vertex, boolean)} */ public DFS(Vertex vertex) { this(vertex, false); } /** * Builds the list of vertices that can be reached from the given vertex * using depth-first search. * * @param vertex * a vertex * @param order * if <code>true</code>, the vertices are visited in a post-order * manner, otherwise in a pre-order manner * @throws NullPointerException * if the given vertex is not contained in a graph */ public DFS(Vertex vertex, boolean order) { this(vertex.getGraph().getVertices().size()); if (order) { visitPost(vertex); } else { visitPre(vertex); } } /** * Returns true if the visited graph contains at least one cycle. * * @return true if the visited graph contains at least one cycle */ public boolean containsCycle() { return containsCycle; } /** * Visits the given vertex. Adds it to the vertices list and sets its * number. * * @param v * a vertex */ protected void visit(Vertex v) { vertices.add(v); v.setNumber(num); num++; } /** * Visits the given vertex and its successors in a post-order manner. The * successors are visited in a reverse order (i.e. last successor is visited * first) to give a more natural reverse post-ordering. * * @param v * a vertex */ public final void visitPost(Vertex v) { visited.add(v); @SuppressWarnings("unchecked") List<Edge> edges = (List<Edge>) v.eGet(refEdges); ListIterator<Edge> it = edges.listIterator(edges.size()); while (it.hasPrevious()) { Vertex w = (Vertex) it.previous().eGet(refVertex); if (!visited.contains(w)) { visitPost(w); } else { containsCycle = true; } } visit(v); } /** * Visits the given vertex and its successors in a pre-order manner. * * @param v * a vertex */ public final void visitPre(Vertex v) { visited.add(v); visit(v); @SuppressWarnings("unchecked") List<Edge> edges = (List<Edge>) v.eGet(refEdges); for (Edge edge : edges) { Vertex w = (Vertex) edge.eGet(refVertex); if (!visited.contains(w)) { visitPre(w); } else { containsCycle = true; } } } }