package spimedb.graph.travel; import org.eclipse.collections.api.tuple.Pair; import org.eclipse.collections.api.tuple.primitive.ObjectIntPair; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * An empty implementation of a graph iterator to minimize the effort required to implement graph * iterators. * * @param <V> the graph vertex type * @param <E> the graph edge type * @author Barak Naveh * @since Jul 19, 2003 */ public abstract class AbstractTravel<V, E> implements Travel<V, E> { protected final List<Traveller<V, E>> travellers = new CopyOnWriteArrayList<>(); protected boolean crossComponentTraversal = true; // We keep this cached redundantly with Travellers.size() // so that subclasses can use it as a fast check to see if // event firing calls can be skipped. // TODO: support ConcurrentModificationException if graph modified // during iteration. //protected Specifics<V, E> specifics; // /** * Sets the cross component traversal flag - indicates whether to traverse the graph across * connected components. * * @param crossComponentTraversal if <code>true</code> traverses across connected components. */ public void setCrossComponentTraversal(boolean crossComponentTraversal) { this.crossComponentTraversal = crossComponentTraversal; } /** * Test whether this iterator is set to traverse the graph across connected components. * * @return <code>true</code> if traverses across connected components, otherwise * <code>false</code>. */ @Override public boolean isCrossComponentTraversal() { return crossComponentTraversal; } /** * Adds the specified traversal listener to this iterator. * * @param passenger the traversal listener to be added. */ @Override public void addTraveller(Traveller<V, E> passenger) { //if (!passengers.contains(passenger)) { travellers.add(passenger); //} } /** * {@inheritDoc} */ @Override public void remove() { throw new UnsupportedOperationException(); } /** * Removes the specified traversal listener from this iterator. * * @param l the traversal listener to be removed. */ @Override public void removeTraveller(Traveller<V, E> l) { travellers.remove(l); } /** * Informs all listeners that the traversal of the current connected component finished. * * @param e the connected component finished event. */ protected void fireConnectedComponentFinished(ObjectIntPair e) { for (int i = 0, passengersSize = travellers.size(); i < passengersSize; i++) { travellers.get(i).componentExit(e); } } /** * Informs all listeners that the traversal of the current connected component finished. * * @param e the connected component finished event. */ protected void fireConnectedComponentStarted(ObjectIntPair e) { for (int i = 0, passengersSize = travellers.size(); i < passengersSize; i++) { travellers.get(i).componentEnter(e); } } boolean hasTravellers() { return !travellers.isEmpty(); } /** * Informs all listeners that a the specified edge was visited. * * @param e the edge traversal event. */ protected void fireEdgeTraversed(V s, E e, V t) { for (int i = 0, passengersSize = travellers.size(); i < passengersSize; i++) { travellers.get(i).edge(s, e, t); } } /** * Informs all listeners that a the specified vertex was visited. * * @param e the vertex traversal event. */ protected void fireVertexEnter(@Nullable Pair<V, E> incoming, V v) { for (int i = 0, passengersSize = travellers.size(); i < passengersSize; i++) { travellers.get(i).vertexEnter(incoming, v); } } /** * Informs all listeners that a the specified vertex was finished. * * @param e the vertex traversal event. */ protected void fireVertexFinished(V v) { for (int i = 0, passengersSize = travellers.size(); i < passengersSize; i++) { travellers.get(i).vertexExit(v); } } // ------------------------------------------------------------------------- // /** // * Creates directed/undirected graph specifics according to the provided graph - // * directed/undirected, respectively. // * // * @param g the graph to create specifics for // * @return the created specifics // */ // static <V, E> Specifics<V, E> createGraphSpecifics(Graph<V, E> g) { // if (g instanceof DirectedGraph<?, ?>) { // return new DirectedSpecifics<>((DirectedGraph<V, E>) g); // } else { // return new UndirectedSpecifics<>(g); // } // } // /** // * Provides unified interface for operations that are different in directed graphs and in // * undirected graphs. // */ // abstract static class Specifics<VV, EE> { // /** // * Returns the edges outgoing from the specified vertex in case of directed graph, and the // * edge touching the specified vertex in case of undirected graph. // * // * @param vertex the vertex whose outgoing edges are to be returned. // * @return the edges outgoing from the specified vertex in case of directed graph, and the // * edge touching the specified vertex in case of undirected graph. // */ // public abstract Set<? extends EE> edgesOf(VV vertex); // } // /** // * An implementation of {@link Specifics} for a directed graph. // */ // static class DirectedSpecifics<VV, EE> // extends Specifics<VV, EE> { // private DirectedGraph<VV, EE> graph; // // /** // * Creates a new DirectedSpecifics object. // * // * @param g the graph for which this specifics object to be created. // */ // public DirectedSpecifics(DirectedGraph<VV, EE> g) { // graph = g; // } // // /** // * @see CrossComponentIterator.Specifics#edgesOf(Object) // */ // @Override // public Set<? extends EE> edgesOf(VV vertex) { // return graph.outgoingEdgesOf(vertex); // } // } // /** // * An implementation of {@link Specifics} in which edge direction (if any) is ignored. // */ // static class UndirectedSpecifics<VV, EE> // extends Specifics<VV, EE> { // private Graph<VV, EE> graph; // // /** // * Creates a new UndirectedSpecifics object. // * // * @param g the graph for which this specifics object to be created. // */ // public UndirectedSpecifics(Graph<VV, EE> g) { // graph = g; // } // // /** // * @see CrossComponentIterator.Specifics#edgesOf(Object) // */ // @Override // public Set<EE> edgesOf(VV vertex) { // return graph.edgesOf(vertex); // } // } }