com.ibm.wala.util.graph.traverse.DFSDiscoverTimeIterator 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
The newest version!
/*
* 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.traverse;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.Iterator2Iterable;
import com.ibm.wala.util.collections.NonNullSingletonIterator;
import com.ibm.wala.util.debug.UnimplementedError;
import com.ibm.wala.util.graph.NumberedGraph;
import com.uber.nullaway.annotations.Initializer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
/**
* This class implements depth-first search over a {@link NumberedGraph}, return an enumeration of
* the nodes of the graph in order of increasing discover time. This class follows the outNodes of
* the graph nodes to define the graph, but this behavior can be changed by overriding the
* getConnected method.
*/
public abstract class DFSDiscoverTimeIterator extends ArrayList implements Iterator {
private static final long serialVersionUID = 4238700455408861924L;
/** an enumeration of all nodes to search from */
private Iterator extends T> roots;
/** subclass constructors must call this! */
@Initializer
protected void init(Iterator extends T> nodes) {
roots = nodes;
assert nodes != null;
if (roots.hasNext()) {
T n = roots.next();
push(n);
setPendingChildren(n, getConnected(n));
}
}
/** subclass constructors must call this! */
protected void init(T N) {
init(new NonNullSingletonIterator<>(N));
}
/**
* Return whether there are any more nodes left to enumerate.
*
* @return true if there nodes left to enumerate.
*/
@Override
public boolean hasNext() {
return !empty();
}
protected abstract @Nullable Iterator extends T> getPendingChildren(T n);
protected abstract void setPendingChildren(T v, Iterator extends T> iterator);
/**
* Find the next graph node in discover time order.
*
* @return the next graph node in discover time order.
*/
@NullUnmarked
@Override
public T next() throws NoSuchElementException {
if (empty()) {
throw new NoSuchElementException();
}
// we always return the top node on the stack.
T toReturn = peek();
// compute the next node to return.
assert getPendingChildren(toReturn) != null;
do {
T stackTop = peek();
for (T child : Iterator2Iterable.make(getPendingChildren(stackTop))) {
if (getPendingChildren(child) == null) {
// found a new child.
visitEdge(stackTop, child);
setPendingChildren(child, getConnected(child));
push(child);
return toReturn;
}
}
// the following saves space by allowing the original iterator to be GCed
Iterator empty = EmptyIterator.instance();
setPendingChildren(stackTop, empty);
// didn't find any new children. pop the stack and try again.
pop();
} while (!empty());
// search for the next unvisited root.
while (roots.hasNext()) {
T nextRoot = roots.next();
if (getPendingChildren(nextRoot) == null) {
push(nextRoot);
setPendingChildren(nextRoot, getConnected(nextRoot));
return toReturn;
}
}
return toReturn;
}
/**
* get the out edges of a given node
*
* @param n the node of which to get the out edges
* @return the out edges
*/
protected abstract Iterator extends T> getConnected(T n);
@Override
public void remove() throws UnimplementedError {
throw new UnimplementedError();
}
/**
* @param from source of the edge to visit
* @param to target of the edge to visit
*/
protected void visitEdge(T from, T to) {
// do nothing. subclasses will override.
}
private boolean empty() {
return size() == 0;
}
private void push(T elt) {
add(elt);
}
private T peek() {
return get(size() - 1);
}
private T pop() {
T e = get(size() - 1);
remove(size() - 1);
return e;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy