OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// A library to work with graphs. It contains a couple algorithms, including | 5 /// A library to work with graphs. It contains a couple algorithms, including |
6 /// Tarjan's algorithm to compute strongest connected components in a graph and | 6 /// Tarjan's algorithm to compute strongly connected components in a graph and |
7 /// Cooper et al's dominator algorithm. | 7 /// Cooper et al's dominator algorithm. |
8 /// | 8 /// |
9 /// Portions of the code in this library was adapted from | 9 /// Portions of the code in this library was adapted from |
10 /// `package:analyzer/src/generated/collection_utilities.dart`. | 10 /// `package:analyzer/src/generated/collection_utilities.dart`. |
11 // TODO(sigmund): move this into a shared place, like quiver? | 11 // TODO(sigmund): move this into a shared place, like quiver? |
12 library dart2js_info.src.graph; | 12 library dart2js_info.src.graph; |
13 | 13 |
14 import 'dart:math' as math; | 14 import 'dart:math' as math; |
15 | 15 |
16 abstract class Graph<N> { | 16 abstract class Graph<N> { |
(...skipping 17 matching lines...) Expand all Loading... |
34 Set<N> seen = new Set<N>(); | 34 Set<N> seen = new Set<N>(); |
35 bool helper(N node) { | 35 bool helper(N node) { |
36 if (identical(node, target)) return true; | 36 if (identical(node, target)) return true; |
37 if (!seen.add(node)) return false; | 37 if (!seen.add(node)) return false; |
38 return targetsOf(node).any(helper); | 38 return targetsOf(node).any(helper); |
39 } | 39 } |
40 return helper(source); | 40 return helper(source); |
41 } | 41 } |
42 | 42 |
43 /// Returns all nodes reachable from [root] in post order. | 43 /// Returns all nodes reachable from [root] in post order. |
44 List<N> postOrder(N root) { | 44 Iterable<N> postOrder(N root) sync* { |
45 var seen = new Set<N>(); | 45 var seen = new Set<N>(); |
46 var result = <N>[]; | 46 Iterable<N> helper(n) sync* { |
47 helper(n) { | |
48 if (!seen.add(n)) return; | 47 if (!seen.add(n)) return; |
49 targetsOf(n).forEach(helper); | 48 for (var x in targetsOf(n)) { |
50 result.add(n); | 49 yield* helper(x); |
| 50 } |
| 51 yield n; |
51 } | 52 } |
52 helper(root); | 53 yield* helper(root); |
53 return result; | |
54 } | 54 } |
55 | 55 |
56 /// Return a list of nodes that form a cycle containing the given node. If the | 56 /// Returns an iterable of all nodes reachable from [root] in preorder. |
57 /// node is not part of a cycle in this graph, then a list containing only the | 57 Iterable<N> preOrder(N root) sync* { |
58 /// node itself will be returned. | 58 var seen = new Set<N>(); |
| 59 var stack = <N>[root]; |
| 60 while (stack.isNotEmpty) { |
| 61 var next = stack.removeLast(); |
| 62 if (!seen.contains(next)) { |
| 63 seen.add(next); |
| 64 yield next; |
| 65 stack.addAll(targetsOf(next)); |
| 66 } |
| 67 } |
| 68 } |
| 69 |
| 70 /// Returns a list of nodes that form a cycle containing the given node. If |
| 71 /// the node is not part of a cycle in this graph, then a list containing only |
| 72 /// the node itself will be returned. |
59 List<N> findCycleContaining(N node) { | 73 List<N> findCycleContaining(N node) { |
60 assert(node != null); | 74 assert(node != null); |
61 _SccFinder<N> finder = new _SccFinder<N>(this); | 75 _SccFinder<N> finder = new _SccFinder<N>(this); |
62 return finder._componentContaining(node); | 76 return finder._componentContaining(node); |
63 } | 77 } |
64 | 78 |
65 /// Returns a dominator tree starting from root. This is a new graph, with the | 79 /// Returns a dominator tree starting from root. This is a new graph, with the |
66 /// same nodes as this graph, but where edges exist between a node and the | 80 /// same nodes as this graph, but where edges exist between a node and the |
67 /// nodes it immediately dominates. For example, this graph: | 81 /// nodes it immediately dominates. For example, this graph: |
68 /// | 82 /// |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 class _DominatorFinder<N> { | 280 class _DominatorFinder<N> { |
267 final Graph<N> _graph; | 281 final Graph<N> _graph; |
268 Map<N, N> immediateDominators = {}; | 282 Map<N, N> immediateDominators = {}; |
269 Map<N, int> postOrderId = {}; | 283 Map<N, int> postOrderId = {}; |
270 _DominatorFinder(this._graph); | 284 _DominatorFinder(this._graph); |
271 | 285 |
272 run(N root) { | 286 run(N root) { |
273 immediateDominators[root] = root; | 287 immediateDominators[root] = root; |
274 bool changed = true; | 288 bool changed = true; |
275 int i = 0; | 289 int i = 0; |
276 var nodesInPostOrder = _graph.postOrder(root); | 290 var nodesInPostOrder = _graph.postOrder(root).toList(); |
277 for (var n in nodesInPostOrder) { | 291 for (var n in nodesInPostOrder) { |
278 postOrderId[n] = i++; | 292 postOrderId[n] = i++; |
279 } | 293 } |
280 var nodesInReversedPostOrder = nodesInPostOrder.reversed; | 294 var nodesInReversedPostOrder = nodesInPostOrder.reversed; |
281 while (changed) { | 295 while (changed) { |
282 changed = false; | 296 changed = false; |
283 for (var n in nodesInReversedPostOrder) { | 297 for (var n in nodesInReversedPostOrder) { |
284 if (n == root) continue; | 298 if (n == root) continue; |
285 bool first = true; | 299 bool first = true; |
286 var idom = null; | 300 var idom = null; |
(...skipping 22 matching lines...) Expand all Loading... |
309 while (postOrderId[finger1] < postOrderId[finger2]) { | 323 while (postOrderId[finger1] < postOrderId[finger2]) { |
310 finger1 = immediateDominators[finger1]; | 324 finger1 = immediateDominators[finger1]; |
311 } | 325 } |
312 while (postOrderId[finger2] < postOrderId[finger1]) { | 326 while (postOrderId[finger2] < postOrderId[finger1]) { |
313 finger2 = immediateDominators[finger2]; | 327 finger2 = immediateDominators[finger2]; |
314 } | 328 } |
315 } | 329 } |
316 return finger1; | 330 return finger1; |
317 } | 331 } |
318 } | 332 } |
OLD | NEW |