12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- export class Node {
- constructor(data) {
- this.incoming = new Map();
- this.outgoing = new Map();
- this.data = data;
- }
- }
- export class Graph {
- constructor(_hashFn) {
- this._hashFn = _hashFn;
- this._nodes = new Map();
- // empty
- }
- roots() {
- const ret = [];
- for (let node of this._nodes.values()) {
- if (node.outgoing.size === 0) {
- ret.push(node);
- }
- }
- return ret;
- }
- insertEdge(from, to) {
- const fromNode = this.lookupOrInsertNode(from);
- const toNode = this.lookupOrInsertNode(to);
- fromNode.outgoing.set(this._hashFn(to), toNode);
- toNode.incoming.set(this._hashFn(from), fromNode);
- }
- removeNode(data) {
- const key = this._hashFn(data);
- this._nodes.delete(key);
- for (let node of this._nodes.values()) {
- node.outgoing.delete(key);
- node.incoming.delete(key);
- }
- }
- lookupOrInsertNode(data) {
- const key = this._hashFn(data);
- let node = this._nodes.get(key);
- if (!node) {
- node = new Node(data);
- this._nodes.set(key, node);
- }
- return node;
- }
- isEmpty() {
- return this._nodes.size === 0;
- }
- toString() {
- let data = [];
- for (let [key, value] of this._nodes) {
- data.push(`${key}, (incoming)[${[...value.incoming.keys()].join(', ')}], (outgoing)[${[...value.outgoing.keys()].join(',')}]`);
- }
- return data.join('\n');
- }
- /**
- * This is brute force and slow and **only** be used
- * to trouble shoot.
- */
- findCycleSlow() {
- for (let [id, node] of this._nodes) {
- const seen = new Set([id]);
- const res = this._findCycle(node, seen);
- if (res) {
- return res;
- }
- }
- return undefined;
- }
- _findCycle(node, seen) {
- for (let [id, outgoing] of node.outgoing) {
- if (seen.has(id)) {
- return [...seen, id].join(' -> ');
- }
- seen.add(id);
- const value = this._findCycle(outgoing, seen);
- if (value) {
- return value;
- }
- seen.delete(id);
- }
- return undefined;
- }
- }
|