Add createMultiMap to replace multiMapAdd and multiMapRemove

This commit is contained in:
Andy Hanson 2016-12-28 09:33:43 -08:00
parent 932eaa3f90
commit 145f0b2f18
6 changed files with 54 additions and 42 deletions

View file

@ -989,43 +989,43 @@ namespace ts {
return result;
}
/**
* Adds the value to an array of values associated with the key, and returns the array.
* Creates the array if it does not already exist.
*/
export function multiMapAdd<V>(map: Map<V[]>, key: string, value: V): V[] {
let values = map.get(key);
export interface MultiMap<T> extends Map<T[]> {
/**
* Adds the value to an array of values associated with the key, and returns the array.
* Creates the array if it does not already exist.
*/
add(key: string, value: T): T[];
/**
* Removes a value from an array of values associated with the key.
* Does not preserve the order of those values.
* Does nothing if `key` is not in `map`, or `value` is not in `map[key]`.
*/
remove(key: string, value: T): void;
}
export function createMultiMap<T>(): MultiMap<T> {
const map = createMap<T[]>() as MultiMap<T>;
map.add = multiMapAdd;
map.remove = multiMapRemove;
return map;
}
function multiMapAdd<T>(this: MultiMap<T>, key: string, value: T) {
let values = this.get(key);
if (values) {
values.push(value);
}
else {
map.set(key, values = [value]);
this.set(key, values = [value]);
}
return values;
}
export function multiMapSparseArrayAdd<V>(map: SparseArray<V[]>, key: number, value: V): V[] {
let values = map[key];
if (values) {
values.push(value);
}
else {
map[key] = values = [value];
}
return values;
}
/**
* Removes a value from an array of values associated with the key.
* Does not preserve the order of those values.
* Does nothing if `key` is not in `map`, or `value` is not in `map[key]`.
*/
export function multiMapRemove<V>(map: Map<V[]>, key: string, value: V): void {
const values = map.get(key);
function multiMapRemove<T>(this: MultiMap<T>, key: string, value: T) {
const values = this.get(key);
if (values) {
unorderedRemoveItem(values, value);
if (!values.length) {
map.delete(key);
this.delete(key);
}
}
}

View file

@ -3298,7 +3298,7 @@ namespace ts {
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
const exportSpecifiers = createMap<ExportSpecifier[]>();
const exportSpecifiers = createMultiMap<ExportSpecifier>();
const exportedBindings: SparseArray<Identifier[]> = [];
const uniqueExports = createMap<boolean>();
let exportedNames: Identifier[];
@ -3352,7 +3352,7 @@ namespace ts {
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
if (!uniqueExports.get(specifier.name.text)) {
const name = specifier.propertyName || specifier.name;
multiMapAdd(exportSpecifiers, name.text, specifier);
exportSpecifiers.add(name.text, specifier);
const decl = resolver.getReferencedImportDeclaration(name)
|| resolver.getReferencedValueDeclaration(name);
@ -3446,4 +3446,16 @@ namespace ts {
}
return exportedNames;
}
/** Use a sparse array as a multi-map. */
function multiMapSparseArrayAdd<V>(map: SparseArray<V[]>, key: number, value: V): V[] {
let values = map[key];
if (values) {
values.push(value);
}
else {
map[key] = values = [value];
}
return values;
}
}

View file

@ -1,4 +1,4 @@
/// <reference path="core.ts"/>
/// <reference path="core.ts"/>
namespace ts {
export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
@ -243,7 +243,7 @@ namespace ts {
function createWatchedFileSet() {
const dirWatchers = createMap<DirectoryWatcher>();
// One file can have multiple watchers
const fileWatcherCallbacks = createMap<FileWatcherCallback[]>();
const fileWatcherCallbacks = createMultiMap<FileWatcherCallback>();
return { addFile, removeFile };
function reduceDirWatcherRefCountForFile(fileName: string) {
@ -275,7 +275,7 @@ namespace ts {
}
function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
multiMapAdd(fileWatcherCallbacks, filePath, callback);
fileWatcherCallbacks.add(filePath, callback);
}
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
@ -291,7 +291,7 @@ namespace ts {
}
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
multiMapRemove(fileWatcherCallbacks, filePath, callback);
fileWatcherCallbacks.remove(filePath, callback);
}
function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: string) {

View file

@ -1760,10 +1760,10 @@ namespace FourSlash {
}
public rangesByText(): ts.Map<Range[]> {
const result = ts.createMap<Range[]>();
const result = ts.createMultiMap<Range>();
for (const range of this.getRanges()) {
const text = this.rangeText(range);
ts.multiMapAdd(result, text, range);
result.add(text, range);
}
return result;
}

View file

@ -334,8 +334,8 @@ namespace ts.projectSystem {
private timeoutCallbacks = new Callbacks();
private immediateCallbacks = new Callbacks();
readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedFiles = createMap<FileWatcherCallback[]>();
readonly watchedDirectories = createMultiMap<{ cb: DirectoryWatcherCallback, recursive: boolean }>();
readonly watchedFiles = createMultiMap<FileWatcherCallback>();
private filesOrFolders: FileOrFolder[];
@ -421,11 +421,11 @@ namespace ts.projectSystem {
watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean): DirectoryWatcher {
const path = this.toPath(directoryName);
const cbWithRecursive = { cb: callback, recursive };
multiMapAdd(this.watchedDirectories, path, cbWithRecursive);
this.watchedDirectories.add(path, cbWithRecursive);
return {
referenceCount: 0,
directoryName,
close: () => multiMapRemove(this.watchedDirectories, path, cbWithRecursive)
close: () => this.watchedDirectories.remove(path, cbWithRecursive)
};
}
@ -455,8 +455,8 @@ namespace ts.projectSystem {
watchFile(fileName: string, callback: FileWatcherCallback) {
const path = this.toPath(fileName);
multiMapAdd(this.watchedFiles, path, callback);
return { close: () => multiMapRemove(this.watchedFiles, path, callback) };
this.watchedFiles.add(path, callback);
return { close: () => this.watchedFiles.remove(path, callback) };
}
// TOOD: record and invoke callbacks to simulate timer events

View file

@ -518,7 +518,7 @@ namespace ts {
}
private computeNamedDeclarations(): Map<Declaration[]> {
const result = createMap<Declaration[]>();
const result = createMultiMap<Declaration>();
forEachChild(this, visit);
@ -527,7 +527,7 @@ namespace ts {
function addDeclaration(declaration: Declaration) {
const name = getDeclarationName(declaration);
if (name) {
multiMapAdd(result, name, declaration);
result.add(name, declaration);
}
}