From b0bcc33d34f504d0bef88cdb1514bb9eecc93bd6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 12 Jun 2023 16:25:07 +0200 Subject: [PATCH] joh/cautious cephalopod (#184692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * improve performance of `TraitSpliceable#splice`, avoid O(n2), avoid loop when not removing anything https://github.com/microsoft/vscode/issues/184615 * improve `Trait#splice` by reducing how often arrays are iterated over (from eight to three) * one more cleanup --------- Co-authored-by: João Moreno --- src/vs/base/browser/ui/list/listWidget.ts | 35 +++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 1aa861d306804..2a282e9f1a35f 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -129,17 +129,30 @@ class Trait implements ISpliceable, IDisposable { const diff = elements.length - deleteCount; const end = start + deleteCount; - const sortedIndexes = [ - ...this.sortedIndexes.filter(i => i < start), - ...elements.map((hasTrait, i) => hasTrait ? i + start : -1).filter(i => i !== -1), - ...this.sortedIndexes.filter(i => i >= end).map(i => i + diff) - ]; + const sortedIndexes: number[] = []; + let firstSortedIndex: number | undefined = undefined; + let i = 0; + + while (i < this.sortedIndexes.length && this.sortedIndexes[i] < start) { + sortedIndexes.push(this.sortedIndexes[i++]); + } + + for (let j = 0; j < elements.length; j++) { + if (elements[j]) { + sortedIndexes.push(j + start); + firstSortedIndex = firstSortedIndex ?? sortedIndexes[sortedIndexes.length - 1]; + } + } + + while (i < this.sortedIndexes.length && this.sortedIndexes[i] >= end) { + sortedIndexes.push(this.sortedIndexes[i++] + diff); + firstSortedIndex = firstSortedIndex ?? sortedIndexes[sortedIndexes.length - 1]; + } const length = this.length + diff; if (this.sortedIndexes.length > 0 && sortedIndexes.length === 0 && length > 0) { - const first = this.sortedIndexes.find(index => index >= start) ?? length - 1; - sortedIndexes.push(Math.min(first, length - 1)); + sortedIndexes.push(Math.min(firstSortedIndex ?? length - 1, length - 1)); } this.renderer.splice(start, deleteCount, elements.length); @@ -226,12 +239,16 @@ class TraitSpliceable implements ISpliceable { splice(start: number, deleteCount: number, elements: T[]): void { if (!this.identityProvider) { - return this.trait.splice(start, deleteCount, elements.map(() => false)); + return this.trait.splice(start, deleteCount, new Array(elements.length).fill(false)); } const pastElementsWithTrait = this.trait.get().map(i => this.identityProvider!.getId(this.view.element(i)).toString()); - const elementsWithTrait = elements.map(e => pastElementsWithTrait.indexOf(this.identityProvider!.getId(e).toString()) > -1); + if (pastElementsWithTrait.length === 0) { + return this.trait.splice(start, deleteCount, new Array(elements.length).fill(false)); + } + const pastElementsWithTraitSet = new Set(pastElementsWithTrait); + const elementsWithTrait = elements.map(e => pastElementsWithTraitSet.has(this.identityProvider!.getId(e).toString())); this.trait.splice(start, deleteCount, elementsWithTrait); } }