< prev index next >

src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java

Print this page


   1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.tools.jdeps;
  26 
  27 import java.io.PrintWriter;
  28 import java.lang.module.ModuleDescriptor;
  29 import java.lang.module.ModuleFinder;
  30 import java.lang.module.ModuleReference;
  31 import java.util.Collections;
  32 import java.util.Deque;
  33 import java.util.HashMap;
  34 import java.util.HashSet;
  35 import java.util.LinkedList;
  36 import java.util.Map;
  37 import java.util.Set;
  38 import java.util.function.Consumer;
  39 import java.util.function.Predicate;
  40 import java.util.stream.Collectors;
  41 import java.util.stream.Stream;
  42 
  43 public final class Graph<T> {
  44     private final Set<T> nodes;
  45     private final Map<T, Set<T>> edges;
  46 
  47     public Graph(Set<T> nodes, Map<T, Set<T>> edges) {
  48         this.nodes = Collections.unmodifiableSet(nodes);
  49         this.edges = Collections.unmodifiableMap(edges);
  50     }
  51 
  52     public Set<T> nodes() {
  53         return nodes;
  54     }
  55 
  56     public Map<T, Set<T>> edges() {
  57         return edges;
  58     }
  59 


 144     }
 145 
 146     /**
 147      * Returns a transposed graph from this graph
 148      */
 149     public Graph<T> transpose() {
 150         Builder<T> builder = new Builder<>();
 151         builder.addNodes(nodes);
 152         // reverse edges
 153         edges.keySet().forEach(u -> {
 154             edges.get(u).stream()
 155                 .forEach(v -> builder.addEdge(v, u));
 156         });
 157         return builder.build();
 158     }
 159 
 160     /**
 161      * Returns all nodes reachable from the given set of roots.
 162      */
 163     public Set<T> dfs(Set<T> roots) {
 164         Deque<T> deque = new LinkedList<>(roots);
 165         Set<T> visited = new HashSet<>();
 166         while (!deque.isEmpty()) {
 167             T u = deque.pop();
 168             if (!visited.contains(u)) {
 169                 visited.add(u);
 170                 if (contains(u)) {
 171                     adjacentNodes(u).stream()
 172                         .filter(v -> !visited.contains(v))
 173                         .forEach(deque::push);
 174                 }
 175             }
 176         }
 177         return visited;
 178     }
 179 
 180     private boolean isAdjacent(T u, T v) {
 181         return edges.containsKey(u) && edges.get(u).contains(v);
 182     }
 183 
 184     private boolean pathExists(T u, T v) {
 185         return pathExists(u, v, true);
 186     }
 187 
 188     /**
 189      * Returns true if there exists a path from u to v in this graph.
 190      * If includeAdjacent is false, it returns true if there exists
 191      * another path from u to v of distance > 1
 192      */
 193     private boolean pathExists(T u, T v, boolean includeAdjacent) {
 194         if (!nodes.contains(u) || !nodes.contains(v)) {
 195             return false;
 196         }
 197         if (includeAdjacent && isAdjacent(u, v)) {
 198             return true;
 199         }
 200         Deque<T> stack = new LinkedList<>();
 201         Set<T> visited = new HashSet<>();
 202         stack.push(u);
 203         while (!stack.isEmpty()) {
 204             T node = stack.pop();
 205             if (node.equals(v)) {
 206                 return true;
 207             }
 208             if (!visited.contains(node)) {
 209                 visited.add(node);
 210                 edges.get(node).stream()
 211                      .filter(e -> includeAdjacent || !node.equals(u) || !e.equals(v))
 212                      .forEach(stack::push);
 213             }
 214         }
 215         assert !visited.contains(v);
 216         return false;
 217     }
 218 
 219     public void printGraph(PrintWriter out) {
 220         out.println("graph for " + nodes);


 275 
 276         public void addNodes(Set<T> nodes) {
 277             this.nodes.addAll(nodes);
 278         }
 279 
 280         public void addEdge(T u, T v) {
 281             addNode(u);
 282             addNode(v);
 283             edges.get(u).add(v);
 284         }
 285 
 286         public Graph<T> build() {
 287             return new Graph<T>(nodes, edges);
 288         }
 289     }
 290 
 291     /**
 292      * Topological sort
 293      */
 294     static class TopoSorter<T> {
 295         final Deque<T> result = new LinkedList<>();
 296         final Deque<T> nodes;
 297         final Graph<T> graph;
 298         TopoSorter(Graph<T> graph) {
 299             this.graph = graph;
 300             this.nodes = new LinkedList<>(graph.nodes);
 301             sort();
 302         }
 303 
 304         public void ordered(Consumer<T> action) {
 305             result.iterator().forEachRemaining(action);
 306         }
 307 
 308         public void reverse(Consumer<T> action) {
 309             result.descendingIterator().forEachRemaining(action);
 310         }
 311 
 312         private void sort() {
 313             Deque<T> visited = new LinkedList<>();
 314             Deque<T> done = new LinkedList<>();
 315             T node;
 316             while ((node = nodes.poll()) != null) {
 317                 if (!visited.contains(node)) {
 318                     visit(node, visited, done);
 319                 }
 320             }
 321         }
 322 
 323         private void visit(T node, Deque<T> visited, Deque<T> done) {
 324             if (visited.contains(node)) {
 325                 if (!done.contains(node)) {
 326                     throw new IllegalArgumentException("Cyclic detected: " +
 327                         node + " " + graph.edges().get(node));
 328                 }
 329                 return;
 330             }
 331             visited.add(node);
 332             graph.edges().get(node).stream()
 333                 .forEach(x -> visit(x, visited, done));
 334             done.add(node);
 335             result.addLast(node);
 336         }
 337     }
 338 }
   1 /*
   2  * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.tools.jdeps;
  26 
  27 import java.io.PrintWriter;
  28 import java.util.ArrayDeque;


  29 import java.util.Collections;
  30 import java.util.Deque;
  31 import java.util.HashMap;
  32 import java.util.HashSet;

  33 import java.util.Map;
  34 import java.util.Set;
  35 import java.util.function.Consumer;

  36 import java.util.stream.Collectors;
  37 import java.util.stream.Stream;
  38 
  39 public final class Graph<T> {
  40     private final Set<T> nodes;
  41     private final Map<T, Set<T>> edges;
  42 
  43     public Graph(Set<T> nodes, Map<T, Set<T>> edges) {
  44         this.nodes = Collections.unmodifiableSet(nodes);
  45         this.edges = Collections.unmodifiableMap(edges);
  46     }
  47 
  48     public Set<T> nodes() {
  49         return nodes;
  50     }
  51 
  52     public Map<T, Set<T>> edges() {
  53         return edges;
  54     }
  55 


 140     }
 141 
 142     /**
 143      * Returns a transposed graph from this graph
 144      */
 145     public Graph<T> transpose() {
 146         Builder<T> builder = new Builder<>();
 147         builder.addNodes(nodes);
 148         // reverse edges
 149         edges.keySet().forEach(u -> {
 150             edges.get(u).stream()
 151                 .forEach(v -> builder.addEdge(v, u));
 152         });
 153         return builder.build();
 154     }
 155 
 156     /**
 157      * Returns all nodes reachable from the given set of roots.
 158      */
 159     public Set<T> dfs(Set<T> roots) {
 160         Deque<T> deque = new ArrayDeque<>(roots);
 161         Set<T> visited = new HashSet<>();
 162         while (!deque.isEmpty()) {
 163             T u = deque.pop();
 164             if (!visited.contains(u)) {
 165                 visited.add(u);
 166                 if (contains(u)) {
 167                     adjacentNodes(u).stream()
 168                         .filter(v -> !visited.contains(v))
 169                         .forEach(deque::push);
 170                 }
 171             }
 172         }
 173         return visited;
 174     }
 175 
 176     private boolean isAdjacent(T u, T v) {
 177         return edges.containsKey(u) && edges.get(u).contains(v);
 178     }
 179 
 180     private boolean pathExists(T u, T v) {
 181         return pathExists(u, v, true);
 182     }
 183 
 184     /**
 185      * Returns true if there exists a path from u to v in this graph.
 186      * If includeAdjacent is false, it returns true if there exists
 187      * another path from u to v of distance > 1
 188      */
 189     private boolean pathExists(T u, T v, boolean includeAdjacent) {
 190         if (!nodes.contains(u) || !nodes.contains(v)) {
 191             return false;
 192         }
 193         if (includeAdjacent && isAdjacent(u, v)) {
 194             return true;
 195         }
 196         Deque<T> stack = new ArrayDeque<>();
 197         Set<T> visited = new HashSet<>();
 198         stack.push(u);
 199         while (!stack.isEmpty()) {
 200             T node = stack.pop();
 201             if (node.equals(v)) {
 202                 return true;
 203             }
 204             if (!visited.contains(node)) {
 205                 visited.add(node);
 206                 edges.get(node).stream()
 207                      .filter(e -> includeAdjacent || !node.equals(u) || !e.equals(v))
 208                      .forEach(stack::push);
 209             }
 210         }
 211         assert !visited.contains(v);
 212         return false;
 213     }
 214 
 215     public void printGraph(PrintWriter out) {
 216         out.println("graph for " + nodes);


 271 
 272         public void addNodes(Set<T> nodes) {
 273             this.nodes.addAll(nodes);
 274         }
 275 
 276         public void addEdge(T u, T v) {
 277             addNode(u);
 278             addNode(v);
 279             edges.get(u).add(v);
 280         }
 281 
 282         public Graph<T> build() {
 283             return new Graph<T>(nodes, edges);
 284         }
 285     }
 286 
 287     /**
 288      * Topological sort
 289      */
 290     static class TopoSorter<T> {
 291         final Deque<T> result = new ArrayDeque<>();

 292         final Graph<T> graph;
 293         TopoSorter(Graph<T> graph) {
 294             this.graph = graph;

 295             sort();
 296         }
 297 
 298         public void ordered(Consumer<T> action) {
 299             result.iterator().forEachRemaining(action);
 300         }
 301 
 302         public void reverse(Consumer<T> action) {
 303             result.descendingIterator().forEachRemaining(action);
 304         }
 305 
 306         private void sort() {
 307             Set<T> visited = new HashSet<>();
 308             Set<T> done = new HashSet<>();
 309             for (T node : graph.nodes()) {

 310                 if (!visited.contains(node)) {
 311                     visit(node, visited, done);
 312                 }
 313             }
 314         }
 315 
 316         private void visit(T node, Set<T> visited, Set<T> done) {
 317             if (visited.contains(node)) {
 318                 if (!done.contains(node)) {
 319                     throw new IllegalArgumentException("Cyclic detected: " +
 320                         node + " " + graph.edges().get(node));
 321                 }
 322                 return;
 323             }
 324             visited.add(node);
 325             graph.edges().get(node).stream()
 326                  .forEach(x -> visit(x, visited, done));
 327             done.add(node);
 328             result.addLast(node);
 329         }
 330     }
 331 }
< prev index next >