/**
*
*/
package soottocfg.cfg.util;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jgrapht.DirectedGraph;
import org.jgrapht.Graphs;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
/**
* @author schaef
*
*/
public abstract class AbstractDominators<V> {
private final DirectedGraph<V, ?> graph;
protected Map<V, Set<V>> dominators;
protected Map<V, V> iDominators;
protected Tree<V> dominatorTree;
public AbstractDominators(DirectedGraph<V, ?> g) {
graph = g;
}
/**
* Get the directed graph for which the dominators are computed.
* @return
*/
public DirectedGraph<V, ?> getGraph() {
return graph;
}
/**
* Check if node is dominated by dominator
* @param node
* @param dominator
* @return
*/
public boolean isDominatedBy(V node, V dominator) {
if (!dominators.containsKey(node)) {
throw new IllegalArgumentException("Node is not part of the graph: "+node);
}
if (!dominators.containsKey(dominator)) {
throw new IllegalArgumentException("Node is not part of the graph: "+node);
}
return dominators.get(node).contains(dominator);
}
/**
* Check if node is strictly dominated by dominator
* (i.e., node!=dominator and dominator dominates node)
* @param node
* @param dominator
* @return
*/
public boolean isStrictlyDominatedBy(V node, V dominator) {
if (node.equals(dominator)) {
return false;
}
return isDominatedBy(node, dominator);
}
/**
* Returns true if there exists an element in dominators that
* strictly dominates node.
* @param node
* @param dominators
* @return
*/
public boolean isStrictlyDominatedByAny(V node, Collection<V> dominators) {
for (V dom : dominators) {
if (isStrictlyDominatedBy(node, dom)) {
return true;
}
}
return false;
}
/**
* Get the immediate dominator for node
* @param node
* @return The immediate dominator of node, or null if node has no dominator.
*/
public V getImmediateDominator(V node) {
if (!iDominators.containsKey(node)) {
throw new IllegalArgumentException("Node is not part of the graph: "+node);
}
return iDominators.get(node);
}
/**
* Get the dominators for node
* @param node
* @return
*/
public Set<V> getDominators(V node) {
if (!dominators.containsKey(node)) {
throw new IllegalArgumentException("Node is not part of the graph: "+node);
}
return new HashSet<V>(dominators.get(node));
}
/**
* Get the mapping from vertex to its set of dominators
* @param node
* @return
*/
public Map<V, Set<V>> getDominators() {
return new HashMap<V, Set<V>>(dominators);
}
/**
* Get the dominator tree of the graph.
* @return
*/
public Tree<V> getDominatorTree() {
return dominatorTree;
}
/**
* Compute the immediate (post)dominator for each vertex.
* @param dom Mapping from each vertex to its set of (post)dominators.
* @return Map from vertex to its immediate (post)dominator, or null if
* the vertex does not have an immediate (post)dominator
*/
protected Map<V, V> computeImmediateDominators(Map<V, Set<V>> dom) {
Map<V, V> idominators = new HashMap<V, V>();
for (Entry<V, Set<V>> entry : dom.entrySet()) {
V idom = null;
for (V dominator : entry.getValue()) {
Set<V> dominatorDiff = new HashSet<V>(entry.getValue());
dominatorDiff.removeAll(dom.get(dominator));
if (dominatorDiff.size() == 1 && dominatorDiff.iterator().next() == entry.getKey()) {
idom = dominator;
break;
}
}
idominators.put(entry.getKey(), idom);
}
return idominators;
}
/**
* Computes the (post)dominators for all vertices in a graph
* starting from the given source.
*
* @param source
* The source vertex to start from (should be either source or
* sink)
* @param forward
* true, for computing dominators; false, for computing
* post-dominators
* @return
*/
protected Map<V, Set<V>> computeDominators(V source, boolean forward) {
Preconditions.checkArgument(graph.containsVertex(source));
Set<V> vertices = graph.vertexSet();
Map<V, Set<V>> dominators = new LinkedHashMap<V, Set<V>>(vertices.size());
// Initialize the set
for (V b : vertices) {
if (b.equals(source)) {
// The Source node only dominates itself
Set<V> tmp = new LinkedHashSet<V>();
tmp.add(b);
dominators.put(b, tmp);
} else {
// All other nodes are initialized to be the full graph. They
// will shrink later
Set<V> tmp = new LinkedHashSet<V>(vertices);
dominators.put(b, tmp);
}
}
boolean changed;
do {
changed = false;
for (V b : vertices) {
// Source node is always only dominated by itself.
if (!b.equals(source)) {
Set<V> newDom = new HashSet<V>(vertices);
// This is a bit ugly way to handle the initialization
// of the intersection problem
// but it should work
if (forward) {
Verify.verify(graph.inDegreeOf(b) != 0, "Unexpected indegree of 0 for " + b);
for (V inBlock : Graphs.predecessorListOf(graph, b)) {
newDom.retainAll(dominators.get(inBlock));
}
} else {
Verify.verify(graph.outDegreeOf(b) != 0, "Unexpected outdegree of 0 for "+b);
for (V inBlock : Graphs.successorListOf(graph, b)) {
newDom.retainAll(dominators.get(inBlock));
}
}
// every node dominates itself
newDom.add(b);
if (!newDom.equals(dominators.get(b))) {
dominators.put(b, newDom);
changed = true;
}
}
}
} while (changed);
return dominators;
}
/**
* Creates a (post)dominator tree from a given map.
* @param immediateDominators Mapping from vertex to its immediate (post)dominator.
* @return A (post)dominator tree.
*/
protected Tree<V> computeDominatorTree(Map<V, V> immediateDominators) {
Tree<V> dominatorTree = new Tree<V>();
for (Entry<V,V> entry : immediateDominators.entrySet()) {
if (entry.getValue()!=null) {
dominatorTree.addEdge(entry.getValue(), entry.getKey());
}
}
return dominatorTree;
}
}