/*
* Copyright 2012 Odysseus Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.odysseus.ithaka.digraph;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Map-based directed graph implementation.
*
* @param <V> vertex type
* @param <E> edge type
*/
public class MapDigraph<V, E> implements Digraph<V, E> {
/**
* Factory creating default <code>MapDigraph</code>.
* @return map digraph factory
*/
public static <V, E> DigraphFactory<MapDigraph<V, E>> getDefaultDigraphFactory() {
return getMapDigraphFactory(MapDigraph.<V,E>getDefaultVertexMapFactory(null), MapDigraph.<V,E>getDefaultEdgeMapFactory(null));
}
/**
* Factory creating <code>MapDigraph</code>.
* @param vertexMapFactory factory to create vertex --> edge-map maps
* @param edgeMapFactory factory to create edge-target --> edge-value maps
* @return map digraph factory
*/
public static <V, E> DigraphFactory<MapDigraph<V, E>> getMapDigraphFactory(
final VertexMapFactory<V, E> vertexMapFactory,
final EdgeMapFactory<V, E> edgeMapFactory) {
return new DigraphFactory<MapDigraph<V, E>>() {
@Override
public MapDigraph<V, E> create() {
return new MapDigraph<V, E>(vertexMapFactory, edgeMapFactory);
}
};
}
/**
* Vertex map factory (vertex to edge map).
*/
public static interface VertexMapFactory<V, E> {
public Map<V, Map<V, E>> create();
}
/**
* Edge map factory (edge target to edge value).
*/
public static interface EdgeMapFactory<V, E> {
public Map<V, E> create(V source);
}
private static final <V, E> VertexMapFactory<V, E> getDefaultVertexMapFactory(final Comparator<? super V> comparator) {
return new VertexMapFactory<V, E>() {
@Override
public Map<V, Map<V, E>> create() {
if (comparator == null) {
return new LinkedHashMap<V, Map<V, E>>(16);
} else {
return new TreeMap<V, Map<V, E>>(comparator);
}
}
};
};
private static final <V, E> EdgeMapFactory<V, E> getDefaultEdgeMapFactory(final Comparator<? super V> comparator) {
return new EdgeMapFactory<V, E>() {
@Override
public Map<V, E> create(V ignore) {
if (comparator == null) {
return new LinkedHashMap<V, E>(16);
} else {
return new TreeMap<V, E>(comparator);
}
}
};
};
private final VertexMapFactory<V, E> vertexMapFactory;
private final EdgeMapFactory<V, E> edgeMapFactory;
private final Map<V, Map<V, E>> vertexMap;
private int edgeCount;
/**
* Create digraph.
* {@link HashMap}s will be used as vertex/edge maps.
* Vertices and edge targets will be iterated in no particular order.
*/
public MapDigraph() {
this(null);
}
/**
* Create digraph.
* If a vertex comparator is given, {@link TreeMap}s will be used as vertex/edge maps.
* Vertices and edge targets will be iterated in the order given by the comparator.
* @param comparator vertex comparator (may be <code>null</code>)
*/
public MapDigraph(final Comparator<? super V> comparator) {
this(comparator, comparator);
}
/**
* Create digraph.
* If a vertex comparator is given, {@link TreeMap}s will be used as vertex maps
* and vertices will be iterated in the order given by the vertex comparator.
* If an edge comparator is given, {@link TreeMap}s will be used as edge maps
* and edge targets will be iterated in the order given by the edge comparator.
* @param vertexComparator
* @param edgeComparator
*/
public MapDigraph(final Comparator<? super V> vertexComparator, final Comparator<? super V> edgeComparator) {
this(MapDigraph.<V, E> getDefaultVertexMapFactory(vertexComparator), MapDigraph.<V, E> getDefaultEdgeMapFactory(edgeComparator));
}
/**
* Create digraph.
* @param vertexMapFactory factory to create vertex --> edge-map maps
* @param edgeMapFactory factory to create edge-target --> edge-value maps
*/
public MapDigraph(VertexMapFactory<V, E> vertexMapFactory, EdgeMapFactory<V, E> edgeMapFactory) {
this.vertexMapFactory = vertexMapFactory;
this.edgeMapFactory = edgeMapFactory;
vertexMap = vertexMapFactory.create();
}
@Override
public boolean add(V vertex) {
if (!vertexMap.containsKey(vertex)) {
vertexMap.put(vertex, Collections.<V, E> emptyMap());
return true;
}
return false;
}
@Override
public E put(V source, V target, E edge) {
Map<V, E> edgeMap = vertexMap.get(source);
if (edgeMap == null || edgeMap.isEmpty()) {
vertexMap.put(source, edgeMap = edgeMapFactory.create(source));
}
E result = edgeMap.put(target, edge);
if (result == null) {
add(target);
edgeCount++;
}
return result;
}
@Override
public E get(Object source, Object target) {
Map<V, E> edgeMap = vertexMap.get(source);
if (edgeMap == null) {
return null;
}
return edgeMap.get(target);
}
@Override
public E remove(V source, V target) {
Map<V, E> edgeMap = vertexMap.get(source);
if (edgeMap == null || !edgeMap.containsKey(target)) {
return null;
}
E result = edgeMap.remove(target);
edgeCount--;
if (edgeMap.isEmpty()) {
vertexMap.put(source, Collections.<V, E> emptyMap());
}
return result;
}
@Override
public boolean remove(V vertex) {
Map<V, E> edgeMap = vertexMap.get(vertex);
if (edgeMap == null) {
return false;
}
edgeCount -= edgeMap.size();
vertexMap.remove(vertex);
for (V source : vertexMap.keySet()) {
remove(source, vertex);
}
return true;
}
@Override
public void removeAll(Collection<V> vertices) {
for (V vertex : vertices) {
Map<V, E> edgeMap = vertexMap.get(vertex);
if (edgeMap != null) {
edgeCount -= edgeMap.size();
vertexMap.remove(vertex);
}
}
for (V source : vertexMap.keySet()) {
Map<V, E> edgeMap = vertexMap.get(source);
Iterator<V> iter = edgeMap.keySet().iterator();
while (iter.hasNext()) {
if (vertices.contains(iter.next())) {
iter.remove();
edgeCount--;
}
}
if (edgeMap.isEmpty()) {
vertexMap.put(source, Collections.<V, E> emptyMap());
}
}
}
@Override
public boolean contains(Object source, Object target) {
Map<V, E> edgeMap = vertexMap.get(source);
if (edgeMap == null) {
return false;
}
return edgeMap.containsKey(target);
}
@Override
public boolean contains(Object vertex) {
return vertexMap.containsKey(vertex);
}
@Override
public Iterable<V> vertices() {
if (vertexMap.isEmpty()) {
return Collections.emptySet();
}
return new Iterable<V>() {
@Override
public Iterator<V> iterator() {
return new Iterator<V>() {
Iterator<V> delegate = vertexMap.keySet().iterator();
V vertex = null;
@Override
public boolean hasNext() {
return delegate.hasNext();
}
@Override
public V next() {
return vertex = delegate.next();
}
@Override
public void remove() {
Map<V, E> edgeMap = vertexMap.get(vertex);
delegate.remove();
edgeCount -= edgeMap.size();
for (V source : vertexMap.keySet()) {
MapDigraph.this.remove(source, vertex);
}
}
};
}
@Override
public String toString() {
return vertexMap.keySet().toString();
}
};
}
@Override
public Iterable<V> targets(final Object source) {
final Map<V, E> edgeMap = vertexMap.get(source);
if (edgeMap == null || edgeMap.isEmpty()) {
return Collections.emptySet();
}
return new Iterable<V>() {
@Override
public Iterator<V> iterator() {
return new Iterator<V>() {
Iterator<V> delegate = edgeMap.keySet().iterator();
@Override
public boolean hasNext() {
return delegate.hasNext();
}
@Override
public V next() {
return delegate.next();
}
@Override
public void remove() {
delegate.remove();
edgeCount--;
if (edgeMap.isEmpty()) {
@SuppressWarnings("unchecked")
V v = (V) source;
vertexMap.put(v, Collections.<V, E> emptyMap());
}
}
};
}
@Override
public String toString() {
return edgeMap.keySet().toString();
}
};
}
@Override
public int getVertexCount() {
return vertexMap.size();
}
@Override
public int getOutDegree(Object vertex) {
Map<V, E> edgeMap = vertexMap.get(vertex);
if (edgeMap == null) {
return 0;
}
return edgeMap.size();
}
@Override
public int getEdgeCount() {
return edgeCount;
}
public DigraphFactory<? extends MapDigraph<V, E>> getDigraphFactory() {
return new DigraphFactory<MapDigraph<V, E>>() {
@Override
public MapDigraph<V, E> create() {
return new MapDigraph<V, E>(vertexMapFactory, edgeMapFactory);
}
};
}
@Override
public MapDigraph<V, E> reverse() {
return Digraphs.<V, E, MapDigraph<V, E>> reverse(this, getDigraphFactory());
}
@Override
public MapDigraph<V, E> subgraph(Set<V> vertices) {
return Digraphs.<V, E, MapDigraph<V, E>> subgraph(this, vertices, getDigraphFactory());
}
@Override
public boolean isAcyclic() {
return Digraphs.isAcyclic(this);
}
@Override
public String toString() {
StringBuffer b = new StringBuffer();
b.append(getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1));
b.append("(");
Iterator<V> vertices = vertices().iterator();
while (vertices.hasNext()) {
V v = vertices.next();
b.append(v);
b.append(targets(v));
if (vertices.hasNext()) {
b.append(", ");
if (b.length() > 1000) {
b.append("...");
break;
}
}
}
b.append(")");
return b.toString();
}
}