//----------------------------------------------------------------------------//
// //
// B a s i c D i g r a p h //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.graph;
import net.jcip.annotations.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Class {@code BasicDigraph} is a basic implementation of Digraph.
*
* @author Hervé Bitteur
*/
@ThreadSafe
public class BasicDigraph<D extends Digraph<D, V>, V extends Vertex>
implements Digraph<D, V>
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(Digraph.class);
//~ Instance fields --------------------------------------------------------
/** Name of this instance, meant to ease debugging */
private final String name;
/** Related Vertex (sub)class, to create vertices of the proper type */
private final Class<? extends V> vertexClass;
/** All current Vertices of the graph, handled by a map: Id -> Vertex */
private final ConcurrentHashMap<Integer, V> vertices = new ConcurrentHashMap<>();
/** Global id to uniquely identify a vertex */
private final AtomicInteger globalVertexId = new AtomicInteger(0);
//~ Constructors -----------------------------------------------------------
//--------------//
// BasicDigraph //
//--------------//
/**
* Construct a BasicDigraph object.
*
* @param name the distinguished name for this instance
* @param vertexClass precise class to be used when instantiating vertices
*/
public BasicDigraph (String name,
Class<? extends V> vertexClass)
{
if (vertexClass == null) {
throw new IllegalArgumentException("null vertex class");
}
this.name = name;
this.vertexClass = vertexClass;
}
//~ Methods ----------------------------------------------------------------
//-----------//
// addVertex //
//-----------//
@Override
public void addVertex (V vertex)
{
if (vertex == null) {
throw new IllegalArgumentException("Cannot add a null vertex");
}
vertex.setGraph(this); // Unchecked
vertex.setId(globalVertexId.incrementAndGet()); // Atomic increment
vertices.put(vertex.getId(), vertex); // Atomic insertion
}
//--------------//
// createVertex //
//--------------//
@Override
public V createVertex ()
{
V vertex;
try {
vertex = vertexClass.newInstance();
addVertex(vertex);
return vertex;
} catch (NullPointerException ex) {
throw new RuntimeException(
"BasicDigraph cannot create vertex, vertexClass not set");
} catch (InstantiationException ex) {
throw new RuntimeException(
"Cannot createVertex with an abstract class or interface: "
+ vertexClass);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
//------//
// dump //
//------//
@Override
public void dump (String title)
{
if (title != null) {
System.out.println(title);
}
System.out.println(this);
for (V vertex : getVertices()) {
vertex.dump();
}
}
//-----------------//
// getLastVertexId //
//-----------------//
@Override
public int getLastVertexId ()
{
return globalVertexId.get();
}
//---------//
// getName //
//---------//
@Override
public String getName ()
{
return name;
}
//---------------//
// getVertexById //
//---------------//
@Override
public V getVertexById (int id)
{
return vertices.get(id);
}
//----------------//
// getVertexCount //
//----------------//
@Override
public int getVertexCount ()
{
return vertices.size();
}
//-------------//
// getVertices //
//-------------//
@Override
public Collection<V> getVertices ()
{
return Collections.unmodifiableCollection(vertices.values());
}
//--------------//
// removeVertex //
//--------------//
@Override
public void removeVertex (V vertex)
{
logger.debug("remove {}", vertex);
if (vertex == null) {
throw new IllegalArgumentException(
"Trying to remove a null vertex");
}
if (vertices.remove(vertex.getId()) == null) { // Atomic removal
throw new RuntimeException(
"Trying to remove an unknown vertex: " + vertex);
}
}
//---------------//
// restoreVertex //
//---------------//
@Override
public void restoreVertex (V vertex)
{
vertices.put(vertex.getId(), vertex); // Atomic insertion
}
//----------//
// toString //
//----------//
@Override
public String toString ()
{
StringBuilder sb = new StringBuilder();
sb.append("{").append(getClass().getSimpleName());
sb.append(internalsString());
sb.append("}");
return sb.toString();
}
//-----------------//
// internalsString //
//-----------------//
/**
* Return the string of the internals of this class, typically for
* inclusion in a toString.
* The overriding methods should comply with the following rule:
* return either a totally empty string, or a string that begins with
* a " " followed by some content.
*
* @return the string of internals
*/
protected String internalsString ()
{
StringBuilder sb = new StringBuilder(25);
sb.append("#").append(name);
sb.append(" vertices=").append(getVertexCount());
if (this.getClass().getName().equals(Digraph.class.getName())) {
sb.append("}");
}
return sb.toString();
}
}