soot.toolkits.graph.HashMutableDirectedGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
package soot.toolkits.graph;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1999 Patrice Pominville, Raja Vallee-Rai, Patrick Lam
* %%
* This program 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 program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* HashMap based implementation of a MutableBlockGraph.
*
* @param
*/
public class HashMutableDirectedGraph implements MutableDirectedGraph {
private static final Logger logger = LoggerFactory.getLogger(HashMutableDirectedGraph.class);
protected final Map> nodeToPreds;
protected final Map> nodeToSuccs;
protected final Set heads;
protected final Set tails;
private static List getCopy(Collection extends T> c) {
return Collections.unmodifiableList(new ArrayList(c));
}
private static Map> deepCopy(Map> in) {
HashMap> retVal = new HashMap<>(in);
for (Map.Entry> e : retVal.entrySet()) {
e.setValue(new LinkedHashSet(e.getValue()));
}
return retVal;
}
public HashMutableDirectedGraph() {
this.nodeToPreds = new HashMap>();
this.nodeToSuccs = new HashMap>();
this.heads = new HashSet();
this.tails = new HashSet();
}
// copy constructor
public HashMutableDirectedGraph(HashMutableDirectedGraph orig) {
this.nodeToPreds = deepCopy(orig.nodeToPreds);
this.nodeToSuccs = deepCopy(orig.nodeToSuccs);
this.heads = new HashSet(orig.heads);
this.tails = new HashSet(orig.tails);
}
@Override
public Object clone() {
return new HashMutableDirectedGraph(this);
}
/** Removes all nodes and edges. */
public void clearAll() {
nodeToPreds.clear();
nodeToSuccs.clear();
heads.clear();
tails.clear();
}
/* Returns an unbacked list of heads for this graph. */
@Override
public List getHeads() {
return getCopy(heads);
}
/* Returns an unbacked list of tails for this graph. */
@Override
public List getTails() {
return getCopy(tails);
}
@Override
public List getPredsOf(N s) {
Set preds = nodeToPreds.get(s);
if (preds != null) {
return getCopy(preds);
}
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(N s) {
Set preds = nodeToPreds.get(s);
if (preds != null) {
return Collections.unmodifiableSet(preds);
}
throw new RuntimeException(s + " not in graph!");
}
@Override
public List getSuccsOf(N s) {
Set succs = nodeToSuccs.get(s);
if (succs != null) {
return getCopy(succs);
}
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(N s) {
Set succs = nodeToSuccs.get(s);
if (succs != null) {
return Collections.unmodifiableSet(succs);
}
throw new RuntimeException(s + " not in graph!");
}
@Override
public int size() {
return nodeToPreds.keySet().size();
}
@Override
public Iterator iterator() {
return nodeToPreds.keySet().iterator();
}
@Override
public void addEdge(N from, N to) {
if (from == null || to == null) {
throw new RuntimeException("edge with null endpoint");
}
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!");
}
heads.remove(to);
tails.remove(from);
succsList.add(to);
predsList.add(from);
}
@Override
public void removeEdge(N from, N to) {
Set succs = nodeToSuccs.get(from);
if (succs == null || !succs.contains(to)) {
// i.e. containsEdge(from, to)==false
return;
}
Set preds = nodeToPreds.get(to);
if (preds == null) {
// i.e. inconsistent data structures
throw new RuntimeException(to + " not in graph!");
}
succs.remove(to);
preds.remove(from);
if (succs.isEmpty()) {
tails.add(from);
}
if (preds.isEmpty()) {
heads.add(to);
}
}
@Override
public boolean containsEdge(N from, N to) {
Set succs = nodeToSuccs.get(from);
return succs != null && succs.contains(to);
}
@Override
public boolean containsNode(N node) {
return nodeToPreds.keySet().contains(node);
}
@Override
public List getNodes() {
return getCopy(nodeToPreds.keySet());
}
@Override
public void addNode(N node) {
if (containsNode(node)) {
throw new RuntimeException("Node already in graph");
}
nodeToSuccs.put(node, new LinkedHashSet());
nodeToPreds.put(node, new LinkedHashSet());
heads.add(node);
tails.add(node);
}
@Override
public void removeNode(N node) {
for (N n : new ArrayList(nodeToSuccs.get(node))) {
removeEdge(node, n);
}
nodeToSuccs.remove(node);
for (N n : new ArrayList(nodeToPreds.get(node))) {
removeEdge(n, node);
}
nodeToPreds.remove(node);
heads.remove(node);
tails.remove(node);
}
public void printGraph() {
for (N node : this) {
logger.debug("Node = " + node);
logger.debug("Preds:");
for (N p : getPredsOf(node)) {
logger.debug(" ");
logger.debug("" + p);
}
logger.debug("Succs:");
for (N s : getSuccsOf(node)) {
logger.debug(" ");
logger.debug("" + s);
}
}
}
}