Move insertSorted from server to core, use for diagnostic collections (#21401)

* Move insertSorted from server to core, use for diagnostic collections

* All keep the overall list sorted, too

* Increase timeout for js verification

* Use knowledge of how diagnostics are sorted to make all diagnostic list creation lazy and more efficient

* Staunchly avoid array allocation in favor of resizing an existing array
This commit is contained in:
Wesley Wigham
2018-02-07 17:00:59 -08:00
committed by GitHub
parent 22fbb8edce
commit 871e71d4ef
8 changed files with 37 additions and 55 deletions

View File

@@ -794,6 +794,18 @@ namespace ts {
return deduplicated;
}
export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Comparer<T>): void {
if (array.length === 0) {
array.push(insert);
return;
}
const insertIndex = binarySearch(array, insert, identity, compare);
if (insertIndex < 0) {
array.splice(~insertIndex, 0, insert);
}
}
export function sortAndDeduplicate<T>(array: ReadonlyArray<T>, comparer: Comparer<T>, equalityComparer?: EqualityComparer<T>) {
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
}

View File

@@ -5009,6 +5009,10 @@ namespace ts {
newLength: number;
}
export interface SortedArray<T> extends Array<T> {
" __sortedArrayBrand": any;
}
/* @internal */
export interface DiagnosticCollection {
// Adds a diagnostic to this diagnostic collection.

View File

@@ -2443,11 +2443,10 @@ namespace ts {
}
export function createDiagnosticCollection(): DiagnosticCollection {
let nonFileDiagnostics: Diagnostic[] = [];
const fileDiagnostics = createMap<Diagnostic[]>();
let nonFileDiagnostics = [] as SortedArray<Diagnostic>;
const filesWithDiagnostics = [] as SortedArray<string>;
const fileDiagnostics = createMap<SortedArray<Diagnostic>>();
let hasReadNonFileDiagnostics = false;
let diagnosticsModified = false;
let modificationCount = 0;
return {
@@ -2467,66 +2466,45 @@ namespace ts {
}
function add(diagnostic: Diagnostic): void {
let diagnostics: Diagnostic[];
let diagnostics: SortedArray<Diagnostic>;
if (diagnostic.file) {
diagnostics = fileDiagnostics.get(diagnostic.file.fileName);
if (!diagnostics) {
diagnostics = [];
diagnostics = [] as SortedArray<Diagnostic>;
fileDiagnostics.set(diagnostic.file.fileName, diagnostics);
insertSorted(filesWithDiagnostics, diagnostic.file.fileName, compareStringsCaseSensitive);
}
}
else {
// If we've already read the non-file diagnostics, do not modify the existing array.
if (hasReadNonFileDiagnostics) {
hasReadNonFileDiagnostics = false;
nonFileDiagnostics = nonFileDiagnostics.slice();
nonFileDiagnostics = nonFileDiagnostics.slice() as SortedArray<Diagnostic>;
}
diagnostics = nonFileDiagnostics;
}
diagnostics.push(diagnostic);
diagnosticsModified = true;
insertSorted(diagnostics, diagnostic, compareDiagnostics);
modificationCount++;
}
function getGlobalDiagnostics(): Diagnostic[] {
sortAndDeduplicate();
hasReadNonFileDiagnostics = true;
return nonFileDiagnostics;
}
function getDiagnostics(fileName?: string): Diagnostic[] {
sortAndDeduplicate();
if (fileName) {
return fileDiagnostics.get(fileName) || [];
}
const allDiagnostics: Diagnostic[] = [];
function pushDiagnostic(d: Diagnostic) {
allDiagnostics.push(d);
const fileDiags = flatMap(filesWithDiagnostics, f => fileDiagnostics.get(f));
if (!nonFileDiagnostics.length) {
return fileDiags;
}
forEach(nonFileDiagnostics, pushDiagnostic);
fileDiagnostics.forEach(diagnostics => {
forEach(diagnostics, pushDiagnostic);
});
return sortAndDeduplicateDiagnostics(allDiagnostics);
}
function sortAndDeduplicate() {
if (!diagnosticsModified) {
return;
}
diagnosticsModified = false;
nonFileDiagnostics = sortAndDeduplicateDiagnostics(nonFileDiagnostics);
fileDiagnostics.forEach((diagnostics, key) => {
fileDiagnostics.set(key, sortAndDeduplicateDiagnostics(diagnostics));
});
fileDiags.unshift(...nonFileDiagnostics);
return fileDiags;
}
}

View File

@@ -170,7 +170,8 @@ namespace RWC {
});
it("has the expected emitted code", () => {
it("has the expected emitted code", function(this: Mocha.ITestCallbackContext) {
this.timeout(10000); // Allow long timeouts for RWC js verification
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
return Harness.Compiler.iterateOutputs(compilerResult.files);
}, baselineOpts, [".js", ".jsx"]);

View File

@@ -22,10 +22,6 @@ declare namespace ts.server {
require?(initialPath: string, moduleName: string): RequireResult;
}
export interface SortedArray<T> extends Array<T> {
" __sortedArrayBrand": any;
}
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}

View File

@@ -232,18 +232,6 @@ namespace ts.server {
return base === "tsconfig.json" || base === "jsconfig.json" ? base : undefined;
}
export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Comparer<T>): void {
if (array.length === 0) {
array.push(insert);
return;
}
const insertIndex = binarySearch(array, insert, identity, compare);
if (insertIndex < 0) {
array.splice(~insertIndex, 0, insert);
}
}
export function removeSorted<T>(array: SortedArray<T>, remove: T, compare: Comparer<T>): void {
if (!array || array.length === 0) {
return;