Files
junegunn--fzf/src/algo/runeindex_ref.go
T
Junegunn Choi 9dfdba41f5 Prefilter rune-mode input for non-ASCII patterns
The scan only ran for ASCII patterns, so searching CJK text with a CJK
query still built the full score matrix. Scan for one byte of the pattern
rune and verify all four.

Which byte matters. Every ASCII rune contributes three zero bytes, so
U+AE00 scanned by its zero low byte hits on nearly every character of an
ASCII-heavy line. Pick a byte that cannot occur in an ASCII rune, else
any non-zero one.

A non-ASCII pattern rune is safe only when no other rune lowercases onto
it. Uncased is not sufficient: U+00DF has no simple uppercase, yet U+1E9E
lowercases to it, so the foldable set is excluded too.

Measured on 1.4M-line corpora, with a non-ASCII query:

- Every line CJK: 5.1x to 10.2x
- Mostly-ASCII paths behind a Hangul prefix: 5.6x to 6.0x, and 1.2x
  where every line matches so nothing can be rejected
- ASCII queries unchanged, kept off the non-inlinable guard
2026-08-08 19:48:04 +09:00

56 lines
1.4 KiB
Go

package algo
// Reference scanners over a []rune, with no representation tricks.
//
// They have two roles. Where reinterpreting a []rune as little-endian bytes is
// not valid, they are the shipped implementation, via runeindex_others.go.
// Everywhere else, the tests feed the same inputs to these and to the byte-view
// scanners in runeindex_x86.go and require identical answers.
//
// They carry no build tag so that both roles hold on every platform. Otherwise
// the portable build would be code that nothing here ever runs.
func indexAsciiRuneRef(runes []rune, caseSensitive bool, b byte, from int) int {
lower, upper := rune(b), rune(-1)
if !caseSensitive && b >= 'a' && b <= 'z' {
upper = rune(b - 32)
}
for i := from; i < len(runes); i++ {
if runes[i] == lower || runes[i] == upper {
return i
}
}
return -1
}
func lastIndexAsciiRuneRef(runes []rune, caseSensitive bool, b byte, from int) int {
lower, upper := rune(b), rune(-1)
if !caseSensitive && b >= 'a' && b <= 'z' {
upper = rune(b - 32)
}
for i := len(runes) - 1; i >= from; i-- {
if runes[i] == lower || runes[i] == upper {
return i
}
}
return -1
}
func indexRuneRef(runes []rune, r rune, from int) int {
for i := from; i < len(runes); i++ {
if runes[i] == r {
return i
}
}
return -1
}
func lastIndexRuneRef(runes []rune, r rune, from int) int {
for i := len(runes) - 1; i >= from; i-- {
if runes[i] == r {
return i
}
}
return -1
}