/** * Given a set of SCC nodes make this the lead member of the SCC and reroute all incoming and * outgoing links accordingly. This eager rewrite is based on the assumption that there are few * cycles so it is better to rewrite once and keep the graph easy to traverse. */ public void makeLeadNodeFor(Set<GraphNode> members) { // Accumulate all successors Set<GraphNode> newSucc = new HashSet<>(); Set<GraphNode> newSuccClosed = new HashSet<>(); for (GraphNode n : members) { newSucc.addAll(n.succ); newSuccClosed.addAll(n.succClosed); } newSucc.removeAll(members); newSuccClosed.removeAll(members); succ = newSucc; succClosed = newSuccClosed; // Rewrite all direct successors to have us as predecessor for (GraphNode n : succ) { n.pred.removeAll(members); n.pred.add(this); } // Find all predecessor nodes and relink link them to point to us Set<GraphNode> done = new HashSet<>(); Set<GraphNode> newAliases = new HashSet<>(); for (GraphNode member : members) { addSiblings(newAliases, member); } becomeLeaderOf(newAliases); for (GraphNode n : members) { if (n != this) { pred.addAll(n.pred); n.relocateAllRefTo(this, done); n.becomeSubordinateOf(this); } } pred.removeAll(members); }
/** Dump a set to a string for debug. */ private static String dumpSet(Set<GraphNode> s) { StringBuffer sb = new StringBuffer(); sb.append("{"); boolean started = false; for (GraphNode value : s) { if (started) { sb.append(", "); } else { started = true; } sb.append(value.toString()); } sb.append("}"); return sb.toString(); }
/** Visit each predecessor of this node applying the given visitor. Breadth first. */ private <Alpha, Beta> void doVisitPredecessors( Visitor<Alpha, Beta> visitor, Alpha arg1, Beta arg2, Set<GraphNode> seen) { if (seen.add(this)) { Collection<GraphNode> allKill = null; for (Iterator<GraphNode> i = pred.iterator(); i.hasNext(); ) { GraphNode pred = i.next(); List<GraphNode> kill = visitor.visit(pred, this, arg1, arg2); if (kill != null) { if (allKill == null) allKill = new ArrayList<GraphNode>(); allKill.addAll(kill); } } if (allKill != null) pred.removeAll(allKill); for (Iterator<GraphNode> i = pred.iterator(); i.hasNext(); ) { GraphNode pred = i.next(); pred.doVisitPredecessors(visitor, arg1, arg2, seen); } } }
@Override GraphNode leadNode(GraphNode unlessSpecified) { return leader.leadNode(); }