Skip to content

Commit 528682c

Browse files
committed
avoid slice-calls, avoid searching for best result when you know it, microsoft#18682
1 parent be5fa39 commit 528682c

1 file changed

Lines changed: 60 additions & 18 deletions

File tree

src/vs/base/common/filters.ts

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -551,31 +551,26 @@ export function fuzzyScore(pattern: string, word: string): [number, number[]] {
551551
console.log(printTable(_scores, pattern, patternLen, word, wordLen));
552552
}
553553

554+
// _bucket is an array of [PrefixArray] we use to keep
555+
// track of scores and matches. After calling `_findAllMatches`
556+
// the best match (if available) is the first item in the array
554557
_bucket.length = 0;
558+
_topScore = -100;
555559
_patternStartPos = patternStartPos;
556-
_findAllMatches(patternLen, wordLen, 0, [], false);
560+
_findAllMatches(patternLen, wordLen, 0, new LazyArray(), false);
557561

558562
if (_bucket.length === 0) {
559563
return undefined;
560564
}
561565

562-
let topMatch = _bucket[0];
563-
for (let i = 1; i < _bucket.length; i++) {
564-
let match = _bucket[i];
565-
if (topMatch[0] < match[0]) {
566-
topMatch = match;
567-
}
568-
}
569-
if (_debug) {
570-
console.log(`${pattern} & ${word} => ${topMatch[0]} points for ${topMatch[1]}`);
571-
}
572-
return topMatch;
566+
return [_topScore, _bucket[0].toArray()];
573567
}
574568

575-
let _bucket: [number, number[]][] = [];
569+
let _bucket: LazyArray[] = [];
570+
let _topScore: number = 0;
576571
let _patternStartPos: number = 0;
577572

578-
function _findAllMatches(patternPos: number, wordPos: number, total: number, matches: number[], lastMatched: boolean): void {
573+
function _findAllMatches(patternPos: number, wordPos: number, total: number, matches: LazyArray, lastMatched: boolean): void {
579574

580575
if (_bucket.length >= 10 || total < -25) {
581576
// stop when having already 10 results, or
@@ -595,7 +590,7 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
595590
wordPos -= 1;
596591
if (lastMatched) {
597592
total -= 5; // new gap penalty
598-
} else if (matches.length !== 0) {
593+
} else if (!matches.isEmpty()) {
599594
total -= 1; // gap penalty after first match
600595
}
601596
lastMatched = false;
@@ -608,8 +603,8 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
608603
_findAllMatches(
609604
patternPos,
610605
wordPos - 1,
611-
matches.length !== 0 ? total - 1 : total,
612-
matches.slice(0),
606+
!matches.isEmpty() ? total - 1 : total, // gap penalty after first match
607+
matches.slice(),
613608
lastMatched
614609
);
615610
}
@@ -646,9 +641,56 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
646641

647642
total -= wordPos >= 3 ? 9 : wordPos * 3; // late start penalty
648643

649-
_bucket.push([total, matches]);
644+
// dynamically keep track of the current top score
645+
// and insert the current best score at head, the rest at tail
646+
if (total > _topScore) {
647+
_topScore = total;
648+
_bucket.unshift(matches);
649+
} else {
650+
_bucket.push(matches);
651+
}
650652
}
651653

654+
class LazyArray {
655+
656+
private _parent: LazyArray;
657+
private _parentLen: number;
658+
private _data: number[];
659+
660+
isEmpty(): boolean {
661+
return !this._data && (!this._parent || this._parent.isEmpty());
662+
}
663+
664+
unshift(n: number) {
665+
if (!this._data) {
666+
this._data = [n];
667+
} else {
668+
this._data.unshift(n);
669+
}
670+
}
671+
672+
slice(): LazyArray {
673+
const ret = new LazyArray();
674+
ret._parent = this;
675+
ret._parentLen = this._data ? this._data.length : 0;
676+
return ret;
677+
}
678+
679+
toArray(): number[] {
680+
if (!this._data) {
681+
return this._parent.toArray();
682+
}
683+
const bucket: number[][] = [];
684+
let element = <LazyArray>this;
685+
while (element) {
686+
if (element._parent && element._parent._data) {
687+
bucket.push(element._parent._data.slice(element._parent._data.length - element._parentLen));
688+
}
689+
element = element._parent;
690+
}
691+
return Array.prototype.concat.apply(this._data, bucket);
692+
}
693+
}
652694

653695
export function nextTypoPermutation(pattern: string, patternPos: number) {
654696

0 commit comments

Comments
 (0)