Skip to content

Commit aa3734c

Browse files
authored
Merge pull request microsoft#28645 from Microsoft/pathPerf
Add perf optimizations for path comparisons
2 parents 973ba8d + 5198bf3 commit aa3734c

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

src/compiler/utilities.ts

+26-4
Original file line numberDiff line numberDiff line change
@@ -6925,7 +6925,7 @@ namespace ts {
69256925

69266926
export interface ObjectAllocator {
69276927
getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node;
6928-
getTokenConstructor(): new <TKind extends SyntaxKind>(kind: TKind, pos?: number, end?: number) => Token<TKind>;
6928+
getTokenConstructor(): { new <TKind extends SyntaxKind>(kind: TKind, pos?: number, end?: number): Token<TKind> };
69296929
getIdentifierConstructor(): new (kind: SyntaxKind.Identifier, pos?: number, end?: number) => Identifier;
69306930
getSourceFileConstructor(): new (kind: SyntaxKind.SourceFile, pos?: number, end?: number) => SourceFile;
69316931
getSymbolConstructor(): new (flags: SymbolFlags, name: __String) => Symbol;
@@ -7687,16 +7687,38 @@ namespace ts {
76877687
return path;
76887688
}
76897689

7690+
// check path for these segments: '', '.'. '..'
7691+
const relativePathSegmentRegExp = /(^|\/)\.{0,2}($|\/)/;
7692+
76907693
function comparePathsWorker(a: string, b: string, componentComparer: (a: string, b: string) => Comparison) {
76917694
if (a === b) return Comparison.EqualTo;
76927695
if (a === undefined) return Comparison.LessThan;
76937696
if (b === undefined) return Comparison.GreaterThan;
7697+
7698+
// NOTE: Performance optimization - shortcut if the root segments differ as there would be no
7699+
// need to perform path reduction.
7700+
const aRoot = a.substring(0, getRootLength(a));
7701+
const bRoot = b.substring(0, getRootLength(b));
7702+
const result = compareStringsCaseInsensitive(aRoot, bRoot);
7703+
if (result !== Comparison.EqualTo) {
7704+
return result;
7705+
}
7706+
7707+
// NOTE: Performance optimization - shortcut if there are no relative path segments in
7708+
// the non-root portion of the path
7709+
const aRest = a.substring(aRoot.length);
7710+
const bRest = b.substring(bRoot.length);
7711+
if (!relativePathSegmentRegExp.test(aRest) && !relativePathSegmentRegExp.test(bRest)) {
7712+
return componentComparer(aRest, bRest);
7713+
}
7714+
7715+
// The path contains a relative path segment. Normalize the paths and perform a slower component
7716+
// by component comparison.
76947717
const aComponents = reducePathComponents(getPathComponents(a));
76957718
const bComponents = reducePathComponents(getPathComponents(b));
76967719
const sharedLength = Math.min(aComponents.length, bComponents.length);
7697-
for (let i = 0; i < sharedLength; i++) {
7698-
const stringComparer = i === 0 ? compareStringsCaseInsensitive : componentComparer;
7699-
const result = stringComparer(aComponents[i], bComponents[i]);
7720+
for (let i = 1; i < sharedLength; i++) {
7721+
const result = componentComparer(aComponents[i], bComponents[i]);
77007722
if (result !== Comparison.EqualTo) {
77017723
return result;
77027724
}

0 commit comments

Comments
 (0)