mirror of
https://github.com/peco/peco.git
synced 2026-09-10 07:16:29 -04:00
Merge pull request #783 from peco/fix-closure-alloc
fix: eliminate closure allocation in fuzzy filter
This commit is contained in:
commit
a91172b458
|
|
@ -2,15 +2,17 @@ package filter
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/peco/peco/internal/util"
|
||||
"github.com/peco/peco/line"
|
||||
"github.com/peco/peco/pipeline"
|
||||
)
|
||||
|
||||
// BenchmarkFuzzyFilter benchmarks the fuzzy filter to measure allocations
|
||||
// in the hot path.
|
||||
// in the hot path (CaseInsensitiveIndexFunc closure, match slices, etc).
|
||||
func BenchmarkFuzzyFilter(b *testing.B) {
|
||||
lines := make([]line.Line, 200)
|
||||
for i := range lines {
|
||||
|
|
@ -18,7 +20,7 @@ func BenchmarkFuzzyFilter(b *testing.B) {
|
|||
}
|
||||
|
||||
f := NewFuzzy(false)
|
||||
query := "trfp"
|
||||
query := "trfp" // matches scattered chars across the line
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
|
@ -29,3 +31,28 @@ func BenchmarkFuzzyFilter(b *testing.B) {
|
|||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkCaseInsensitiveIndexClosure measures the old closure-based approach.
|
||||
func BenchmarkCaseInsensitiveIndexClosure(b *testing.B) {
|
||||
txt := "this is a reasonably long line for benchmarking"
|
||||
r := 'r'
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
fn := util.CaseInsensitiveIndexFunc(r)
|
||||
strings.IndexFunc(txt, fn)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkCaseInsensitiveIndexDirect measures the new direct approach.
|
||||
func BenchmarkCaseInsensitiveIndexDirect(b *testing.B) {
|
||||
txt := "this is a reasonably long line for benchmarking"
|
||||
r := 'r'
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
util.CaseInsensitiveIndex(txt, r)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ LINE:
|
|||
if hasUpper {
|
||||
idx = strings.IndexRune(remaining, firstRune)
|
||||
} else {
|
||||
idx = strings.IndexFunc(remaining, util.CaseInsensitiveIndexFunc(firstRune))
|
||||
idx = util.CaseInsensitiveIndex(remaining, firstRune)
|
||||
}
|
||||
if idx == -1 {
|
||||
break
|
||||
|
|
@ -157,7 +157,7 @@ LINE:
|
|||
if hasUpper {
|
||||
idx = strings.IndexRune(candidateTxt, r)
|
||||
} else {
|
||||
idx = strings.IndexFunc(candidateTxt, util.CaseInsensitiveIndexFunc(r))
|
||||
idx = util.CaseInsensitiveIndex(candidateTxt, r)
|
||||
}
|
||||
if idx == -1 {
|
||||
continue OUTER
|
||||
|
|
|
|||
|
|
@ -18,6 +18,19 @@ func CaseInsensitiveIndexFunc(r rune) func(rune) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// CaseInsensitiveIndex returns the byte index of the first rune in s that
|
||||
// is case-insensitively equal to r. Returns -1 if not found. This avoids
|
||||
// the closure allocation of CaseInsensitiveIndexFunc + strings.IndexFunc.
|
||||
func CaseInsensitiveIndex(s string, r rune) int {
|
||||
upper := unicode.ToUpper(r)
|
||||
for i, c := range s {
|
||||
if unicode.ToUpper(c) == upper {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ContainsUpper reports whether the string contains any uppercase letter.
|
||||
func ContainsUpper(query string) bool {
|
||||
for _, c := range query {
|
||||
|
|
|
|||
Loading…
Reference in a new issue