summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2024-04-13 16:11:18 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2024-04-14 11:47:05 +0900
commit7ce6452d83a62a3bc409fef8face1cfaef6e0146 (patch)
treea6aa9e4f05fe196160277e1b310e4fd2d76e30ea
parent5643a306bdb094aaa64204a2dde0cfbff8373228 (diff)
Improve search performance by pre-calculating character classes
This simple optmization can give more than 15% performance boost in some scenarios.
-rw-r--r--src/algo/algo.go41
-rw-r--r--src/algo/algo_test.go4
-rw-r--r--src/options.go4
3 files changed, 28 insertions, 21 deletions
diff --git a/src/algo/algo.go b/src/algo/algo.go
index 5cb82bdd..6e0d437c 100644
--- a/src/algo/algo.go
+++ b/src/algo/algo.go
@@ -153,6 +153,9 @@ var (
bonusBoundaryDelimiter int16 = bonusBoundary + 1
initialCharClass charClass = charWhite
+
+ // A minor optimization that can give 15%+ performance boost
+ asciiCharClasses [unicode.MaxASCII + 1]charClass
)
type charClass int
@@ -187,6 +190,22 @@ func Init(scheme string) bool {
default:
return false
}
+ for i := 0; i <= unicode.MaxASCII; i++ {
+ char := rune(i)
+ c := charNonWord
+ if char >= 'a' && char <= 'z' {
+ c = charLower
+ } else if char >= 'A' && char <= 'Z' {
+ c = charUpper
+ } else if char >= '0' && char <= '9' {
+ c = charNumber
+ } else if strings.ContainsRune(whiteChars, char) {
+ c = charWhite
+ } else if strings.ContainsRune(delimiterChars, char) {
+ c = charDelimiter
+ }
+ asciiCharClasses[i] = c
+ }
return true
}
@@ -214,21 +233,6 @@ func alloc32(offset int, slab *util.Slab, size int) (int, []int32) {
return offset, make([]int32, size)
}
-func charClassOfAscii(char rune) charClass {
- if char >= 'a' && char <= 'z' {
- return charLower
- } else if char >= 'A' && char <= 'Z' {
- return charUpper
- } else if char >= '0' && char <= '9' {
- return charNumber
- } else if strings.ContainsRune(whiteChars, char) {
- return charWhite
- } else if strings.ContainsRune(delimiterChars, char) {
- return charDelimiter
- }
- return charNonWord
-}
-
func charClassOfNonAscii(char rune) charClass {
if unicode.IsLower(char) {
return charLower
@@ -248,7 +252,7 @@ func charClassOfNonAscii(char rune) charClass {
func charClassOf(char rune) charClass {
if char <= unicode.MaxASCII {
- return charClassOfAscii(char)
+ return asciiCharClasses[char]
}
return charClassOfNonAscii(char)
}
@@ -447,9 +451,10 @@ func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input *util.
for off, char := range Tsub {
var class charClass
if char <= unicode.MaxASCII {
- class = charClassOfAscii(char)
+ class = asciiCharClasses[char]
if !caseSensitive && class == charUpper {
char += 32
+ Tsub[off] = char
}
} else {
class = charClassOfNonAscii(char)
@@ -459,9 +464,9 @@ func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input *util.
if normalize {
char = normalizeRune(char)
}
+ Tsub[off] = char
}
- Tsub[off] = char
bonus := bonusFor(prevClass, class)
Bsub[off] = bonus
prevClass = class
diff --git a/src/algo/algo_test.go b/src/algo/algo_test.go
index a7c4e1d3..b5ed0e77 100644
--- a/src/algo/algo_test.go
+++ b/src/algo/algo_test.go
@@ -9,6 +9,10 @@ import (
"github.com/junegunn/fzf/src/util"
)
+func init() {
+ Init("default")
+}
+
func assertMatch(t *testing.T, fun Algo, caseSensitive, forward bool, input, pattern string, sidx int, eidx int, score int) {
assertMatch2(t, fun, caseSensitive, false, forward, input, pattern, sidx, eidx, score)
}
diff --git a/src/options.go b/src/options.go
index 76fe9ee9..38a5ba7c 100644
--- a/src/options.go
+++ b/src/options.go
@@ -2259,9 +2259,7 @@ func postProcessOptions(opts *Options) {
theme.Spinner = boldify(theme.Spinner)
}
- if opts.Scheme != "default" {
- processScheme(opts)
- }
+ processScheme(opts)
}
func expectsArbitraryString(opt string) bool {