blob: dda6c118c07a6b78d461d567507b52d6986cab3d [file] [log] [blame]
dpbe8d79aa2018-03-19 07:28:13 -07001/*
2 * Copyright (C) 2018 The Dagger Authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package dagger.internal.codegen;
18
dpb43e0c4a2018-08-13 07:12:24 -070019import static com.google.common.collect.Sets.difference;
20import static com.google.common.graph.Graphs.reachableNodes;
21
dpbe8d79aa2018-03-19 07:28:13 -070022import com.google.common.collect.ImmutableList;
23import com.google.common.collect.ImmutableSet;
dpb43e0c4a2018-08-13 07:12:24 -070024import com.google.common.graph.Graph;
dpbe8d79aa2018-03-19 07:28:13 -070025import com.google.common.graph.SuccessorsFunction;
26import java.util.ArrayDeque;
27import java.util.HashMap;
28import java.util.Map;
29import java.util.Queue;
30import java.util.Set;
31
32/** Utility methods for {@link com.google.common.graph} types. */
dpb916356a2018-11-26 13:44:17 -080033public final class DaggerGraphs {
dpbe8d79aa2018-03-19 07:28:13 -070034 /**
35 * Returns a shortest path from {@code nodeU} to {@code nodeV} in {@code graph} as a list of the
36 * nodes visited in sequence, including both {@code nodeU} and {@code nodeV}. (Note that there may
37 * be many possible shortest paths.)
38 *
39 * <p>If {@code nodeV} is not {@link
40 * com.google.common.graph.Graphs#reachableNodes(com.google.common.graph.Graph, Object) reachable}
41 * from {@code nodeU}, the list returned is empty.
42 *
43 * @throws IllegalArgumentException if {@code nodeU} or {@code nodeV} is not present in {@code
44 * graph}
45 */
dpb916356a2018-11-26 13:44:17 -080046 public static <N> ImmutableList<N> shortestPath(SuccessorsFunction<N> graph, N nodeU, N nodeV) {
dpbe8d79aa2018-03-19 07:28:13 -070047 if (nodeU.equals(nodeV)) {
48 return ImmutableList.of(nodeU);
49 }
50 Set<N> successors = ImmutableSet.copyOf(graph.successors(nodeU));
51 if (successors.contains(nodeV)) {
52 return ImmutableList.of(nodeU, nodeV);
53 }
54
55 Map<N, N> visitedNodeToPathPredecessor = new HashMap<>(); // encodes shortest path tree
dpbe8d79aa2018-03-19 07:28:13 -070056 for (N node : successors) {
57 visitedNodeToPathPredecessor.put(node, nodeU);
58 }
cgdecker531f1c62018-07-11 12:01:39 -070059 Queue<N> currentNodes = new ArrayDeque<N>(successors);
60 Queue<N> nextNodes = new ArrayDeque<N>();
dpbe8d79aa2018-03-19 07:28:13 -070061
62 // Perform a breadth-first traversal starting with the successors of nodeU.
63 while (!currentNodes.isEmpty()) {
64 while (!currentNodes.isEmpty()) {
65 N currentNode = currentNodes.remove();
66 for (N nextNode : graph.successors(currentNode)) {
67 if (visitedNodeToPathPredecessor.containsKey(nextNode)) {
68 continue; // we already have a shortest path to nextNode
69 }
70 visitedNodeToPathPredecessor.put(nextNode, currentNode);
71 if (nextNode.equals(nodeV)) {
72 ImmutableList.Builder<N> builder = ImmutableList.builder();
73 N node = nodeV;
74 builder.add(node);
75 while (!node.equals(nodeU)) {
76 node = visitedNodeToPathPredecessor.get(node);
77 builder.add(node);
78 }
79 return builder.build().reverse();
80 }
81 nextNodes.add(nextNode);
82 }
83 }
84 Queue<N> emptyQueue = currentNodes;
85 currentNodes = nextNodes;
86 nextNodes = emptyQueue; // reusing empty queue faster than allocating new one
87 }
88
89 return ImmutableList.of();
90 }
91
dpb43e0c4a2018-08-13 07:12:24 -070092 /** Returns the nodes in a graph that are not reachable from a node. */
dpb916356a2018-11-26 13:44:17 -080093 public static <N> ImmutableSet<N> unreachableNodes(Graph<N> graph, N node) {
dpb43e0c4a2018-08-13 07:12:24 -070094 return ImmutableSet.copyOf(difference(graph.nodes(), reachableNodes(graph, node)));
95 }
96
dpbe8d79aa2018-03-19 07:28:13 -070097 private DaggerGraphs() {}
98}