Files
vscode/src/vs/base/common/graph.ts
T
2015-11-24 19:09:38 +01:00

97 lines
2.5 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import objects = require('vs/base/common/types');
import collections = require('vs/base/common/collections');
export interface Node<T> {
data:T;
incoming:{[key:string]:Node<T>};
outgoing:{[key:string]:Node<T>};
}
export function newNode<T>(data:T):Node<T> {
return {
data: data,
incoming: {},
outgoing: {}
};
}
export class Graph<T> {
private _nodes:{[key:string]:Node<T>} = Object.create(null);
constructor(private _hashFn:(element:T)=>string) {
// empty
}
public roots():Node<T>[] {
var ret:Node<T>[] = [];
collections.forEach(this._nodes, entry => {
if(objects.isEmptyObject(entry.value.outgoing)) {
ret.push(entry.value);
}
});
return ret;
}
public traverse(start:T, inwards:boolean, callback:(data:T)=>void):void {
var startNode = this.lookup(start);
if(!startNode) {
return;
}
this._traverse(startNode, inwards, {}, callback);
}
private _traverse(node:Node<T>, inwards:boolean, seen:{[key:string]:boolean}, callback:(data:T)=>void):void {
var key = this._hashFn(node.data);
if(collections.contains(seen, key)) {
return;
}
seen[key] = true;
callback(node.data);
var nodes = inwards ? node.outgoing : node.incoming;
collections.forEach(nodes, (entry) => this._traverse(entry.value, inwards, seen, callback));
}
public insertEdge(from:T, to:T):void {
var fromNode = this.lookupOrInsertNode(from),
toNode = this.lookupOrInsertNode(to);
fromNode.outgoing[this._hashFn(to)] = toNode;
toNode.incoming[this._hashFn(from)] = fromNode;
}
public removeNode(data:T):void {
var key = this._hashFn(data);
delete this._nodes[key];
collections.forEach(this._nodes, (entry) => {
delete entry.value.outgoing[key];
delete entry.value.incoming[key];
});
}
public lookupOrInsertNode(data:T):Node<T> {
var key = this._hashFn(data),
node = collections.lookup(this._nodes, key);
if(!node) {
node = newNode(data);
this._nodes[key] = node;
}
return node;
}
public lookup(data:T):Node<T> {
return collections.lookup(this._nodes, this._hashFn(data));
}
public get length():number {
return Object.keys(this._nodes).length;
}
}