graph.js 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. export class Node {
  6. constructor(data) {
  7. this.incoming = new Map();
  8. this.outgoing = new Map();
  9. this.data = data;
  10. }
  11. }
  12. export class Graph {
  13. constructor(_hashFn) {
  14. this._hashFn = _hashFn;
  15. this._nodes = new Map();
  16. // empty
  17. }
  18. roots() {
  19. const ret = [];
  20. for (let node of this._nodes.values()) {
  21. if (node.outgoing.size === 0) {
  22. ret.push(node);
  23. }
  24. }
  25. return ret;
  26. }
  27. insertEdge(from, to) {
  28. const fromNode = this.lookupOrInsertNode(from);
  29. const toNode = this.lookupOrInsertNode(to);
  30. fromNode.outgoing.set(this._hashFn(to), toNode);
  31. toNode.incoming.set(this._hashFn(from), fromNode);
  32. }
  33. removeNode(data) {
  34. const key = this._hashFn(data);
  35. this._nodes.delete(key);
  36. for (let node of this._nodes.values()) {
  37. node.outgoing.delete(key);
  38. node.incoming.delete(key);
  39. }
  40. }
  41. lookupOrInsertNode(data) {
  42. const key = this._hashFn(data);
  43. let node = this._nodes.get(key);
  44. if (!node) {
  45. node = new Node(data);
  46. this._nodes.set(key, node);
  47. }
  48. return node;
  49. }
  50. isEmpty() {
  51. return this._nodes.size === 0;
  52. }
  53. toString() {
  54. let data = [];
  55. for (let [key, value] of this._nodes) {
  56. data.push(`${key}, (incoming)[${[...value.incoming.keys()].join(', ')}], (outgoing)[${[...value.outgoing.keys()].join(',')}]`);
  57. }
  58. return data.join('\n');
  59. }
  60. /**
  61. * This is brute force and slow and **only** be used
  62. * to trouble shoot.
  63. */
  64. findCycleSlow() {
  65. for (let [id, node] of this._nodes) {
  66. const seen = new Set([id]);
  67. const res = this._findCycle(node, seen);
  68. if (res) {
  69. return res;
  70. }
  71. }
  72. return undefined;
  73. }
  74. _findCycle(node, seen) {
  75. for (let [id, outgoing] of node.outgoing) {
  76. if (seen.has(id)) {
  77. return [...seen, id].join(' -> ');
  78. }
  79. seen.add(id);
  80. const value = this._findCycle(outgoing, seen);
  81. if (value) {
  82. return value;
  83. }
  84. seen.delete(id);
  85. }
  86. return undefined;
  87. }
  88. }