/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.util;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* This class implements depth-first search over a Graph,
* return an enumeration of the nodes of the graph in order of
* increasing finishing time. This class follows the outNodes of the
* graph nodes to define the graph, but this behavior can be changed
* by overriding the getConnected method.
*/
public class DFSenumerateByFinish extends Stack<GraphNode> implements Enumeration<GraphNode> {
/**
* Construct a depth-first enumerator across all the nodes of a
* graph.
*
* @param net the graph whose nodes to enumerate
*/
protected DFSenumerateByFinish(Graph net) {
this(net, net.enumerateNodes());
}
/**
* Construct a depth-first enumerator across the (possibly
* improper) subset of nodes reachable from the nodes in the given
* enumeration.
*
* @param net the graph whose nodes to enumerate
* @param nodes the set of nodes from which to start searching
*/
public DFSenumerateByFinish(Graph net, Enumeration<GraphNode> nodes) {
e = nodes;
net.compactNodeNumbering();
info = new ArrayList<Enumeration<GraphNode>>(net.numberOfNodes() + 1);
// info = new java.util.HashMap( net.numberOfNodes() );
if (e.hasMoreElements()) {
theNextElement = e.nextElement();
}
}
/**
* While a depth-first enumeration is in progress, this field
* holds the current root node, i.e. the current bottom of the
* search stack (assuming stacks grow upward). This is used
* primarily when constructing strongly connected components.
*/
public GraphNode currentRoot;
/**
* Return whether there are any more nodes left to enumerate.
*
* @return true if there nodes left to enumerate.
*/
@Override
public boolean hasMoreElements() {
return (!empty() || (theNextElement != null && info.get(theNextElement.getIndex()) == null));
}
/**
* Find the next graph node in finishing time order.
*
* @see #nextElement
*
* @return the next graph node in finishing time order.
*/
@Override
public GraphNode nextElement() {
if (empty()) {
GraphNode v = theNextElement;
currentRoot = theNextElement;
info.set(v.getIndex(), getConnected(v));
push(v);
}
recurse:
while (!empty()) {
GraphNode v = peek();
Enumeration<GraphNode> pendingChildren = info.get(v.getIndex());
for (Enumeration<GraphNode> e = pendingChildren; e.hasMoreElements();) {
GraphNode n = e.nextElement();
Enumeration<GraphNode> nChildren = info.get(n.getIndex());
if (nChildren == null) {
// found a new child: recurse to it.
info.set(n.getIndex(), getConnected(n));
push(n);
continue recurse;
}
}
// no more children to visit: finished this vertex
while (info.get(theNextElement.getIndex()) != null && e.hasMoreElements()) {
theNextElement = e.nextElement();
}
return pop();
}
return null;
}
/**
* the current next element in finishing time order
*/
private GraphNode theNextElement;
/**
* an enumeration of all nodes to search from
*/
private final Enumeration<GraphNode> e;
/**
* an enumeration of child nodes for each node being searched
*/
private final List<Enumeration<GraphNode>> info;
/**
* get the out edges of a given node
*
* @param n the node of which to get the out edges
* @return the out edges
*/
protected Enumeration<GraphNode> getConnected(GraphNode n) {
return n.outNodes();
}
}