/******************************************************************************
* Copyright (c) 2002 - 2014 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.CompoundIterator;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.graph.NumberedEdgeManager;
import com.ibm.wala.util.graph.NumberedGraph;
import com.ibm.wala.util.graph.NumberedNodeManager;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntIterator;
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 ExtensionGraph<T> implements NumberedGraph<T> {
private final NumberedGraph<T> original;
private final NumberedNodeManager<T> additionalNodes = new SlowNumberedNodeManager<T>();
private final NumberedEdgeManager<T> edgeManager = new NumberedEdgeManager<T>() {
private final Map<T, MutableIntSet> inEdges = HashMapFactory.make();
private final Map<T, MutableIntSet> outEdges = HashMapFactory.make();
private Iterator<T> nodes(final T node, final Map<T,? extends IntSet> extra) {
if (extra.containsKey(node)) {
return new Iterator<T>() {
private final IntIterator i = extra.get(node).intIterator();
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public T next() {
return ExtensionGraph.this.getNode(i.next());
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
} else {
return EmptyIterator.instance();
}
}
@Override
public Iterator<T> getPredNodes(T n) {
Iterator<T> orig = (original.containsNode(n)? original.getPredNodes(n): EmptyIterator.<T>instance());
return new CompoundIterator<T>(orig, nodes(n, inEdges));
}
@Override
public int getPredNodeCount(T n) {
return
(original.containsNode(n)? original.getPredNodeCount(n): 0) +
(inEdges.containsKey(n)? inEdges.get(n).size(): 0);
}
@Override
public Iterator<T> getSuccNodes(T n) {
Iterator<T> orig = (original.containsNode(n)? original.getSuccNodes(n): EmptyIterator.<T>instance());
return new CompoundIterator<T>(orig, nodes(n, outEdges));
}
@Override
public int getSuccNodeCount(T n) {
return
(original.containsNode(n)? original.getSuccNodeCount(n): 0) +
(outEdges.containsKey(n)? outEdges.get(n).size(): 0);
}
@Override
public void addEdge(T src, T dst) {
assert !original.hasEdge(src, dst);
assert containsNode(src) && containsNode(dst);
if (! inEdges.containsKey(dst)) { inEdges.put(dst, IntSetUtil.make()); }
inEdges.get(dst).add(getNumber(src));
if (! outEdges.containsKey(src)) { outEdges.put(src, IntSetUtil.make()); }
outEdges.get(src).add(getNumber(dst));
}
@Override
public void removeEdge(T src, T dst) throws UnsupportedOperationException {
assert hasEdge(src, dst);
assert !original.hasEdge(src, dst);
assert containsNode(src) && containsNode(dst);
inEdges.get(dst).remove(getNumber(src));
outEdges.get(src).remove(getNumber(dst));
}
@Override
public void removeAllIncidentEdges(T node) throws UnsupportedOperationException {
removeIncomingEdges(node);
removeOutgoingEdges(node);
}
@Override
public void removeIncomingEdges(T node) throws UnsupportedOperationException {
assert !original.containsNode(node) || original.getPredNodeCount(node) == 0;
inEdges.remove(node);
}
@Override
public void removeOutgoingEdges(T node) throws UnsupportedOperationException {
assert !original.containsNode(node) || original.getSuccNodeCount(node) == 0;
outEdges.remove(node);
}
@Override
public boolean hasEdge(T src, T dst) {
return original.hasEdge(src, dst) ||
(outEdges.containsKey(src) && outEdges.get(src).contains(getNumber(dst)));
}
@Override
public IntSet getSuccNodeNumbers(T node) {
if (original.containsNode(node)) {
if (outEdges.containsKey(node)) {
MutableIntSet x = IntSetUtil.makeMutableCopy(original.getSuccNodeNumbers(node));
x.addAll(outEdges.get(node));
return x;
} else {
return original.getSuccNodeNumbers(node);
}
} else {
if (outEdges.containsKey(node)) {
return outEdges.get(node);
} else {
return EmptyIntSet.instance;
}
}
}
@Override
public IntSet getPredNodeNumbers(T node) {
if (original.containsNode(node)) {
if (inEdges.containsKey(node)) {
MutableIntSet x = IntSetUtil.makeMutableCopy(original.getPredNodeNumbers(node));
x.addAll(inEdges.get(node));
return x;
} else {
return original.getPredNodeNumbers(node);
}
} else {
if (inEdges.containsKey(node)) {
return inEdges.get(node);
} else {
return EmptyIntSet.instance;
}
}
}
};
public ExtensionGraph(NumberedGraph<T> original) {
this.original = original;
}
@Override
public Iterator<T> iterator() {
return new CompoundIterator<T>(original.iterator(), additionalNodes.iterator());
}
@Override
public int getNumberOfNodes() {
return original.getNumberOfNodes() + additionalNodes.getNumberOfNodes();
}
@Override
public void addNode(T n) {
assert !original.containsNode(n);
additionalNodes.addNode(n);
}
@Override
public void removeNode(T n) throws UnsupportedOperationException {
assert !original.containsNode(n);
additionalNodes.removeNode(n);
}
@Override
public boolean containsNode(T n) {
return original.containsNode(n) || additionalNodes.containsNode(n);
}
@Override
public int getNumber(T N) {
if (original.containsNode(N)) {
return original.getNumber(N);
} else {
return additionalNodes.getNumber(N) + original.getMaxNumber() + 1;
}
}
@Override
public T getNode(int number) {
if (number <= original.getMaxNumber()) {
return original.getNode(number);
} else {
return additionalNodes.getNode(number - original.getMaxNumber() - 1);
}
}
@Override
public int getMaxNumber() {
if (additionalNodes.iterator().hasNext()) {
return original.getMaxNumber() + 1 + additionalNodes.getMaxNumber();
} else {
return original.getMaxNumber();
}
}
@Override
public Iterator<T> iterateNodes(IntSet s) {
final MutableIntSet os = IntSetUtil.make();
final MutableIntSet es = IntSetUtil.make();
s.foreach(new IntSetAction() {
@Override
public void act(int x) {
if (x <= original.getMaxNumber()) {
os.add(x);
} else {
es.add(x - original.getMaxNumber() - 1);
}
}
});
return new CompoundIterator<T>(original.iterateNodes(os), additionalNodes.iterateNodes(es));
}
@Override
public Iterator<T> getPredNodes(T n) {
return edgeManager.getPredNodes(n);
}
@Override
public int getPredNodeCount(T n) {
return edgeManager.getPredNodeCount(n);
}
@Override
public IntSet getPredNodeNumbers(T node) {
return edgeManager.getPredNodeNumbers(node);
}
@Override
public Iterator<T> getSuccNodes(T n) {
return edgeManager.getSuccNodes(n);
}
@Override
public int getSuccNodeCount(T N) {
return edgeManager.getSuccNodeCount(N);
}
@Override
public IntSet getSuccNodeNumbers(T node) {
return edgeManager.getSuccNodeNumbers(node);
}
@Override
public void addEdge(T src, T dst) {
assert !original.hasEdge(src, dst);
edgeManager.addEdge(src, dst);
}
@Override
public void removeEdge(T src, T dst) throws UnsupportedOperationException {
assert !original.hasEdge(src, dst);
edgeManager.removeEdge(src, dst);
}
@Override
public void removeAllIncidentEdges(T node) throws UnsupportedOperationException {
assert !original.containsNode(node);
edgeManager.removeAllIncidentEdges(node);
}
@Override
public void removeIncomingEdges(T node) throws UnsupportedOperationException {
assert !original.containsNode(node);
edgeManager.removeIncomingEdges(node);
}
@Override
public void removeOutgoingEdges(T node) throws UnsupportedOperationException {
assert !original.containsNode(node);
edgeManager.removeOutgoingEdges(node);
}
@Override
public boolean hasEdge(T src, T dst) {
return edgeManager.hasEdge(src, dst);
}
@Override
public void removeNodeAndEdges(T n) throws UnsupportedOperationException {
assert !original.containsNode(n);
edgeManager.removeAllIncidentEdges(n);
additionalNodes.removeNode(n);
}
}