/* * DirectedGraph.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.core.client; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.rstudio.core.client.container.SafeMap; public class DirectedGraph<K, V> { public interface DefaultConstructor<R> { public R create(); } public interface ForEachNodeCommand<K, V> { public boolean continueExecution(DirectedGraph<K, V> node); } public DirectedGraph() { this(null, null, null, null); } public DirectedGraph(V value) { this(null, null, value, null); } public DirectedGraph(DefaultConstructor<V> constructor) { this(null, null, null, constructor); } public DirectedGraph(V value, DefaultConstructor<V> constructor) { this(null, null, value, constructor); } private DefaultConstructor<V> createNullDefaultConstructor() { return new DefaultConstructor<V>() { @Override public V create() { return null; } }; } private DirectedGraph(DirectedGraph<K, V> parent, K key, V value, DefaultConstructor<V> constructor) { parent_ = parent; children_ = new SafeMap<K, DirectedGraph<K, V>>(); key_ = key; constructor_ = constructor == null ? createNullDefaultConstructor() : constructor; value_ = value == null ? constructor_.create() : value; } public DirectedGraph<K, V> ensureNode(K key) { return ensureChild(key); } public DirectedGraph<K, V> ensureNode(Collection<K> keys) { DirectedGraph<K, V> node = this; for (K key : keys) node = node.ensureChild(key); return node; } public DirectedGraph<K, V> findNode(K key) { return getChild(key); } public DirectedGraph<K, V> findNode(Collection<K> keys) { DirectedGraph<K, V> node = this; for (K key : keys) { if (!node.hasChild(key)) return null; node = node.getChild(key); } return node; } private DirectedGraph<K, V> addChild(K key) { DirectedGraph<K, V> child = new DirectedGraph<K, V>(this, key, null, constructor_); children_.put(key, child); return child; } public DirectedGraph<K, V> getChild(K key) { return children_.get(key); } public boolean hasChild(K key) { return children_.containsKey(key); } private DirectedGraph<K, V> ensureChild(K key) { if (hasChild(key)) return getChild(key); else return addChild(key); } public List<Pair<List<K>, V>> flatten() { List<Pair<List<K>, V>> list = new ArrayList<Pair<List<K>, V>>(); List<K> keys = new ArrayList<K>(); fillRecursive(list, keys, this); return list; } private static <K, V> void fillRecursive(List<Pair<List<K>, V>> list, List<K> keys, DirectedGraph<K, V> node) { keys.add(node.getKey()); list.add(new Pair<List<K>, V>(new ArrayList<K>(keys), node.getValue())); for (Map.Entry<K, DirectedGraph<K, V>> entry : node.getChildren().entrySet()) fillRecursive(list, keys, entry.getValue()); } public List<K> getKeyChain() { List<K> chain = new ArrayList<K>(); DirectedGraph<K, V> node = this; while (!node.isRoot()) { chain.add(node.getKey()); node = node.getParent(); } Collections.reverse(chain); return chain; } public void forEachNode(ForEachNodeCommand<K, V> command) { forEachNodeImpl(this, command); } private static <K, V> void forEachNodeImpl( DirectedGraph<K, V> node, ForEachNodeCommand<K, V> command) { if (!command.continueExecution(node)) return; for (Map.Entry<K, DirectedGraph<K, V>> entry : node.getChildren().entrySet()) forEachNodeImpl(entry.getValue(), command); } // Simple getters, setters ---- public V getValue() { return value_; } public void setValue(V value) { value_ = value; } public K getKey() { return key_; } public DirectedGraph<K, V> getParent() { return parent_; } public SafeMap<K, DirectedGraph<K, V>> getChildren() { return children_; } public boolean isRoot() { return parent_ == null; } // Private members ---- private final DirectedGraph<K, V> parent_; private final SafeMap<K, DirectedGraph<K, V>> children_; private final K key_; private V value_; private DefaultConstructor<V> constructor_; }