
org.opentripplanner.street.model.vertex.TemporaryVertexDispose Maven / Gradle / Ivy
Show all versions of otp Show documentation
package org.opentripplanner.street.model.vertex;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.opentripplanner.street.model.edge.Edge;
/**
* This is a utility class used to remove a temporary subgraph from the manin graph. It traverse the
* subgraph of temporary vertices, and cuts that subgraph off from the main graph at each point it
* encounters a non-temporary vertexes.
*
* OTP then holds no references to the temporary subgraph and it is garbage collected.
*
* The static {@link #dispose(Vertex)} utility method is the only way to access the logic, hence
* preventing this class from reuse. This make the class thread safe, and simplify the
* implementation.
*/
class TemporaryVertexDispose {
/**
* A list of all Vertexes not jet processed.
*/
private final List todo = new ArrayList<>();
/**
* Processed vertexes. To prevent looping and processing the same vertex twice we keep all
* processed vertexes in the 'done' set.
*/
private final Set done = new HashSet<>();
/** Intentionally private constructor to prevent instantiation outside of the class. */
private TemporaryVertexDispose(Vertex tempVertex) {
todo.add(tempVertex);
}
/**
* Create an instance and dispose temporary subgraph.
*
* @param tempVertex any temporary vertex part of the temporary subgrap.
*/
static void dispose(Vertex tempVertex) {
if (tempVertex instanceof TemporaryVertex) {
new TemporaryVertexDispose(tempVertex).dispose();
}
}
/* private methods */
private void dispose() {
// Add all connected vertexes to the TODO_list and disconnect all
// main graph vertexes. We use a loop and not recursion to avoid
// stack overflow in the case of deep temporary graphs.
while (!todo.isEmpty()) {
Vertex current = next();
if (isNotAlreadyProcessed(current)) {
for (Edge edge : current.getOutgoing()) {
disposeVertex(edge.getToVertex(), edge, true);
}
for (Edge edge : current.getIncoming()) {
disposeVertex(edge.getFromVertex(), edge, false);
}
done.add(current);
}
}
}
/**
* Add the temporary vertex to processing queue OR disconnect edge from vertex if vertex is part
* of the main graph.
*
* @param v the vertex to dispose
* @param connectedEdge the connected temporary edge
* @param incoming true if the edge is an incoming edge, false if it is an outgoing edge
*/
private void disposeVertex(Vertex v, Edge connectedEdge, boolean incoming) {
if (v instanceof TemporaryVertex) {
addVertexToProcessTodoList(v);
} else {
removeEdgeFromMainGraphVertex(v, connectedEdge, incoming);
}
}
/**
* We have reached a NONE temporary Vertex and need to remove the temporary `connectedEdge` from
* the Vertex part of the main graph.
*
* @param v the vertex part of the main graph
* @param connectedEdge the connected temporary edge to be removed
* @param incoming true if the edge is an incoming edge, false if it is an outgoing edge
*/
private void removeEdgeFromMainGraphVertex(Vertex v, Edge connectedEdge, boolean incoming) {
if (incoming) {
v.removeIncoming(connectedEdge);
} else {
v.removeOutgoing(connectedEdge);
}
}
private void addVertexToProcessTodoList(Vertex v) {
if (isNotAlreadyProcessed(v)) {
todo.add(v);
}
}
private boolean isNotAlreadyProcessed(Vertex v) {
return !done.contains(v);
}
private Vertex next() {
return todo.remove(todo.size() - 1);
}
}