migrate more stuff to wala.util
git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4036 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
5e4e9f010e
commit
16e9c0fa67
|
@ -1,31 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util;
|
||||
|
||||
/**
|
||||
* An exception for when work is canceled in eclipse. This version forces every API that uses it to declare it. Use
|
||||
* {@link CancelRuntimeException} to avoid the need to declare a cancel exception.
|
||||
*/
|
||||
public class CancelException extends Exception {
|
||||
|
||||
protected CancelException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public CancelException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public static CancelException make(String msg) {
|
||||
return new CancelException(msg);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple utilities for Eclipse progress monitors
|
||||
*/
|
||||
public class MonitorUtil {
|
||||
|
||||
/**
|
||||
* Use this interface to decouple core utilities from the Eclipse layer
|
||||
*/
|
||||
public interface IProgressMonitor {
|
||||
|
||||
void beginTask(String task, int totalWork);
|
||||
|
||||
boolean isCanceled();
|
||||
|
||||
void done();
|
||||
|
||||
void worked(int units);
|
||||
}
|
||||
|
||||
public static void beginTask(IProgressMonitor monitor, String task, int totalWork) throws CancelException {
|
||||
if (monitor != null) {
|
||||
monitor.beginTask(task, totalWork);
|
||||
if (monitor.isCanceled()) {
|
||||
throw CancelException.make("cancelled in " + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void done(IProgressMonitor monitor) throws CancelException {
|
||||
if (monitor != null) {
|
||||
monitor.done();
|
||||
if (monitor.isCanceled()) {
|
||||
throw CancelException.make("cancelled in " + monitor.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void worked(IProgressMonitor monitor, int units) throws CancelException {
|
||||
if (monitor != null) {
|
||||
monitor.worked(units);
|
||||
if (monitor.isCanceled()) {
|
||||
throw CancelException.make("cancelled in " + monitor.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void throwExceptionIfCanceled(IProgressMonitor progressMonitor) throws CancelException {
|
||||
if (progressMonitor != null) {
|
||||
if (progressMonitor.isCanceled()) {
|
||||
throw CancelException.make("operation cancelled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public static IProgressMonitor subProgress(ProgressMaster progress, int i) {
|
||||
// if (progress == null) {
|
||||
// return null;
|
||||
// } else {
|
||||
// return new SubProgressMonitor(progress, i);
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Basic functionality for a {@link Graph} that delegates node and edge management.
|
||||
*/
|
||||
public abstract class AbstractGraph<T> implements Graph<T> {
|
||||
|
||||
/**
|
||||
* @return the object which manages nodes in the graph
|
||||
*/
|
||||
protected abstract NodeManager<T> getNodeManager();
|
||||
|
||||
/**
|
||||
* @return the object which manages edges in the graph
|
||||
*/
|
||||
protected abstract EdgeManager<T> getEdgeManager();
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.Graph#iterateNodes()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
return getNodeManager().iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.Graph#getNumberOfNodes()
|
||||
*/
|
||||
public int getNumberOfNodes() {
|
||||
return getNodeManager().getNumberOfNodes();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object)
|
||||
*/
|
||||
public int getPredNodeCount(T n) throws IllegalArgumentException {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n cannot be null");
|
||||
}
|
||||
return getEdgeManager().getPredNodeCount(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object)
|
||||
*/
|
||||
public Iterator<T> getPredNodes(T n) throws IllegalArgumentException {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n cannot be null");
|
||||
}
|
||||
return getEdgeManager().getPredNodes(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object)
|
||||
*/
|
||||
public int getSuccNodeCount(T n) throws IllegalArgumentException {
|
||||
if (!containsNode(n) || n == null) {
|
||||
throw new IllegalArgumentException("node not in graph " + n);
|
||||
}
|
||||
return getEdgeManager().getSuccNodeCount(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object)
|
||||
*/
|
||||
public Iterator<T> getSuccNodes(T n) throws IllegalArgumentException {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n cannot be null");
|
||||
}
|
||||
return getEdgeManager().getSuccNodes(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#addNode(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void addNode(T n) {
|
||||
getNodeManager().addNode(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#addEdge(com.ibm.wala.util.graph.Node,
|
||||
* com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void addEdge(T src, T dst) throws IllegalArgumentException {
|
||||
getEdgeManager().addEdge(src, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdge(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void removeEdge(T src, T dst) throws IllegalArgumentException {
|
||||
getEdgeManager().removeEdge(src, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#hasEdge(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
if (src == null) {
|
||||
throw new IllegalArgumentException("src is null");
|
||||
}
|
||||
if (dst == null) {
|
||||
throw new IllegalArgumentException("dst is null");
|
||||
}
|
||||
return getEdgeManager().hasEdge(src, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeAllIncidentEdges(T node) throws IllegalArgumentException {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node cannot be null");
|
||||
}
|
||||
getEdgeManager().removeAllIncidentEdges(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeIncomingEdges(T node) throws IllegalArgumentException {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node cannot be null");
|
||||
}
|
||||
getEdgeManager().removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeOutgoingEdges(T node) throws IllegalArgumentException {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node cannot be null");
|
||||
}
|
||||
getEdgeManager().removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.Graph#removeNode(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeNodeAndEdges(T N) throws IllegalArgumentException {
|
||||
if (N == null) {
|
||||
throw new IllegalArgumentException("N cannot be null");
|
||||
}
|
||||
getEdgeManager().removeAllIncidentEdges(N);
|
||||
getNodeManager().removeNode(N);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeNode(T n) throws IllegalArgumentException {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("N cannot be null");
|
||||
}
|
||||
getNodeManager().removeNode(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Iterator<? extends T> ns = iterator(); ns.hasNext();) {
|
||||
T n = ns.next();
|
||||
sb.append(n.toString()).append("\n");
|
||||
for (Iterator ss = getSuccNodes(n); ss.hasNext();) {
|
||||
Object s = ss.next();
|
||||
sb.append(" --> ").append(s);
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public boolean containsNode(T n) {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n cannot be null");
|
||||
}
|
||||
return getNodeManager().containsNode(n);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.impl.NumberedNodeIterator;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
* Basic functionality for a graph that delegates node and edge management, and tracks node numbers
|
||||
*/
|
||||
public abstract class AbstractNumberedGraph<T> extends AbstractGraph<T> implements NumberedGraph<T> {
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedNodeManager#getMaxNumber()
|
||||
*/
|
||||
public int getMaxNumber() {
|
||||
return ((NumberedNodeManager<T>) getNodeManager()).getMaxNumber();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedNodeManager#getNode(int)
|
||||
*/
|
||||
public T getNode(int number) {
|
||||
return ((NumberedNodeManager<T>) getNodeManager()).getNode(number);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedNodeManager#getNumber(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public int getNumber(T N) {
|
||||
if (N == null) {
|
||||
throw new IllegalArgumentException("N cannot be null");
|
||||
}
|
||||
return ((NumberedNodeManager<T>) getNodeManager()).getNumber(N);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet)
|
||||
*/
|
||||
public Iterator<T> iterateNodes(final IntSet s) {
|
||||
return new NumberedNodeIterator<T>(s, this);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedEdgeManager#getPredNodeNumbers(java.lang.Object)
|
||||
*/
|
||||
public IntSet getPredNodeNumbers(T node) throws IllegalArgumentException {
|
||||
assert getEdgeManager() != null;
|
||||
return ((NumberedEdgeManager<T>) getEdgeManager()).getPredNodeNumbers(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedEdgeManager#getSuccNodeNumbers(java.lang.Object)
|
||||
*/
|
||||
public IntSet getSuccNodeNumbers(T node) throws IllegalArgumentException {
|
||||
return ((NumberedEdgeManager<T>) getEdgeManager()).getSuccNodeNumbers(node);
|
||||
}
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.intset.BasicNaturalRelation;
|
||||
import com.ibm.wala.util.intset.IBinaryNaturalRelation;
|
||||
import com.ibm.wala.util.intset.IntIterator;
|
||||
import com.ibm.wala.util.intset.IntPair;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
import com.ibm.wala.util.intset.MutableSparseIntSet;
|
||||
|
||||
/**
|
||||
* Utilities for dealing with acyclic subgraphs
|
||||
*/
|
||||
public class Acyclic {
|
||||
|
||||
/*
|
||||
* prevent instantiation
|
||||
*/
|
||||
private Acyclic() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is slow. Fix it.
|
||||
*/
|
||||
public static <T> boolean isAcyclic(NumberedGraph<T> G, T root) {
|
||||
IBinaryNaturalRelation r = computeBackEdges(G, root);
|
||||
Iterator<IntPair> it = r.iterator();
|
||||
return !it.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a relation R s.t. (i,j) \in R iff (i,j) is a backedge according to a DFS of a numbered graph starting from some root.
|
||||
*
|
||||
* Not efficient. Recursive and uses hash sets.
|
||||
*/
|
||||
public static <T> IBinaryNaturalRelation computeBackEdges(NumberedGraph<T> G, T root) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
BasicNaturalRelation result = new BasicNaturalRelation();
|
||||
|
||||
Set<T> visited = HashSetFactory.make();
|
||||
Set<T> onstack = HashSetFactory.make();
|
||||
dfs(result, root, G, visited, onstack);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <T> void dfs(BasicNaturalRelation result, T root, NumberedGraph<T> G, Set<T> visited, Set<T> onstack) {
|
||||
visited.add(root);
|
||||
onstack.add(root);
|
||||
for (Iterator<? extends T> it = G.getSuccNodes(root); it.hasNext();) {
|
||||
T dstNode = it.next();
|
||||
if (onstack.contains(dstNode)) {
|
||||
int src = G.getNumber(root);
|
||||
int dst = G.getNumber(dstNode);
|
||||
result.add(src, dst);
|
||||
}
|
||||
if (!visited.contains(dstNode)) {
|
||||
dfs(result, dstNode, G, visited, onstack);
|
||||
}
|
||||
}
|
||||
onstack.remove(root);
|
||||
}
|
||||
|
||||
public static <T> boolean hasIncomingBackEdges(Path p, NumberedGraph<T> G, T root) {
|
||||
/*
|
||||
* TODO: pull out computeBackEdges, and pass in the backedge relation as a parameter to this call
|
||||
*/
|
||||
IBinaryNaturalRelation backedges = computeBackEdges(G, root);
|
||||
for (int index = 0; index < p.size(); index++) {
|
||||
int gn = p.get(index);
|
||||
Iterator<? extends T> predIter = G.getPredNodes(G.getNode(gn));
|
||||
while (predIter.hasNext()) {
|
||||
if (backedges.contains(G.getNumber(predIter.next()), gn))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a set of acyclic paths through a graph G from a node src to a node sink.
|
||||
*
|
||||
* This is not terribly efficient.
|
||||
*
|
||||
* @param max the max number of paths to return.
|
||||
*/
|
||||
public static <T> Collection<Path> computeAcyclicPaths(NumberedGraph<T> G, T root, T src, T sink, int max) {
|
||||
Collection<Path> result = HashSetFactory.make();
|
||||
SubGraph<T> acyclic = new SubGraph<T>(G, computeBackEdges(G, root));
|
||||
|
||||
Collection<Path> worklist = HashSetFactory.make();
|
||||
Path sinkPath = Path.make(G.getNumber(sink));
|
||||
worklist.add(sinkPath);
|
||||
while (!worklist.isEmpty() && result.size() <= max) {
|
||||
Path p = worklist.iterator().next();
|
||||
worklist.remove(p);
|
||||
int first = p.get(0);
|
||||
if (first == G.getNumber(src)) {
|
||||
result.add(p);
|
||||
} else {
|
||||
for (IntIterator it = acyclic.getPredNodeNumbers(acyclic.getNode(first)).intIterator(); it.hasNext();) {
|
||||
worklist.add(Path.prepend(it.next(), p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class SubGraph<T> extends AbstractNumberedGraph<T> {
|
||||
|
||||
private final NumberedGraph<T> delegate;
|
||||
|
||||
private final IBinaryNaturalRelation ignoreEdges;
|
||||
|
||||
private final Edges edges;
|
||||
|
||||
SubGraph(NumberedGraph<T> delegate, IBinaryNaturalRelation ignoreEdges) {
|
||||
super();
|
||||
this.delegate = delegate;
|
||||
this.ignoreEdges = ignoreEdges;
|
||||
this.edges = new Edges();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EdgeManager<T> getEdgeManager() {
|
||||
return edges;
|
||||
}
|
||||
|
||||
private final class Edges implements NumberedEdgeManager<T> {
|
||||
|
||||
public void addEdge(T src, T dst) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N) {
|
||||
Assertions.UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N) {
|
||||
Assertions.UNREACHABLE();
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N) {
|
||||
Assertions.UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(T N) {
|
||||
Assertions.UNREACHABLE();
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
Assertions.UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(T node) throws UnsupportedOperationException {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) throws UnsupportedOperationException {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(T node) throws UnsupportedOperationException {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(T node) throws UnsupportedOperationException {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(T node) {
|
||||
IntSet s = delegate.getPredNodeNumbers(node);
|
||||
MutableIntSet result = MutableSparseIntSet.makeEmpty();
|
||||
for (IntIterator it = s.intIterator(); it.hasNext();) {
|
||||
int y = it.next();
|
||||
if (!ignoreEdges.contains(y, getNumber(node))) {
|
||||
result.add(y);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node) {
|
||||
Assertions.UNREACHABLE();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import com.ibm.wala.util.collections.SimpleVector;
|
||||
|
||||
/**
|
||||
* A simple, extremely inefficient tree implementation
|
||||
*/
|
||||
public class BasicTree<T> {
|
||||
|
||||
private final T value;
|
||||
final private SimpleVector<BasicTree<T>> children = new SimpleVector<BasicTree<T>>();
|
||||
|
||||
protected BasicTree(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static <T> BasicTree<T> make(T value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("null value");
|
||||
}
|
||||
return new BasicTree<T>(value);
|
||||
}
|
||||
|
||||
public T getRootValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public T getChildValue(int i) {
|
||||
if (children.get(i) == null) {
|
||||
return null;
|
||||
} else {
|
||||
return children.get(i).getRootValue();
|
||||
}
|
||||
}
|
||||
|
||||
public BasicTree<T> getChild(int i) {
|
||||
return children.get(i);
|
||||
}
|
||||
|
||||
public void setChild(int i, BasicTree<T> tree) {
|
||||
children.set(i, tree);
|
||||
}
|
||||
|
||||
public int getMaxChildIndex() {
|
||||
return children.getMaxIndex();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An object which manages edges in a directed graph.
|
||||
*
|
||||
* @param <T> the type of node in the graph
|
||||
*/
|
||||
public interface EdgeManager<T> {
|
||||
|
||||
/**
|
||||
* Return an {@link Iterator} over the immediate predecessor nodes of n
|
||||
*
|
||||
* This method never returns <code>null</code>.
|
||||
*
|
||||
* @return an {@link Iterator} over the immediate predecessor nodes of this Node.
|
||||
*/
|
||||
public Iterator<T> getPredNodes(T n);
|
||||
|
||||
/**
|
||||
* Return the number of {@link #getPredNodes immediate predecessor} nodes of n
|
||||
*
|
||||
* @return the number of immediate predecessors of n.
|
||||
*/
|
||||
public int getPredNodeCount(T n);
|
||||
|
||||
/**
|
||||
* Return an Iterator over the immediate successor nodes of n
|
||||
* <p>
|
||||
* This method never returns <code>null</code>.
|
||||
*
|
||||
* @return an Iterator over the immediate successor nodes of n
|
||||
*/
|
||||
public Iterator<T> getSuccNodes(T n);
|
||||
|
||||
/**
|
||||
* Return the number of {@link #getSuccNodes immediate successor} nodes of this Node in the Graph
|
||||
*
|
||||
* @return the number of immediate successor Nodes of this Node in the Graph.
|
||||
*/
|
||||
public int getSuccNodeCount(T N);
|
||||
|
||||
public void addEdge(T src, T dst);
|
||||
|
||||
public void removeEdge(T src, T dst) throws UnsupportedOperationException;
|
||||
|
||||
public void removeAllIncidentEdges(T node) throws UnsupportedOperationException;
|
||||
|
||||
public void removeIncomingEdges(T node) throws UnsupportedOperationException;
|
||||
|
||||
public void removeOutgoingEdges(T node) throws UnsupportedOperationException;
|
||||
|
||||
public boolean hasEdge(T src, T dst);
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
/**
|
||||
* Basic interface for a directed graph.
|
||||
*
|
||||
* We choose to define a {@link Graph} as a composition of a {@link NodeManager} and an {@link EdgeManager}, which
|
||||
* track nodes and edges, respectively. This way, in many cases we can compose separate {@link NodeManager} and
|
||||
* {@link EdgeManager} implementations to create {@link Graph} implementations, using delegation.
|
||||
*
|
||||
* @param <T> the type of nodes in this graph.
|
||||
*/
|
||||
public interface Graph<T> extends NodeManager<T>, EdgeManager<T> {
|
||||
/**
|
||||
* remove a node and all its incident edges
|
||||
* @throws UnsupportedOperationException if the graph implementation does not allow removal
|
||||
*/
|
||||
public void removeNodeAndEdges(T n) throws UnsupportedOperationException;
|
||||
|
||||
}
|
|
@ -1,242 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.graph.traverse.BFSIterator;
|
||||
import com.ibm.wala.util.graph.traverse.DFS;
|
||||
|
||||
/**
|
||||
* Utility class to check integrity of a graph data structure.
|
||||
*/
|
||||
public class GraphIntegrity {
|
||||
|
||||
/**
|
||||
* DEBUG_LEVEL:
|
||||
* <ul>
|
||||
* <li>0 No output
|
||||
* <li>1 Print some simple stats and warning information
|
||||
* <li>2 Detailed debugging
|
||||
* </ul>
|
||||
*/
|
||||
static final int DEBUG_LEVEL = 0;
|
||||
|
||||
public static <T> void check(Graph<T> G) throws UnsoundGraphException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
checkNodeCount(G);
|
||||
checkEdges(G);
|
||||
checkEdgeCounts(G);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param G
|
||||
*/
|
||||
private static <T> void checkEdgeCounts(Graph<T> G) throws UnsoundGraphException {
|
||||
for (Iterator<? extends T> it = G.iterator(); it.hasNext();) {
|
||||
T N = it.next();
|
||||
int count1 = G.getSuccNodeCount(N);
|
||||
int count2 = 0;
|
||||
for (Iterator it2 = G.getSuccNodes(N); it2.hasNext();) {
|
||||
it2.next();
|
||||
count2++;
|
||||
}
|
||||
if (count1 != count2) {
|
||||
throw new UnsoundGraphException("getSuccNodeCount " + count1 + " is wrong for node " + N);
|
||||
}
|
||||
|
||||
int count3 = G.getPredNodeCount(N);
|
||||
int count4 = 0;
|
||||
for (Iterator it2 = G.getPredNodes(N); it2.hasNext();) {
|
||||
it2.next();
|
||||
count4++;
|
||||
}
|
||||
if (count3 != count4) {
|
||||
throw new UnsoundGraphException("getPredNodeCount " + count1 + " is wrong for node " + N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param G
|
||||
*/
|
||||
private static <T> void checkEdges(Graph<T> G) throws UnsoundGraphException {
|
||||
for (Iterator<? extends T> it = G.iterator(); it.hasNext();) {
|
||||
T N = it.next();
|
||||
if (!G.containsNode(N)) {
|
||||
throw new UnsoundGraphException(N + " is not contained in the the graph " + G.containsNode(N));
|
||||
}
|
||||
PRED: for (Iterator<? extends T> p = G.getPredNodes(N); p.hasNext();) {
|
||||
T pred = p.next();
|
||||
if (!G.containsNode(pred)) {
|
||||
throw new UnsoundGraphException(pred + " is a predecessor of " + N + " but is not contained in the graph");
|
||||
}
|
||||
for (Iterator s = G.getSuccNodes(pred); s.hasNext();) {
|
||||
Object succ = s.next();
|
||||
if (succ.equals(N)) {
|
||||
continue PRED;
|
||||
}
|
||||
}
|
||||
// didn't find N
|
||||
G.getPredNodes(N);
|
||||
G.getSuccNodes(pred);
|
||||
throw new UnsoundGraphException(pred + " is a predecessor of " + N + " but inverse doesn't hold");
|
||||
}
|
||||
SUCC: for (Iterator<? extends T> s = G.getSuccNodes(N); s.hasNext();) {
|
||||
T succ = s.next();
|
||||
if (!G.containsNode(succ)) {
|
||||
throw new UnsoundGraphException(succ + " is a successor of " + N + " but is not contained in the graph");
|
||||
}
|
||||
for (Iterator p = G.getPredNodes(succ); p.hasNext();) {
|
||||
Object pred = p.next();
|
||||
if (pred.equals(N)) {
|
||||
continue SUCC;
|
||||
}
|
||||
}
|
||||
// didn't find N
|
||||
throw new UnsoundGraphException(succ + " is a successor of " + N + " but inverse doesn't hold");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param G
|
||||
*/
|
||||
private static <T> void checkNodeCount(Graph<T> G) throws UnsoundGraphException {
|
||||
int n1 = 0;
|
||||
int n2 = 0;
|
||||
int n3 = 0;
|
||||
int n4 = 0;
|
||||
int n5 = 0;
|
||||
try {
|
||||
n1 = G.getNumberOfNodes();
|
||||
n2 = 0;
|
||||
for (Iterator it = G.iterator(); it.hasNext();) {
|
||||
Object n = it.next();
|
||||
if (DEBUG_LEVEL > 1) {
|
||||
System.err.println(("n2 loop: " + n));
|
||||
}
|
||||
n2++;
|
||||
}
|
||||
n3 = 0;
|
||||
for (Iterator it = new BFSIterator<T>(G); it.hasNext();) {
|
||||
it.next();
|
||||
n3++;
|
||||
}
|
||||
n4 = 0;
|
||||
for (Iterator it = DFS.iterateDiscoverTime(G); it.hasNext();) {
|
||||
it.next();
|
||||
n4++;
|
||||
}
|
||||
n5 = 0;
|
||||
for (Iterator it = DFS.iterateFinishTime(G); it.hasNext();) {
|
||||
it.next();
|
||||
n5++;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
throw new UnsoundGraphException(e.toString());
|
||||
}
|
||||
if (n1 != n2) {
|
||||
throw new UnsoundGraphException("n1: " + n1 + " n2: " + n2);
|
||||
}
|
||||
if (n1 != n3) {
|
||||
throw setDiffException("n1: " + n1 + " n3: " + n3, G.iterator(), new BFSIterator<T>(G));
|
||||
}
|
||||
if (n1 != n4) {
|
||||
throw new UnsoundGraphException("n1: " + n1 + " n4: " + n3);
|
||||
}
|
||||
if (n1 != n5) {
|
||||
throw new UnsoundGraphException("n1: " + n1 + " n5: " + n3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static <T> UnsoundGraphException setDiffException(String msg, Iterator<? extends T> i1, Iterator<T> i2) {
|
||||
HashSet<T> set1 = HashSetFactory.make();
|
||||
while (i1.hasNext()) {
|
||||
T o1 = i1.next();
|
||||
boolean b = set1.add(o1);
|
||||
if (!b) {
|
||||
return new UnsoundGraphException("set1 already contained " + o1);
|
||||
}
|
||||
}
|
||||
HashSet<T> set2 = HashSetFactory.make();
|
||||
while (i2.hasNext()) {
|
||||
T o2 = i2.next();
|
||||
boolean b = set2.add(o2);
|
||||
if (!b) {
|
||||
return new UnsoundGraphException("set2 already contained " + o2);
|
||||
}
|
||||
}
|
||||
GraphIntegrity.printCollection("set 1 ", set1);
|
||||
GraphIntegrity.printCollection("set 2 ", set2);
|
||||
HashSet s1clone = (HashSet) set1.clone();
|
||||
set1.removeAll(set2);
|
||||
if (set1.size() > 0) {
|
||||
Object first = set1.iterator().next();
|
||||
msg = msg + ", first iterator contained " + first;
|
||||
return new UnsoundGraphException(msg);
|
||||
} else {
|
||||
set2.removeAll(s1clone);
|
||||
if (set2.size() > 0) {
|
||||
Object first = set2.iterator().next();
|
||||
msg = msg + ", 2nd iterator contained " + first;
|
||||
return new UnsoundGraphException(msg);
|
||||
} else {
|
||||
msg = msg + "set2.size = 0";
|
||||
return new UnsoundGraphException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnsoundGraphException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1503478788521696930L;
|
||||
|
||||
public UnsoundGraphException() {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
public UnsoundGraphException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @param c
|
||||
* @throws IllegalArgumentException if c is null
|
||||
*/
|
||||
public static void printCollection(String string, Collection c) {
|
||||
if (c == null) {
|
||||
throw new IllegalArgumentException("c is null");
|
||||
}
|
||||
System.err.println(string);
|
||||
if (c.isEmpty()) {
|
||||
System.err.println("none\n");
|
||||
} else {
|
||||
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||
System.err.println(it.next().toString());
|
||||
}
|
||||
System.err.println("\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph;
|
||||
|
||||
/**
|
||||
* Simple graph printing utility
|
||||
*/
|
||||
public class GraphPrint {
|
||||
|
||||
public static <T> String genericToString(Graph<T> G) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
SlowSparseNumberedGraph<T> sg = SlowSparseNumberedGraph.make();
|
||||
for (Iterator<? extends T> it = G.iterator(); it.hasNext(); ) {
|
||||
sg.addNode(it.next());
|
||||
}
|
||||
for (Iterator<? extends T> it = G.iterator(); it.hasNext(); ) {
|
||||
T n = it.next();
|
||||
for (Iterator<? extends T> it2 = G.getSuccNodes(n); it2.hasNext(); ) {
|
||||
T d = it2.next();
|
||||
sg.addEdge(n,d);
|
||||
}
|
||||
}
|
||||
return sg.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorFramework;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorIdentity;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorSolver;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorUnion;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorUnionConstant;
|
||||
import com.ibm.wala.dataflow.graph.DataflowSolver;
|
||||
import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
|
||||
import com.ibm.wala.fixpoint.BitVectorVariable;
|
||||
import com.ibm.wala.fixpoint.UnaryOperator;
|
||||
import com.ibm.wala.util.CancelException;
|
||||
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
||||
import com.ibm.wala.util.collections.Filter;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.Iterator2Collection;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.graph.impl.GraphInverter;
|
||||
import com.ibm.wala.util.intset.MutableMapping;
|
||||
import com.ibm.wala.util.intset.OrdinalSet;
|
||||
import com.ibm.wala.util.intset.OrdinalSetMapping;
|
||||
|
||||
/**
|
||||
* A dataflow system that computes, for each graph node, the set of "interesting" nodes that are reachable
|
||||
*/
|
||||
public class GraphReachability<T> {
|
||||
|
||||
/**
|
||||
* Governing graph
|
||||
*/
|
||||
private final Graph<T> g;
|
||||
|
||||
/**
|
||||
* Killdall-style dataflow solver
|
||||
*/
|
||||
private DataflowSolver solver;
|
||||
|
||||
/**
|
||||
* set of "interesting" CGNodes
|
||||
*/
|
||||
final OrdinalSetMapping<T> domain;
|
||||
|
||||
/**
|
||||
* @param g call graph to analyze
|
||||
* @param filter "interesting" node definition
|
||||
* @throws IllegalArgumentException if g is null
|
||||
*/
|
||||
public GraphReachability(Graph<T> g, Filter filter) {
|
||||
if (g == null) {
|
||||
throw new IllegalArgumentException("g is null");
|
||||
}
|
||||
this.g = g;
|
||||
Iterator<T> i = new FilterIterator<T>(g.iterator(), filter);
|
||||
domain = new MutableMapping<T>((Iterator2Collection.toSet(i)).toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n
|
||||
* @return the set of interesting nodes reachable from n
|
||||
*/
|
||||
public OrdinalSet<T> getReachableSet(Object n) throws IllegalStateException {
|
||||
if (solver == null) {
|
||||
throw new IllegalStateException("must call solve() before calling getReachableSet()");
|
||||
}
|
||||
BitVectorVariable v = (BitVectorVariable) solver.getOut(n);
|
||||
assert v != null : "null variable for node " + n;
|
||||
if (v.getValue() == null) {
|
||||
return OrdinalSet.empty();
|
||||
} else {
|
||||
return new OrdinalSet<T>(v.getValue(), domain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true iff the evaluation of some equation caused a change in the value of some variable.
|
||||
*/
|
||||
public boolean solve(IProgressMonitor monitor) throws CancelException {
|
||||
|
||||
ITransferFunctionProvider<T, BitVectorVariable> functions = new ITransferFunctionProvider<T, BitVectorVariable>() {
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#getNodeTransferFunction(java.lang.Object)
|
||||
*/
|
||||
public UnaryOperator<BitVectorVariable> getNodeTransferFunction(T n) {
|
||||
int index = domain.getMappedIndex(n);
|
||||
if (index > -1) {
|
||||
return new BitVectorUnionConstant(index);
|
||||
} else {
|
||||
return BitVectorIdentity.instance();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#hasNodeTransferFunctions()
|
||||
*/
|
||||
public boolean hasNodeTransferFunctions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#getEdgeTransferFunction(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public UnaryOperator<BitVectorVariable> getEdgeTransferFunction(Object from, Object to) {
|
||||
Assertions.UNREACHABLE();
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#hasEdgeTransferFunctions()
|
||||
*/
|
||||
public boolean hasEdgeTransferFunctions() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#getMeetOperator()
|
||||
*/
|
||||
public AbstractMeetOperator<BitVectorVariable> getMeetOperator() {
|
||||
return BitVectorUnion.instance();
|
||||
}
|
||||
};
|
||||
|
||||
BitVectorFramework<T, T> f = new BitVectorFramework<T, T>(GraphInverter.invert(g), functions, domain);
|
||||
solver = new BitVectorSolver<T>(f);
|
||||
return solver.solve(monitor);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,307 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.collections.Filter;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Iterator2Collection;
|
||||
import com.ibm.wala.util.collections.IteratorUtil;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.functions.Function;
|
||||
import com.ibm.wala.util.graph.impl.GraphInverter;
|
||||
import com.ibm.wala.util.graph.traverse.DFS;
|
||||
import com.ibm.wala.util.warnings.WalaException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class GraphSlicer {
|
||||
|
||||
/**
|
||||
* Performs a backward slice.
|
||||
*
|
||||
* @param <T> type for nodes
|
||||
* @param g the graph to slice
|
||||
* @param f identifies targets for the backward slice
|
||||
* @return the set of nodes in g, from which any of the targets (nodes that f accepts) is reachable.
|
||||
* @throws WalaException
|
||||
*/
|
||||
public static <T> Set<T> slice(Graph<T> g, Filter<T> f) throws WalaException {
|
||||
|
||||
if (g == null) {
|
||||
throw new IllegalArgumentException("g is null");
|
||||
}
|
||||
HashSet<T> roots = HashSetFactory.make();
|
||||
for (Iterator<? extends T> it = g.iterator(); it.hasNext();) {
|
||||
T o = it.next();
|
||||
if (f.accepts(o)) {
|
||||
roots.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
Set<T> result = DFS.getReachableNodes(GraphInverter.invert(g), roots);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune a graph to only the nodes accepted by the filter f
|
||||
*/
|
||||
public static <T> Graph<T> prune(final Graph<T> g, final Filter<T> f) {
|
||||
if (g == null) {
|
||||
throw new IllegalArgumentException("g is null");
|
||||
}
|
||||
final NodeManager<T> n = new NodeManager<T>() {
|
||||
int nodeCount = -1;
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return new FilterIterator<T>(g.iterator(), f);
|
||||
}
|
||||
|
||||
public int getNumberOfNodes() {
|
||||
if (nodeCount == -1) {
|
||||
nodeCount = IteratorUtil.count(iterator());
|
||||
}
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
public void addNode(T n) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeNode(T n) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public boolean containsNode(T N) {
|
||||
return f.accepts(N) && g.containsNode(N);
|
||||
}
|
||||
|
||||
};
|
||||
final EdgeManager<T> e = new EdgeManager<T>() {
|
||||
|
||||
public Iterator<T> getPredNodes(T N) {
|
||||
return new FilterIterator<T>(g.getPredNodes(N), f);
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N) {
|
||||
return IteratorUtil.count(getPredNodes(N));
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(T N) {
|
||||
return new FilterIterator<T>(g.getSuccNodes(N), f);
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N) {
|
||||
return IteratorUtil.count(getSuccNodes(N));
|
||||
}
|
||||
|
||||
public void addEdge(T src, T dst) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(T node) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(T node) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(T node) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return g.hasEdge(src, dst) && f.accepts(src) && f.accepts(dst);
|
||||
}
|
||||
|
||||
};
|
||||
AbstractGraph<T> output = new AbstractGraph<T>() {
|
||||
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EdgeManager<T> getEdgeManager() {
|
||||
return e;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static <E> AbstractGraph<E> project(final Graph<E> G, final Filter<E> fmember) {
|
||||
final NodeManager<E> nodeManager = new NodeManager<E>() {
|
||||
private int count = -1;
|
||||
|
||||
public void addNode(E n) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean containsNode(E N) {
|
||||
return G.containsNode(N) && fmember.accepts(N);
|
||||
}
|
||||
|
||||
public int getNumberOfNodes() {
|
||||
if (count == -1) {
|
||||
count = IteratorUtil.count(iterator());
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
return new FilterIterator<E>(G.iterator(), fmember);
|
||||
}
|
||||
|
||||
public void removeNode(E n) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
final EdgeManager<E> edgeManager = new EdgeManager<E>() {
|
||||
|
||||
private Map<E, Collection<E>> succs = new HashMap<E, Collection<E>>();
|
||||
|
||||
private Map<E, Collection<E>> preds = new HashMap<E, Collection<E>>();
|
||||
|
||||
private Set<E> getConnected(E inst, Function<E, Iterator<? extends E>> fconnected) {
|
||||
Set<E> result = new LinkedHashSet<E>();
|
||||
Set<E> seenInsts = new HashSet<E>();
|
||||
Set<E> newInsts = Iterator2Collection.toSet(fconnected.apply(inst));
|
||||
while (!newInsts.isEmpty()) {
|
||||
Set<E> nextInsts = new HashSet<E>();
|
||||
for (E s : newInsts) {
|
||||
if (!seenInsts.contains(s)) {
|
||||
seenInsts.add(s);
|
||||
if (nodeManager.containsNode(s)) {
|
||||
result.add(s);
|
||||
} else {
|
||||
Iterator<? extends E> ss = fconnected.apply(s);
|
||||
while (ss.hasNext()) {
|
||||
E n = ss.next();
|
||||
if (!seenInsts.contains(n)) {
|
||||
nextInsts.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newInsts = nextInsts;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void setPredNodes(E N) {
|
||||
preds.put(N, getConnected(N, new Function<E, Iterator<? extends E>>() {
|
||||
public Iterator<? extends E> apply(E object) {
|
||||
return G.getPredNodes(object);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void setSuccNodes(E N) {
|
||||
succs.put(N, getConnected(N, new Function<E, Iterator<? extends E>>() {
|
||||
public Iterator<? extends E> apply(E object) {
|
||||
return G.getSuccNodes(object);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public int getPredNodeCount(E N) {
|
||||
if (!preds.containsKey(N)) {
|
||||
setPredNodes(N);
|
||||
}
|
||||
return preds.get(N).size();
|
||||
}
|
||||
|
||||
public Iterator<E> getPredNodes(E N) {
|
||||
if (!preds.containsKey(N)) {
|
||||
setPredNodes(N);
|
||||
}
|
||||
return preds.get(N).iterator();
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(E N) {
|
||||
if (!succs.containsKey(N)) {
|
||||
setSuccNodes(N);
|
||||
}
|
||||
return succs.get(N).size();
|
||||
}
|
||||
|
||||
public Iterator<E> getSuccNodes(E N) {
|
||||
if (!succs.containsKey(N)) {
|
||||
setSuccNodes(N);
|
||||
}
|
||||
return succs.get(N).iterator();
|
||||
}
|
||||
|
||||
public boolean hasEdge(E src, E dst) {
|
||||
if (!preds.containsKey(dst)) {
|
||||
setPredNodes(dst);
|
||||
}
|
||||
return preds.get(dst).contains(src);
|
||||
}
|
||||
|
||||
public void addEdge(E src, E dst) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(E node) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void removeEdge(E src, E dst) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(E node) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(E node) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
return new AbstractGraph<E>() {
|
||||
|
||||
@Override
|
||||
protected EdgeManager<E> getEdgeManager() {
|
||||
return edgeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeManager<E> getNodeManager() {
|
||||
return nodeManager;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
|
||||
/**
|
||||
* Utility methods for graphs.
|
||||
*/
|
||||
public class GraphUtil {
|
||||
|
||||
/**
|
||||
* count the number of edges in g
|
||||
*/
|
||||
public static <T> long countEdges(Graph<T> g) {
|
||||
if (g == null) {
|
||||
throw new IllegalArgumentException("g is null");
|
||||
}
|
||||
long edgeCount = 0;
|
||||
for (T t : g) {
|
||||
edgeCount += g.getSuccNodeCount(t);
|
||||
}
|
||||
return edgeCount;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
|
||||
/**
|
||||
* Basic interface for a node which lives in one graph ... it's id is used
|
||||
* to implement the {@link NumberedGraph} interface.
|
||||
*/
|
||||
|
||||
public interface INodeWithNumber {
|
||||
|
||||
/**
|
||||
* A non-negative integer which serves as an identifier for this node in
|
||||
* it's "dominant" graph. Initially this number is -1; a NumberedGraph
|
||||
* will set it to a non-negative value when this node is inserted into
|
||||
* the graph
|
||||
* @return the identifier
|
||||
*/
|
||||
public int getGraphNodeId();
|
||||
|
||||
/**
|
||||
* @param number
|
||||
*/
|
||||
void setGraphNodeId(int number);
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
* Basic interface for a node which lives in one graph ... it's id is used to implement the {@link NumberedGraph} interface.
|
||||
*/
|
||||
public interface INodeWithNumberedEdges extends INodeWithNumber {
|
||||
/**
|
||||
* @return set of node numbers which are successors of this node
|
||||
*/
|
||||
public IntSet getSuccNumbers();
|
||||
|
||||
/**
|
||||
* @return set of node numbers which are predecessors of this node
|
||||
*/
|
||||
public IntSet getPredNumbers();
|
||||
|
||||
/**
|
||||
* Modify the graph so that node number n is a successor of this node
|
||||
*/
|
||||
public void addSucc(int n);
|
||||
|
||||
/**
|
||||
* Modify the graph so that node number n is a predecessor of this node
|
||||
*/
|
||||
public void addPred(int n);
|
||||
|
||||
/**
|
||||
* remove all edges that involve this node. This must fix up the other nodes involved in each edge removed.
|
||||
*/
|
||||
public void removeAllIncidentEdges();
|
||||
|
||||
/**
|
||||
* remove all incoming edges to this this node. This must fix up the other nodes involved in each edge removed.
|
||||
*/
|
||||
public void removeIncomingEdges();
|
||||
|
||||
/**
|
||||
* remove all outgoing edges to this this node. This must fix up the other nodes involved in each edge removed.
|
||||
*/
|
||||
public void removeOutgoingEdges();
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
|
||||
/**
|
||||
* TODO: Move this somewhere.
|
||||
*/
|
||||
public class InferGraphRoots {
|
||||
|
||||
public static <T> Collection<T> inferRoots(Graph<T> g){
|
||||
if (g == null) {
|
||||
throw new IllegalArgumentException("g is null");
|
||||
}
|
||||
HashSet<T> s = HashSetFactory.make();
|
||||
for (Iterator<? extends T> it = g.iterator(); it.hasNext();) {
|
||||
T node = it.next();
|
||||
if (g.getPredNodeCount(node) == 0) {
|
||||
s.add(node);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An object which tracks graph nodes.
|
||||
*
|
||||
* This is effectively a stripped-down collection interface. We choose to avoid using the full {@link Collection} interface, so that
|
||||
* it takes less code to implement a new {@link NodeManager}.
|
||||
*
|
||||
* @param <T> the type of nodes this {@link NodeManager} tracks.
|
||||
*/
|
||||
public interface NodeManager<T> extends Iterable<T> {
|
||||
|
||||
/**
|
||||
* @return an {@link Iterator} of the nodes in this graph
|
||||
*/
|
||||
public Iterator<T> iterator();
|
||||
|
||||
/**
|
||||
* @return the number of nodes in this graph
|
||||
*/
|
||||
public int getNumberOfNodes();
|
||||
|
||||
/**
|
||||
* add a node to this graph
|
||||
*/
|
||||
public void addNode(T n);
|
||||
|
||||
/**
|
||||
* remove a node from this graph
|
||||
*/
|
||||
public void removeNode(T n) throws UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* @return true iff the graph contains the specified node
|
||||
*/
|
||||
public boolean containsNode(T n);
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
|
||||
/**
|
||||
* Additional functionality for edges in numbered graphs
|
||||
*/
|
||||
public interface NumberedEdgeManager<T> extends EdgeManager<T> {
|
||||
|
||||
/**
|
||||
* @return the numbers identifying the immediate successors of node
|
||||
*/
|
||||
public IntSet getSuccNodeNumbers(T node);
|
||||
|
||||
/**
|
||||
* @return the numbers identifying the immediate predecessors of node
|
||||
*/
|
||||
public IntSet getPredNodeNumbers(T node);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
/**
|
||||
* A numbered graph is a {@link Graph} where each node has a unique persistent non-negative integer id.
|
||||
*/
|
||||
public interface NumberedGraph<T> extends Graph<T>, NumberedNodeManager<T>, NumberedEdgeManager<T> {
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
* An object which tracks nodes with numbers.
|
||||
*/
|
||||
public interface NumberedNodeManager<T> extends NodeManager<T> {
|
||||
|
||||
public abstract int getNumber(T N);
|
||||
|
||||
|
||||
public abstract T getNode(int number);
|
||||
|
||||
|
||||
public abstract int getMaxNumber();
|
||||
|
||||
/**
|
||||
* @param s
|
||||
* @return iterator of nodes with the numbers in set s
|
||||
*/
|
||||
public abstract Iterator<T> iterateNodes(IntSet s);
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface OrderedMultiGraph<T> extends Graph<T> {
|
||||
|
||||
/**
|
||||
* get the ith successor of a node
|
||||
*/
|
||||
public T getSuccessor(T node, int i);
|
||||
|
||||
/**
|
||||
* add an edge and record it so dst is the ith successor of src
|
||||
*/
|
||||
public void addEdge(int i, T src, T dst);
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph;
|
||||
|
||||
import com.ibm.wala.util.intset.SimpleIntVector;
|
||||
|
||||
/**
|
||||
* We represent a path in a numbered graph as a vector of integers <i_1, ...,
|
||||
* i_n> where node i_1 is the src and node i_n is the sink
|
||||
*/
|
||||
public class Path extends SimpleIntVector {
|
||||
|
||||
final int size;
|
||||
|
||||
private Path(int defaultValue, int size) {
|
||||
super(defaultValue, size);
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public static Path make(int value) {
|
||||
return new Path(value, 1);
|
||||
}
|
||||
|
||||
public static Path prepend(int x, Path p) {
|
||||
if (p == null) {
|
||||
throw new IllegalArgumentException("null p");
|
||||
}
|
||||
Path result = new Path(0, p.size + 1);
|
||||
result.set(0, x);
|
||||
for (int i = 0; i < p.size; i++) {
|
||||
result.set(i + 1, p.get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 7;
|
||||
for (int i = 0; i < size; i++) {
|
||||
result += 31 * (get(i) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Path) {
|
||||
Path other = (Path) obj;
|
||||
if (size == other.size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (get(i) != other.get(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer result = new StringBuffer("[");
|
||||
for (int i = 0; i < size; i++) {
|
||||
result.append(get(i));
|
||||
if (i < size -1) {
|
||||
result.append(",");
|
||||
}
|
||||
}
|
||||
result.append("]");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.dominators;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.traverse.DFS;
|
||||
|
||||
/**
|
||||
* An object that computes the dominance frontiers of a graph
|
||||
*/
|
||||
public class DominanceFrontiers<T> {
|
||||
|
||||
final private Map<T, Set<T>> DF = HashMapFactory.make();
|
||||
|
||||
final private Dominators<T> dom;
|
||||
|
||||
final private Graph<T> G;
|
||||
|
||||
final private T root;
|
||||
|
||||
/**
|
||||
* @param G
|
||||
* The graph
|
||||
* @param root
|
||||
* The root from which to compute dominators
|
||||
*/
|
||||
public DominanceFrontiers(Graph<T> G, T root) {
|
||||
this.root = root;
|
||||
this.G = G;
|
||||
this.dom = Dominators.make(G, root);
|
||||
analyze();
|
||||
}
|
||||
|
||||
public Iterator<T> getDominanceFrontier(T n) {
|
||||
return DF.get(n).iterator();
|
||||
}
|
||||
|
||||
public boolean isDominatedBy(T node, T master) {
|
||||
return dom.isDominatedBy(node, master);
|
||||
}
|
||||
|
||||
public Iterator<T> dominators(T node) {
|
||||
return dom.dominators(node);
|
||||
}
|
||||
|
||||
public Graph<T> dominatorTree() {
|
||||
return dom.dominatorTree();
|
||||
}
|
||||
|
||||
private void analyze() {
|
||||
Graph<T> DT = dom.dominatorTree();
|
||||
|
||||
Iterator<T> XS = DFS.iterateFinishTime(DT, new NonNullSingletonIterator<T>(root));
|
||||
while (XS.hasNext()) {
|
||||
T X = XS.next();
|
||||
Set<T> DF_X = HashSetFactory.make();
|
||||
DF.put(X, DF_X);
|
||||
|
||||
// DF_local
|
||||
for (Iterator<? extends T> YS = G.getSuccNodes(X); YS.hasNext();) {
|
||||
T Y = YS.next();
|
||||
if (dom.getIdom(Y) != X) {
|
||||
DF_X.add(Y);
|
||||
}
|
||||
}
|
||||
|
||||
// DF_up
|
||||
for (Iterator<? extends T> ZS = DT.getSuccNodes(X); ZS.hasNext();) {
|
||||
T Z = ZS.next();
|
||||
for (Iterator<T> YS2 = getDominanceFrontier(Z); YS2.hasNext();) {
|
||||
T Y2 = YS2.next();
|
||||
if (dom.getIdom(Y2) != X)
|
||||
DF_X.add(Y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,585 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.dominators;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.graph.AbstractGraph;
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
import com.ibm.wala.util.graph.traverse.DFSDiscoverTimeIterator;
|
||||
import com.ibm.wala.util.graph.traverse.SlowDFSDiscoverTimeIterator;
|
||||
|
||||
/**
|
||||
* Calculate dominators using Langauer and Tarjan's fastest algorithm. TOPLAS 1(1), July 1979. This implementation uses path
|
||||
* compression and results in a O(e * alpha(e,n)) complexity, where e is the number of edges in the CFG and n is the number of
|
||||
* nodes.
|
||||
*
|
||||
* Sources: TOPLAS article, Muchnick book
|
||||
*/
|
||||
|
||||
public abstract class Dominators<T> {
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* a mapping from DFS number to node
|
||||
*/
|
||||
private final T[] vertex;
|
||||
|
||||
/**
|
||||
* a convenient place to locate the graph to avoid passing it internally
|
||||
*/
|
||||
protected final Graph<T> G;
|
||||
|
||||
/**
|
||||
* the root node from which to build dominators
|
||||
*/
|
||||
protected final T root;
|
||||
|
||||
/**
|
||||
* the number of nodes reachable from the root
|
||||
*/
|
||||
protected int reachableNodeCount = 0;
|
||||
|
||||
/**
|
||||
* @param G The graph
|
||||
* @param root The root from which to compute dominators
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Dominators(Graph<T> G, T root) throws IllegalArgumentException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
this.G = G;
|
||||
this.root = root;
|
||||
if (G.getNumberOfNodes() == 0) {
|
||||
throw new IllegalArgumentException("G has no nodes");
|
||||
}
|
||||
this.vertex = (T[]) new Object[G.getNumberOfNodes() + 1];
|
||||
}
|
||||
|
||||
public static <T> Dominators<T> make(Graph<T> G, T root) {
|
||||
if (G instanceof NumberedGraph) {
|
||||
return new NumberedDominators<T>((NumberedGraph<T>) G, root);
|
||||
} else {
|
||||
return new GenericDominators<T>(G, root);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* is node dominated by master?
|
||||
*/
|
||||
public boolean isDominatedBy(T node, T master) {
|
||||
for (T ptr = node; ptr != null; ptr = getIdom(ptr))
|
||||
// use equals() since sometimes the CFGs get
|
||||
// reconstructed --MS
|
||||
if (ptr.equals(master))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Graph<T> getGraph() {
|
||||
return G;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the immediate dominator of node
|
||||
*/
|
||||
public T getIdom(T node) {
|
||||
return getInfo(node).dominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an Iterator over all nodes that dominate node
|
||||
*/
|
||||
public Iterator<T> dominators(final T node) {
|
||||
return new Iterator<T>() {
|
||||
private T current = node;
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return current != null;
|
||||
}
|
||||
|
||||
public T next() {
|
||||
if (current == null)
|
||||
throw new NoSuchElementException();
|
||||
T nextNode = current;
|
||||
current = getIdom(current);
|
||||
return nextNode;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* return the dominator tree, which has an edge from n to n' if n dominates n'
|
||||
*/
|
||||
public Graph<T> dominatorTree() {
|
||||
return new AbstractGraph<T>() {
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return G;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EdgeManager<T> getEdgeManager() {
|
||||
return edges;
|
||||
}
|
||||
|
||||
private final EdgeManager<T> edges = new EdgeManager<T>() {
|
||||
private final Map<T, Set<T>> nextMap = HashMapFactory.make();
|
||||
|
||||
{
|
||||
for (Iterator<? extends T> ns = G.iterator(); ns.hasNext();) {
|
||||
T n = ns.next();
|
||||
if (n != root) {
|
||||
T prev = getIdom(n);
|
||||
Set<T> next = nextMap.get(prev);
|
||||
if (next == null)
|
||||
nextMap.put(prev, next = HashSetFactory.make(2));
|
||||
next.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N) {
|
||||
if (N == root)
|
||||
return EmptyIterator.instance();
|
||||
else
|
||||
return new NonNullSingletonIterator<T>(getIdom(N));
|
||||
}
|
||||
|
||||
public int getPredNodeCount(Object N) {
|
||||
return (N == root) ? 0 : 1;
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(Object N) {
|
||||
if (nextMap.containsKey(N))
|
||||
return nextMap.get(N).iterator();
|
||||
else
|
||||
return EmptyIterator.instance();
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(Object N) {
|
||||
if (nextMap.containsKey(N))
|
||||
return nextMap.get(N).size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void addEdge(Object src, Object dst) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeEdge(Object src, Object dst) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(Object node) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(Object node) {
|
||||
// TODO Auto-generated method stub
|
||||
Assertions.UNREACHABLE();
|
||||
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(Object node) {
|
||||
// TODO Auto-generated method stub
|
||||
Assertions.UNREACHABLE();
|
||||
|
||||
}
|
||||
|
||||
public boolean hasEdge(Object src, Object dst) {
|
||||
// TODO Auto-generated method stub
|
||||
Assertions.UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// IMPLEMENTATION -- MAIN ALGORITHM
|
||||
//
|
||||
|
||||
/**
|
||||
* analyze dominators
|
||||
*/
|
||||
protected void analyze() {
|
||||
if (DEBUG)
|
||||
System.out.println("Dominators for " + G);
|
||||
|
||||
// Step 1: Perform a DFS numbering
|
||||
step1();
|
||||
|
||||
// Step 2: the heart of the algorithm
|
||||
step2();
|
||||
|
||||
// Step 3: adjust immediate dominators of nodes whose current version of
|
||||
// the immediate dominators differs from the nodes with the depth-first
|
||||
// number of the node's semidominator.
|
||||
step3();
|
||||
|
||||
if (DEBUG)
|
||||
System.err.println(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The goal of this step is to perform a DFS numbering on the CFG, starting at the root. The exit node is not included.
|
||||
*/
|
||||
private void step1() {
|
||||
reachableNodeCount = 0;
|
||||
|
||||
DFSDiscoverTimeIterator<T> dfs = new SlowDFSDiscoverTimeIterator<T>(G, root) {
|
||||
public static final long serialVersionUID = 88831771771711L;
|
||||
|
||||
@Override
|
||||
protected void visitEdge(T from, T to) {
|
||||
if (DEBUG)
|
||||
System.out.println("visiting edge " + from + " --> " + to);
|
||||
setParent(to, from);
|
||||
}
|
||||
};
|
||||
|
||||
while (dfs.hasNext()) {
|
||||
T node = dfs.next();
|
||||
assert node != null;
|
||||
vertex[++reachableNodeCount] = node;
|
||||
setSemi(node, reachableNodeCount);
|
||||
if (DEBUG)
|
||||
System.out.println(node + " is DFS number " + reachableNodeCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the heart of the algorithm. See sources for details.
|
||||
*/
|
||||
private void step2() {
|
||||
if (DEBUG) {
|
||||
System.out.println(" ******* Beginning STEP 2 *******\n");
|
||||
}
|
||||
|
||||
// Visit each node in reverse DFS order, except for the root, which
|
||||
// has number 1
|
||||
// for i=n downto 2
|
||||
for (int i = reachableNodeCount; i > 1; i--) {
|
||||
T node = vertex[i];
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println(" Processing: " + node + "\n");
|
||||
}
|
||||
|
||||
// visit each predecessor
|
||||
Iterator<? extends T> e = G.getPredNodes(node);
|
||||
while (e.hasNext()) {
|
||||
T prev = e.next();
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println(" Inspecting prev: " + prev);
|
||||
}
|
||||
T u = EVAL(prev);
|
||||
// if semi(u) < semi(node) then semi(node) = semi(u)
|
||||
// u may be part of infinite loop and thus, is unreachable from the exit
|
||||
// node.
|
||||
// In this case, it will have a semi value of 0. Thus, we screen for it
|
||||
// here
|
||||
if (getSemi(u) != 0 && getSemi(u) < getSemi(node)) {
|
||||
setSemi(node, getSemi(u));
|
||||
}
|
||||
} // while prev
|
||||
|
||||
// add "node" to bucket(vertex(semi(node)));
|
||||
addToBucket(vertex[getSemi(node)], node);
|
||||
|
||||
// LINK(parent(node), node)
|
||||
LINK(getParent(node), node);
|
||||
|
||||
// foreach node2 in bucket(parent(node)) do
|
||||
Iterator<T> bucketEnum = iterateBucket(getParent(node));
|
||||
while (bucketEnum.hasNext()) {
|
||||
T node2 = bucketEnum.next();
|
||||
|
||||
// u = EVAL(node2)
|
||||
T u = EVAL(node2);
|
||||
|
||||
// if semi(u) < semi(node2) then
|
||||
// dom(node2) = u
|
||||
// else
|
||||
// dom(node2) = parent(node)
|
||||
if (getSemi(u) < getSemi(node2)) {
|
||||
setDominator(node2, u);
|
||||
} else {
|
||||
setDominator(node2, getParent(node));
|
||||
}
|
||||
} // while bucket has more elements
|
||||
} // for DFSCounter .. 1
|
||||
} // method
|
||||
|
||||
/**
|
||||
* This method inspects the passed node and returns the following: node, if node is a root of a tree in the forest
|
||||
*
|
||||
* any vertex, u != r such that otherwise r is the root of the tree containing node and * semi(u) is minimum on the path r -> v
|
||||
*
|
||||
* See TOPLAS 1(1), July 1979, p 128 for details.
|
||||
*
|
||||
* @param node the node to evaluate
|
||||
* @return the node as described above
|
||||
*/
|
||||
private T EVAL(T node) {
|
||||
if (DEBUG) {
|
||||
System.out.println(" Evaling " + node);
|
||||
}
|
||||
if (getAncestor(node) == null) {
|
||||
return getLabel(node);
|
||||
} else {
|
||||
compress(node);
|
||||
if (getSemi(getLabel(getAncestor(node))) >= getSemi(getLabel(node))) {
|
||||
return getLabel(node);
|
||||
} else {
|
||||
return getLabel(getAncestor(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This recursive method performs the path compression
|
||||
*
|
||||
* @param node node of interest
|
||||
*/
|
||||
private void compress(T node) {
|
||||
if (getAncestor(getAncestor(node)) != null) {
|
||||
compress(getAncestor(node));
|
||||
if (getSemi(getLabel(getAncestor(node))) < getSemi(getLabel(node))) {
|
||||
setLabel(node, getLabel(getAncestor(node)));
|
||||
}
|
||||
setAncestor(node, getAncestor(getAncestor(node)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds edge (node1, node2) to the forest maintained as an auxiliary data structure. This implementation uses path compression and
|
||||
* results in a O(e * alpha(e,n)) complexity, where e is the number of edges in the CFG and n is the number of nodes.
|
||||
*
|
||||
* @param node1 a basic node corresponding to the source of the new edge
|
||||
* @param node2 a basic node corresponding to the source of the new edge
|
||||
*/
|
||||
private void LINK(T node1, T node2) {
|
||||
if (DEBUG) {
|
||||
System.out.println(" Linking " + node1 + " with " + node2);
|
||||
}
|
||||
T s = node2;
|
||||
while (getSemi(getLabel(node2)) < getSemi(getLabel(getChild(s)))) {
|
||||
if (getSize(s) + getSize(getChild(getChild(s))) >= 2 * getSize(getChild(s))) {
|
||||
setAncestor(getChild(s), s);
|
||||
setChild(s, getChild(getChild(s)));
|
||||
} else {
|
||||
setSize(getChild(s), getSize(s));
|
||||
setAncestor(s, getChild(s));
|
||||
s = getChild(s);
|
||||
}
|
||||
}
|
||||
setLabel(s, getLabel(node2));
|
||||
setSize(node1, getSize(node1) + getSize(node2));
|
||||
if (getSize(node1) < 2 * getSize(node2)) {
|
||||
T tmp = s;
|
||||
s = getChild(node1);
|
||||
setChild(node1, tmp);
|
||||
}
|
||||
while (s != null) {
|
||||
setAncestor(s, node1);
|
||||
s = getChild(s);
|
||||
}
|
||||
if (DEBUG) {
|
||||
System.out.println(" .... done");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This final step sets the final dominator information.
|
||||
*/
|
||||
private void step3() {
|
||||
// Visit each node in DFS order, except for the root, which has number 1
|
||||
for (int i = 2; i <= reachableNodeCount; i++) {
|
||||
T node = vertex[i];
|
||||
// if dom(node) != vertex[semi(node)]
|
||||
if (getDominator(node) != vertex[getSemi(node)]) {
|
||||
// dom(node) = dom(dom(node))
|
||||
setDominator(node, getDominator(getDominator(node)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LOOK-ASIDE TABLE FOR PER-NODE STATE AND ITS ACCESSORS
|
||||
*/
|
||||
protected final class DominatorInfo {
|
||||
/*
|
||||
* The result of this computation: the immediate dominator of this node
|
||||
*/
|
||||
private T dominator;
|
||||
|
||||
/*
|
||||
* The parent node in the DFS tree used in dominator computation
|
||||
*/
|
||||
private T parent;
|
||||
|
||||
/*
|
||||
* the ``semi-dominator,'' which starts as the DFS number in step 1
|
||||
*/
|
||||
private int semiDominator;
|
||||
|
||||
/*
|
||||
* The buckets used in step 2
|
||||
*/
|
||||
final private Set<T> bucket;
|
||||
|
||||
/*
|
||||
* the labels used in the fast union-find structure
|
||||
*/
|
||||
private T label;
|
||||
|
||||
/*
|
||||
* ancestor for fast union-find data structure
|
||||
*/
|
||||
private T ancestor;
|
||||
|
||||
/*
|
||||
* the size used by the fast union-find structure
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/*
|
||||
* the child used by the fast union-find structure
|
||||
*/
|
||||
private T child;
|
||||
|
||||
DominatorInfo(T node) {
|
||||
semiDominator = 0;
|
||||
dominator = null;
|
||||
parent = null;
|
||||
bucket = HashSetFactory.make();
|
||||
ancestor = null;
|
||||
label = node;
|
||||
size = 1;
|
||||
child = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look-aside table for DominatorInfo objects
|
||||
*/
|
||||
protected abstract DominatorInfo getInfo(T node);
|
||||
|
||||
private Iterator<T> iterateBucket(T node) {
|
||||
return getInfo(node).bucket.iterator();
|
||||
}
|
||||
|
||||
private void addToBucket(T node, T addend) {
|
||||
getInfo(node).bucket.add(addend);
|
||||
}
|
||||
|
||||
private T getDominator(T node) {
|
||||
assert node != null;
|
||||
return getInfo(node).dominator;
|
||||
}
|
||||
|
||||
private void setDominator(T node, T dominator) {
|
||||
getInfo(node).dominator = dominator;
|
||||
}
|
||||
|
||||
private T getParent(T node) {
|
||||
return getInfo(node).parent;
|
||||
}
|
||||
|
||||
private void setParent(T node, T parent) {
|
||||
getInfo(node).parent = parent;
|
||||
}
|
||||
|
||||
private T getAncestor(T node) {
|
||||
return getInfo(node).ancestor;
|
||||
}
|
||||
|
||||
private void setAncestor(T node, T ancestor) {
|
||||
getInfo(node).ancestor = ancestor;
|
||||
}
|
||||
|
||||
private T getLabel(T node) {
|
||||
if (node == null)
|
||||
return null;
|
||||
else
|
||||
return getInfo(node).label;
|
||||
}
|
||||
|
||||
private void setLabel(T node, T label) {
|
||||
getInfo(node).label = label;
|
||||
}
|
||||
|
||||
private int getSize(T node) {
|
||||
if (node == null)
|
||||
return 0;
|
||||
else
|
||||
return getInfo(node).size;
|
||||
}
|
||||
|
||||
private void setSize(T node, int size) {
|
||||
getInfo(node).size = size;
|
||||
}
|
||||
|
||||
private T getChild(T node) {
|
||||
return getInfo(node).child;
|
||||
}
|
||||
|
||||
private void setChild(T node, T child) {
|
||||
getInfo(node).child = child;
|
||||
}
|
||||
|
||||
private int getSemi(T node) {
|
||||
if (node == null)
|
||||
return 0;
|
||||
else
|
||||
return getInfo(node).semiDominator;
|
||||
}
|
||||
|
||||
private void setSemi(T node, int semi) {
|
||||
getInfo(node).semiDominator = semi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Iterator<? extends T> i = G.iterator(); i.hasNext();) {
|
||||
T node = i.next();
|
||||
sb.append("Dominators of " + node + ":\n");
|
||||
for (Iterator j = dominators(node); j.hasNext();)
|
||||
sb.append(" " + j.next() + "\n");
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.dominators;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* Calculate dominators using Langauer and Tarjan's fastest algorithm. TOPLAS
|
||||
* 1(1), July 1979. This implementation uses path compression and results in a
|
||||
* O(e * alpha(e,n)) complexity, where e is the number of edges in the CFG and n
|
||||
* is the number of nodes.
|
||||
*
|
||||
* Sources: TOPLAS article, Muchnick book
|
||||
*/
|
||||
|
||||
public class GenericDominators<T> extends Dominators<T> {
|
||||
|
||||
public GenericDominators(Graph<T> G, T root)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
super(G, root);
|
||||
this.infoMap = HashMapFactory.make(G.getNumberOfNodes());
|
||||
analyze();
|
||||
}
|
||||
|
||||
/*
|
||||
* Look-aside table for DominatorInfo objects
|
||||
*/
|
||||
private final Map<Object, DominatorInfo> infoMap;
|
||||
|
||||
@Override
|
||||
protected DominatorInfo getInfo(T node) {
|
||||
if (!infoMap.containsKey(node))
|
||||
infoMap.put(node, new DominatorInfo(node));
|
||||
return infoMap.get(node);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.dominators;
|
||||
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
|
||||
/**
|
||||
* Calculate dominators using Langauer and Tarjan's fastest algorithm. TOPLAS
|
||||
* 1(1), July 1979. This implementation uses path compression and results in a
|
||||
* O(e * alpha(e,n)) complexity, where e is the number of edges in the CFG and n
|
||||
* is the number of nodes.
|
||||
*
|
||||
* Sources: TOPLAS article, Muchnick book
|
||||
*/
|
||||
|
||||
public class NumberedDominators<T> extends Dominators<T> {
|
||||
|
||||
public NumberedDominators(NumberedGraph<T> G, T root) throws IllegalArgumentException {
|
||||
super(G, root);
|
||||
|
||||
this.infoMap = new Object[G.getMaxNumber() + 1];
|
||||
for (T n : G) {
|
||||
infoMap[G.getNumber(n)] = new DominatorInfo(n);
|
||||
}
|
||||
|
||||
analyze();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberedGraph<T> getGraph() {
|
||||
return (NumberedGraph<T>) G;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look-aside table for DominatorInfo objects
|
||||
*/
|
||||
private final Object[] infoMap;
|
||||
|
||||
@Override
|
||||
protected final DominatorInfo getInfo(T node) {
|
||||
assert node != null;
|
||||
return (DominatorInfo) infoMap[getGraph().getNumber(node)];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
|
||||
/**
|
||||
* Simple implementation of a {@link NodeManager}.
|
||||
*/
|
||||
public class BasicNodeManager<T> implements NodeManager<T> {
|
||||
|
||||
final private HashSet<T> nodes = HashSetFactory.make();
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return nodes.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes()
|
||||
*/
|
||||
public int getNumberOfNodes() {
|
||||
return nodes.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#addNode(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void addNode(T n) {
|
||||
nodes.add(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeNode(T n) {
|
||||
nodes.remove(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public boolean containsNode(T N) {
|
||||
return nodes.contains(N);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.SimpleVector;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.OrderedMultiGraph;
|
||||
|
||||
/**
|
||||
* Inefficient implementation of OrderedMultiGraph.
|
||||
*
|
||||
* UNDER CONSTRUCTION.
|
||||
*
|
||||
* @param <T> type of node in the graph
|
||||
*/
|
||||
public class BasicOrderedMultiGraph<T> implements OrderedMultiGraph<T> {
|
||||
|
||||
final Map<T, SimpleVector<T>> successorEdges = HashMapFactory.make();
|
||||
|
||||
private final Graph<T> delegate;
|
||||
|
||||
public BasicOrderedMultiGraph() {
|
||||
this.delegate = SlowSparseNumberedGraph.make();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this edge, unconditionally setting it as the next successor.
|
||||
*/
|
||||
public void addEdge(T src, T dst) throws IllegalArgumentException {
|
||||
delegate.addEdge(src, dst);
|
||||
SimpleVector<T> s = successorEdges.get(src);
|
||||
if (s == null) {
|
||||
s = new SimpleVector<T>();
|
||||
successorEdges.put(src, s);
|
||||
}
|
||||
s.set(s.getMaxIndex() + 1, dst);
|
||||
}
|
||||
|
||||
public void addEdge(int i, T src, T dst) throws IllegalArgumentException {
|
||||
delegate.addEdge(src, dst);
|
||||
SimpleVector<T> s = successorEdges.get(src);
|
||||
if (s == null) {
|
||||
s = new SimpleVector<T>();
|
||||
successorEdges.put(src, s);
|
||||
}
|
||||
s.set(i, dst);
|
||||
}
|
||||
|
||||
public void addNode(T n) {
|
||||
delegate.addNode(n);
|
||||
}
|
||||
|
||||
public boolean containsNode(T N) {
|
||||
return delegate.containsNode(N);
|
||||
}
|
||||
|
||||
public int getNumberOfNodes() {
|
||||
return delegate.getNumberOfNodes();
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N) throws IllegalArgumentException {
|
||||
return delegate.getPredNodeCount(N);
|
||||
}
|
||||
|
||||
/**
|
||||
* For now, this returns nodes in no particular order! Fix this when needed.
|
||||
*/
|
||||
public Iterator<T> getPredNodes(T N) throws IllegalArgumentException {
|
||||
return delegate.getPredNodes(N);
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N) throws IllegalArgumentException {
|
||||
return delegate.getSuccNodeCount(N);
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(T N) throws IllegalArgumentException {
|
||||
return delegate.getSuccNodes(N);
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return delegate.hasEdge(src, dst);
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return delegate.iterator();
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(T node) throws UnimplementedError {
|
||||
Assertions.UNREACHABLE();
|
||||
delegate.removeAllIncidentEdges(node);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) throws UnimplementedError {
|
||||
Assertions.UNREACHABLE();
|
||||
delegate.removeEdge(src, dst);
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(T node) throws UnimplementedError {
|
||||
Assertions.UNREACHABLE();
|
||||
delegate.removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
public void removeNode(T n) throws UnimplementedError {
|
||||
Assertions.UNREACHABLE();
|
||||
delegate.removeNode(n);
|
||||
}
|
||||
|
||||
public void removeNodeAndEdges(T N) throws UnimplementedError {
|
||||
Assertions.UNREACHABLE();
|
||||
delegate.removeNodeAndEdges(N);
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(T node) throws UnimplementedError {
|
||||
Assertions.UNREACHABLE();
|
||||
delegate.removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
public T getSuccessor(T node, int i) throws IllegalArgumentException {
|
||||
SimpleVector<T> s = successorEdges.get(node);
|
||||
if (s == null) {
|
||||
throw new IllegalArgumentException("no successors for node " + node);
|
||||
}
|
||||
if (i > s.getMaxIndex()) {
|
||||
throw new IllegalArgumentException("no successor number " + i + " for " + node);
|
||||
}
|
||||
return s.get(i);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* A utility class.
|
||||
*/
|
||||
public class DelegatingGraph<T> implements Graph<T> {
|
||||
|
||||
private final Graph<T> delegate;
|
||||
|
||||
public DelegatingGraph(Graph<T> delegate) {
|
||||
if (delegate == null) {
|
||||
throw new IllegalArgumentException("delegate is null");
|
||||
}
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public void addEdge(T src, T dst) throws IllegalArgumentException {
|
||||
delegate.addEdge(src, dst);
|
||||
}
|
||||
|
||||
public void addNode(T n) {
|
||||
delegate.addNode(n);
|
||||
}
|
||||
|
||||
public boolean containsNode(T N) {
|
||||
return delegate.containsNode(N);
|
||||
}
|
||||
|
||||
public int getNumberOfNodes() {
|
||||
return delegate.getNumberOfNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N) throws IllegalArgumentException {
|
||||
return delegate.getPredNodeCount(N);
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N) throws IllegalArgumentException {
|
||||
return delegate.getPredNodes(N);
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N) throws IllegalArgumentException {
|
||||
return delegate.getSuccNodeCount(N);
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(T N) throws IllegalArgumentException {
|
||||
return delegate.getSuccNodes(N);
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return delegate.hasEdge(src, dst);
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return delegate.iterator();
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(T node) throws IllegalArgumentException {
|
||||
delegate.removeAllIncidentEdges(node);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) throws IllegalArgumentException {
|
||||
delegate.removeEdge(src, dst);
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(T node) throws IllegalArgumentException {
|
||||
delegate.removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
public void removeNode(T n) {
|
||||
delegate.removeNode(n);
|
||||
}
|
||||
|
||||
public void removeNodeAndEdges(T N) throws IllegalArgumentException {
|
||||
delegate.removeNodeAndEdges(N);
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(T node) throws IllegalArgumentException {
|
||||
delegate.removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.graph.INodeWithNumberedEdges;
|
||||
import com.ibm.wala.util.graph.NumberedEdgeManager;
|
||||
import com.ibm.wala.util.intset.IntIterator;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.SparseIntSet;
|
||||
|
||||
/**
|
||||
* An object that delegates edge management to the nodes, {@link INodeWithNumberedEdges}
|
||||
*/
|
||||
public class DelegatingNumberedEdgeManager<T extends INodeWithNumberedEdges> implements NumberedEdgeManager<T> {
|
||||
|
||||
private final DelegatingNumberedNodeManager<T> nodeManager;
|
||||
|
||||
public DelegatingNumberedEdgeManager(DelegatingNumberedNodeManager<T> nodeManager) {
|
||||
if (nodeManager == null) {
|
||||
throw new IllegalArgumentException("nodeManager is null");
|
||||
}
|
||||
this.nodeManager = nodeManager;
|
||||
}
|
||||
|
||||
// TODO: optimization is possible
|
||||
private class IntSetNodeIterator implements Iterator<T> {
|
||||
|
||||
private final IntIterator delegate;
|
||||
|
||||
IntSetNodeIterator(IntIterator delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return delegate.hasNext();
|
||||
}
|
||||
|
||||
public T next() {
|
||||
return nodeManager.getNode(delegate.next());
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
// TODO Auto-generated method stub
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public Iterator<T> getPredNodes(T N) throws IllegalArgumentException {
|
||||
if (N == null) {
|
||||
throw new IllegalArgumentException("N cannot be null");
|
||||
}
|
||||
INodeWithNumberedEdges en = N;
|
||||
IntSet pred = en.getPredNumbers();
|
||||
Iterator<T> empty = EmptyIterator.instance();
|
||||
return (pred == null) ? empty : (Iterator<T>) new IntSetNodeIterator(pred.intIterator());
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(T node) {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("N cannot be null");
|
||||
}
|
||||
INodeWithNumberedEdges en = node;
|
||||
IntSet pred = en.getPredNumbers();
|
||||
return (pred == null) ? new SparseIntSet() : pred;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public int getPredNodeCount(T N) throws IllegalArgumentException {
|
||||
if (N == null) {
|
||||
throw new IllegalArgumentException("N cannot be null");
|
||||
}
|
||||
INodeWithNumberedEdges en = N;
|
||||
IntSet s = en.getPredNumbers();
|
||||
if (s == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return s.size();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public Iterator<T> getSuccNodes(T N) {
|
||||
if (N == null) {
|
||||
throw new IllegalArgumentException("N cannot be null");
|
||||
}
|
||||
INodeWithNumberedEdges en = N;
|
||||
IntSet succ = en.getSuccNumbers();
|
||||
Iterator<T> empty = EmptyIterator.instance();
|
||||
return (succ == null) ? empty : (Iterator<T>) new IntSetNodeIterator(succ.intIterator());
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public int getSuccNodeCount(T N) {
|
||||
if (N == null) {
|
||||
throw new IllegalArgumentException("N is null");
|
||||
}
|
||||
INodeWithNumberedEdges en = N;
|
||||
IntSet s = en.getSuccNumbers();
|
||||
return s == null ? 0 : s.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#addEdge(com.ibm.wala.util.graph.Node, com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void addEdge(T src, T dst) {
|
||||
if (dst == null || src == null) {
|
||||
throw new IllegalArgumentException("parameter is null");
|
||||
}
|
||||
src.addSucc(dst.getGraphNodeId());
|
||||
dst.addPred(src.getGraphNodeId());
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) throws UnimplementedError {
|
||||
Assertions.UNREACHABLE("Implement me");
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeAllIncidentEdges(T node) throws UnimplementedError {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node is null");
|
||||
}
|
||||
INodeWithNumberedEdges n = node;
|
||||
n.removeAllIncidentEdges();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeIncomingEdges(T node) throws UnimplementedError {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node cannot be null");
|
||||
}
|
||||
INodeWithNumberedEdges n = node;
|
||||
n.removeIncomingEdges();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeOutgoingEdges(T node) throws UnimplementedError {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node cannot be null");
|
||||
}
|
||||
INodeWithNumberedEdges n = node;
|
||||
n.removeOutgoingEdges();
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) throws IllegalArgumentException {
|
||||
if (dst == null) {
|
||||
throw new IllegalArgumentException("dst == null");
|
||||
}
|
||||
return getSuccNodeNumbers(src).contains(dst.getGraphNodeId());
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node) {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node cannot be null");
|
||||
}
|
||||
INodeWithNumberedEdges en = node;
|
||||
IntSet succ = en.getSuccNumbers();
|
||||
return (succ == null) ? new SparseIntSet() : succ;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
import com.ibm.wala.util.graph.INodeWithNumberedEdges;
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
|
||||
/**
|
||||
* Basic functionality for a graph that delegates node and edge management, and
|
||||
* tracks node numbers
|
||||
*/
|
||||
public class DelegatingNumberedGraph<T extends INodeWithNumberedEdges> extends AbstractNumberedGraph<T> {
|
||||
|
||||
final private DelegatingNumberedNodeManager<T> nodeManager = new DelegatingNumberedNodeManager<T>();
|
||||
|
||||
final private DelegatingNumberedEdgeManager<T> edgeManager = new DelegatingNumberedEdgeManager<T>(nodeManager);
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager()
|
||||
*/
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return nodeManager;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager()
|
||||
*/
|
||||
@Override
|
||||
protected EdgeManager<T> getEdgeManager() {
|
||||
return edgeManager;
|
||||
}
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.graph.INodeWithNumber;
|
||||
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
* Basic implementation of a numbered graph -- this implementation relies on nodes that carry numbers and edges.
|
||||
*
|
||||
* The management of node numbers is a bit fragile, but designed this way for efficiency. Use this class with care.
|
||||
*/
|
||||
public class DelegatingNumberedNodeManager<T extends INodeWithNumber> implements NumberedNodeManager<T> {
|
||||
|
||||
private final double BUFFER_FACTOR = 1.5;
|
||||
|
||||
private INodeWithNumber[] nodes = new INodeWithNumber[20];
|
||||
|
||||
private int maxNumber = -1;
|
||||
|
||||
private int numberOfNodes = 0;
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedGraph#getNumber(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public int getNumber(T N) {
|
||||
if (N == null) {
|
||||
throw new IllegalArgumentException("N is null");
|
||||
}
|
||||
INodeWithNumber n = N;
|
||||
return n.getGraphNodeId();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T getNode(int number) {
|
||||
try {
|
||||
return (T) nodes[number];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException("Invalid number " + number);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedGraph#getMaxNumber()
|
||||
*/
|
||||
public int getMaxNumber() {
|
||||
return maxNumber;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.Graph#iterateNodes()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
final INodeWithNumber[] arr = nodes;
|
||||
return new Iterator<T>() {
|
||||
int next = -1;
|
||||
{
|
||||
advance();
|
||||
}
|
||||
|
||||
void advance() {
|
||||
for (int i = next + 1; i < arr.length; i++) {
|
||||
if (arr[i] != null) {
|
||||
next = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
next = -1;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return next != -1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T next() {
|
||||
if (hasNext()) {
|
||||
int r = next;
|
||||
advance();
|
||||
return (T) arr[r];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.Graph#getNumberOfNodes()
|
||||
*/
|
||||
public int getNumberOfNodes() {
|
||||
return numberOfNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* If N.getNumber() == -1, then set N.number and insert this node in the graph. Use with extreme care.
|
||||
*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object)
|
||||
* @throws IllegalArgumentException if n is null
|
||||
*/
|
||||
public void addNode(T n) {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n is null");
|
||||
}
|
||||
INodeWithNumber N = n;
|
||||
int number = N.getGraphNodeId();
|
||||
if (number == -1) {
|
||||
maxNumber++;
|
||||
N.setGraphNodeId(maxNumber);
|
||||
number = maxNumber;
|
||||
} else {
|
||||
if (number > maxNumber) {
|
||||
maxNumber = number;
|
||||
}
|
||||
}
|
||||
ensureCapacity(number);
|
||||
if (nodes[number] != null && nodes[number] != N) {
|
||||
Assertions.UNREACHABLE("number: " + number + " N: " + N + " nodes[number]: " + nodes[number]);
|
||||
}
|
||||
nodes[number] = N;
|
||||
numberOfNodes++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param number
|
||||
*/
|
||||
private void ensureCapacity(int number) {
|
||||
if (nodes.length < number + 1) {
|
||||
int newLength = (int) ((number + 1) * BUFFER_FACTOR);
|
||||
INodeWithNumber[] old = nodes;
|
||||
nodes = new INodeWithNumber[newLength];
|
||||
System.arraycopy(old, 0, nodes, 0, old.length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeNode(T n) {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n is null");
|
||||
}
|
||||
INodeWithNumber N = n;
|
||||
int number = N.getGraphNodeId();
|
||||
if (number == -1) {
|
||||
throw new IllegalArgumentException("Cannot remove node, not in graph");
|
||||
}
|
||||
if (nodes[number] != null) {
|
||||
nodes[number] = null;
|
||||
numberOfNodes--;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer result = new StringBuffer("Nodes:\n");
|
||||
for (int i = 0; i < maxNumber; i++) {
|
||||
result.append(i).append(" ");
|
||||
if (nodes[i] != null) {
|
||||
result.append(nodes[i].toString());
|
||||
}
|
||||
result.append("\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public boolean containsNode(T n) {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n is null");
|
||||
}
|
||||
INodeWithNumber N = n;
|
||||
int number = N.getGraphNodeId();
|
||||
if (number == -1) {
|
||||
return false;
|
||||
}
|
||||
if (number >= nodes.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"node already has a graph node id, but is not registered there in this graph (number too big)\n"
|
||||
+ "this graph implementation is fragile and won't support this kind of test\n" + n.getClass() + " : " + n);
|
||||
}
|
||||
if (nodes[number] != N) {
|
||||
throw new IllegalArgumentException("node already has a graph node id, but is not registered there in this graph\n"
|
||||
+ "this graph implementation is fragile and won't support this kind of test\n" + n.getClass() + " : " + n);
|
||||
}
|
||||
return true;
|
||||
// return (nodes[number] == N);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet)
|
||||
*/
|
||||
public Iterator<T> iterateNodes(IntSet s) {
|
||||
return new NumberedNodeIterator<T>(s, this);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
/**
|
||||
* A utility class for use by clients. Use with care ... this will be slow and a space hog.
|
||||
*/
|
||||
public class ExplicitEdge {
|
||||
|
||||
final private Object src;
|
||||
final private Object dest;
|
||||
|
||||
public ExplicitEdge(Object src, Object dest) {
|
||||
if (src == null) {
|
||||
throw new IllegalArgumentException("null src");
|
||||
}
|
||||
if (dest == null) {
|
||||
throw new IllegalArgumentException("null dest");
|
||||
}
|
||||
this.src = src;
|
||||
this.dest = dest;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<" + src + "->" + dest + ">";
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return src.hashCode() * 947 + dest.hashCode();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass().equals(obj.getClass())) {
|
||||
ExplicitEdge other = (ExplicitEdge)obj;
|
||||
return src.equals(other.src) && dest.equals(other.dest);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
|
||||
/**
|
||||
* A graph view that reverses the edges in a graph
|
||||
*/
|
||||
public class GraphInverter {
|
||||
|
||||
/**
|
||||
* @param G
|
||||
* @return A graph view that reverses the edges in G
|
||||
*/
|
||||
public static <T> Graph<T> invert(final Graph<T> G) {
|
||||
if (G instanceof NumberedGraph) {
|
||||
return new InvertedNumberedGraph<T>((NumberedGraph<T>) G);
|
||||
} else {
|
||||
return new InvertedGraph<T>(G);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import com.ibm.wala.util.graph.AbstractGraph;
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
|
||||
/**
|
||||
* A graph view that reverses the edges in a graph
|
||||
*/
|
||||
public class InvertedGraph<T> extends AbstractGraph<T> {
|
||||
|
||||
final private NodeManager<T> nodes;
|
||||
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
final private EdgeManager<T> edges;
|
||||
|
||||
@Override
|
||||
protected EdgeManager<T> getEdgeManager() {
|
||||
return edges;
|
||||
}
|
||||
|
||||
public InvertedGraph(Graph<T> G) {
|
||||
nodes = G;
|
||||
edges = new InvertingEdgeManager<T>(G);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
import com.ibm.wala.util.graph.NumberedEdgeManager;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||
|
||||
/**
|
||||
* A graph view that reverses the edges in a graph
|
||||
*/
|
||||
public class InvertedNumberedGraph<T> extends AbstractNumberedGraph<T> {
|
||||
|
||||
final private NumberedNodeManager<T> nodes;
|
||||
final private NumberedEdgeManager<T> edges;
|
||||
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EdgeManager<T> getEdgeManager() {
|
||||
return edges;
|
||||
}
|
||||
|
||||
InvertedNumberedGraph(NumberedGraph<T> G) {
|
||||
nodes = G;
|
||||
edges = new InvertingNumberedEdgeManager<T>(G);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
|
||||
/**
|
||||
* An edge manager that reverses the edges in a graph
|
||||
*/
|
||||
public class InvertingEdgeManager<T> implements EdgeManager<T> {
|
||||
|
||||
private final EdgeManager<T> original;
|
||||
|
||||
public InvertingEdgeManager(EdgeManager<T> original) {
|
||||
if (original == null) {
|
||||
throw new IllegalArgumentException("original is null");
|
||||
}
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N) throws IllegalArgumentException {
|
||||
return original.getSuccNodes(N);
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N) throws IllegalArgumentException{
|
||||
return original.getSuccNodeCount(N);
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(T N) throws IllegalArgumentException{
|
||||
return original.getPredNodes(N);
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N) throws IllegalArgumentException{
|
||||
return original.getPredNodeCount(N);
|
||||
}
|
||||
|
||||
public void addEdge(T src, T dst)throws IllegalArgumentException {
|
||||
original.addEdge(dst, src);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) throws IllegalArgumentException{
|
||||
original.removeEdge(dst, src);
|
||||
}
|
||||
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return original.hasEdge(dst, src);
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(T node) throws IllegalArgumentException {
|
||||
original.removeAllIncidentEdges(node);
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(T node) throws IllegalArgumentException{
|
||||
original.removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(T node)throws IllegalArgumentException {
|
||||
original.removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.NumberedEdgeManager;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
* An edge manager that reverses the edges in a graph
|
||||
*/
|
||||
public class InvertingNumberedEdgeManager<T> implements NumberedEdgeManager<T> {
|
||||
|
||||
private final NumberedEdgeManager<T> original;
|
||||
|
||||
public InvertingNumberedEdgeManager(NumberedEdgeManager<T> original) {
|
||||
if (original == null) {
|
||||
throw new IllegalArgumentException("null original");
|
||||
}
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N) throws IllegalArgumentException{
|
||||
return original.getSuccNodes(N);
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N) throws IllegalArgumentException{
|
||||
return original.getSuccNodeCount(N);
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(T N) throws IllegalArgumentException{
|
||||
return original.getPredNodes(N);
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N) throws IllegalArgumentException{
|
||||
return original.getPredNodeCount(N);
|
||||
}
|
||||
|
||||
public void addEdge(T src, T dst) throws IllegalArgumentException{
|
||||
original.addEdge(dst, src);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst)throws IllegalArgumentException {
|
||||
original.removeEdge(dst, src);
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return original.hasEdge(dst, src);
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(T node) throws IllegalArgumentException{
|
||||
original.removeAllIncidentEdges(node);
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(T node) throws IllegalArgumentException{
|
||||
original.removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(T node) throws IllegalArgumentException{
|
||||
original.removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node) throws IllegalArgumentException{
|
||||
return original.getPredNodeNumbers(node);
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(T node) throws IllegalArgumentException{
|
||||
return original.getSuccNodeNumbers(node);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import com.ibm.wala.util.graph.INodeWithNumber;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
|
||||
/**
|
||||
* A node which carries it's own number; which identifies it in a {@link NumberedGraph} implementation.
|
||||
*
|
||||
* Note that a {@link NodeWithNumber} can live it at most one {@link NumberedGraph} at a time. The {@link NumberedGraph} will mutate
|
||||
* the number here. So this is a bit fragile. Use this only if you know what you're doing.
|
||||
*/
|
||||
public class NodeWithNumber implements INodeWithNumber {
|
||||
|
||||
private int number = -1;
|
||||
|
||||
/**
|
||||
* @return the number which identifies this node in the numbered graph
|
||||
*/
|
||||
public int getGraphNodeId() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setGraphNodeId(int i) {
|
||||
number = i;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.graph.INodeWithNumberedEdges;
|
||||
import com.ibm.wala.util.intset.BimodalMutableIntSet;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link INodeWithNumberedEdges}
|
||||
*/
|
||||
public class NodeWithNumberedEdges extends NodeWithNumber implements INodeWithNumberedEdges {
|
||||
|
||||
private BimodalMutableIntSet predNumbers;
|
||||
|
||||
private BimodalMutableIntSet succNumbers;
|
||||
|
||||
public IntSet getSuccNumbers() {
|
||||
return succNumbers;
|
||||
}
|
||||
|
||||
public IntSet getPredNumbers() {
|
||||
return predNumbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this variable appears on the RHS of an equation.
|
||||
*
|
||||
* @param eqNumber
|
||||
* the equation number
|
||||
*/
|
||||
public void addSucc(int eqNumber) {
|
||||
if (succNumbers == null) {
|
||||
succNumbers = new BimodalMutableIntSet();
|
||||
succNumbers.add(eqNumber);
|
||||
} else {
|
||||
succNumbers.add(eqNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this variable appears on the LHS of an equation.
|
||||
*
|
||||
* @param eqNumber
|
||||
* the equation number
|
||||
*/
|
||||
public void addPred(int eqNumber) {
|
||||
if (predNumbers == null) {
|
||||
predNumbers = new BimodalMutableIntSet();
|
||||
predNumbers.add(eqNumber);
|
||||
} else {
|
||||
predNumbers.add(eqNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the edge that indicates this variable is Succd by a certain equation
|
||||
*
|
||||
* @param eqNumber
|
||||
*/
|
||||
public void deleteSucc(int eqNumber) {
|
||||
if (succNumbers != null) {
|
||||
succNumbers.remove(eqNumber);
|
||||
if (succNumbers.size() == 0) {
|
||||
succNumbers = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the edge that indicates this variable is Predined by a certain
|
||||
* equation
|
||||
*
|
||||
* @param eqNumber
|
||||
*/
|
||||
public void deletePred(int eqNumber) {
|
||||
if (predNumbers != null) {
|
||||
predNumbers.remove(eqNumber);
|
||||
if (predNumbers.size() == 0) {
|
||||
predNumbers = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.INodeWithNumberedEdges#removeAllIncidentEdges()
|
||||
*/
|
||||
public void removeAllIncidentEdges() throws UnimplementedError {
|
||||
Assertions.UNREACHABLE("Implement me");
|
||||
}
|
||||
|
||||
public void removeIncomingEdges() throws UnimplementedError {
|
||||
Assertions.UNREACHABLE("Implement me");
|
||||
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges() throws UnimplementedError {
|
||||
Assertions.UNREACHABLE("Implement me");
|
||||
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||
import com.ibm.wala.util.intset.IntIterator;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class NumberedNodeIterator<T> implements Iterator<T> {
|
||||
final IntIterator numbers;
|
||||
|
||||
final NumberedNodeManager<T> nodeManager;
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if s is null
|
||||
*/
|
||||
public NumberedNodeIterator(IntSet s, NumberedNodeManager<T> nodeManager) {
|
||||
if (s == null) {
|
||||
throw new IllegalArgumentException("s is null");
|
||||
}
|
||||
this.numbers = s.intIterator();
|
||||
this.nodeManager = nodeManager;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return numbers.hasNext();
|
||||
}
|
||||
|
||||
public T next() throws NoSuchElementException {
|
||||
int i = numbers.next();
|
||||
T result = nodeManager.getNode(i);
|
||||
assert result != null : "null node for " + i;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void remove() throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.MutableMapping;
|
||||
|
||||
/**
|
||||
* An object which manages node numbers via a mapping.
|
||||
*/
|
||||
public class SlowNumberedNodeManager<T> implements NumberedNodeManager<T> {
|
||||
|
||||
/**
|
||||
* A bijection between integer <-> node
|
||||
*/
|
||||
final private MutableMapping<T> map = MutableMapping.make();
|
||||
|
||||
|
||||
public int getNumber(T obj) {
|
||||
return map.getMappedIndex(obj);
|
||||
}
|
||||
|
||||
|
||||
public T getNode(int number) {
|
||||
if (number < 0) {
|
||||
throw new IllegalArgumentException("number must be >= 0");
|
||||
}
|
||||
T result = map.getMappedObject(number);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedGraph#getMaxNumber()
|
||||
*/
|
||||
public int getMaxNumber() {
|
||||
return map.getMaximumIndex();
|
||||
}
|
||||
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return map.iterator();
|
||||
}
|
||||
|
||||
|
||||
public int getNumberOfNodes() {
|
||||
return map.getSize();
|
||||
}
|
||||
|
||||
public void addNode(T n) {
|
||||
if (n == null) {
|
||||
throw new IllegalArgumentException("n is null");
|
||||
}
|
||||
map.add(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public void removeNode(T n) {
|
||||
map.deleteMappedObject(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer result = new StringBuffer("Nodes:\n");
|
||||
for (int i = 0; i <= getMaxNumber(); i++) {
|
||||
result.append(i).append(" ");
|
||||
result.append(map.getMappedObject(i));
|
||||
result.append("\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node)
|
||||
*/
|
||||
public boolean containsNode(T N) {
|
||||
return getNumber(N) != -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet)
|
||||
*/
|
||||
public Iterator<T> iterateNodes(IntSet s) {
|
||||
return new NumberedNodeIterator<T>(s, this);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
import com.ibm.wala.util.intset.BasicNaturalRelation;
|
||||
|
||||
/**
|
||||
* A graph of numbered nodes, expected to have a fairly sparse edge structure.
|
||||
*/
|
||||
public class SlowSparseNumberedGraph<T> extends AbstractNumberedGraph<T> {
|
||||
|
||||
private final SlowNumberedNodeManager<T> nodeManager = new SlowNumberedNodeManager<T>();
|
||||
|
||||
private final SparseNumberedEdgeManager<T> edgeManager;
|
||||
|
||||
protected SlowSparseNumberedGraph() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* If normalOutCount == n, this edge manager will eagerly allocated n words to hold out edges for each node. (performance
|
||||
* optimization for time)
|
||||
*
|
||||
* @param normalOutCount what is the "normal" number of out edges for a node?
|
||||
*/
|
||||
public SlowSparseNumberedGraph(int normalOutCount) {
|
||||
edgeManager = new SparseNumberedEdgeManager<T>(nodeManager, normalOutCount, BasicNaturalRelation.TWO_LEVEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager()
|
||||
*/
|
||||
@Override
|
||||
public NodeManager<T> getNodeManager() {
|
||||
return nodeManager;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager()
|
||||
*/
|
||||
@Override
|
||||
public EdgeManager<T> getEdgeManager() {
|
||||
return edgeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a graph with the same nodes and edges as g
|
||||
*/
|
||||
public static <T> SlowSparseNumberedGraph<T> duplicate(Graph<T> g) {
|
||||
SlowSparseNumberedGraph<T> result = make();
|
||||
copyInto(g, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> void copyInto(Graph<T> g, Graph<T> into) {
|
||||
if (g == null) {
|
||||
throw new IllegalArgumentException("g is null");
|
||||
}
|
||||
for (Iterator<? extends T> it = g.iterator(); it.hasNext();) {
|
||||
into.addNode(it.next());
|
||||
}
|
||||
for (Iterator<? extends T> it = g.iterator(); it.hasNext();) {
|
||||
T n = it.next();
|
||||
for (Iterator<? extends T> it2 = g.getSuccNodes(n); it2.hasNext();) {
|
||||
into.addEdge(n, it2.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> SlowSparseNumberedGraph<T> make() {
|
||||
return new SlowSparseNumberedGraph<T>();
|
||||
}
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.graph.NumberedEdgeManager;
|
||||
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||
import com.ibm.wala.util.intset.BasicNaturalRelation;
|
||||
import com.ibm.wala.util.intset.BitVector;
|
||||
import com.ibm.wala.util.intset.IBinaryNaturalRelation;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetAction;
|
||||
|
||||
/**
|
||||
* An object which tracks edges for nodes that have numbers.
|
||||
*/
|
||||
public final class SparseNumberedEdgeManager<T> implements NumberedEdgeManager<T> {
|
||||
|
||||
private final NumberedNodeManager<T> nodeManager;
|
||||
|
||||
/**
|
||||
* cache this state here for efficiency
|
||||
*/
|
||||
private final BitVector hasSuccessor = new BitVector();
|
||||
|
||||
/**
|
||||
* @param nodeManager
|
||||
* an object to track nodes
|
||||
*/
|
||||
public SparseNumberedEdgeManager(NumberedNodeManager<T> nodeManager) {
|
||||
this(nodeManager, 0, BasicNaturalRelation.TWO_LEVEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* If normalOutCount == n, this edge manager will eagerly allocated n words to
|
||||
* hold out edges for each node. (performance optimization for time)
|
||||
*
|
||||
* @param nodeManager
|
||||
* an object to track nodes
|
||||
* @param normalCase
|
||||
* what is the "normal" number of out edges for a node?
|
||||
* @throws IllegalArgumentException if normalCase < 0
|
||||
*/
|
||||
public SparseNumberedEdgeManager(NumberedNodeManager<T> nodeManager, int normalCase, byte delegateImpl) throws IllegalArgumentException {
|
||||
if (nodeManager == null) {
|
||||
throw new IllegalArgumentException("null nodeManager");
|
||||
}
|
||||
if (normalCase < 0) {
|
||||
throw new IllegalArgumentException("normalCase < 0");
|
||||
}
|
||||
this.nodeManager = nodeManager;
|
||||
if (normalCase == 0) {
|
||||
successors = new BasicNaturalRelation(defaultImpl, delegateImpl);
|
||||
predecessors = new BasicNaturalRelation(defaultImpl, delegateImpl);
|
||||
} else {
|
||||
byte[] impl = new byte[normalCase];
|
||||
Arrays.fill(impl, BasicNaturalRelation.SIMPLE);
|
||||
successors = new BasicNaturalRelation(impl, delegateImpl);
|
||||
predecessors = new BasicNaturalRelation(impl, delegateImpl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation policy conservatively uses 2-level vectors, in
|
||||
* an attempt to somewhat optimize for space.
|
||||
*/
|
||||
private final static byte[] defaultImpl = new byte[] { BasicNaturalRelation.TWO_LEVEL };
|
||||
|
||||
private final IBinaryNaturalRelation successors;
|
||||
|
||||
private final IBinaryNaturalRelation predecessors;
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object)
|
||||
*/
|
||||
public Iterator<T> getPredNodes(T N) throws IllegalArgumentException {
|
||||
int number = nodeManager.getNumber(N);
|
||||
if (number < 0) {
|
||||
throw new IllegalArgumentException(N + " is not in graph");
|
||||
}
|
||||
IntSet s = predecessors.getRelated(number);
|
||||
Iterator<T> empty = EmptyIterator.instance();
|
||||
return (s == null) ? empty : nodeManager.iterateNodes(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object)
|
||||
*/
|
||||
public int getPredNodeCount(T N) throws IllegalArgumentException {
|
||||
int number = nodeManager.getNumber(N);
|
||||
if (number < 0) {
|
||||
throw new IllegalArgumentException(N + " is not in graph");
|
||||
}
|
||||
return predecessors.getRelatedCount(number);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object)
|
||||
*/
|
||||
public Iterator<T> getSuccNodes(T N) throws IllegalArgumentException {
|
||||
int number = nodeManager.getNumber(N);
|
||||
if (number == -1) {
|
||||
throw new IllegalArgumentException(N + " is not in graph");
|
||||
}
|
||||
IntSet s = successors.getRelated(number);
|
||||
Iterator<T> empty = EmptyIterator.instance();
|
||||
return (s == null) ? empty : nodeManager.iterateNodes(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object)
|
||||
*/
|
||||
public Iterator<T> getSuccNodes(int number) {
|
||||
IntSet s = successors.getRelated(number);
|
||||
Iterator<T> empty = EmptyIterator.instance();
|
||||
return (s == null) ? empty : nodeManager.iterateNodes(s);
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node) throws IllegalArgumentException {
|
||||
if (nodeManager.getNumber(node) < 0) {
|
||||
throw new IllegalArgumentException("Node not in graph " + node);
|
||||
}
|
||||
return successors.getRelated(nodeManager.getNumber(node));
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(T node) throws IllegalArgumentException {
|
||||
if (nodeManager.getNumber(node) < 0) {
|
||||
throw new IllegalArgumentException("Node not in graph " + node);
|
||||
}
|
||||
return predecessors.getRelated(nodeManager.getNumber(node));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object)
|
||||
*/
|
||||
public int getSuccNodeCount(T N) throws IllegalArgumentException {
|
||||
return getSuccNodeCount(nodeManager.getNumber(N));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object)
|
||||
*/
|
||||
public int getSuccNodeCount(int number) {
|
||||
return successors.getRelatedCount(number);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
public void addEdge(T src, T dst) throws IllegalArgumentException {
|
||||
int x = nodeManager.getNumber(src);
|
||||
int y = nodeManager.getNumber(dst);
|
||||
if (x < 0) {
|
||||
throw new IllegalArgumentException("src " + src + " is not in graph");
|
||||
}
|
||||
if (y < 0) {
|
||||
throw new IllegalArgumentException("dst " + dst + " is not in graph");
|
||||
}
|
||||
predecessors.add(y, x);
|
||||
successors.add(x, y);
|
||||
hasSuccessor.set(x);
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
int x = nodeManager.getNumber(src);
|
||||
int y = nodeManager.getNumber(dst);
|
||||
if (x < 0 || y < 0) {
|
||||
return false;
|
||||
}
|
||||
return successors.contains(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object)
|
||||
*/
|
||||
public void removeAllIncidentEdges(T node) throws IllegalArgumentException {
|
||||
final int number = nodeManager.getNumber(node);
|
||||
if (number < 0) {
|
||||
throw new IllegalArgumentException("node not in graph: " + node);
|
||||
}
|
||||
IntSet succ = successors.getRelated(number);
|
||||
if (succ != null) {
|
||||
succ.foreach(new IntSetAction() {
|
||||
public void act(int x) {
|
||||
predecessors.remove(x, number);
|
||||
}
|
||||
});
|
||||
}
|
||||
IntSet pred = predecessors.getRelated(number);
|
||||
if (pred != null) {
|
||||
pred.foreach(new IntSetAction() {
|
||||
public void act(int x) {
|
||||
successors.remove(x, number);
|
||||
if (successors.getRelatedCount(x) == 0) {
|
||||
hasSuccessor.clear(x);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
successors.removeAll(number);
|
||||
hasSuccessor.clear(number);
|
||||
predecessors.removeAll(number);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object)
|
||||
*/
|
||||
public void removeIncomingEdges(T node) throws IllegalArgumentException {
|
||||
final int number = nodeManager.getNumber(node);
|
||||
if (number < 0) {
|
||||
throw new IllegalArgumentException("node not in graph: " + node);
|
||||
}
|
||||
IntSet pred = predecessors.getRelated(number);
|
||||
if (pred != null) {
|
||||
pred.foreach(new IntSetAction() {
|
||||
public void act(int x) {
|
||||
successors.remove(x, number);
|
||||
if (successors.getRelatedCount(x) == 0) {
|
||||
hasSuccessor.clear(x);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
predecessors.removeAll(number);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) throws IllegalArgumentException {
|
||||
final int srcNumber = nodeManager.getNumber(src);
|
||||
final int dstNumber = nodeManager.getNumber(dst);
|
||||
if (srcNumber < 0) {
|
||||
throw new IllegalArgumentException("src not in graph: " + src);
|
||||
}
|
||||
if (dstNumber < 0) {
|
||||
throw new IllegalArgumentException("dst not in graph: " + dst);
|
||||
}
|
||||
successors.remove(srcNumber, dstNumber);
|
||||
if (successors.getRelatedCount(srcNumber) == 0) {
|
||||
hasSuccessor.clear(srcNumber);
|
||||
}
|
||||
predecessors.remove(dstNumber, srcNumber);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object)
|
||||
*/
|
||||
public void removeOutgoingEdges(T node) throws IllegalArgumentException {
|
||||
final int number = nodeManager.getNumber(node);
|
||||
if (number < 0) {
|
||||
throw new IllegalArgumentException("node not in graph: " + node);
|
||||
}
|
||||
IntSet succ = successors.getRelated(number);
|
||||
if (succ != null) {
|
||||
succ.foreach(new IntSetAction() {
|
||||
public void act(int x) {
|
||||
predecessors.remove(x, number);
|
||||
}
|
||||
});
|
||||
}
|
||||
successors.removeAll(number);
|
||||
hasSuccessor.clear(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is implemented as a shortcut for efficiency
|
||||
*
|
||||
* @return true iff that node has any successors
|
||||
*/
|
||||
public boolean hasAnySuccessor(int node) {
|
||||
return hasSuccessor.get(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Successors relation:\n" + successors;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.impl;
|
||||
|
||||
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
import com.ibm.wala.util.graph.INodeWithNumber;
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
import com.ibm.wala.util.intset.BasicNaturalRelation;
|
||||
|
||||
/**
|
||||
* A graph of numbered nodes, expected to have a fairly sparse edge structure.
|
||||
*/
|
||||
public class SparseNumberedGraph<T extends INodeWithNumber> extends AbstractNumberedGraph<T> {
|
||||
|
||||
private final DelegatingNumberedNodeManager<T> nodeManager;
|
||||
|
||||
private final SparseNumberedEdgeManager<T> edgeManager;
|
||||
|
||||
public SparseNumberedGraph() {
|
||||
nodeManager = new DelegatingNumberedNodeManager<T>();
|
||||
edgeManager = new SparseNumberedEdgeManager<T>(nodeManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* If normalCase == n, the s edge manager will eagerly allocated n words to hold out edges for each node. (performance
|
||||
* optimization for time)
|
||||
*
|
||||
* @param normalCase what is the "normal" number of out edges for a node?
|
||||
*/
|
||||
public SparseNumberedGraph(int normalCase) {
|
||||
nodeManager = new DelegatingNumberedNodeManager<T>();
|
||||
edgeManager = new SparseNumberedEdgeManager<T>(nodeManager, normalCase, BasicNaturalRelation.TWO_LEVEL);
|
||||
}
|
||||
|
||||
public SparseNumberedGraph(DelegatingNumberedNodeManager<T> nodeManager, SparseNumberedEdgeManager<T> edgeManager) {
|
||||
this.nodeManager = nodeManager;
|
||||
this.edgeManager = edgeManager;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager()
|
||||
*/
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return nodeManager;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager()
|
||||
*/
|
||||
@Override
|
||||
protected EdgeManager<T> getEdgeManager() {
|
||||
return edgeManager;
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<HTML>
|
||||
<BODY>
|
||||
Graph implementations
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -1,104 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Manu Sridharan and Juergen Graf
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Manu Sridharan
|
||||
* Juergen Graf
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html.
|
||||
*
|
||||
* This file is a derivative of code released by the University of
|
||||
* California under the terms listed below.
|
||||
*
|
||||
* Refinement Analysis Tools is Copyright (c) 2007 The Regents of the
|
||||
* University of California (Regents). Provided that this notice and
|
||||
* the following two paragraphs are included in any distribution of
|
||||
* Refinement Analysis Tools or its derivative work, Regents agrees
|
||||
* not to assert any of Regents' copyright rights in Refinement
|
||||
* Analysis Tools against recipient for recipient's reproduction,
|
||||
* preparation of derivative works, public display, public
|
||||
* performance, distribution or sublicensing of Refinement Analysis
|
||||
* Tools and derivative works, in source code and object code form.
|
||||
* This agreement not to assert does not confer, by implication,
|
||||
* estoppel, or otherwise any license or rights in any intellectual
|
||||
* property of Regents, including, but not limited to, any patents
|
||||
* of Regents or Regents' employees.
|
||||
*
|
||||
* IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
|
||||
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
* INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
|
||||
* AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
|
||||
* WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
|
||||
* DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
|
||||
* IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
|
||||
* UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
package com.ibm.wala.util.graph.labeled;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.graph.AbstractGraph;
|
||||
|
||||
public abstract class AbstractLabeledGraph<T, U> extends AbstractGraph<T> implements LabeledGraph<T, U> {
|
||||
|
||||
/**
|
||||
* @return the object which manages edges in the graph
|
||||
*/
|
||||
@Override
|
||||
protected abstract LabeledEdgeManager<T, U> getEdgeManager();
|
||||
|
||||
public void addEdge(T src, T dst, U label) {
|
||||
getEdgeManager().addEdge(src, dst, label);
|
||||
}
|
||||
|
||||
public Iterator<? extends U> getPredLabels(T N) {
|
||||
return getEdgeManager().getPredLabels(N);
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N, U label) {
|
||||
return getEdgeManager().getPredNodeCount(N, label);
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N, U label) {
|
||||
return getEdgeManager().getPredNodes(N, label);
|
||||
}
|
||||
|
||||
public Iterator<? extends U> getSuccLabels(T N) {
|
||||
return getEdgeManager().getSuccLabels(N);
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N, U label) {
|
||||
return getEdgeManager().getSuccNodeCount(N, label);
|
||||
}
|
||||
|
||||
public Iterator<? extends T> getSuccNodes(T N, U label) {
|
||||
return getEdgeManager().getSuccNodes(N, label);
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst, U label) {
|
||||
return getEdgeManager().hasEdge(src, dst, label);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst, U label) {
|
||||
getEdgeManager().removeEdge(src, dst, label);
|
||||
}
|
||||
|
||||
public Set<? extends U> getEdgeLabels(T src, T dst) {
|
||||
return getEdgeManager().getEdgeLabels(src, dst);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Juergen Graf
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Juergen Graf
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.labeled;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
public abstract class AbstractNumberedLabeledGraph<T, U> extends AbstractNumberedGraph<T> implements LabeledGraph<T, U> {
|
||||
|
||||
/**
|
||||
* @return the object which manages edges in the graph
|
||||
*/
|
||||
@Override
|
||||
protected abstract NumberedLabeledEdgeManager<T, U> getEdgeManager();
|
||||
|
||||
public void addEdge(T src, T dst, U label) {
|
||||
getEdgeManager().addEdge(src, dst, label);
|
||||
}
|
||||
|
||||
public Iterator<? extends U> getPredLabels(T N) {
|
||||
return getEdgeManager().getPredLabels(N);
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N, U label) {
|
||||
return getEdgeManager().getPredNodeCount(N, label);
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N, U label) {
|
||||
return getEdgeManager().getPredNodes(N, label);
|
||||
}
|
||||
|
||||
public Iterator<? extends U> getSuccLabels(T N) {
|
||||
return getEdgeManager().getSuccLabels(N);
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N, U label) {
|
||||
return getEdgeManager().getSuccNodeCount(N, label);
|
||||
}
|
||||
|
||||
public Iterator<? extends T> getSuccNodes(T N, U label) {
|
||||
return getEdgeManager().getSuccNodes(N, label);
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(T node, U label) throws IllegalArgumentException {
|
||||
return getEdgeManager().getPredNodeNumbers(node, label);
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node, U label) throws IllegalArgumentException {
|
||||
return getEdgeManager().getSuccNodeNumbers(node, label);
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst, U label) {
|
||||
return getEdgeManager().hasEdge(src, dst, label);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst, U label) {
|
||||
getEdgeManager().removeEdge(src, dst, label);
|
||||
}
|
||||
|
||||
public Set<? extends U> getEdgeLabels(T src, T dst) {
|
||||
return getEdgeManager().getEdgeLabels(src, dst);
|
||||
}
|
||||
|
||||
public U getDefaultLabel() {
|
||||
return getEdgeManager().getDefaultLabel();
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Manu Sridharan and Juergen Graf
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Manu Sridharan
|
||||
* Juergen Graf
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html.
|
||||
*
|
||||
* This file is a derivative of code released by the University of
|
||||
* California under the terms listed below.
|
||||
*
|
||||
* Refinement Analysis Tools is Copyright (c) 2007 The Regents of the
|
||||
* University of California (Regents). Provided that this notice and
|
||||
* the following two paragraphs are included in any distribution of
|
||||
* Refinement Analysis Tools or its derivative work, Regents agrees
|
||||
* not to assert any of Regents' copyright rights in Refinement
|
||||
* Analysis Tools against recipient for recipient's reproduction,
|
||||
* preparation of derivative works, public display, public
|
||||
* performance, distribution or sublicensing of Refinement Analysis
|
||||
* Tools and derivative works, in source code and object code form.
|
||||
* This agreement not to assert does not confer, by implication,
|
||||
* estoppel, or otherwise any license or rights in any intellectual
|
||||
* property of Regents, including, but not limited to, any patents
|
||||
* of Regents or Regents' employees.
|
||||
*
|
||||
* IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
|
||||
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
* INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
|
||||
* AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
|
||||
* WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
|
||||
* DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
|
||||
* IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
|
||||
* UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
package com.ibm.wala.util.graph.labeled;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.graph.EdgeManager;
|
||||
|
||||
/**
|
||||
* An object which tracks labeled edges in a graph.
|
||||
*
|
||||
* @param <T> type of nodes in this graph
|
||||
* @param <U> types of edge labels.
|
||||
*/
|
||||
public interface LabeledEdgeManager<T, U> extends EdgeManager<T> {
|
||||
|
||||
/**
|
||||
* Sets the default object used as label for operations where no specific edge label is provided. This is due to compatibility
|
||||
* with the EdgeManager interface
|
||||
*/
|
||||
public U getDefaultLabel();
|
||||
|
||||
/**
|
||||
* Return an Iterator over the immediate predecessor nodes of this Node in the Graph on edges with some label.
|
||||
*
|
||||
* This method never returns <code>null</code>.
|
||||
*
|
||||
* @return an Iterator over the immediate predecessor nodes of this Node.
|
||||
*/
|
||||
public Iterator<T> getPredNodes(T N, U label);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param N
|
||||
* @return the labels on edges whose destination is N
|
||||
*/
|
||||
public Iterator<? extends U> getPredLabels(T N);
|
||||
|
||||
/**
|
||||
* Return the number of {@link #getPredNodes immediate predecessor} nodes of this Node in the Graph on edges with some label.
|
||||
*
|
||||
* @return the number of immediate predecessor Nodes of this Node in the Graph.
|
||||
*/
|
||||
public int getPredNodeCount(T N, U label);
|
||||
|
||||
/**
|
||||
* Return an Iterator over the immediate successor nodes of this Node in the Graph on edges with some label.
|
||||
* <p>
|
||||
* This method never returns <code>null</code>.
|
||||
*
|
||||
* @return an Iterator over the immediate successor Nodes of this Node.
|
||||
*/
|
||||
public Iterator<? extends T> getSuccNodes(T N, U label);
|
||||
|
||||
/**
|
||||
* @return the labels on edges whose source is N
|
||||
*/
|
||||
public Iterator<? extends U> getSuccLabels(T N);
|
||||
|
||||
/**
|
||||
* Return the number of {@link #getSuccNodes immediate successor} nodes of this Node in the Graph
|
||||
*
|
||||
* @return the number of immediate successor Nodes of this Node in the Graph.
|
||||
*/
|
||||
public int getSuccNodeCount(T N, U label);
|
||||
|
||||
/**
|
||||
* adds an edge with some label
|
||||
*/
|
||||
public void addEdge(T src, T dst, U label);
|
||||
|
||||
public void removeEdge(T src, T dst, U label) throws UnsupportedOperationException;
|
||||
|
||||
public boolean hasEdge(T src, T dst, U label);
|
||||
|
||||
/**
|
||||
* Returns a set of all labeled edges between node src and node dst
|
||||
*
|
||||
* @param src source node of the edge
|
||||
* @param dst target node of the edge
|
||||
* @return Set of edge labels
|
||||
*/
|
||||
public Set<? extends U> getEdgeLabels(T src, T dst);
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Manu Sridharan and Juergen Graf
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Manu Sridharan
|
||||
* Juergen Graf
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html.
|
||||
*
|
||||
* This file is a derivative of code released by the University of
|
||||
* California under the terms listed below.
|
||||
*
|
||||
* Refinement Analysis Tools is Copyright (c) 2007 The Regents of the
|
||||
* University of California (Regents). Provided that this notice and
|
||||
* the following two paragraphs are included in any distribution of
|
||||
* Refinement Analysis Tools or its derivative work, Regents agrees
|
||||
* not to assert any of Regents' copyright rights in Refinement
|
||||
* Analysis Tools against recipient for recipient's reproduction,
|
||||
* preparation of derivative works, public display, public
|
||||
* performance, distribution or sublicensing of Refinement Analysis
|
||||
* Tools and derivative works, in source code and object code form.
|
||||
* This agreement not to assert does not confer, by implication,
|
||||
* estoppel, or otherwise any license or rights in any intellectual
|
||||
* property of Regents, including, but not limited to, any patents
|
||||
* of Regents or Regents' employees.
|
||||
*
|
||||
* IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
|
||||
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
* INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
|
||||
* AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
|
||||
* WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
|
||||
* DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
|
||||
* IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
|
||||
* UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
package com.ibm.wala.util.graph.labeled;
|
||||
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* A graph with labeled edges.
|
||||
*/
|
||||
public interface LabeledGraph<T, U> extends Graph<T>, LabeledEdgeManager<T, U> {
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.labeled;
|
||||
|
||||
import com.ibm.wala.util.graph.NumberedEdgeManager;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
public interface NumberedLabeledEdgeManager<T, U> extends LabeledEdgeManager<T, U>, NumberedEdgeManager<T> {
|
||||
|
||||
public IntSet getPredNodeNumbers(T node, U label) throws IllegalArgumentException;
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node, U label) throws IllegalArgumentException;
|
||||
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Manu Sridharan and Juergen Graf
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Manu Sridharan
|
||||
* Juergen Graf
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html.
|
||||
*
|
||||
* This file is a derivative of code released by the University of
|
||||
* California under the terms listed below.
|
||||
*
|
||||
* Refinement Analysis Tools is Copyright (c) 2007 The Regents of the
|
||||
* University of California (Regents). Provided that this notice and
|
||||
* the following two paragraphs are included in any distribution of
|
||||
* Refinement Analysis Tools or its derivative work, Regents agrees
|
||||
* not to assert any of Regents' copyright rights in Refinement
|
||||
* Analysis Tools against recipient for recipient's reproduction,
|
||||
* preparation of derivative works, public display, public
|
||||
* performance, distribution or sublicensing of Refinement Analysis
|
||||
* Tools and derivative works, in source code and object code form.
|
||||
* This agreement not to assert does not confer, by implication,
|
||||
* estoppel, or otherwise any license or rights in any intellectual
|
||||
* property of Regents, including, but not limited to, any patents
|
||||
* of Regents or Regents' employees.
|
||||
*
|
||||
* IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
|
||||
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
* INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
|
||||
* AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
|
||||
* WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
|
||||
* DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
|
||||
* IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
|
||||
* UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
package com.ibm.wala.util.graph.labeled;
|
||||
|
||||
import com.ibm.wala.util.graph.NodeManager;
|
||||
import com.ibm.wala.util.graph.impl.SlowNumberedNodeManager;
|
||||
|
||||
/**
|
||||
* A labeled graph implementation suitable for sparse graphs.
|
||||
*/
|
||||
public class SlowSparseNumberedLabeledGraph<T, U> extends AbstractNumberedLabeledGraph<T, U> {
|
||||
|
||||
private final SlowNumberedNodeManager<T> nodeManager;
|
||||
|
||||
private final SparseNumberedLabeledEdgeManager<T, U> edgeManager;
|
||||
|
||||
public SlowSparseNumberedLabeledGraph(U defaultLabel) {
|
||||
if (defaultLabel == null) {
|
||||
throw new IllegalArgumentException("null default label");
|
||||
}
|
||||
nodeManager = new SlowNumberedNodeManager<T>();
|
||||
edgeManager = new SparseNumberedLabeledEdgeManager<T, U>(nodeManager, defaultLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NumberedLabeledEdgeManager<T, U> getEdgeManager() {
|
||||
return edgeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeManager<T> getNodeManager() {
|
||||
return nodeManager;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,292 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Manu Sridharan and Juergen Graf
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Manu Sridharan
|
||||
* Juergen Graf
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html.
|
||||
*
|
||||
* This file is a derivative of code released by the University of
|
||||
* California under the terms listed below.
|
||||
*
|
||||
* Refinement Analysis Tools is Copyright (c) 2007 The Regents of the
|
||||
* University of California (Regents). Provided that this notice and
|
||||
* the following two paragraphs are included in any distribution of
|
||||
* Refinement Analysis Tools or its derivative work, Regents agrees
|
||||
* not to assert any of Regents' copyright rights in Refinement
|
||||
* Analysis Tools against recipient for recipient's reproduction,
|
||||
* preparation of derivative works, public display, public
|
||||
* performance, distribution or sublicensing of Refinement Analysis
|
||||
* Tools and derivative works, in source code and object code form.
|
||||
* This agreement not to assert does not confer, by implication,
|
||||
* estoppel, or otherwise any license or rights in any intellectual
|
||||
* property of Regents, including, but not limited to, any patents
|
||||
* of Regents or Regents' employees.
|
||||
*
|
||||
* IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
|
||||
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
* INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
|
||||
* AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
|
||||
* WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
|
||||
* DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
|
||||
* IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
|
||||
* UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
package com.ibm.wala.util.graph.labeled;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.collections.ArraySetMultiMap;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Iterator2Collection;
|
||||
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||
import com.ibm.wala.util.graph.impl.SparseNumberedEdgeManager;
|
||||
import com.ibm.wala.util.intset.BitVectorIntSet;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SparseNumberedLabeledEdgeManager<T, U> implements NumberedLabeledEdgeManager<T, U> {
|
||||
|
||||
/**
|
||||
* the label to be attached to an edge when no label is specified
|
||||
*/
|
||||
private final U defaultLabel;
|
||||
|
||||
private final NumberedNodeManager<T> nodeManager;
|
||||
|
||||
/**
|
||||
* maps each edge label to its own {@link SparseNumberedEdgeManager}
|
||||
*/
|
||||
private final Map<U, SparseNumberedEdgeManager<T>> edgeLabelToManager = HashMapFactory.make();
|
||||
|
||||
private final ArraySetMultiMap<T, U> nodeToPredLabels = new ArraySetMultiMap<T, U>();
|
||||
|
||||
private final ArraySetMultiMap<T, U> nodeToSuccLabels = new ArraySetMultiMap<T, U>();
|
||||
|
||||
private SparseNumberedEdgeManager<T> getManagerForLabel(U label) {
|
||||
SparseNumberedEdgeManager<T> ret = edgeLabelToManager.get(label);
|
||||
if (ret == null) {
|
||||
ret = new SparseNumberedEdgeManager<T>(nodeManager);
|
||||
edgeLabelToManager.put(label, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#addEdge(java.lang.Object, java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
public void addEdge(T src, T dst, U label) {
|
||||
nodeToSuccLabels.put(src, label);
|
||||
nodeToPredLabels.put(dst, label);
|
||||
getManagerForLabel(label).addEdge(src, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#getPredNodeCount(java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
public int getPredNodeCount(T N, U label) {
|
||||
return getManagerForLabel(label).getPredNodeCount(N);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#getPredNodes(java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
public Iterator<T> getPredNodes(T N, U label) {
|
||||
return getManagerForLabel(label).getPredNodes(N);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#getSuccNodeCount(java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
public int getSuccNodeCount(T N, U label) {
|
||||
return getManagerForLabel(label).getSuccNodeCount(N);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#getSuccNodes(java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
public Iterator<? extends T> getSuccNodes(T N, U label) {
|
||||
return getManagerForLabel(label).getSuccNodes(N);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#hasEdge(java.lang.Object, java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
public boolean hasEdge(T src, T dst, U label) {
|
||||
return getManagerForLabel(label).hasEdge(src, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see util.LabelledEdgeManager#removeAllIncidentEdges(java.lang.Object)
|
||||
*/
|
||||
public void removeAllIncidentEdges(T node) {
|
||||
removeIncomingEdges(node);
|
||||
removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#removeEdge(java.lang.Object,
|
||||
* java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public void removeEdge(T src, T dst, U label) throws IllegalArgumentException {
|
||||
getManagerForLabel(label).removeEdge(src, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#removeIncomingEdges(java.lang.Object)
|
||||
*/
|
||||
public void removeIncomingEdges(T node) throws IllegalArgumentException {
|
||||
for (Iterator<U> inLabelIter = nodeToPredLabels.get(node).iterator(); inLabelIter.hasNext();) {
|
||||
U label = inLabelIter.next();
|
||||
getManagerForLabel(label).removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* @see util.LabelledEdgeManager#removeOutgoingEdges(java.lang.Object)
|
||||
*/
|
||||
public void removeOutgoingEdges(T node) throws IllegalArgumentException {
|
||||
for (Iterator<U> outLabelIter = nodeToSuccLabels.get(node).iterator(); outLabelIter.hasNext();) {
|
||||
U label = outLabelIter.next();
|
||||
getManagerForLabel(label).removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SparseNumberedLabeledEdgeManager(final NumberedNodeManager<T> nodeManager, U defaultLabel) {
|
||||
super();
|
||||
this.defaultLabel = defaultLabel;
|
||||
this.nodeManager = nodeManager;
|
||||
if (defaultLabel == null) {
|
||||
throw new IllegalArgumentException("null default label");
|
||||
}
|
||||
if (nodeManager == null) {
|
||||
throw new IllegalArgumentException("null nodeManager");
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<? extends U> getPredLabels(T N) {
|
||||
return nodeToPredLabels.get(N).iterator();
|
||||
}
|
||||
|
||||
public Iterator<? extends U> getSuccLabels(T N) {
|
||||
return nodeToSuccLabels.get(N).iterator();
|
||||
}
|
||||
|
||||
public Set<? extends U> getEdgeLabels(T src, T dst) {
|
||||
Set<U> labels = HashSetFactory.make();
|
||||
|
||||
for (U key : edgeLabelToManager.keySet()) {
|
||||
if (edgeLabelToManager.get(key).hasEdge(src, dst)) {
|
||||
labels.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void addEdge(T src, T dst) {
|
||||
addEdge(src, dst, defaultLabel);
|
||||
}
|
||||
|
||||
public int getPredNodeCount(T N) {
|
||||
int count = 0;
|
||||
for (U label : nodeToPredLabels.get(N)) {
|
||||
count += getPredNodeCount(N, label);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public Iterator<T> getPredNodes(T N) {
|
||||
Collection<T> preds = HashSetFactory.make();
|
||||
for (U label : nodeToPredLabels.get(N)) {
|
||||
preds.addAll(Iterator2Collection.toSet(getPredNodes(N, label)));
|
||||
}
|
||||
return preds.iterator();
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(T N) {
|
||||
int count = 0;
|
||||
for (U label : nodeToSuccLabels.get(N)) {
|
||||
count += getSuccNodeCount(N, label);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public Iterator<T> getSuccNodes(T N) {
|
||||
Collection<T> succs = HashSetFactory.make();
|
||||
for (U label : nodeToSuccLabels.get(N)) {
|
||||
succs.addAll(Iterator2Collection.toSet(getSuccNodes(N, label)));
|
||||
}
|
||||
return succs.iterator();
|
||||
}
|
||||
|
||||
public boolean hasEdge(T src, T dst) {
|
||||
return hasEdge(src, dst, defaultLabel);
|
||||
}
|
||||
|
||||
public void removeEdge(T src, T dst) throws UnsupportedOperationException {
|
||||
removeEdge(src, dst, defaultLabel);
|
||||
}
|
||||
|
||||
public U getDefaultLabel() {
|
||||
return defaultLabel;
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(T node, U label) throws IllegalArgumentException {
|
||||
return getManagerForLabel(label).getPredNodeNumbers(node);
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node, U label) throws IllegalArgumentException {
|
||||
return getManagerForLabel(label).getSuccNodeNumbers(node);
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(T node) {
|
||||
BitVectorIntSet preds = new BitVectorIntSet();
|
||||
|
||||
for (U label : nodeToPredLabels.get(node)) {
|
||||
preds.addAll(getPredNodeNumbers(node, label));
|
||||
}
|
||||
|
||||
return preds;
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(T node) {
|
||||
BitVectorIntSet succs = new BitVectorIntSet();
|
||||
|
||||
for (U label : nodeToSuccLabels.get(node)) {
|
||||
succs.addAll(getSuccNodeNumbers(node, label));
|
||||
}
|
||||
|
||||
return succs;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<HTML>
|
||||
<BODY>
|
||||
Graph interfaces
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -1,161 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* This class implements breadth-first search over a Graph, returning an Iterator of the nodes of the graph in order of discovery.
|
||||
* This class follows the outNodes of the graph nodes to define the graph, but this behavior can be changed by overriding the
|
||||
* getConnected method.
|
||||
*/
|
||||
public class BFSIterator<T> implements Iterator<T> {
|
||||
|
||||
/**
|
||||
* List of nodes as discovered
|
||||
*/
|
||||
final ArrayList<T> Q = new ArrayList<T>();
|
||||
|
||||
/**
|
||||
* Set of nodes that have been visited
|
||||
*/
|
||||
final HashSet<T> visited = HashSetFactory.make();
|
||||
|
||||
/**
|
||||
* index of the node currently being searched
|
||||
*/
|
||||
private int index = 0;
|
||||
|
||||
/**
|
||||
* Governing Graph
|
||||
*/
|
||||
protected Graph<T> G;
|
||||
|
||||
/**
|
||||
* Construct a breadth-first iterator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
public BFSIterator(Graph<T> G, T N) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
init(G, new NonNullSingletonIterator<T>(N));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a breadth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
public BFSIterator(Graph<T> G, Iterator<? extends T> nodes) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (nodes == null) {
|
||||
throw new IllegalArgumentException("nodes is null");
|
||||
}
|
||||
init(G, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor DFSFinishTimeIterator.
|
||||
*
|
||||
* @param G
|
||||
* @throws NullPointerException if G is null
|
||||
*/
|
||||
public BFSIterator(Graph<T> G) throws NullPointerException {
|
||||
this(G, G == null ? null : G.iterator());
|
||||
}
|
||||
|
||||
private void init(Graph<T> G, Iterator<? extends T> nodes) {
|
||||
this.G = G;
|
||||
|
||||
while (nodes.hasNext()) {
|
||||
T o = nodes.next();
|
||||
if (!visited.contains(o)) {
|
||||
Q.add(o);
|
||||
visited.add(o);
|
||||
}
|
||||
}
|
||||
index = 0;
|
||||
if (Q.size() > 0) {
|
||||
T current = Q.get(0);
|
||||
visitChildren(current);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitChildren(T N) {
|
||||
for (Iterator<? extends T> children = getConnected(N); children.hasNext();) {
|
||||
T child = children.next();
|
||||
if (!visited.contains(child)) {
|
||||
Q.add(child);
|
||||
visited.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether there are any more nodes left to enumerate.
|
||||
*
|
||||
* @return true if there nodes left to enumerate.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return (Q.size() > index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next graph node in discover time order.
|
||||
*
|
||||
* @return the next graph node in discover time order.
|
||||
*/
|
||||
public T next() throws NoSuchElementException {
|
||||
if (index >= Q.size()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
T result = Q.get(index);
|
||||
index++;
|
||||
if (hasNext()) {
|
||||
T N = Q.get(index);
|
||||
visitChildren(N);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the out edges of a given node
|
||||
*
|
||||
* @param n the node of which to get the out edges
|
||||
* @return the out edges
|
||||
*
|
||||
*/
|
||||
protected Iterator<? extends T> getConnected(T n) {
|
||||
return G.getSuccNodes(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.util.Iterator#remove()
|
||||
*/
|
||||
public void remove() throws UnimplementedError {
|
||||
throw new UnimplementedError();
|
||||
}
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.collections.Filter;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* This class searches breadth-first for node that matches some criteria. If found, it reports a path to the first node found.
|
||||
*
|
||||
* This class follows the outNodes of the graph nodes to define the graph, but this behavior can be changed by overriding the
|
||||
* getConnected method.
|
||||
*
|
||||
* TODO: if finding many paths, use a dynamic programming algorithm instead of calling this repeatedly.
|
||||
*/
|
||||
public class BFSPathFinder<T> {
|
||||
|
||||
private final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* The graph to search
|
||||
*/
|
||||
final private Graph<T> G;
|
||||
|
||||
/**
|
||||
* The Filter which defines the target set of nodes to find
|
||||
*/
|
||||
final private Filter<T> filter;
|
||||
|
||||
/**
|
||||
* an enumeration of all nodes to search from
|
||||
*/
|
||||
final private Iterator<T> roots;
|
||||
|
||||
/**
|
||||
* Construct a breadth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
*/
|
||||
public BFSPathFinder(Graph<T> G, T N, Filter<T> f) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (f == null) {
|
||||
throw new IllegalArgumentException("null f");
|
||||
}
|
||||
this.G = G;
|
||||
this.roots = new NonNullSingletonIterator<T>(N);
|
||||
this.filter = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a breadth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
public BFSPathFinder(Graph<T> G, T src, final T target) throws IllegalArgumentException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
this.G = G;
|
||||
this.roots = new NonNullSingletonIterator<T>(src);
|
||||
if (!G.containsNode(src)) {
|
||||
throw new IllegalArgumentException("src is not in graph " + src);
|
||||
}
|
||||
this.filter = new Filter<T>() {
|
||||
public boolean accepts(T o) {
|
||||
return target.equals(o);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a breadth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
*/
|
||||
public BFSPathFinder(Graph<T> G, T src, Iterator<T> targets) {
|
||||
if (targets == null) {
|
||||
throw new IllegalArgumentException("targets is null");
|
||||
}
|
||||
final Set<T> ts = HashSetFactory.make();
|
||||
while (targets.hasNext()) {
|
||||
ts.add(targets.next());
|
||||
}
|
||||
|
||||
this.G = G;
|
||||
this.roots = new NonNullSingletonIterator<T>(src);
|
||||
|
||||
this.filter = new Filter<T>() {
|
||||
public boolean accepts(T o) {
|
||||
return ts.contains(o);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a breadth-first enumerator starting with any of a set of nodes in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
*/
|
||||
public BFSPathFinder(Graph<T> G, Iterator<T> sources, final T target) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (sources == null) {
|
||||
throw new IllegalArgumentException("sources is null");
|
||||
}
|
||||
this.G = G;
|
||||
this.roots = sources;
|
||||
this.filter = new Filter<T>() {
|
||||
public boolean accepts(T o) {
|
||||
return target.equals(o);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a breadth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
*/
|
||||
public BFSPathFinder(Graph<T> G, Iterator<T> nodes, Filter<T> f) {
|
||||
this.G = G;
|
||||
this.roots = nodes;
|
||||
this.filter = f;
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (roots == null) {
|
||||
throw new IllegalArgumentException("roots is null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a List of nodes that specifies the first path found from a root to a node accepted by the filter. Returns null if no
|
||||
* path found.
|
||||
*/
|
||||
public List<T> find() {
|
||||
|
||||
LinkedList<T> Q = new LinkedList<T>();
|
||||
HashMap<Object, T> history = HashMapFactory.make();
|
||||
while (roots.hasNext()) {
|
||||
T next = roots.next();
|
||||
Q.addLast(next);
|
||||
history.put(next, null);
|
||||
}
|
||||
while (!Q.isEmpty()) {
|
||||
T N = Q.removeFirst();
|
||||
if (DEBUG) {
|
||||
System.err.println(("visit " + N));
|
||||
}
|
||||
if (filter.accepts(N)) {
|
||||
return makePath(N, history);
|
||||
}
|
||||
Iterator<? extends T> children = getConnected(N);
|
||||
while (children.hasNext()) {
|
||||
T c = children.next();
|
||||
if (!history.containsKey(c)) {
|
||||
Q.addLast(c);
|
||||
history.put(c, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a List which represents a path in the breadth-first search to Q[i]. Q holds the nodes visited during the BFS, in order.
|
||||
*/
|
||||
private List<T> makePath(T node, Map<Object, T> history) {
|
||||
ArrayList<T> result = new ArrayList<T>();
|
||||
T n = node;
|
||||
result.add(n);
|
||||
while (true) {
|
||||
T parent = history.get(n);
|
||||
if (parent == null)
|
||||
return result;
|
||||
else {
|
||||
result.add(parent);
|
||||
n = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the out edges of a given node
|
||||
*
|
||||
* @param n the node of which to get the out edges
|
||||
* @return the out edges
|
||||
*
|
||||
*/
|
||||
protected Iterator<? extends T> getConnected(T n) {
|
||||
return G.getSuccNodes(n);
|
||||
}
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* This class implements breadth-first search over a Graph, returning an Iterator of the nodes of the graph in order of discovery.
|
||||
* This class follows the outNodes of the graph nodes to define the graph, but this behavior can be changed by overriding the
|
||||
* getConnected method.
|
||||
*
|
||||
* This traversal only visits nodes within k hops of a root.
|
||||
*/
|
||||
public class BoundedBFSIterator<T> implements Iterator<T> {
|
||||
|
||||
/**
|
||||
* List of nodes as discovered
|
||||
*/
|
||||
final ArrayList<T> Q = new ArrayList<T>();
|
||||
|
||||
/**
|
||||
* Set of nodes that have been visited
|
||||
*/
|
||||
final HashSet<T> visited = HashSetFactory.make();
|
||||
|
||||
/**
|
||||
* index of the node currently being searched
|
||||
*/
|
||||
private int index = 0;
|
||||
|
||||
/**
|
||||
* Governing Graph
|
||||
*/
|
||||
protected Graph<T> G;
|
||||
|
||||
/**
|
||||
* limit on number of hops
|
||||
*/
|
||||
private final int k;
|
||||
|
||||
/**
|
||||
* boundary[i] is the first index which represents a child that is > i hops away.
|
||||
*/
|
||||
private final int[] boundary;
|
||||
|
||||
/**
|
||||
* how many hops away is the next element.
|
||||
*/
|
||||
private int currentHops = 0;
|
||||
|
||||
/**
|
||||
* Construct a breadth-first iterator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
public BoundedBFSIterator(Graph<T> G, T N, int k) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (k < 0) {
|
||||
throw new IllegalArgumentException("invalid k : " + k);
|
||||
}
|
||||
this.k = k;
|
||||
boundary = new int[k];
|
||||
init(G, new NonNullSingletonIterator<T>(N));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a breadth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
public BoundedBFSIterator(Graph<T> G, Iterator<? extends T> nodes, int k) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (k < 0) {
|
||||
throw new IllegalArgumentException("invalid k: " + k);
|
||||
}
|
||||
this.k = k;
|
||||
boundary = new int[k];
|
||||
init(G, nodes);
|
||||
}
|
||||
|
||||
private void init(Graph<T> G, Iterator<? extends T> nodes) {
|
||||
this.G = G;
|
||||
if (G.getNumberOfNodes() == 0) {
|
||||
return;
|
||||
}
|
||||
while (nodes.hasNext()) {
|
||||
T o = nodes.next();
|
||||
if (!visited.contains(o)) {
|
||||
Q.add(o);
|
||||
visited.add(o);
|
||||
}
|
||||
}
|
||||
index = 0;
|
||||
if (Q.size() > 0) {
|
||||
T current = Q.get(0);
|
||||
visitChildren(current);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitChildren(T N) {
|
||||
if (currentHops == k) {
|
||||
return;
|
||||
}
|
||||
if (boundary[currentHops] == 0) {
|
||||
boundary[currentHops] = Q.size();
|
||||
}
|
||||
for (Iterator<? extends T> children = getConnected(N); children.hasNext();) {
|
||||
T child = children.next();
|
||||
if (!visited.contains(child)) {
|
||||
Q.add(child);
|
||||
visited.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether there are any more nodes left to enumerate.
|
||||
*
|
||||
* @return true if there nodes left to enumerate.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return (Q.size() > index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next graph node in discover time order.
|
||||
*
|
||||
* @return the next graph node in discover time order.
|
||||
*/
|
||||
public T next() throws NoSuchElementException {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
T result = Q.get(index);
|
||||
index++;
|
||||
if (currentHops < k && index == boundary[currentHops]) {
|
||||
currentHops++;
|
||||
}
|
||||
if (hasNext()) {
|
||||
T N = Q.get(index);
|
||||
visitChildren(N);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the out edges of a given node
|
||||
*
|
||||
* @param n the node of which to get the out edges
|
||||
* @return the out edges
|
||||
*
|
||||
*/
|
||||
protected Iterator<? extends T> getConnected(T n) {
|
||||
return G.getSuccNodes(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.util.Iterator#remove()
|
||||
*/
|
||||
public void remove() throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currentHops
|
||||
*/
|
||||
public int getCurrentHops() {
|
||||
return currentHops;
|
||||
}
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.ibm.wala.util.collections.Filter;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Iterator2Collection;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
|
||||
/**
|
||||
* utilities related to depth-first search.
|
||||
*/
|
||||
public class DFS {
|
||||
|
||||
/**
|
||||
* Perform a DFS starting with a particular node and return the set of all nodes visited.
|
||||
*
|
||||
* @param C collection of nodes to start from
|
||||
* @param filter only traverse nodes that need this filter
|
||||
* @throws IllegalArgumentException if C is null
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static <T> Collection<T> getReachableNodes(final Graph<T> G, Collection<? extends T> C, final Filter filter) {
|
||||
if (C == null) {
|
||||
throw new IllegalArgumentException("C is null");
|
||||
}
|
||||
Iterator<T> dfs = new SlowDFSFinishTimeIterator<T>(G, C.iterator()) {
|
||||
|
||||
@Override
|
||||
protected Iterator<T> getConnected(T n) {
|
||||
return new FilterIterator<T>(G.getSuccNodes(n), filter);
|
||||
}
|
||||
};
|
||||
return Iterator2Collection.toSet(dfs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a DFS starting with a particular node set and return the set of all nodes visited.
|
||||
*
|
||||
* @param G the graph containing n
|
||||
* @return Set
|
||||
* @throws IllegalArgumentException if C is null
|
||||
*/
|
||||
public static <T> Set<T> getReachableNodes(Graph<T> G, Collection<? extends T> C) {
|
||||
if (C == null) {
|
||||
throw new IllegalArgumentException("C is null");
|
||||
}
|
||||
HashSet<T> result = HashSetFactory.make();
|
||||
Iterator<T> dfs = iterateFinishTime(G, C.iterator());
|
||||
while (dfs.hasNext()) {
|
||||
result.add(dfs.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform a DFS and return the set of all nodes visited.
|
||||
*
|
||||
* @param G the graph containing n
|
||||
* @return Set
|
||||
* @throws IllegalArgumentException if G == null
|
||||
*/
|
||||
public static <T> Set<T> getReachableNodes(Graph<T> G) throws IllegalArgumentException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G == null");
|
||||
}
|
||||
HashSet<T> result = HashSetFactory.make();
|
||||
Iterator<T> dfs = iterateFinishTime(G);
|
||||
while (dfs.hasNext()) {
|
||||
result.add(dfs.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a DFS of a graph starting with a specified node and return a sorted list of nodes. The nodes are sorted by depth first
|
||||
* order.
|
||||
*
|
||||
* @param G a graph
|
||||
* @param n the initial node
|
||||
* @return a sorted set of nodes in the graph in depth first order
|
||||
*/
|
||||
public static <T> SortedSet<T> sortByDepthFirstOrder(Graph<T> G, T n) {
|
||||
Map<T, Integer> order = HashMapFactory.make();
|
||||
TreeSet<T> result = new TreeSet<T>(new DFSComparator<T>(order));
|
||||
|
||||
Iterator<T> dfs = iterateFinishTime(G, new NonNullSingletonIterator<T>(n));
|
||||
int i = 0;
|
||||
while (dfs.hasNext()) {
|
||||
T nxt = dfs.next();
|
||||
order.put(nxt, new Integer(i++));
|
||||
result.add(nxt);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator class to order the nodes in the DFS according to the depth first order
|
||||
*/
|
||||
static class DFSComparator<T> implements Comparator<T> {
|
||||
final private Map<T, Integer> order;
|
||||
|
||||
DFSComparator(Map<T, Integer> order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int compare(T o1, T o2) {
|
||||
// throws an exception if either argument is not a Node object
|
||||
if (o1 == o2) {
|
||||
return 0;
|
||||
}
|
||||
Integer t1 = order.get(o1);
|
||||
Integer t2 = order.get(o2);
|
||||
// throws an exception if either node has not been ordered
|
||||
return (t1.intValue() - t2.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param G
|
||||
* @return iterator of nodes of G in order of DFS discover time
|
||||
*/
|
||||
public static <T> DFSDiscoverTimeIterator iterateDiscoverTime(Graph<T> G) {
|
||||
if (G instanceof NumberedGraph) {
|
||||
return new NumberedDFSDiscoverTimeIterator<T>((NumberedGraph<T>) G);
|
||||
} else {
|
||||
return new SlowDFSDiscoverTimeIterator<T>(G);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param roots roots of traversal, in order to visit in outermost loop of DFS
|
||||
* @return iterator of nodes of G in order of DFS discover time
|
||||
* @throws IllegalArgumentException if roots == null
|
||||
*/
|
||||
public static <T> Iterator<T> iterateDiscoverTime(Graph<T> G, Iterator<T> roots) throws IllegalArgumentException {
|
||||
if (roots == null) {
|
||||
throw new IllegalArgumentException("roots == null");
|
||||
}
|
||||
if (G instanceof NumberedGraph) {
|
||||
return new NumberedDFSDiscoverTimeIterator<T>((NumberedGraph<T>) G, roots);
|
||||
} else {
|
||||
return new SlowDFSDiscoverTimeIterator<T>(G, roots);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param N root of traversal
|
||||
* @return iterator of nodes of G in order of DFS discover time
|
||||
*/
|
||||
public static <T> DFSDiscoverTimeIterator<T> iterateDiscoverTime(Graph<T> G, T N) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G == null");
|
||||
}
|
||||
if (G instanceof NumberedGraph) {
|
||||
return new NumberedDFSDiscoverTimeIterator<T>((NumberedGraph<T>) G, N);
|
||||
} else {
|
||||
return new SlowDFSDiscoverTimeIterator<T>(G, N);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param G a graph
|
||||
* @return iterator of nodes of G in order of DFS finish time
|
||||
* @throws IllegalArgumentException if G == null
|
||||
*/
|
||||
public static <T> DFSFinishTimeIterator<T> iterateFinishTime(Graph<T> G) throws IllegalArgumentException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G == null");
|
||||
}
|
||||
if (G instanceof NumberedGraph) {
|
||||
return new NumberedDFSFinishTimeIterator<T>((NumberedGraph<T>) G);
|
||||
} else {
|
||||
return new SlowDFSFinishTimeIterator<T>(G);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param G a graph
|
||||
* @param ie roots of traversal, in order to visit in outermost loop of DFS
|
||||
* @return iterator of nodes of G in order of DFS finish time
|
||||
*/
|
||||
public static <T> DFSFinishTimeIterator<T> iterateFinishTime(Graph<T> G, Iterator<? extends T> ie) {
|
||||
if (ie == null) {
|
||||
throw new IllegalArgumentException("null ie");
|
||||
}
|
||||
if (G instanceof NumberedGraph) {
|
||||
return new NumberedDFSFinishTimeIterator<T>((NumberedGraph<T>) G, ie);
|
||||
} else {
|
||||
return new SlowDFSFinishTimeIterator<T>(G, ie);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
|
||||
/**
|
||||
* This class implements depth-first search over a {@link NumberedGraph}, return an enumeration of the nodes of the graph in order of
|
||||
* increasing discover time. This class follows the outNodes of the graph nodes to define the graph, but this behavior can be
|
||||
* changed by overriding the getConnected method.
|
||||
*/
|
||||
public abstract class DFSDiscoverTimeIterator<T> extends Stack<T> implements Iterator<T> {
|
||||
|
||||
/**
|
||||
* an enumeration of all nodes to search from
|
||||
*/
|
||||
private Iterator<? extends T> roots;
|
||||
|
||||
/**
|
||||
* subclass constructors must call this!
|
||||
*/
|
||||
protected void init(Iterator<? extends T> nodes) {
|
||||
roots = nodes;
|
||||
assert nodes != null;
|
||||
if (roots.hasNext()) {
|
||||
T n = roots.next();
|
||||
push(n);
|
||||
setPendingChildren(n, getConnected(n));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* subclass constructors must call this!
|
||||
*/
|
||||
protected void init(T N) {
|
||||
init(new NonNullSingletonIterator<T>(N));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether there are any more nodes left to enumerate.
|
||||
*
|
||||
* @return true if there nodes left to enumerate.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return (!empty());
|
||||
}
|
||||
|
||||
abstract protected Iterator<? extends T> getPendingChildren(T n);
|
||||
|
||||
abstract protected void setPendingChildren(T v, Iterator<? extends T> iterator);
|
||||
|
||||
/**
|
||||
* Find the next graph node in discover time order.
|
||||
*
|
||||
* @return the next graph node in discover time order.
|
||||
*/
|
||||
public T next() throws NoSuchElementException {
|
||||
|
||||
if (empty()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
// we always return the top node on the stack.
|
||||
T toReturn = peek();
|
||||
|
||||
// compute the next node to return.
|
||||
assert getPendingChildren(toReturn) != null;
|
||||
do {
|
||||
T stackTop = peek();
|
||||
for (Iterator<? extends T> it = getPendingChildren(stackTop); it.hasNext();) {
|
||||
T child = it.next();
|
||||
if (getPendingChildren(child) == null) {
|
||||
// found a new child.
|
||||
visitEdge(stackTop, child);
|
||||
setPendingChildren(child, getConnected(child));
|
||||
push(child);
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
// the following saves space by allowing the original iterator to be GCed
|
||||
Iterator<T> empty = EmptyIterator.instance();
|
||||
setPendingChildren(stackTop, empty);
|
||||
// didn't find any new children. pop the stack and try again.
|
||||
pop();
|
||||
|
||||
} while (!empty());
|
||||
|
||||
// search for the next unvisited root.
|
||||
while (roots.hasNext()) {
|
||||
T nextRoot = roots.next();
|
||||
if (getPendingChildren(nextRoot) == null) {
|
||||
push(nextRoot);
|
||||
setPendingChildren(nextRoot, getConnected(nextRoot));
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the out edges of a given node
|
||||
*
|
||||
* @param n the node of which to get the out edges
|
||||
* @return the out edges
|
||||
*
|
||||
*/
|
||||
abstract protected Iterator<? extends T> getConnected(T n);
|
||||
|
||||
public void remove() throws UnimplementedError {
|
||||
throw new UnimplementedError();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param from source of the edge to visit
|
||||
* @param to target of the edge to visit
|
||||
*/
|
||||
protected void visitEdge(T from, T to) {
|
||||
// do nothing. subclasses will override.
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* This class implements depth-first search over a {@link Graph}, return an enumeration of the nodes of the graph in order of increasing
|
||||
* finishing time. This class follows the outNodes of the graph nodes to define the graph, but this behavior can be changed by
|
||||
* overriding the getConnected method.
|
||||
*/
|
||||
public abstract class DFSFinishTimeIterator<T> extends Stack<T> implements Iterator<T> {
|
||||
|
||||
/**
|
||||
* the current next element in finishing time order
|
||||
*/
|
||||
private T theNextElement;
|
||||
|
||||
/**
|
||||
* an enumeration of all nodes to search from
|
||||
*/
|
||||
private Iterator<? extends T> roots;
|
||||
|
||||
/**
|
||||
* The governing graph.
|
||||
*/
|
||||
private Graph<T> G;
|
||||
|
||||
/**
|
||||
* Subclasses must call this in the constructor!
|
||||
*
|
||||
* @param G
|
||||
* @param nodes
|
||||
*/
|
||||
protected void init(Graph<T> G, Iterator<? extends T> nodes) {
|
||||
this.G = G;
|
||||
roots = nodes;
|
||||
if (roots.hasNext())
|
||||
theNextElement = roots.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether there are any more nodes left to enumerate.
|
||||
*
|
||||
* @return true if there nodes left to enumerate.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return (!empty() || (theNextElement != null && getPendingChildren(theNextElement) == null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPendingChildren.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
abstract Iterator getPendingChildren(T n);
|
||||
|
||||
/**
|
||||
* Method setPendingChildren.
|
||||
*
|
||||
* @param v
|
||||
* @param iterator
|
||||
*/
|
||||
abstract void setPendingChildren(T v, Iterator<? extends T> iterator);
|
||||
|
||||
/**
|
||||
* Find the next graph node in finishing time order.
|
||||
*
|
||||
* @return the next graph node in finishing time order.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T next() throws NoSuchElementException {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
if (empty()) {
|
||||
T v = theNextElement;
|
||||
setPendingChildren(v, getConnected(v));
|
||||
push(v);
|
||||
}
|
||||
recurse: while (!empty()) {
|
||||
T v = peek();
|
||||
Iterator<? extends T> pc = getPendingChildren(v);
|
||||
for (Iterator<? extends T> e = pc; e.hasNext();) {
|
||||
T n = e.next();
|
||||
assert n != null : "null node in pc";
|
||||
Iterator nChildren = getPendingChildren(n);
|
||||
if (nChildren == null) {
|
||||
// found a new child: recurse to it.
|
||||
setPendingChildren(n, getConnected(n));
|
||||
push(n);
|
||||
continue recurse;
|
||||
}
|
||||
}
|
||||
// the following saves space by allowing the original iterator to be GCed
|
||||
setPendingChildren(v, (Iterator<T>) EmptyIterator.instance());
|
||||
|
||||
// no more children to visit: finished this vertex
|
||||
while (getPendingChildren(theNextElement) != null && roots.hasNext()) {
|
||||
theNextElement = roots.next();
|
||||
}
|
||||
|
||||
return pop();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the out edges of a given node
|
||||
*
|
||||
* @param n the node of which to get the out edges
|
||||
* @return the out edges
|
||||
*
|
||||
*/
|
||||
protected Iterator<? extends T> getConnected(T n) {
|
||||
return G.getSuccNodes(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.util.Iterator#remove()
|
||||
*/
|
||||
public void remove() throws UnimplementedError {
|
||||
throw new UnimplementedError();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.ibm.wala.util.collections.Filter;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* This class searches depth-first search for node that matches some criteria. If found, it reports a path to the first node found.
|
||||
*
|
||||
* This class follows the outNodes of the graph nodes to define the graph, but this behavior can be changed by overriding the
|
||||
* getConnected method.
|
||||
*/
|
||||
public class DFSPathFinder<T> extends Stack<T> {
|
||||
public static final long serialVersionUID = 9939900773328288L;
|
||||
|
||||
/**
|
||||
* The graph to search
|
||||
*/
|
||||
final private Graph<T> G;
|
||||
|
||||
/**
|
||||
* The Filter which defines the target set of nodes to find
|
||||
*/
|
||||
final private Filter<T> filter;
|
||||
|
||||
/**
|
||||
* an enumeration of all nodes to search from
|
||||
*/
|
||||
final private Iterator<T> roots;
|
||||
|
||||
/**
|
||||
* An iterator of child nodes for each node being searched
|
||||
*/
|
||||
final private Map<T, Iterator<? extends T>> pendingChildren = HashMapFactory.make(25);
|
||||
|
||||
/**
|
||||
* Flag recording whether initialization has happened.
|
||||
*/
|
||||
private boolean initialized = false;
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
public DFSPathFinder(Graph<T> G, T N, Filter<T> f) throws IllegalArgumentException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (!G.containsNode(N)) {
|
||||
throw new IllegalArgumentException("source node not in graph: " + N);
|
||||
}
|
||||
this.G = G;
|
||||
this.roots = new NonNullSingletonIterator<T>(N);
|
||||
this.filter = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
*/
|
||||
public DFSPathFinder(Graph<T> G, Iterator<T> nodes, Filter<T> f) {
|
||||
this.G = G;
|
||||
this.roots = nodes;
|
||||
this.filter = f;
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (roots == null) {
|
||||
throw new IllegalArgumentException("roots is null");
|
||||
}
|
||||
if (filter == null) {
|
||||
throw new IllegalArgumentException("filter is null");
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
initialized = true;
|
||||
if (roots.hasNext()) {
|
||||
T n = roots.next();
|
||||
push(n);
|
||||
setPendingChildren(n, getConnected(n));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a List of nodes that specifies the first path found from a root to a node accepted by the filter. Returns null if no
|
||||
* path found.
|
||||
*/
|
||||
public List<T> find() {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
while (hasNext()) {
|
||||
T n = peek();
|
||||
if (filter.accepts(n)) {
|
||||
List<T> path = currentPath();
|
||||
advance();
|
||||
return path;
|
||||
}
|
||||
advance();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<T> currentPath() {
|
||||
ArrayList<T> result = new ArrayList<T>();
|
||||
for (Iterator<T> path = iterator(); path.hasNext();) {
|
||||
result.add(0, path.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether there are any more nodes left to enumerate.
|
||||
*
|
||||
* @return true if there nodes left to enumerate.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return (!empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPendingChildren.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
private Iterator<? extends T> getPendingChildren(T n) {
|
||||
return pendingChildren.get(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setPendingChildren.
|
||||
*
|
||||
* @param v
|
||||
* @param iterator
|
||||
*/
|
||||
private void setPendingChildren(T v, Iterator<? extends T> iterator) {
|
||||
pendingChildren.put(v, iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance to the next graph node in discover time order.
|
||||
*/
|
||||
private void advance() {
|
||||
|
||||
// we always return the top node on the stack.
|
||||
T currentNode = peek();
|
||||
|
||||
// compute the next node to return.
|
||||
assert getPendingChildren(currentNode) != null;
|
||||
do {
|
||||
T stackTop = peek();
|
||||
for (Iterator<? extends T> it = getPendingChildren(stackTop); it.hasNext();) {
|
||||
T child = it.next();
|
||||
if (getPendingChildren(child) == null) {
|
||||
// found a new child.
|
||||
setPendingChildren(child, getConnected(child));
|
||||
push(child);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// didn't find any new children. pop the stack and try again.
|
||||
pop();
|
||||
|
||||
} while (!empty());
|
||||
|
||||
// search for the next unvisited root.
|
||||
while (roots.hasNext()) {
|
||||
T nextRoot = roots.next();
|
||||
if (getPendingChildren(nextRoot) == null) {
|
||||
push(nextRoot);
|
||||
setPendingChildren(nextRoot, getConnected(nextRoot));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the out edges of a given node
|
||||
*
|
||||
* @param n the node of which to get the out edges
|
||||
* @return the out edges
|
||||
*
|
||||
*/
|
||||
protected Iterator<? extends T> getConnected(T n) {
|
||||
return G.getSuccNodes(n);
|
||||
}
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002-2010 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetAction;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
|
||||
public class FloydWarshall<T> {
|
||||
|
||||
public interface GetPath<T> {
|
||||
List<T> getPath(T from, T to);
|
||||
}
|
||||
|
||||
public interface GetPaths<T> {
|
||||
Set<List<T>> getPaths(T from, T to);
|
||||
}
|
||||
|
||||
protected final NumberedGraph<T> G;
|
||||
|
||||
public FloydWarshall(NumberedGraph<T> g) {
|
||||
G = g;
|
||||
}
|
||||
|
||||
protected int edgeCost(int from, int to) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected void pathCallback(int i, int j, int k) {
|
||||
|
||||
}
|
||||
|
||||
int[][] allPairsShortestPaths() {
|
||||
final int[][] result = new int[G.getNumberOfNodes()][G.getNumberOfNodes()];
|
||||
|
||||
for(int i = 0; i < result.length; i++) {
|
||||
for(int j = 0; j < result[i].length; j++) {
|
||||
result[i][j] = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
for(T from : G) {
|
||||
final int fn = G.getNumber(from);
|
||||
IntSet tos = G.getSuccNodeNumbers(from);
|
||||
tos.foreach(new IntSetAction() {
|
||||
public void act(int x) {
|
||||
result[fn][x] = edgeCost(fn, x);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(T kn : G) {
|
||||
int k = G.getNumber(kn);
|
||||
for(T in : G) {
|
||||
int i = G.getNumber(in);
|
||||
for(T jn : G) {
|
||||
int j = G.getNumber(jn);
|
||||
long newLen = (long)result[i][k] + (long)result[k][j];
|
||||
if (newLen <= result[i][j]) {
|
||||
pathCallback(i, j, k);
|
||||
}
|
||||
if (newLen < result[i][j]) {
|
||||
result[i][j] = (int)newLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> int[][] shortestPathLengths(NumberedGraph<T> G) {
|
||||
return new FloydWarshall<T>(G).allPairsShortestPaths();
|
||||
}
|
||||
|
||||
public static <T> GetPath<T> allPairsShortestPath(final NumberedGraph<T> G) {
|
||||
return new FloydWarshall<T>(G) {
|
||||
int[][] next = new int[G.getNumberOfNodes()][G.getNumberOfNodes()];
|
||||
|
||||
@Override
|
||||
protected void pathCallback(int i, int j, int k) {
|
||||
next[i][j] = k;
|
||||
}
|
||||
|
||||
private GetPath<T> doit() {
|
||||
for(int i = 0; i < next.length; i++) {
|
||||
for(int j = 0; j < next[i].length; j++) {
|
||||
next[i][j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
final int[][] paths = allPairsShortestPaths();
|
||||
return new GetPath<T>() {
|
||||
public List<T> getPath(T from, T to) {
|
||||
int fn = G.getNumber(from);
|
||||
int tn = G.getNumber(to);
|
||||
if (paths[fn][tn] == Integer.MAX_VALUE) {
|
||||
throw new UnsupportedOperationException("no path from " + from + " to " + to);
|
||||
} else {
|
||||
int intermediate = next[fn][tn];
|
||||
if (intermediate == -1) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
T in = G.getNode(intermediate);
|
||||
List<T> result = new LinkedList<T>(getPath(from, in));
|
||||
result.add(in);
|
||||
result.addAll(getPath(in, to));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}.doit();
|
||||
}
|
||||
|
||||
public static <T> GetPaths<T> allPairsShortestPaths(final NumberedGraph<T> G) {
|
||||
return new FloydWarshall<T>(G) {
|
||||
MutableIntSet[][] next = new MutableIntSet[G.getNumberOfNodes()][G.getNumberOfNodes()];
|
||||
|
||||
@Override
|
||||
protected void pathCallback(int i, int j, int k) {
|
||||
if (next[i][j] == null) {
|
||||
next[i][j] = IntSetUtil.make();
|
||||
}
|
||||
next[i][j].add(k);
|
||||
}
|
||||
|
||||
private GetPaths<T> doit() {
|
||||
final int[][] paths = allPairsShortestPaths();
|
||||
return new GetPaths<T>() {
|
||||
public Set<List<T>> getPaths(final T from, final T to) {
|
||||
int fn = G.getNumber(from);
|
||||
int tn = G.getNumber(to);
|
||||
if (paths[fn][tn] == Integer.MAX_VALUE) {
|
||||
throw new UnsupportedOperationException("no path from " + from + " to " + to);
|
||||
} else {
|
||||
MutableIntSet intermediate = next[fn][tn];
|
||||
if (intermediate == null) {
|
||||
List<T> none = Collections.emptyList();
|
||||
return Collections.singleton(none);
|
||||
} else {
|
||||
final Set<List<T>> result = new HashSet<List<T>>();
|
||||
|
||||
intermediate.foreach(new IntSetAction() {
|
||||
public void act(int x) {
|
||||
T in = G.getNode(x);
|
||||
for(List<T> pre : getPaths(from, in)) {
|
||||
for(List<T> post : getPaths(in, to)) {
|
||||
List<T> path = new LinkedList<T>(pre);
|
||||
path.add(in);
|
||||
path.addAll(post);
|
||||
result.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}.doit();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
abstract class GraphDFSDiscoverTimeIterator<T> extends DFSDiscoverTimeIterator<T> {
|
||||
|
||||
/**
|
||||
* the graph being searched
|
||||
*/
|
||||
private Graph<T> G;
|
||||
|
||||
protected void init(Graph<T> G, Iterator<? extends T> nodes) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
this.G = G;
|
||||
super.init(nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<? extends T> getConnected(T n) {
|
||||
return G.getSuccNodes(n);
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
|
||||
/**
|
||||
* This class implements depth-first search over a NumberedGraph, return an enumeration of the nodes of the graph in order of
|
||||
* increasing discover time. This class follows the outNodes of the graph nodes to define the graph, but this behavior can be
|
||||
* changed by overriding the getConnected method.
|
||||
*/
|
||||
public class NumberedDFSDiscoverTimeIterator<T> extends GraphDFSDiscoverTimeIterator<T> implements Iterator<T> {
|
||||
|
||||
private static final long serialVersionUID = -3919708273323217304L;
|
||||
|
||||
/**
|
||||
* An iterator of child nodes for each node being searched
|
||||
*/
|
||||
private final Iterator<? extends T>[] pendingChildren;
|
||||
|
||||
/**
|
||||
* The Graph being traversed
|
||||
*/
|
||||
protected final NumberedGraph<T> G;
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public NumberedDFSDiscoverTimeIterator(NumberedGraph<T> G, T N) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
this.G = G;
|
||||
pendingChildren = new Iterator[G.getMaxNumber() + 1];
|
||||
init(G, new NonNullSingletonIterator<T>(N));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
* @throws IllegalArgumentException if G is null
|
||||
* @throws IllegalArgumentException if nodes == null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public NumberedDFSDiscoverTimeIterator(NumberedGraph<T> G, Iterator<? extends T> nodes) throws IllegalArgumentException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (nodes == null) {
|
||||
throw new IllegalArgumentException("nodes == null");
|
||||
}
|
||||
|
||||
this.G = G;
|
||||
pendingChildren = new Iterator[G.getMaxNumber() + 1];
|
||||
init(G, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor DFSFinishTimeIterator.
|
||||
*
|
||||
* @param G
|
||||
* @throws NullPointerException if G is null
|
||||
*/
|
||||
public NumberedDFSDiscoverTimeIterator(NumberedGraph<T> G) throws NullPointerException {
|
||||
this(G, G == null ? null : G.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPendingChildren.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
@Override
|
||||
protected Iterator<? extends T> getPendingChildren(T n) {
|
||||
return pendingChildren[G.getNumber(n)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setPendingChildren.
|
||||
*
|
||||
* @param v
|
||||
* @param iterator
|
||||
*/
|
||||
@Override
|
||||
protected void setPendingChildren(T v, Iterator<? extends T> iterator) {
|
||||
pendingChildren[G.getNumber(v)] = iterator;
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.NumberedGraph;
|
||||
|
||||
/**
|
||||
* This class implements depth-first search over a NumberedGraph, return an enumeration of the nodes of the graph in order of
|
||||
* increasing discover time. This class follows the outNodes of the graph nodes to define the graph, but this behavior can be
|
||||
* changed by overriding the getConnected method.
|
||||
*/
|
||||
public class NumberedDFSFinishTimeIterator<T> extends DFSFinishTimeIterator<T> implements Iterator<T> {
|
||||
public static final long serialVersionUID = 8737376661L;
|
||||
|
||||
/**
|
||||
* An iterator of child nodes for each node being searched
|
||||
*/
|
||||
private Iterator[] pendingChildren;
|
||||
|
||||
/**
|
||||
* The Graph being traversed
|
||||
*/
|
||||
private final NumberedGraph<T> G;
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
*/
|
||||
NumberedDFSFinishTimeIterator(NumberedGraph<T> G, T N) {
|
||||
this.G = G;
|
||||
pendingChildren = new Iterator[G.getMaxNumber() + 1];
|
||||
init(G, new NonNullSingletonIterator<T>(N));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
*/
|
||||
NumberedDFSFinishTimeIterator(NumberedGraph<T> G, Iterator<? extends T> nodes) {
|
||||
this.G = G;
|
||||
pendingChildren = new Iterator[G.getMaxNumber() + 1];
|
||||
init(G, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor DFSFinishTimeIterator.
|
||||
*
|
||||
* @param G
|
||||
*/
|
||||
NumberedDFSFinishTimeIterator(NumberedGraph<T> G) {
|
||||
this(G, G.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator getPendingChildren(T n) {
|
||||
int number = G.getNumber(n);
|
||||
if (number >= pendingChildren.length) {
|
||||
// the graph is probably growing as we travserse
|
||||
Iterator[] old = pendingChildren;
|
||||
pendingChildren = new Iterator[number * 2];
|
||||
System.arraycopy(old, 0, pendingChildren, 0, old.length);
|
||||
return null;
|
||||
}
|
||||
if (number < 0) {
|
||||
assert false : "negative number for " + n + " " + n.getClass();
|
||||
}
|
||||
return pendingChildren[number];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setPendingChildren.
|
||||
*
|
||||
* @param v
|
||||
* @param iterator
|
||||
*/
|
||||
@Override
|
||||
void setPendingChildren(T v, Iterator<? extends T> iterator) {
|
||||
pendingChildren[G.getNumber(v)] = iterator;
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.ReverseIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.impl.GraphInverter;
|
||||
|
||||
/**
|
||||
* This class computes strongly connected components for a Graph (or a subset of
|
||||
* it). It does not store the SCCs in any lookaside structure, but rather simply
|
||||
* generates an enumeration of them. See Cormen, Leiserson, Rivest Ch. 23 Sec. 5
|
||||
*/
|
||||
public class SCCIterator<T> implements Iterator<Set<T>> {
|
||||
/**
|
||||
* The second DFS (the reverse one) needed while computing SCCs
|
||||
*/
|
||||
final private DFSFinishTimeIterator<T> rev;
|
||||
|
||||
/**
|
||||
* Construct an enumeration across the SCCs of a given graph.
|
||||
*
|
||||
* @param G
|
||||
* The graph over which to construct SCCs
|
||||
* @throws NullPointerException if G is null
|
||||
*/
|
||||
public SCCIterator(Graph<T> G) throws NullPointerException {
|
||||
this(G, G == null ? null : G.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an enumeration of the SCCs of the subset of a given graph
|
||||
* determined by starting at a given set of nodes.
|
||||
*/
|
||||
public SCCIterator(Graph<T> G, Iterator<T> nodes) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G cannot be null");
|
||||
}
|
||||
Iterator<T> reverseFinishTime = ReverseIterator.reverse(DFS.iterateFinishTime(G, nodes));
|
||||
|
||||
rev = DFS.iterateFinishTime(GraphInverter.invert(G), reverseFinishTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether there are any more SCCs remaining in this enumeration.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return rev.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next SCC in this enumeration
|
||||
*/
|
||||
public Set<T> next() throws NoSuchElementException {
|
||||
Set<T> currentSCC = HashSetFactory.make();
|
||||
|
||||
T v = rev.next();
|
||||
currentSCC.add(v);
|
||||
|
||||
while (rev.hasNext() && !rev.isEmpty()) {
|
||||
currentSCC.add(rev.next());
|
||||
}
|
||||
|
||||
return currentSCC;
|
||||
}
|
||||
|
||||
|
||||
public void remove() throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* This class implements depth-first search over a Graph, return an enumeration of the nodes of the graph in order of increasing
|
||||
* discover time. This class follows the outNodes of the graph nodes to define the graph, but this behavior can be changed by
|
||||
* overriding the getConnected method.
|
||||
*/
|
||||
public class SlowDFSDiscoverTimeIterator<T> extends GraphDFSDiscoverTimeIterator<T> implements Iterator<T> {
|
||||
public static final long serialVersionUID = 9439217987188L;
|
||||
|
||||
/**
|
||||
* An iterator of child nodes for each node being searched A Map: Node -> Iterator
|
||||
*/
|
||||
final private Map<T, Iterator<? extends T>> pendingChildren = HashMapFactory.make(25);
|
||||
|
||||
/**
|
||||
* For use with extreme care by subclasses that know what they're doing.
|
||||
*/
|
||||
protected SlowDFSDiscoverTimeIterator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
*/
|
||||
public SlowDFSDiscoverTimeIterator(Graph<T> G, T N) {
|
||||
init(G, new NonNullSingletonIterator<T>(N));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
*/
|
||||
public SlowDFSDiscoverTimeIterator(Graph<T> G, Iterator<T> nodes) {
|
||||
if (nodes == null) {
|
||||
throw new IllegalArgumentException("null nodes");
|
||||
}
|
||||
init(G, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor SlowDFSDiscoverTimeIterator.
|
||||
*
|
||||
* @param G
|
||||
* @throws NullPointerException if G is null
|
||||
*/
|
||||
public SlowDFSDiscoverTimeIterator(Graph<T> G) throws NullPointerException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
init(G, G.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<? extends T> getPendingChildren(Object n) {
|
||||
return pendingChildren.get(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setPendingChildren.
|
||||
*
|
||||
* @param v
|
||||
* @param iterator
|
||||
*/
|
||||
@Override
|
||||
protected void setPendingChildren(T v, Iterator<? extends T> iterator) {
|
||||
pendingChildren.put(v, iterator);
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* This class implements depth-first search over a Graph, return an enumeration of the nodes of the graph in order of increasing
|
||||
* finishing time. This class follows the outNodes of the graph nodes to define the graph, but this behavior can be changed by
|
||||
* overriding the getConnected method.
|
||||
*/
|
||||
public class SlowDFSFinishTimeIterator<T> extends DFSFinishTimeIterator<T> {
|
||||
public static final long serialVersionUID = 3903190104743762628L;
|
||||
|
||||
/**
|
||||
* An iterator of child nodes for each node being searched
|
||||
*/
|
||||
final private Map<T, Iterator<? extends T>> pendingChildren = HashMapFactory.make(25);
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator starting with a particular node in a directed graph.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @throws IllegalArgumentException if G is null
|
||||
*/
|
||||
public SlowDFSFinishTimeIterator(Graph<T> G, T N) throws IllegalArgumentException {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (!G.containsNode(N)) {
|
||||
throw new IllegalArgumentException("source node not in graph: " + N);
|
||||
}
|
||||
init(G, new NonNullSingletonIterator<T>(N));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a depth-first enumerator across the (possibly improper) subset of nodes reachable from the nodes in the given
|
||||
* enumeration.
|
||||
*
|
||||
* @param G the graph whose nodes to enumerate
|
||||
* @param nodes the set of nodes from which to start searching
|
||||
*/
|
||||
public SlowDFSFinishTimeIterator(Graph<T> G, Iterator<? extends T> nodes) {
|
||||
if (G == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
if (nodes == null) {
|
||||
throw new IllegalArgumentException("G is null");
|
||||
}
|
||||
init(G, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NullPointerException if G is null
|
||||
*/
|
||||
public SlowDFSFinishTimeIterator(Graph<T> G) throws NullPointerException {
|
||||
this(G, G == null ? null : G.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator<? extends T> getPendingChildren(T n) {
|
||||
return pendingChildren.get(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setPendingChildren(T v, Iterator<? extends T> iterator) {
|
||||
pendingChildren.put(v, iterator);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.util.graph.traverse;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.util.collections.ReverseIterator;
|
||||
import com.ibm.wala.util.graph.Graph;
|
||||
import com.ibm.wala.util.graph.impl.GraphInverter;
|
||||
|
||||
/**
|
||||
* Utilities for iterating over graphs in topological order.
|
||||
*/
|
||||
public class Topological {
|
||||
|
||||
/**
|
||||
* Build an Iterator over all the nodes in the graph, in an order such that SCCs are visited in topological order.
|
||||
*
|
||||
* @throws IllegalArgumentException if graph == null
|
||||
*/
|
||||
public static <T> Iterator<T> makeTopologicalIter(Graph<T> graph) throws IllegalArgumentException {
|
||||
// the following code ensures a topological order over SCCs.
|
||||
// note that the first two lines of the following give a topological
|
||||
// order for dags, but that can get screwed up by cycles. so
|
||||
// instead, we use Tarjan's SCC algorithm, which happens to
|
||||
// visit nodes in an order consistent with a top. order over SCCs.
|
||||
|
||||
if (graph == null) {
|
||||
throw new IllegalArgumentException("graph == null");
|
||||
}
|
||||
// finish time is post-order
|
||||
// note that if you pay attention only to the first representative
|
||||
// of each SCC discovered, we have a top. order of these SCC
|
||||
// representatives
|
||||
Iterator<T> finishTime = DFS.iterateFinishTime(graph);
|
||||
// reverse postorder is usual topological sort.
|
||||
Iterator<T> rev = ReverseIterator.reverse(finishTime);
|
||||
// the following statement helps out the GC; note that finishTime holds
|
||||
// on to a large array
|
||||
finishTime = null;
|
||||
Graph<T> G_T = GraphInverter.invert(graph);
|
||||
Iterator<T> order = DFS.iterateFinishTime(G_T, rev);
|
||||
return order;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<HTML>
|
||||
<BODY>
|
||||
Graph traversal algorithms
|
||||
</BODY>
|
||||
</HTML>
|
Loading…
Reference in New Issue