Path: blob/main/src/vs/platform/instantiation/common/graph.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45export class Node<T> {678readonly incoming = new Map<string, Node<T>>();9readonly outgoing = new Map<string, Node<T>>();1011constructor(12readonly key: string,13readonly data: T14) { }15}1617export class Graph<T> {1819private readonly _nodes = new Map<string, Node<T>>();2021constructor(private readonly _hashFn: (element: T) => string) {22// empty23}2425roots(): Node<T>[] {26const ret: Node<T>[] = [];27for (const node of this._nodes.values()) {28if (node.outgoing.size === 0) {29ret.push(node);30}31}32return ret;33}3435insertEdge(from: T, to: T): void {36const fromNode = this.lookupOrInsertNode(from);37const toNode = this.lookupOrInsertNode(to);3839fromNode.outgoing.set(toNode.key, toNode);40toNode.incoming.set(fromNode.key, fromNode);41}4243removeNode(data: T): void {44const key = this._hashFn(data);45this._nodes.delete(key);46for (const node of this._nodes.values()) {47node.outgoing.delete(key);48node.incoming.delete(key);49}50}5152lookupOrInsertNode(data: T): Node<T> {53const key = this._hashFn(data);54let node = this._nodes.get(key);5556if (!node) {57node = new Node(key, data);58this._nodes.set(key, node);59}6061return node;62}6364lookup(data: T): Node<T> | undefined {65return this._nodes.get(this._hashFn(data));66}6768isEmpty(): boolean {69return this._nodes.size === 0;70}7172toString(): string {73const data: string[] = [];74for (const [key, value] of this._nodes) {75data.push(`${key}\n\t(-> incoming)[${[...value.incoming.keys()].join(', ')}]\n\t(outgoing ->)[${[...value.outgoing.keys()].join(',')}]\n`);7677}78return data.join('\n');79}8081/**82* This is brute force and slow and **only** be used83* to trouble shoot.84*/85findCycleSlow() {86for (const [id, node] of this._nodes) {87const seen = new Set<string>([id]);88const res = this._findCycle(node, seen);89if (res) {90return res;91}92}93return undefined;94}9596private _findCycle(node: Node<T>, seen: Set<string>): string | undefined {97for (const [id, outgoing] of node.outgoing) {98if (seen.has(id)) {99return [...seen, id].join(' -> ');100}101seen.add(id);102const value = this._findCycle(outgoing, seen);103if (value) {104return value;105}106seen.delete(id);107}108return undefined;109}110}111112113