org.opentripplanner.routing.vertextype.TemporaryVertexDispose Maven / Gradle / Ivy
Show all versions of otp Show documentation
package org.opentripplanner.routing.vertextype;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Vertex;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 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 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 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);
}
}