/* Soot - a J*va Optimization Framework * Copyright (C) 1999 Patrice Pominville, Raja Vallee-Rai, Patrick Lam * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the Sable Research Group and others 1997-1999. * See the 'credits' file distributed with Soot for the complete list of * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot) */ package soot.toolkits.graph; import java.util.*; import soot.*; import soot.util.*; /** * HashMap based implementation of a MutableBlockGraph. */ public class HashMutableDirectedGraph implements MutableDirectedGraph { protected HashMap<Object,LinkedHashSet<Object>> nodeToPreds = new HashMap(); protected HashMap<Object,LinkedHashSet<Object>> nodeToSuccs = new HashMap(); protected Chain heads = new HashChain(); protected Chain tails = new HashChain(); public HashMutableDirectedGraph() { } /** Removes all nodes and edges. */ public void clearAll() { nodeToPreds = new HashMap(); nodeToSuccs = new HashMap(); heads = new HashChain(); tails = new HashChain(); } public Object clone() { HashMutableDirectedGraph g = new HashMutableDirectedGraph(); g.nodeToPreds = (HashMap)nodeToPreds.clone(); g.nodeToSuccs = (HashMap)nodeToSuccs.clone(); g.heads = HashChain.listToHashChain(HashChain.toList(heads)); g.tails = HashChain.listToHashChain(HashChain.toList(tails)); return g; } /* Returns an unbacked list of heads for this graph. */ public List getHeads() { ArrayList l = new ArrayList(); l.addAll(heads); return Collections.unmodifiableList(l); } /* Returns an unbacked list of tails for this graph. */ public List getTails() { ArrayList l = new ArrayList(); l.addAll(tails); return Collections.unmodifiableList(l); } public List getPredsOf(Object s) { Set preds = nodeToPreds.get(s); if (preds != null) return new LinkedList(preds); else throw new RuntimeException(s+"not in graph!"); } /** * Same as {@link #getPredsOf(Object)} but returns a set. * This is faster than calling {@link #getPredsOf(Object)}. * Also, certain operations like {@link Collection#contains(Object)} * execute faster on the set than on the list. * The returned set is unmodifiable. */ public Set getPredsOfAsSet(Object s) { Set preds = nodeToPreds.get(s); if (preds != null) return Collections.unmodifiableSet(preds); else throw new RuntimeException(s+"not in graph!"); } public List getSuccsOf(Object s) { Set succs = nodeToSuccs.get(s); if (succs != null) return new LinkedList(succs); else throw new RuntimeException(s+"not in graph!"); } /** * Same as {@link #getSuccsOf(Object)} but returns a set. * This is faster than calling {@link #getSuccsOf(Object)}. * Also, certain operations like {@link Collection#contains(Object)} * execute faster on the set than on the list. * The returned set is unmodifiable. */ public Set getSuccsOfAsSet(Object s) { Set succs = nodeToSuccs.get(s); if (succs != null) return Collections.unmodifiableSet(succs); else throw new RuntimeException(s+"not in graph!"); } public int size() { return nodeToPreds.keySet().size(); } public Iterator iterator() { return nodeToPreds.keySet().iterator(); } public void addEdge(Object from, Object to) { if (from == null || to == null) throw new RuntimeException("edge from or to null"); if (containsEdge(from, to)) return; Set<Object> succsList = nodeToSuccs.get(from); if (succsList == null) throw new RuntimeException(from + " not in graph!"); Set<Object> predsList = nodeToPreds.get(to); if (predsList == null) throw new RuntimeException(to + " not in graph!"); if (heads.contains(to)) heads.remove(to); if (tails.contains(from)) tails.remove(from); succsList.add(to); predsList.add(from); } public void removeEdge(Object from, Object to) { if (!containsEdge(from, to)) return; Set succsList = nodeToSuccs.get(from); if (succsList == null) throw new RuntimeException(from + " not in graph!"); Set predsList = nodeToPreds.get(to); if (predsList == null) throw new RuntimeException(to + " not in graph!"); succsList.remove(to); predsList.remove(from); if (succsList.isEmpty()) tails.add(from); if (predsList.isEmpty()) heads.add(to); } public boolean containsEdge(Object from, Object to) { Set succs = nodeToSuccs.get(from); if (succs == null) return false; return succs.contains(to); } public boolean containsNode(Object node) { return nodeToPreds.keySet().contains(node); } public List<Object> getNodes() { return Arrays.asList(nodeToPreds.keySet().toArray()); } public void addNode(Object node) { if (containsNode(node)) throw new RuntimeException("Node already in graph"); nodeToSuccs.put(node, new LinkedHashSet<Object>()); nodeToPreds.put(node, new LinkedHashSet<Object>()); heads.add(node); tails.add(node); } public void removeNode(Object node) { LinkedHashSet succs = (LinkedHashSet)nodeToSuccs.get(node).clone(); for (Iterator succsIt = succs.iterator(); succsIt.hasNext(); ) removeEdge(node, succsIt.next()); nodeToSuccs.remove(node); LinkedHashSet preds = (LinkedHashSet)nodeToPreds.get(node).clone(); for (Iterator predsIt = preds.iterator(); predsIt.hasNext(); ) removeEdge(predsIt.next(), node); nodeToPreds.remove(node); if (heads.contains(node)) heads.remove(node); if (tails.contains(node)) tails.remove(node); } public void printGraph() { for (Iterator it = iterator(); it.hasNext(); ) { Object node = it.next(); G.v().out.println("Node = "+node); G.v().out.println("Preds:"); for (Iterator predsIt = getPredsOf(node).iterator(); predsIt.hasNext(); ) { G.v().out.print(" "); G.v().out.println(predsIt.next()); } G.v().out.println("Succs:"); for (Iterator succsIt = getSuccsOf(node).iterator(); succsIt.hasNext(); ) { G.v().out.print(" "); G.v().out.println(succsIt.next()); } } } }