/******************************************************************************* * 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) */ @Override public int getNumber(T N) { if (N == null) { throw new IllegalArgumentException("N is null"); } INodeWithNumber n = N; return n.getGraphNodeId(); } @Override @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() */ @Override public int getMaxNumber() { return maxNumber; } /* * @see com.ibm.wala.util.graph.Graph#iterateNodes() */ @Override 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; } @Override public boolean hasNext() { return next != -1; } @Override @SuppressWarnings("unchecked") public T next() { if (hasNext()) { int r = next; advance(); return (T) arr[r]; } else { return null; } } @Override public void remove() { Assertions.UNREACHABLE(); } }; } /* * @see com.ibm.wala.util.graph.Graph#getNumberOfNodes() */ @Override 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 */ @Override 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) */ @Override 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) */ @Override 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) */ @Override public Iterator<T> iterateNodes(IntSet s) { return new NumberedNodeIterator<T>(s, this); } }