/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.depgraph.impl;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import com.opengamma.engine.depgraph.DependencyGraph;
import com.opengamma.engine.depgraph.DependencyNode;
/**
* Iterator over all nodes in a graph in execution order.
*/
public final class ExecutionOrderNodeIterator extends HashSet<DependencyNode> implements Iterator<DependencyNode> {
private static final long serialVersionUID = 1L;
private final DependencyGraph _graph;
private final int _rootCount;
private DependencyNode[] _node;
private int[] _index;
private int _stack;
private DependencyNode _next;
// _node[_stack] is the parent we're returning child nodes from
// _index[_stack] is the child index last used from _node[_stack]
private static int defaultLoadFactorSize(final int elements) {
return elements + (elements / 3);
}
public ExecutionOrderNodeIterator(final DependencyGraph graph) {
super(defaultLoadFactorSize(graph.getSize()));
_node = new DependencyNode[16];
_index = new int[_node.length];
_graph = graph;
_rootCount = graph.getRootCount();
if (_rootCount != 0) {
_next = graph.getRootNode(0);
_node[0] = null;
_index[0] = 0;
while (_next.getInputCount() != 0) {
final int nextIndex = ++_stack;
if (nextIndex >= _node.length) {
resize();
}
_node[nextIndex] = _next;
_next = _next.getInputNode(0);
}
add(_next);
} else {
_stack = -1;
}
}
private void resize() {
final DependencyNode[] newNode = new DependencyNode[_node.length * 2];
System.arraycopy(_node, 0, newNode, 0, _node.length);
_node = newNode;
final int[] newIndex = new int[_index.length * 2];
System.arraycopy(_index, 0, newIndex, 0, _index.length);
_index = newIndex;
}
@Override
public boolean hasNext() {
if (_next != null) {
return true;
}
nextNode: do { //CSIGNORE
if (_stack > 0) {
final DependencyNode parent = _node[_stack];
final int child = _index[_stack] + 1;
if (child < parent.getInputCount()) {
_index[_stack] = child;
_next = parent.getInputNode(child);
if (contains(_next)) {
// Already visited this child; don't go any deeper
continue;
}
while (_next.getInputCount() != 0) {
final int nextIndex = ++_stack;
if (nextIndex >= _node.length) {
resize();
}
_node[nextIndex] = _next;
_index[nextIndex] = 0;
_next = _next.getInputNode(0);
if (contains(_next)) {
// Already visited this child
continue nextNode;
}
}
add(_next);
} else {
_stack--;
_next = parent;
if (!add(_next)) {
continue;
}
}
return true;
} else if (_stack == 0) {
final int root = _index[0] + 1;
if (root >= _rootCount) {
_stack = -1;
return false;
} else {
_index[0] = root;
_next = _graph.getRootNode(root);
assert !contains(_next); // Already visited this root; this is bad - the roots should not be present elsewhere
while (_next.getInputCount() != 0) {
final int nextIndex = ++_stack;
if (nextIndex >= _node.length) {
resize();
}
_node[nextIndex] = _next;
_index[nextIndex] = 0;
_next = _next.getInputNode(0);
if (contains(_next)) {
// Already visited this child
continue nextNode;
}
}
add(_next);
return true;
}
} else {
return false;
}
} while (true);
}
@Override
public DependencyNode next() {
if (_next == null) {
if (!hasNext()) {
throw new NoSuchElementException();
}
}
DependencyNode next = _next;
_next = null;
return next;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}