Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java
41161 views
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
56
public Set<T> adjacentNodes(T u) {
57
return edges.get(u);
58
}
59
60
public boolean contains(T u) {
61
return nodes.contains(u);
62
}
63
64
public Set<Edge<T>> edgesFrom(T u) {
65
return edges.get(u).stream()
66
.map(v -> new Edge<T>(u, v))
67
.collect(Collectors.toSet());
68
}
69
70
/**
71
* Returns a new Graph after transitive reduction
72
*/
73
public Graph<T> reduce() {
74
Builder<T> builder = new Builder<>();
75
nodes.stream()
76
.forEach(u -> {
77
builder.addNode(u);
78
edges.get(u).stream()
79
.filter(v -> !pathExists(u, v, false))
80
.forEach(v -> builder.addEdge(u, v));
81
});
82
return builder.build();
83
}
84
85
/**
86
* Returns a new Graph after transitive reduction. All edges in
87
* the given g takes precedence over this graph.
88
*
89
* @throw IllegalArgumentException g must be a subgraph this graph
90
*/
91
public Graph<T> reduce(Graph<T> g) {
92
boolean subgraph = nodes.containsAll(g.nodes) &&
93
g.edges.keySet().stream()
94
.allMatch(u -> adjacentNodes(u).containsAll(g.adjacentNodes(u)));
95
if (!subgraph) {
96
throw new IllegalArgumentException(g + " is not a subgraph of " + this);
97
}
98
99
Builder<T> builder = new Builder<>();
100
nodes.stream()
101
.forEach(u -> {
102
builder.addNode(u);
103
// filter the edge if there exists a path from u to v in the given g
104
// or there exists another path from u to v in this graph
105
edges.get(u).stream()
106
.filter(v -> !g.pathExists(u, v) && !pathExists(u, v, false))
107
.forEach(v -> builder.addEdge(u, v));
108
});
109
110
// add the overlapped edges from this graph and the given g
111
g.edges().keySet().stream()
112
.forEach(u -> g.adjacentNodes(u).stream()
113
.filter(v -> isAdjacent(u, v))
114
.forEach(v -> builder.addEdge(u, v)));
115
return builder.build().reduce();
116
}
117
118
/**
119
* Returns nodes sorted in topological order.
120
*/
121
public Stream<T> orderedNodes() {
122
TopoSorter<T> sorter = new TopoSorter<>(this);
123
return sorter.result.stream();
124
}
125
126
/**
127
* Traverse this graph and performs the given action in topological order
128
*/
129
public void ordered(Consumer<T> action) {
130
TopoSorter<T> sorter = new TopoSorter<>(this);
131
sorter.ordered(action);
132
}
133
134
/**
135
* Traverses this graph and performs the given action in reverse topological order
136
*/
137
public void reverse(Consumer<T> action) {
138
TopoSorter<T> sorter = new TopoSorter<>(this);
139
sorter.reverse(action);
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);
217
nodes.stream()
218
.forEach(u -> adjacentNodes(u).stream()
219
.forEach(v -> out.format(" %s -> %s%n", u, v)));
220
}
221
222
@Override
223
public String toString() {
224
return nodes.toString();
225
}
226
227
static class Edge<T> {
228
final T u;
229
final T v;
230
Edge(T u, T v) {
231
this.u = u;
232
this.v = v;
233
}
234
235
@Override
236
public String toString() {
237
return String.format("%s -> %s", u, v);
238
}
239
240
@Override
241
public boolean equals(Object o) {
242
if (this == o) return true;
243
if (o == null || !(o instanceof Edge))
244
return false;
245
246
@SuppressWarnings("unchecked")
247
Edge<T> edge = (Edge<T>) o;
248
249
return u.equals(edge.u) && v.equals(edge.v);
250
}
251
252
@Override
253
public int hashCode() {
254
int result = u.hashCode();
255
result = 31 * result + v.hashCode();
256
return result;
257
}
258
}
259
260
static class Builder<T> {
261
final Set<T> nodes = new HashSet<>();
262
final Map<T, Set<T>> edges = new HashMap<>();
263
264
public void addNode(T node) {
265
if (nodes.contains(node)) {
266
return;
267
}
268
nodes.add(node);
269
edges.computeIfAbsent(node, _e -> new HashSet<>());
270
}
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
}
332
333