Files
sdk/pkg/front_end/test/dijkstras_sssp_algorithm.dart
T
Jens Johansen 6aa7407d63 [CFE] Proof of concept of using vm service to find leaks
Use the VM service to find leaks in the incremental compiler via the
incremental compiler test suite.

Currently the following tests leak:

incremental_load_from_dill/no_outline_change_2
incremental_load_from_dill/no_outline_change_6
incremental_load_from_dill/no_outline_change_7
incremental_load_from_dill/no_outline_change_10
incremental_load_from_dill/no_outline_change_34

Change-Id: Ie05ad5994f518422c553dc52bd57908ebbf1b16b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132283
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
2020-01-23 08:30:07 +00:00

109 lines
3.3 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.
import 'dart:collection';
/// Dijkstra's algorithm for single source shortest path.
///
/// Adopted from https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm#Pseudocode
///
/// Note that this is not an optimal implementation in that it uses a
/// (Splay) Tree as the priority queue which takes O(log n) time to (fake) a
/// decrease of priority whereas e.g. a fibonacci heap would have done it in
/// (amortized) O(1).
class DijkstrasAlgorithm<E> {
Map<GraphNode<E>, int> dist = new Map<GraphNode<E>, int>();
Map<GraphNode<E>, GraphNode<E>> prev = new Map<GraphNode<E>, GraphNode<E>>();
DijkstrasAlgorithm(Iterable<GraphNode<E>> graphNodes, GraphNode<E> source,
int Function(E, E) comparator, int Function(E, E) distance) {
SplayTreeSet<GraphNode<E>> q = new SplayTreeSet<GraphNode<E>>((a, b) {
int distA = dist[a];
int distB = dist[b];
int when0() {
if (identical(a, b)) return 0;
int result = comparator(a.node, b.node);
if (result == 0) {
throw "The nodes ${b.node} and ${a.node} are not the same but "
"compares to the same. That's not allowed!";
}
return result;
}
if (distA != null && distB == null) return -1;
if (distA == null && distB != null) return 1;
if (distA == null && distB == null) {
return when0();
}
if (distA < distB) return -1;
if (distA > distB) return 1;
return when0();
});
dist[source] = 0;
int index = 0;
for (GraphNode<E> g in graphNodes) {
// dist and prev not set, we see "null" as "infinity" and "undefined".
if (!q.add(g)) {
throw "Couldn't add ${g.node} (index $index).";
}
index++;
}
while (q.isNotEmpty) {
GraphNode<E> u = q.first;
int distToU = dist[u];
if (distToU == null) {
// No path to any of the remaining ${q.length} nodes.
break;
}
q.remove(u);
for (GraphNode<E> v in u.outgoing) {
// Wikipedia says "only v that are still in Q" but it shouldn't matter
// --- the length via u would be longer.
int distanceUToV = distance(u.node, v.node);
if (distanceUToV < 0) throw "Got negative distance. That's not allowed";
int alt = distToU + distanceUToV;
int distToV = dist[v];
if (distToV == null || alt < distToV) {
// Decrease length (decrease priority in priority queue).
q.remove(v);
dist[v] = alt;
prev[v] = u;
q.add(v);
}
}
}
}
List<E> getPathFromTarget(GraphNode<E> source, GraphNode<E> target) {
List<E> path = new List<E>();
GraphNode<E> u = target;
while (u == source || prev[u] != null) {
path.add(u.node);
u = prev[u];
}
return path.reversed.toList();
}
}
class GraphNode<E> {
final E node;
final Set<GraphNode<E>> outgoing = new Set<GraphNode<E>>();
final Set<GraphNode<E>> incoming = new Set<GraphNode<E>>();
GraphNode(this.node);
void addOutgoing(GraphNode<E> other) {
if (outgoing.add(other)) {
other.incoming.add(this);
}
}
String toString() {
return "GraphNode[$node]";
}
}