/* * 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.Iterator; import java.util.NoSuchElementException; import java.util.Set; /** * Convenience class representing a digraph with zero or one vertex and an optional loop edge. * Vertex as well as edge <code>null</code> is forbidden. * @author beck * * @param <V> vertex type * @param <E> edge type */ public class TrivialDigraph<V,E> implements DoubledDigraph<V,E> { /** * Answer a factory which creates empty trivial digraphs. * @param <V> vertex type * @param <E> edge type * @return trivial digraph factory */ public static <V,E> DigraphFactory<TrivialDigraph<V,E>> getDigraphFactory() { return new DigraphFactory<TrivialDigraph<V,E>>() { @Override public TrivialDigraph<V,E> create() { return new TrivialDigraph<V,E>(); } }; } private V vertex; private E loop; public TrivialDigraph() { } public TrivialDigraph(V vertex) { this(vertex, null); } public TrivialDigraph(V vertex, E loop) { this.vertex = vertex; this.loop = loop; } /** * @throws UnsupportedOperationException if adding the vertex would result in having 2 vertices in the graph * @throws IllegalArgumentException if <code>vertex == null</code> */ @Override public boolean add(V vertex) { if (vertex == null) { throw new IllegalArgumentException("Cannot add vertex null!"); } if (this.vertex == null) { this.vertex = vertex; return true; } if (this.vertex.equals(vertex)) { return false; } throw new UnsupportedOperationException("TrivialDigraph must contain at most one vertex!"); } @Override public boolean contains(Object source, Object target) { return vertex != null && loop != null && vertex.equals(source) && vertex.equals(target); } @Override public boolean contains(Object vertex) { return this.vertex != null && this.vertex.equals(vertex); } @Override public E get(Object source, Object target) { return contains(source, target) ? loop : null; } @Override public int getInDegree(Object vertex) { return loop == null ? 0 : 1; } @Override public int getOutDegree(Object vertex) { return loop == null ? 0 : 1; } @Override public int getEdgeCount() { return loop == null ? 0 : 1; } @Override public int getVertexCount() { return vertex == null ? 0 : 1; } @Override public Iterable<V> vertices() { if (vertex == null) { return Collections.emptyList(); } return new Iterable<V>() { @Override public Iterator<V> iterator() { return new Iterator<V>() { boolean hasNext = true; @Override public boolean hasNext() { return hasNext; } @Override public V next() { if (hasNext) { hasNext = false; return vertex; } throw new NoSuchElementException("No more vertices"); } @Override public void remove() { if (hasNext) { throw new IllegalStateException(); } TrivialDigraph.this.remove(vertex); } }; } @Override public String toString() { return "[" + vertex + "]"; } }; } @Override public E put(V source, V target, E edge) { if (edge == null) { throw new IllegalArgumentException("Cannot add edge null!"); } if (source != target) { throw new UnsupportedOperationException("TrivialDigraph must not contain no-loop edges!"); } E result = loop; add(source); loop = edge; return result; } @Override public E remove(V source, V target) { if (contains(source, target)) { E result = loop; loop = null; return result; } return null; } @Override public boolean remove(V vertex) { if (this.vertex != null && this.vertex.equals(vertex)) { this.vertex = null; loop = null; return true; } return false; } @Override public void removeAll(Collection<V> vertices) { if (vertices.contains(vertex)) { remove(vertex); } } @Override public DoubledDigraph<V,E> reverse() { return this; } @Override public Digraph<V, E> subgraph(Set<V> vertices) { return vertex != null && vertices.contains(vertex) ? this : Digraphs.<V,E>emptyDigraph(); } @Override public Iterable<V> sources(Object target) { return targets(target); } @Override public Iterable<V> targets(Object source) { if (loop == null || vertex == null || !vertex.equals(source)) { return Collections.emptyList(); } return new Iterable<V>() { @Override public Iterator<V> iterator() { return new Iterator<V>() { boolean hasNext = true; @Override public boolean hasNext() { return hasNext; } @Override public V next() { if (hasNext) { hasNext = false; return vertex; } throw new NoSuchElementException("No more vertices"); } @Override public void remove() { if (hasNext) { throw new IllegalStateException(); } TrivialDigraph.this.remove(vertex, vertex); } }; } @Override public String toString() { return "[" + vertex + "]"; } }; } @Override public boolean isAcyclic() { return loop == null; } }