Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/inlineCompletions/browser/model/graph.ts
4797 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
export class DirectedGraph<T> {
7
private readonly _nodes = new Set<T>();
8
private readonly _outgoingEdges = new Map<T, Set<T>>();
9
10
public static from<T>(nodes: readonly T[], getOutgoing: (node: T) => readonly T[]): DirectedGraph<T> {
11
const graph = new DirectedGraph<T>();
12
13
for (const node of nodes) {
14
graph._nodes.add(node);
15
}
16
17
for (const node of nodes) {
18
const outgoing = getOutgoing(node);
19
if (outgoing.length > 0) {
20
const outgoingSet = new Set<T>();
21
for (const target of outgoing) {
22
outgoingSet.add(target);
23
}
24
graph._outgoingEdges.set(node, outgoingSet);
25
}
26
}
27
28
return graph;
29
}
30
31
/**
32
* After this, the graph is guaranteed to have no cycles.
33
*/
34
removeCycles(): { foundCycles: T[] } {
35
const foundCycles: T[] = [];
36
const visited = new Set<T>();
37
const recursionStack = new Set<T>();
38
const toRemove: Array<{ from: T; to: T }> = [];
39
40
const dfs = (node: T): void => {
41
visited.add(node);
42
recursionStack.add(node);
43
44
const outgoing = this._outgoingEdges.get(node);
45
if (outgoing) {
46
for (const neighbor of outgoing) {
47
if (!visited.has(neighbor)) {
48
dfs(neighbor);
49
} else if (recursionStack.has(neighbor)) {
50
// Found a cycle
51
foundCycles.push(neighbor);
52
toRemove.push({ from: node, to: neighbor });
53
}
54
}
55
}
56
57
recursionStack.delete(node);
58
};
59
60
// Run DFS from all unvisited nodes
61
for (const node of this._nodes) {
62
if (!visited.has(node)) {
63
dfs(node);
64
}
65
}
66
67
// Remove edges that cause cycles
68
for (const { from, to } of toRemove) {
69
const outgoingSet = this._outgoingEdges.get(from);
70
if (outgoingSet) {
71
outgoingSet.delete(to);
72
}
73
}
74
75
return { foundCycles };
76
}
77
78
getOutgoing(node: T): readonly T[] {
79
const outgoing = this._outgoingEdges.get(node);
80
return outgoing ? Array.from(outgoing) : [];
81
}
82
}
83
84