Skip to content

Commit a1f7130

Browse files
committed
perf(tspath): avoid string copy in ToFileNameLowerCase
Use unsafe.String to convert the lowercase byte slice to a string without an extra allocation and copy, reducing overhead in the ASCII fast path. ``` │ bench-to-file-name-lower-case-BASE.txt │ bench-to-file-name-lower-case-with-unsafe-string.txt │ │ sec/op │ sec/op vs base │ ToFileNameLowerCase//path/to/file.ext-12 8.348n ± ∞ ¹ 8.505n ± ∞ ¹ ~ (p=0.151 n=5) ToFileNameLowerCase//PATH/TO/FILE.EXT-12 37.94n ± ∞ ¹ 27.80n ± ∞ ¹ -26.73% (p=0.008 n=5) ToFileNameLowerCase//path/to/FILE.EXT-12 40.96n ± ∞ ¹ 30.67n ± ∞ ¹ -25.12% (p=0.008 n=5) ToFileNameLowerCase//user/UserName/proje...etc-12 58.11n ± ∞ ¹ 46.78n ± ∞ ¹ -19.50% (p=0.008 n=5) ToFileNameLowerCase//user/UserName/proje...etc#01-12 160.7n ± ∞ ¹ 161.3n ± ∞ ¹ ~ (p=0.286 n=5) ToFileNameLowerCase//user/UserName/proje...etc#02-12 155.5n ± ∞ ¹ 155.9n ± ∞ ¹ ~ (p=0.381 n=5) ToFileNameLowerCase//user/UserName/proje...etc#03-12 138.1n ± ∞ ¹ 137.8n ± ∞ ¹ ~ (p=0.421 n=5) ToFileNameLowerCase/FoO/FoO/FoO/FoO/FoO/...etc-12 543.2n ± ∞ ¹ 515.3n ± ∞ ¹ -5.14% (p=0.008 n=5) geomean 78.30n 70.43n -10.05% ¹ need >= 6 samples for confidence interval at level 0.95 ```
1 parent eb88029 commit a1f7130

File tree

1 file changed

+7
-1
lines changed

1 file changed

+7
-1
lines changed

internal/tspath/path.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"cmp"
55
"strings"
66
"unicode"
7+
"unsafe"
78

89
"github.com/microsoft/typescript-go/internal/stringutil"
910
)
@@ -606,7 +607,12 @@ func ToFileNameLowerCase(fileName string) string {
606607
}
607608
b[i] = c
608609
}
609-
return string(b)
610+
// SAFETY: `b` is a freshly allocated, non-empty byte slice whose contents are
611+
// fully initialized. We do not mutate `b` after this point, and the returned
612+
// string becomes the only live reference to its backing array. The array is
613+
// heap-allocated (via make), so the GC keeps it alive for the lifetime of the
614+
// returned string. Since len(b) > 0 here, &b[0] is a valid pointer.
615+
return unsafe.String(&b[0], len(b))
610616
}
611617

612618
return strings.Map(func(r rune) rune {

0 commit comments

Comments
 (0)