com.ibm.wala.util.graph.impl.SparseNumberedEdgeManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.ibm.wala.util Show documentation
Show all versions of com.ibm.wala.util Show documentation
T. J. Watson Libraries for Analysis
/*
* 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.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.EmptyIntSet;
import com.ibm.wala.util.intset.IBinaryNaturalRelation;
import com.ibm.wala.util.intset.IntSet;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import org.jspecify.annotations.Nullable;
/** An object which tracks edges for nodes that have numbers. */
public final class SparseNumberedEdgeManager implements NumberedEdgeManager, Serializable {
private static final long serialVersionUID = 6751048618312429623L;
private final NumberedNodeManager nodeManager;
/** cache this state here for efficiency */
private final BitVector hasSuccessor = new BitVector();
/**
* @param nodeManager an object to track nodes
*/
public SparseNumberedEdgeManager(NumberedNodeManager 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 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 static final 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)
*/
@Override
public Iterator getPredNodes(@Nullable 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 empty = EmptyIterator.instance();
return (s == null) ? empty : nodeManager.iterateNodes(s);
}
/**
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object)
*/
@Override
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)
*/
@Override
public Iterator getSuccNodes(@Nullable 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 empty = EmptyIterator.instance();
return (s == null) ? empty : nodeManager.iterateNodes(s);
}
/**
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object)
*/
public Iterator getSuccNodes(int number) {
IntSet s = successors.getRelated(number);
Iterator empty = EmptyIterator.instance();
return (s == null) ? empty : nodeManager.iterateNodes(s);
}
@Override
public IntSet getSuccNodeNumbers(@Nullable T node) throws IllegalArgumentException {
if (nodeManager.getNumber(node) < 0) {
throw new IllegalArgumentException("Node not in graph " + node);
}
IntSet x = successors.getRelated(nodeManager.getNumber(node));
if (x == null) {
return EmptyIntSet.instance;
} else {
return x;
}
}
@Override
public IntSet getPredNodeNumbers(@Nullable 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)
*/
@Override
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)
*/
@Override
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);
}
@Override
public boolean hasEdge(@Nullable T src, @Nullable 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#removeAllIncidentEdges(Object)
*/
@Override
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(x -> predecessors.remove(x, number));
}
IntSet pred = predecessors.getRelated(number);
if (pred != null) {
pred.foreach(
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#removeAllIncidentEdges(Object)
*/
@Override
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(
x -> {
successors.remove(x, number);
if (successors.getRelatedCount(x) == 0) {
hasSuccessor.clear(x);
}
});
}
predecessors.removeAll(number);
}
@Override
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#removeAllIncidentEdges(Object)
*/
@Override
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(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;
}
}