use Map instead of StringHashTable

This commit is contained in:
Mohamed Hegazy 2014-07-23 16:52:43 -07:00
parent 346809ba2b
commit 212c184602
2 changed files with 143 additions and 138 deletions

View file

@ -43,145 +43,145 @@ module TypeScript {
return new BlockIntrinsics<T>(); return new BlockIntrinsics<T>();
} }
export interface IHashTable<T> { //export interface IHashTable<T> {
getAllKeys(): string[]; // getAllKeys(): string[];
add(key: string, data: T): boolean; // add(key: string, data: T): boolean;
addOrUpdate(key: string, data: T): boolean; // addOrUpdate(key: string, data: T): boolean;
map(fn: (k: string, value: T, context: any) => void , context: any): void; // map(fn: (k: string, value: T, context: any) => void , context: any): void;
every(fn: (k: string, value: T, context: any) => void , context: any): boolean; // every(fn: (k: string, value: T, context: any) => void , context: any): boolean;
some(fn: (k: string, value: T, context: any) => void , context: any): boolean; // some(fn: (k: string, value: T, context: any) => void , context: any): boolean;
count(): number; // count(): number;
lookup(key: string): T; // lookup(key: string): T;
} //}
export class StringHashTable<T> implements IHashTable<T> { //export class StringHashTable<T> implements IHashTable<T> {
private itemCount = 0; // private itemCount = 0;
private table: IIndexable<T> = createIntrinsicsObject<T>(); // private table: IIndexable<T> = createIntrinsicsObject<T>();
public getAllKeys(): string[] { // public getAllKeys(): string[] {
var result: string[] = []; // var result: string[] = [];
for (var k in this.table) { // for (var k in this.table) {
if (this.table[k] !== undefined) { // if (this.table[k] !== undefined) {
result.push(k); // result.push(k);
} // }
} // }
return result; // return result;
} // }
public add(key: string, data: T): boolean { // public add(key: string, data: T): boolean {
if (this.table[key] !== undefined) { // if (this.table[key] !== undefined) {
return false; // return false;
} // }
this.table[key] = data; // this.table[key] = data;
this.itemCount++; // this.itemCount++;
return true; // return true;
} // }
public addOrUpdate(key: string, data: T): boolean { // public addOrUpdate(key: string, data: T): boolean {
if (this.table[key] !== undefined) { // if (this.table[key] !== undefined) {
this.table[key] = data; // this.table[key] = data;
return false; // return false;
} // }
this.table[key] = data; // this.table[key] = data;
this.itemCount++; // this.itemCount++;
return true; // return true;
} // }
public map(fn: (k: string, value: T, context: any) => void , context: any) { // public map(fn: (k: string, value: T, context: any) => void , context: any) {
for (var k in this.table) { // for (var k in this.table) {
var data = this.table[k]; // var data = this.table[k];
if (data !== undefined) { // if (data !== undefined) {
fn(k, this.table[k], context); // fn(k, this.table[k], context);
} // }
} // }
} // }
public every(fn: (k: string, value: T, context: any) => void , context: any) { // public every(fn: (k: string, value: T, context: any) => void , context: any) {
for (var k in this.table) { // for (var k in this.table) {
var data = this.table[k]; // var data = this.table[k];
if (data !== undefined) { // if (data !== undefined) {
if (!fn(k, this.table[k], context)) { // if (!fn(k, this.table[k], context)) {
return false; // return false;
} // }
} // }
} // }
return true; // return true;
} // }
public some(fn: (k: string, value: T, context: any) => void , context: any) { // public some(fn: (k: string, value: T, context: any) => void , context: any) {
for (var k in this.table) { // for (var k in this.table) {
var data = this.table[k]; // var data = this.table[k];
if (data !== undefined) { // if (data !== undefined) {
if (fn(k, this.table[k], context)) { // if (fn(k, this.table[k], context)) {
return true; // return true;
} // }
} // }
} // }
return false; // return false;
} // }
public count(): number { // public count(): number {
return this.itemCount; // return this.itemCount;
} // }
public lookup(key: string) : T { // public lookup(key: string) : T {
var data = this.table[key]; // var data = this.table[key];
return data === undefined ? null : data; // return data === undefined ? null : data;
} // }
public remove(key: string): void { // public remove(key: string): void {
if (this.table[key] !== undefined) { // if (this.table[key] !== undefined) {
this.table[key] = undefined; // this.table[key] = undefined;
this.itemCount--; // this.itemCount--;
} // }
} // }
} //}
export class IdentiferNameHashTable<T> extends StringHashTable<T> { //export class IdentiferNameHashTable<T> extends StringHashTable<T> {
public getAllKeys(): string[]{ // public getAllKeys(): string[]{
var result: string[] = []; // var result: string[] = [];
super.map((k, v, c) => { // super.map((k, v, c) => {
if (v !== undefined) { // if (v !== undefined) {
result.push(k.substring(1)); // result.push(k.substring(1));
} // }
}, null); // }, null);
return result; // return result;
} // }
public add(key: string, data: T): boolean { // public add(key: string, data: T): boolean {
return super.add("#" + key, data); // return super.add("#" + key, data);
} // }
public addOrUpdate(key: string, data: T): boolean { // public addOrUpdate(key: string, data: T): boolean {
return super.addOrUpdate("#" + key, data); // return super.addOrUpdate("#" + key, data);
} // }
public map(fn: (k: string, value: T, context: any) => void , context: any) { // public map(fn: (k: string, value: T, context: any) => void , context: any) {
return super.map((k, v, c) => fn(k.substring(1), v, c), context); // return super.map((k, v, c) => fn(k.substring(1), v, c), context);
} // }
public every(fn: (k: string, value: T, context: any) => void , context: any) { // public every(fn: (k: string, value: T, context: any) => void , context: any) {
return super.every((k, v, c) => fn(k.substring(1), v, c), context); // return super.every((k, v, c) => fn(k.substring(1), v, c), context);
} // }
public some(fn: (k: string, value: any, context: any) => void , context: any) { // public some(fn: (k: string, value: any, context: any) => void , context: any) {
return super.some((k, v, c) => fn(k.substring(1), v, c), context); // return super.some((k, v, c) => fn(k.substring(1), v, c), context);
} // }
public lookup(key: string): T { // public lookup(key: string): T {
return super.lookup("#" + key); // return super.lookup("#" + key);
} // }
} //}
} }

View file

@ -50,18 +50,18 @@ module TypeScript.Services {
// at each language service public entry point, since we don't know when // at each language service public entry point, since we don't know when
// set of scripts handled by the host changes. // set of scripts handled by the host changes.
class HostCache { class HostCache {
private _filenameToEntry: TypeScript.StringHashTable<HostFileInformation>; private _filenameToEntry: ts.Map<HostFileInformation>;
private _compilationSettings: ts.CompilerOptions; private _compilationSettings: ts.CompilerOptions;
constructor(host: ILanguageServiceHost) { constructor(host: ILanguageServiceHost) {
// script id => script index // script id => script index
this._filenameToEntry = new TypeScript.StringHashTable<HostFileInformation>(); this._filenameToEntry = {};
var filenames = host.getScriptFileNames(); var filenames = host.getScriptFileNames();
for (var i = 0, n = filenames.length; i < n; i++) { for (var i = 0, n = filenames.length; i < n; i++) {
var filename = filenames[i]; var filename = filenames[i];
this._filenameToEntry.add(TypeScript.switchToForwardSlashes(filename), new HostFileInformation( this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = new HostFileInformation(
filename, host, host.getScriptVersion(filename), host.getScriptIsOpen(filename), host.getScriptByteOrderMark(filename))); filename, host, host.getScriptVersion(filename), host.getScriptIsOpen(filename), host.getScriptByteOrderMark(filename));
} }
this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions();
@ -72,35 +72,39 @@ module TypeScript.Services {
} }
public contains(filename: string): boolean { public contains(filename: string): boolean {
return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)) !== null; return !!this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)];
} }
public getHostfilename(filename: string) { public getHostfilename(filename: string) {
var hostCacheEntry = this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)); var hostCacheEntry = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)];
if (hostCacheEntry) { if (hostCacheEntry) {
return hostCacheEntry.filename; return hostCacheEntry.filename;
} }
return filename; return filename;
} }
public getfilenames(): string[] { public getfilenames(): string[]{
return this._filenameToEntry.getAllKeys(); var fileNames: string[] = [];
for (var id in this._filenameToEntry) {
fileNames.push(id);
}
return fileNames;
} }
public getVersion(filename: string): number { public getVersion(filename: string): number {
return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).version; return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].version;
} }
public isOpen(filename: string): boolean { public isOpen(filename: string): boolean {
return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).isOpen; return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen;
} }
public getByteOrderMark(filename: string): TypeScript.ByteOrderMark { public getByteOrderMark(filename: string): TypeScript.ByteOrderMark {
return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).byteOrderMark; return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark;
} }
public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot {
return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).getScriptSnapshot(); return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].getScriptSnapshot();
} }
public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange { public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange {
@ -325,17 +329,17 @@ module TypeScript.Services {
} }
export class DocumentRegistry implements IDocumentRegistry { export class DocumentRegistry implements IDocumentRegistry {
private buckets: IIndexable<StringHashTable<DocumentRegistryEntry>> = {}; private buckets: ts.Map<ts.Map<DocumentRegistryEntry>> = {};
private getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { private getKeyFromCompilationSettings(settings: ts.CompilerOptions): string {
return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString() return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString()
} }
private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): StringHashTable<DocumentRegistryEntry> { private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): ts.Map<DocumentRegistryEntry> {
var key = this.getKeyFromCompilationSettings(settings); var key = this.getKeyFromCompilationSettings(settings);
var bucket = this.buckets[key]; var bucket = this.buckets[key];
if (!bucket && createIfMissing) { if (!bucket && createIfMissing) {
this.buckets[key] = bucket = new StringHashTable<DocumentRegistryEntry>(); this.buckets[key] = bucket = {};
} }
return bucket; return bucket;
} }
@ -343,14 +347,15 @@ module TypeScript.Services {
public reportStats() { public reportStats() {
var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => { var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => {
var entries = this.buckets[name]; var entries = this.buckets[name];
var documents = entries.getAllKeys().map((name) => { var documents = [];
var entry = entries.lookup(name); for (var i in entries) {
return { var entry = entries[i];
name: name, documents.push({
name: i,
refCount: entry.refCount, refCount: entry.refCount,
references: entry.owners.slice(0) references: entry.owners.slice(0)
}; });
}); }
documents.sort((x, y) => y.refCount - x.refCount); documents.sort((x, y) => y.refCount - x.refCount);
return { bucket: name, documents: documents } return { bucket: name, documents: documents }
}); });
@ -367,12 +372,12 @@ module TypeScript.Services {
referencedFiles: string[]= []): TypeScript.Document { referencedFiles: string[]= []): TypeScript.Document {
var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true);
var entry = bucket.lookup(filename); var entry = bucket[filename];
if (!entry) { if (!entry) {
var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles);
entry = new DocumentRegistryEntry(document); entry = new DocumentRegistryEntry(document);
bucket.add(filename, entry); bucket[filename] = entry;
} }
entry.refCount++; entry.refCount++;
@ -391,7 +396,7 @@ module TypeScript.Services {
var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false);
Debug.assert(bucket); Debug.assert(bucket);
var entry = bucket.lookup(filename); var entry = bucket[filename];
Debug.assert(entry); Debug.assert(entry);
if (entry.document.isOpen === isOpen && entry.document.version === version) { if (entry.document.isOpen === isOpen && entry.document.version === version) {
@ -406,12 +411,12 @@ module TypeScript.Services {
var bucket = this.getBucketForCompilationSettings(compilationSettings, false); var bucket = this.getBucketForCompilationSettings(compilationSettings, false);
Debug.assert(bucket); Debug.assert(bucket);
var entry = bucket.lookup(filename); var entry = bucket[filename];
entry.refCount--; entry.refCount--;
Debug.assert(entry.refCount >= 0); Debug.assert(entry.refCount >= 0);
if (entry.refCount === 0) { if (entry.refCount === 0) {
bucket.remove(filename); delete bucket[filename];
} }
} }
} }