Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/instantiation/common/graph.ts
3296 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 Node<T> {
7
8
9
readonly incoming = new Map<string, Node<T>>();
10
readonly outgoing = new Map<string, Node<T>>();
11
12
constructor(
13
readonly key: string,
14
readonly data: T
15
) { }
16
}
17
18
export class Graph<T> {
19
20
private readonly _nodes = new Map<string, Node<T>>();
21
22
constructor(private readonly _hashFn: (element: T) => string) {
23
// empty
24
}
25
26
roots(): Node<T>[] {
27
const ret: Node<T>[] = [];
28
for (const node of this._nodes.values()) {
29
if (node.outgoing.size === 0) {
30
ret.push(node);
31
}
32
}
33
return ret;
34
}
35
36
insertEdge(from: T, to: T): void {
37
const fromNode = this.lookupOrInsertNode(from);
38
const toNode = this.lookupOrInsertNode(to);
39
40
fromNode.outgoing.set(toNode.key, toNode);
41
toNode.incoming.set(fromNode.key, fromNode);
42
}
43
44
removeNode(data: T): void {
45
const key = this._hashFn(data);
46
this._nodes.delete(key);
47
for (const node of this._nodes.values()) {
48
node.outgoing.delete(key);
49
node.incoming.delete(key);
50
}
51
}
52
53
lookupOrInsertNode(data: T): Node<T> {
54
const key = this._hashFn(data);
55
let node = this._nodes.get(key);
56
57
if (!node) {
58
node = new Node(key, data);
59
this._nodes.set(key, node);
60
}
61
62
return node;
63
}
64
65
lookup(data: T): Node<T> | undefined {
66
return this._nodes.get(this._hashFn(data));
67
}
68
69
isEmpty(): boolean {
70
return this._nodes.size === 0;
71
}
72
73
toString(): string {
74
const data: string[] = [];
75
for (const [key, value] of this._nodes) {
76
data.push(`${key}\n\t(-> incoming)[${[...value.incoming.keys()].join(', ')}]\n\t(outgoing ->)[${[...value.outgoing.keys()].join(',')}]\n`);
77
78
}
79
return data.join('\n');
80
}
81
82
/**
83
* This is brute force and slow and **only** be used
84
* to trouble shoot.
85
*/
86
findCycleSlow() {
87
for (const [id, node] of this._nodes) {
88
const seen = new Set<string>([id]);
89
const res = this._findCycle(node, seen);
90
if (res) {
91
return res;
92
}
93
}
94
return undefined;
95
}
96
97
private _findCycle(node: Node<T>, seen: Set<string>): string | undefined {
98
for (const [id, outgoing] of node.outgoing) {
99
if (seen.has(id)) {
100
return [...seen, id].join(' -> ');
101
}
102
seen.add(id);
103
const value = this._findCycle(outgoing, seen);
104
if (value) {
105
return value;
106
}
107
seen.delete(id);
108
}
109
return undefined;
110
}
111
}
112
113