blob: 8a1eeff16867245ec801b8df6cb28e426f47a2fe [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2015 itemis and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* itemis - Initial API and implementation
*
* </copyright>
*/
package org.eclipse.sphinx.platform.util;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.osgi.util.NLS;
import org.eclipse.sphinx.platform.internal.messages.Messages;
public class DirectedGraph<V> {
private Set<Edge> edges;
private boolean allowLoops;
private boolean allowMultipleEdges;
private DirectedGraphInternal graphInternal;
public DirectedGraph(boolean allowLoops, boolean allowMultipleEdges) {
edges = new HashSet<Edge>();
graphInternal = new DirectedGraphInternal();
this.allowLoops = allowLoops;
this.allowMultipleEdges = allowMultipleEdges;
}
protected boolean assertVertexExist(V vertex) {
if (containsVertex(vertex)) {
return true;
} else if (vertex == null) {
throw new NullPointerException();
} else {
throw new IllegalArgumentException(NLS.bind(Messages.error_NoSuchVertex, vertex));
}
}
public boolean addVertex(V vertex) {
if (vertex == null) {
throw new NullPointerException();
} else if (containsVertex(vertex)) {
return false;
} else {
graphInternal.addVertex(vertex);
return true;
}
}
public boolean containsVertex(V vertex) {
return graphInternal.getVertexSet().contains(vertex);
}
public Set<Edge> outgoingEdgesOf(V vertex) {
return graphInternal.outgoingEdgesOf(vertex);
}
public Set<Edge> incomingEdgesOf(V vertex) {
return graphInternal.incomingEdgesOf(vertex);
}
public int inDegreeOf(V vertex) {
return graphInternal.inDegreeOf(vertex);
}
public int outDegreeOf(V vertex) {
return graphInternal.outDegreeOf(vertex);
}
public Edge addEdge(V srcVertex, V trgtVertex) {
assertVertexExist(srcVertex);
assertVertexExist(trgtVertex);
if (!allowMultipleEdges && containsEdge(srcVertex, trgtVertex)) {
return null;
}
if (!allowLoops && srcVertex.equals(trgtVertex)) {
throw new IllegalArgumentException(Messages.error_LoopsNotAllowed);
}
Edge edge = new Edge(srcVertex, trgtVertex);
if (containsEdge(edge)) {
return null;
} else {
edges.add(edge);
graphInternal.addEdgeToTouchingVertices(edge);
return edge;
}
}
public boolean containsEdge(Edge edge) {
return edges.contains(edge);
}
public boolean containsEdge(V srcVertex, V trgtVertex) {
return getEdge(srcVertex, trgtVertex) != null;
}
public Edge getEdge(V srcVertex, V trgtVertex) {
return graphInternal.getEdge(srcVertex, trgtVertex);
}
public void clear() {
edges.clear();
graphInternal.clear();
}
protected class DirectedGraphInternal {
private Map<V, DirectedEdgeContainer> verticesMap = new LinkedHashMap<V, DirectedEdgeContainer>();
protected void addVertex(V v) {
verticesMap.put(v, null);
}
public Set<V> getVertexSet() {
return verticesMap.keySet();
}
public int inDegreeOf(V vertex) {
return getEdgeContainer(vertex).incomingEdges.size();
}
public Set<Edge> incomingEdgesOf(V vertex) {
return getEdgeContainer(vertex).getUnmodifiableIncomingEdges();
}
public int outDegreeOf(V vertex) {
return getEdgeContainer(vertex).outgoingEdges.size();
}
public Set<Edge> outgoingEdgesOf(V vertex) {
return getEdgeContainer(vertex).getUnmodifiableOutgoingEdges();
}
public void addEdgeToTouchingVertices(Edge edge) {
V source = edge.getSource();
V target = edge.getTarget();
getEdgeContainer(source).addOutgoingEdge(edge);
getEdgeContainer(target).addIncomingEdge(edge);
}
public Edge getEdge(V srcVertex, V trgtVertex) {
if (containsVertex(srcVertex) && containsVertex(trgtVertex)) {
DirectedEdgeContainer edgeContainer = getEdgeContainer(srcVertex);
Iterator<Edge> edgesIterator = edgeContainer.outgoingEdges.iterator();
while (edgesIterator.hasNext()) {
Edge edge = edgesIterator.next();
if (edge.getTarget().equals(trgtVertex)) {
return edge;
}
}
}
return null;
}
private DirectedEdgeContainer getEdgeContainer(V vertex) {
if (getVertexSet().contains(vertex)) {
DirectedEdgeContainer edgeContainer = verticesMap.get(vertex);
if (edgeContainer == null) {
edgeContainer = new DirectedEdgeContainer();
verticesMap.put(vertex, edgeContainer);
}
return edgeContainer;
} else if (vertex == null) {
throw new NullPointerException();
} else {
throw new IllegalArgumentException(NLS.bind(Messages.error_NoSuchVertex, vertex));
}
}
public void clear() {
verticesMap.clear();
}
}
protected class DirectedEdgeContainer {
Set<Edge> incomingEdges;
Set<Edge> outgoingEdges;
private transient Set<Edge> unmodifiableIncoming = null;
private transient Set<Edge> unmodifiableOutgoing = null;
protected DirectedEdgeContainer() {
incomingEdges = new HashSet<Edge>();
outgoingEdges = new HashSet<Edge>();
}
public Set<Edge> getUnmodifiableIncomingEdges() {
if (unmodifiableIncoming == null) {
unmodifiableIncoming = Collections.unmodifiableSet(incomingEdges);
}
return unmodifiableIncoming;
}
public Set<Edge> getUnmodifiableOutgoingEdges() {
if (unmodifiableOutgoing == null) {
unmodifiableOutgoing = Collections.unmodifiableSet(outgoingEdges);
}
return unmodifiableOutgoing;
}
public void addIncomingEdge(Edge edge) {
incomingEdges.add(edge);
}
public void addOutgoingEdge(Edge edge) {
outgoingEdges.add(edge);
}
public void removeIncomingEdge(Edge edge) {
incomingEdges.remove(edge);
}
public void removeOutgoingEdge(Edge edge) {
outgoingEdges.remove(edge);
}
}
public class Edge {
private V sourceVertex;
private V targetVertex;
public Edge(V srcVertex, V trgtVertex) {
sourceVertex = srcVertex;
targetVertex = trgtVertex;
}
public V getSource() {
return sourceVertex;
}
public V getTarget() {
return targetVertex;
}
@Override
public String toString() {
return NLS.bind(Messages.toString_Edge, sourceVertex, targetVertex);
}
}
}