/*
* @(#)SSABlockNode.java
*/
package org.jf.dexlib.Code.Analysis.ssa;
import java.util.Iterator;
import java.util.LinkedList;
import org.jf.dexlib.Code.Analysis.ssa.graphs.AbstractNode;
import org.jf.dexlib.Code.Analysis.ssa.graphs.Node;
/**
* A CDG block node containing CDG nodes.
* @param <V>
* @author Patrick Kuhn
*/
public class SSABlockNode<V> extends AbstractNode implements Iterable<V> {
private static final LinkedList<SSABlockNode<?>> NODES = new LinkedList<SSABlockNode<?>>();
/** Nodes in this block. */
protected final LinkedList<V> block;
/**
* Find the block node containing a certain node.
* @param <V> type of nodes
* @param startNode first node of block to find
* @return the block
*/
@SuppressWarnings("unchecked")
public static <V> SSABlockNode<V> getInstance(final V startNode) {
SSABlockNode<V> result = null;
for (SSABlockNode<?> v : NODES) {
if (v.getFirst().equals(startNode)) {
result = (SSABlockNode<V>) v;
break;
}
}
if (result == null) {
result = new SSABlockNode<V>(startNode);
NODES.add(result);
}
return result;
}
public static void clear() {
NODES.clear();
}
/**
* Create an empty block and add node.
* @param node the first node of the block
*/
private SSABlockNode(final V node) {
this();
block.add(node);
}
/**
* Create an empty block.
*/
public SSABlockNode() {
super();
this.block = new LinkedList<V>();
}
/**
* Add a node to the end of this block.
* @param node a node
* @return <tt>true</tt> p.d.
*/
public boolean add(V node) {
return this.block.add(node);
}
/**
* Add a node as first element in the block.
* @param node node to add
*/
public void addFirst(V node) {
this.block.addFirst(node);
}
/**
* Checks whether a node is in this block.
* @param o a node
* @return <tt>true</tt> if node is in this block
*/
public boolean contains(V o) {
return block.contains(o);
}
public V getFirst() {
return block.getFirst();
}
public V getFirstNotPhi() {
V v = block.getFirst();
int i = 0;
while (((Node) v).isPHI() && i < block.size()) {
v = block.get(i);
++i;
}
if (!((Node) v).isPHI()) {
return v;
}
return null;
}
public V getLastNotPhi() {
V v = block.getLast();
int i = block.size() - 1;
while (((Node) v).isPHI() && i >= 0) {
v = block.get(i);
--i;
}
if (!((Node) v).isPHI()) {
return v;
}
return null;
}
public V getLast() {
return block.getLast();
}
/**
* Check whether the last node in block is the EXIT node.
* @return <tt>true</tt> if last node in block is EXIT
*/
public boolean hasExit() {
return ((Node)block.getLast()).isExit();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
for (V v : block) {
sb.append(v.toString());
sb.append("\\n");
}
return sb.substring(0, sb.length() - 2);
}
public Iterator<V> iterator() {
return block.iterator();
}
@Override
public void changeVariableName(int varOriginal, String varNewName) {
throw new UnsupportedOperationException("Not possible with Block Nodes");
}
}