/** * */ package soottocfg.cfg.util; import java.util.HashSet; import java.util.List; import java.util.Set; import org.jgrapht.Graphs; import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.graph.DefaultEdge; import com.google.common.base.Verify; /** * @author schaef * */ public class Tree<V> { private final DefaultDirectedGraph<V, DefaultEdge> tree; private boolean isDirty = false; private V root = null; private Set<V> leaves = new HashSet<V>(); public Tree() { tree = new DefaultDirectedGraph<V, DefaultEdge>(DefaultEdge.class); } public void addEdge(V parent, V child) { tree.addVertex(parent); tree.addVertex(child); Verify.verify(tree.inDegreeOf(child)==0, "Node already has a parent: "+child); tree.addEdge(parent, child); isDirty = true; } public V getRoot() { recomputeRootAndLeavesIfDirty(); return root; } public V getParentOf(V node) { List<V> pred = Graphs.predecessorListOf(tree, node); Verify.verify(pred.size()<=1); if (pred.isEmpty()) return null; return pred.get(0); } public boolean isAncestor(V node, V ancestor) { if (node.equals(ancestor)) { return true; } V parent = getParentOf(node); if (parent==null) { return false; } return isAncestor(parent, ancestor); } public boolean isDescendant(V node, V descendant) { if (node.equals(descendant)) { return true; } for (V c: getChildrenOf(node)) { if (isDescendant(c, descendant)) { return true; } } return false; } public List<V> getChildrenOf(V node) { return Graphs.successorListOf(tree, node); } public Set<V> getLeaves() { recomputeRootAndLeavesIfDirty(); return leaves; } private void recomputeRootAndLeavesIfDirty() { if (isDirty) { root = null; leaves = new HashSet<V>(); isDirty = false; for (V vertex : tree.vertexSet()) { if (tree.inDegreeOf(vertex)==0) { Verify.verify(root==null, "More than one root in tree."); root = vertex; } if (tree.outDegreeOf(vertex)==0) { leaves.add(vertex); } } } } }