/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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 com.asakusafw.utils.graph;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* An implementation of {@link Graph} which uses {@link HashMap} in the internal storage.
* @param <V> the vertex value type
*/
public class HashGraph<V> implements Graph<V> {
private final HashMap<V, HashVertex<V>> entity = new HashMap<>();
@Override
public void addEdge(V from, V to) {
HashVertex<V> vertex = prepare(from);
prepare(to);
vertex.to.add(to);
}
@Override
public void addEdges(V from, Collection<? extends V> to) {
if (to == null) {
throw new IllegalArgumentException("to must not be null"); //$NON-NLS-1$
}
HashVertex<V> vertex = prepare(from);
for (V v : to) {
prepare(v);
vertex.to.add(v);
}
}
@Override
public void addNode(V node) {
prepare(node);
}
@Override
public void clear() {
entity.clear();
}
@Override
public boolean contains(Object node) {
return entity.containsKey(node);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
HashGraph<?> other = (HashGraph<?>) obj;
if ((this.entity.equals(other.entity)) == false) {
return false;
}
return true;
}
@Override
public Set<V> getConnected(Object key) {
HashVertex<V> vertex = entity.get(key);
if (vertex != null) {
return vertex.to;
}
return Collections.emptySet();
}
@Override
public Set<V> getNodeSet() {
return entity.keySet();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + this.entity.hashCode();
return result;
}
@Override
public boolean isConnected(Object from, Object to) {
HashVertex<V> vertex = entity.get(from);
if (vertex == null) {
return false;
}
return vertex.to.contains(to);
}
@Override
public boolean isEmpty() {
return entity.isEmpty();
}
@Override
public Iterator<Graph.Vertex<V>> iterator() {
return new IteratorWrapper<>(entity.values().iterator());
}
@Override
public void removeEdge(Object from, Object to) {
HashVertex<V> vertex = entity.get(from);
if (vertex != null) {
vertex.to.remove(to);
}
}
@Override
public void removeNode(Object node) {
if (entity.remove(node) == null) {
return;
}
for (HashVertex<V> vertex : entity.values()) {
vertex.to.remove(node);
}
}
@Override
public void removeNodes(Collection<?> nodes) {
if (nodes == null) {
throw new IllegalArgumentException("nodes must not be null"); //$NON-NLS-1$
}
if (entity.keySet().removeAll(nodes) == false) {
return;
}
for (HashVertex<V> vertex : entity.values()) {
vertex.to.removeAll(nodes);
}
}
@Override
public String toString() {
return entity.values().toString();
}
private HashVertex<V> prepare(V node) {
HashVertex<V> vertex = entity.get(node);
if (vertex == null) {
vertex = new HashVertex<>(node);
entity.put(node, vertex);
}
return vertex;
}
private static class HashVertex<V> implements Vertex<V> {
final V from;
final Set<V> to;
HashVertex(V node) {
this.from = node;
this.to = new HashSet<>();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
HashVertex<?> other = (HashVertex<?>) obj;
if (this.from == null) {
if (other.from != null) {
return false;
}
} else if ((this.from.equals(other.from)) == false) {
return false;
}
if ((this.to.equals(other.to)) == false) {
return false;
}
return true;
}
@Override
public Set<V> getConnected() {
return to;
}
@Override
public V getNode() {
return from;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((from == null) ? 0 : from.hashCode());
result = prime * result + to.hashCode();
return result;
}
@Override
public String toString() {
return MessageFormat.format("{0} => {1}", from, to); //$NON-NLS-1$
}
}
private static final class IteratorWrapper<V> implements Iterator<V> {
private final Iterator<? extends V> iterator;
IteratorWrapper(Iterator<? extends V> iterator) {
assert iterator != null;
this.iterator = iterator;
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public V next() {
return iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
}
}