diff --git a/src/vs/platform/instantiation/common/graph.ts b/src/vs/platform/instantiation/common/graph.ts index 2786107e3a2c5291a555c88c847b3fd3c2f414fb..9c55ae35f27856a1046af044988a6654bd7c0448 100644 --- a/src/vs/platform/instantiation/common/graph.ts +++ b/src/vs/platform/instantiation/common/graph.ts @@ -3,86 +3,78 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { isEmptyObject } from 'vs/base/common/types'; -import { forEach } from 'vs/base/common/collections'; +export class Node { -export interface Node { - data: T; - incoming: { [key: string]: Node }; - outgoing: { [key: string]: Node }; -} + readonly data: T; + readonly incoming = new Map>(); + readonly outgoing = new Map>(); -function newNode(data: T): Node { - return { - data: data, - incoming: Object.create(null), - outgoing: Object.create(null) - }; + constructor(data: T) { + this.data = data; + } } export class Graph { - private _nodes: { [key: string]: Node } = Object.create(null); + private readonly _nodes = new Map>(); - constructor(private _hashFn: (element: T) => string) { + constructor(private readonly _hashFn: (element: T) => string) { // empty } roots(): Node[] { const ret: Node[] = []; - forEach(this._nodes, entry => { - if (isEmptyObject(entry.value.outgoing)) { - ret.push(entry.value); + for (let node of this._nodes.values()) { + if (node.outgoing.size === 0) { + ret.push(node); } - }); + } return ret; } insertEdge(from: T, to: T): void { - const fromNode = this.lookupOrInsertNode(from), - toNode = this.lookupOrInsertNode(to); + const fromNode = this.lookupOrInsertNode(from); + const toNode = this.lookupOrInsertNode(to); - fromNode.outgoing[this._hashFn(to)] = toNode; - toNode.incoming[this._hashFn(from)] = fromNode; + fromNode.outgoing.set(this._hashFn(to), toNode); + toNode.incoming.set(this._hashFn(from), fromNode); } removeNode(data: T): void { const key = this._hashFn(data); - delete this._nodes[key]; - forEach(this._nodes, (entry) => { - delete entry.value.outgoing[key]; - delete entry.value.incoming[key]; - }); + this._nodes.delete(key); + for (let node of this._nodes.values()) { + node.outgoing.delete(key); + node.incoming.delete(key); + } } lookupOrInsertNode(data: T): Node { const key = this._hashFn(data); - let node = this._nodes[key]; + let node = this._nodes.get(key); if (!node) { - node = newNode(data); - this._nodes[key] = node; + node = new Node(data); + this._nodes.set(key, node); } return node; } - lookup(data: T): Node { - return this._nodes[this._hashFn(data)]; + lookup(data: T): Node | undefined { + return this._nodes.get(this._hashFn(data)); } isEmpty(): boolean { - for (const _key in this._nodes) { - return false; - } - return true; + return this._nodes.size === 0; } toString(): string { let data: string[] = []; - forEach(this._nodes, entry => { - data.push(`${entry.key}, (incoming)[${Object.keys(entry.value.incoming).join(', ')}], (outgoing)[${Object.keys(entry.value.outgoing).join(',')}]`); - }); + for (let [key, value] of this._nodes) { + data.push(`${key}, (incoming)[${[...value.incoming.keys()].join(', ')}], (outgoing)[${[...value.outgoing.keys()].join(',')}]`); + + } return data.join('\n'); } } diff --git a/src/vs/platform/instantiation/test/common/graph.test.ts b/src/vs/platform/instantiation/test/common/graph.test.ts index 717bc319744a05cb70a237028385fd6534c83463..58002e0df083c262f7726bb71a177feb49d15f04 100644 --- a/src/vs/platform/instantiation/test/common/graph.test.ts +++ b/src/vs/platform/instantiation/test/common/graph.test.ts @@ -19,7 +19,7 @@ suite('Graph', () => { test('inserts nodes when not there yet', function () { assert.deepEqual(graph.lookup('ddd'), null); assert.deepEqual(graph.lookupOrInsertNode('ddd').data, 'ddd'); - assert.deepEqual(graph.lookup('ddd').data, 'ddd'); + assert.deepEqual(graph.lookup('ddd')!.data, 'ddd'); }); test('can remove nodes and get length', function () {