mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 05:47:14 +00:00
3a96674d3d
TEST=ci Issue: https://github.com/dart-lang/sdk/issues/46620 Change-Id: I18bab8755bfa937b6de07a738e3f22309240da22 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207365 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
126 lines
2.7 KiB
Dart
126 lines
2.7 KiB
Dart
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
class Vertex<T extends Vertex<T>> {
|
|
// Input: vertices directly reachable from this vertex.
|
|
final List<T> successors = <T>[];
|
|
|
|
// Output: the nearest vertex that all paths from the root must go through to
|
|
// reach this vertex.
|
|
T? dominator;
|
|
|
|
bool isDominatedBy(T other) {
|
|
Vertex<T>? d = this;
|
|
while (d != null) {
|
|
if (d == other) {
|
|
return true;
|
|
}
|
|
d = d.dominator;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Temporaries. See Lengauer and Tarjan.
|
|
final List<T> _predecessors = <T>[];
|
|
int _semi = 0;
|
|
T? _label;
|
|
T? _ancestor;
|
|
T? _parent;
|
|
List<T>? _bucket;
|
|
}
|
|
|
|
// T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators
|
|
// in a Flowgraph."
|
|
computeDominators<T extends Vertex<T>>(T root) {
|
|
// Lengauer and Tarjan Step 1.
|
|
final vertex = <T?>[];
|
|
vertex.add(null);
|
|
|
|
var n = 0;
|
|
dfs(T v) {
|
|
n++;
|
|
|
|
vertex.add(v);
|
|
v._semi = n;
|
|
v._label = v;
|
|
v._ancestor = null;
|
|
|
|
for (final w in v.successors) {
|
|
if (w._semi == 0) {
|
|
w._parent = v;
|
|
dfs(w);
|
|
}
|
|
w._predecessors.add(v);
|
|
}
|
|
}
|
|
|
|
dfs(root);
|
|
|
|
forestCompress(T v) {
|
|
T ancestor = v._ancestor!;
|
|
if (ancestor._ancestor != null) {
|
|
forestCompress(ancestor);
|
|
ancestor = v._ancestor!;
|
|
if (ancestor._label!._semi < v._label!._semi) {
|
|
v._label = ancestor._label;
|
|
}
|
|
v._ancestor = ancestor._ancestor;
|
|
}
|
|
}
|
|
|
|
T forestEval(T v) {
|
|
if (v._ancestor == null) {
|
|
return v;
|
|
} else {
|
|
forestCompress(v);
|
|
return v._label!;
|
|
}
|
|
}
|
|
|
|
forestLink(T? v, T w) {
|
|
w._ancestor = v;
|
|
}
|
|
|
|
for (var i = vertex.length - 1; i > 1; i--) {
|
|
final T w = vertex[i]!;
|
|
|
|
// Lengauer and Tarjan Step 2.
|
|
for (T v in w._predecessors) {
|
|
if (v._semi == 0) continue; // Unreachable
|
|
|
|
final u = forestEval(v);
|
|
if (u._semi < w._semi) {
|
|
w._semi = u._semi;
|
|
}
|
|
}
|
|
|
|
Vertex<T> z = vertex[w._semi]!;
|
|
var b = z._bucket;
|
|
if (b == null) {
|
|
z._bucket = b = <T>[];
|
|
}
|
|
b.add(w);
|
|
forestLink(w._parent, w);
|
|
|
|
// Lengauer and Tarjan Step 3.
|
|
z = w._parent!;
|
|
b = z._bucket;
|
|
z._bucket = null;
|
|
if (b != null) {
|
|
for (final v in b) {
|
|
final u = forestEval(v);
|
|
v.dominator = u._semi < v._semi ? u : w._parent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lengauer and Tarjan Step 4.
|
|
for (var i = 2; i < vertex.length; i++) {
|
|
final T w = vertex[i]!;
|
|
if (w.dominator != vertex[w._semi]) {
|
|
w.dominator = w.dominator!.dominator;
|
|
}
|
|
}
|
|
}
|