Path: blob/main/src/vs/editor/contrib/inlineCompletions/browser/model/graph.ts
4797 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 DirectedGraph<T> {6private readonly _nodes = new Set<T>();7private readonly _outgoingEdges = new Map<T, Set<T>>();89public static from<T>(nodes: readonly T[], getOutgoing: (node: T) => readonly T[]): DirectedGraph<T> {10const graph = new DirectedGraph<T>();1112for (const node of nodes) {13graph._nodes.add(node);14}1516for (const node of nodes) {17const outgoing = getOutgoing(node);18if (outgoing.length > 0) {19const outgoingSet = new Set<T>();20for (const target of outgoing) {21outgoingSet.add(target);22}23graph._outgoingEdges.set(node, outgoingSet);24}25}2627return graph;28}2930/**31* After this, the graph is guaranteed to have no cycles.32*/33removeCycles(): { foundCycles: T[] } {34const foundCycles: T[] = [];35const visited = new Set<T>();36const recursionStack = new Set<T>();37const toRemove: Array<{ from: T; to: T }> = [];3839const dfs = (node: T): void => {40visited.add(node);41recursionStack.add(node);4243const outgoing = this._outgoingEdges.get(node);44if (outgoing) {45for (const neighbor of outgoing) {46if (!visited.has(neighbor)) {47dfs(neighbor);48} else if (recursionStack.has(neighbor)) {49// Found a cycle50foundCycles.push(neighbor);51toRemove.push({ from: node, to: neighbor });52}53}54}5556recursionStack.delete(node);57};5859// Run DFS from all unvisited nodes60for (const node of this._nodes) {61if (!visited.has(node)) {62dfs(node);63}64}6566// Remove edges that cause cycles67for (const { from, to } of toRemove) {68const outgoingSet = this._outgoingEdges.get(from);69if (outgoingSet) {70outgoingSet.delete(to);71}72}7374return { foundCycles };75}7677getOutgoing(node: T): readonly T[] {78const outgoing = this._outgoingEdges.get(node);79return outgoing ? Array.from(outgoing) : [];80}81}828384