summaryrefslogtreecommitdiffstats
path: root/src/pattern.go
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2016-08-19 02:39:32 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2016-08-19 02:39:32 +0900
commit37dc273148df0893053bf5cda0582a23f5c2b2d2 (patch)
treed90f5e96fa97de429265461268b1a6db2703cb4c /src/pattern.go
parentf7f01d109eb05c7eae82c243b6b6d5c5951ee707 (diff)
Micro-optimizations
- Make structs smaller - Introduce Result struct and use it to represent matched items instead of reusing Item struct for that purpose - Avoid unnecessary memory allocation - Avoid growing slice from the initial capacity - Code cleanup
Diffstat (limited to 'src/pattern.go')
-rw-r--r--src/pattern.go110
1 files changed, 51 insertions, 59 deletions
diff --git a/src/pattern.go b/src/pattern.go
index 0bf9af30..4c35a127 100644
--- a/src/pattern.go
+++ b/src/pattern.go
@@ -2,7 +2,6 @@ package fzf
import (
"regexp"
- "sort"
"strings"
"github.com/junegunn/fzf/src/algo"
@@ -235,9 +234,7 @@ func (p *Pattern) CacheKey() string {
}
// Match returns the list of matches Items in the given Chunk
-func (p *Pattern) Match(chunk *Chunk) []*Item {
- space := chunk
-
+func (p *Pattern) Match(chunk *Chunk) []*Result {
// ChunkCache: Exact match
cacheKey := p.CacheKey()
if p.cacheable {
@@ -246,7 +243,8 @@ func (p *Pattern) Match(chunk *Chunk) []*Item {
}
}
- // ChunkCache: Prefix/suffix match
+ // Prefix/suffix cache
+ var space []*Result
Loop:
for idx := 1; idx < len(cacheKey); idx++ {
// [---------| ] | [ |---------]
@@ -256,14 +254,13 @@ Loop:
suffix := cacheKey[idx:]
for _, substr := range [2]*string{&prefix, &suffix} {
if cached, found := _cache.Find(chunk, *substr); found {
- cachedChunk := Chunk(cached)
- space = &cachedChunk
+ space = cached
break Loop
}
}
}
- matches := p.matchChunk(space)
+ matches := p.matchChunk(chunk, space)
if p.cacheable {
_cache.Add(chunk, cacheKey, matches)
@@ -271,20 +268,19 @@ Loop:
return matches
}
-func (p *Pattern) matchChunk(chunk *Chunk) []*Item {
- matches := []*Item{}
- if !p.extended {
+func (p *Pattern) matchChunk(chunk *Chunk, space []*Result) []*Result {
+ matches := []*Result{}
+
+ if space == nil {
for _, item := range *chunk {
- offset, bonus := p.basicMatch(item)
- if sidx := offset[0]; sidx >= 0 {
- matches = append(matches,
- dupItem(item, []Offset{offset}, bonus))
+ if match := p.MatchItem(item); match != nil {
+ matches = append(matches, match)
}
}
} else {
- for _, item := range *chunk {
- if offsets, bonus := p.extendedMatch(item); len(offsets) == len(p.termSets) {
- matches = append(matches, dupItem(item, offsets, bonus))
+ for _, result := range space {
+ if match := p.MatchItem(result.item); match != nil {
+ matches = append(matches, match)
}
}
}
@@ -292,29 +288,21 @@ func (p *Pattern) matchChunk(chunk *Chunk) []*Item {
}
// MatchItem returns true if the Item is a match
-func (p *Pattern) MatchItem(item *Item) bool {
- if !p.extended {
- offset, _ := p.basicMatch(item)
- sidx := offset[0]
- return sidx >= 0
+func (p *Pattern) MatchItem(item *Item) *Result {
+ if p.extended {
+ if offsets, bonus, trimLen := p.extendedMatch(item); len(offsets) == len(p.termSets) {
+ return buildResult(item, offsets, bonus, trimLen)
+ }
+ return nil
}
- offsets, _ := p.extendedMatch(item)
- return len(offsets) == len(p.termSets)
-}
-
-func dupItem(item *Item, offsets []Offset, bonus int32) *Item {
- sort.Sort(ByOrder(offsets))
- return &Item{
- text: item.text,
- origText: item.origText,
- transformed: item.transformed,
- offsets: offsets,
- bonus: bonus,
- colors: item.colors,
- rank: buildEmptyRank(item.Index())}
+ offset, bonus, trimLen := p.basicMatch(item)
+ if sidx := offset[0]; sidx >= 0 {
+ return buildResult(item, []Offset{offset}, bonus, trimLen)
+ }
+ return nil
}
-func (p *Pattern) basicMatch(item *Item) (Offset, int32) {
+func (p *Pattern) basicMatch(item *Item) (Offset, int, int) {
input := p.prepareInput(item)
if p.fuzzy {
return p.iter(algo.FuzzyMatch, input, p.caseSensitive, p.forward, p.text)
@@ -322,33 +310,39 @@ func (p *Pattern) basicMatch(item *Item) (Offset, int32) {
return p.iter(algo.ExactMatchNaive, input, p.caseSensitive, p.forward, p.text)
}
-func (p *Pattern) extendedMatch(item *Item) ([]Offset, int32) {
+func (p *Pattern) extendedMatch(item *Item) ([]Offset, int, int) {
input := p.prepareInput(item)
offsets := []Offset{}
- var totalBonus int32
+ var totalBonus int
+ var totalTrimLen int
for _, termSet := range p.termSets {
- var offset *Offset
- var bonus int32
+ var offset Offset
+ var bonus int
+ var trimLen int
+ matched := false
for _, term := range termSet {
pfun := p.procFun[term.typ]
- off, pen := p.iter(pfun, input, term.caseSensitive, p.forward, term.text)
+ off, pen, tLen := p.iter(pfun, input, term.caseSensitive, p.forward, term.text)
if sidx := off[0]; sidx >= 0 {
if term.inv {
continue
}
- offset, bonus = &off, pen
+ offset, bonus, trimLen = off, pen, tLen
+ matched = true
break
} else if term.inv {
- offset, bonus = &Offset{0, 0, 0}, 0
+ offset, bonus, trimLen = Offset{0, 0}, 0, 0
+ matched = true
continue
}
}
- if offset != nil {
- offsets = append(offsets, *offset)
+ if matched {
+ offsets = append(offsets, offset)
totalBonus += bonus
+ totalTrimLen += trimLen
}
}
- return offsets, totalBonus
+ return offsets, totalBonus, totalTrimLen
}
func (p *Pattern) prepareInput(item *Item) []Token {
@@ -357,26 +351,24 @@ func (p *Pattern) prepareInput(item *Item) []Token {
}
var ret []Token
- if len(p.nth) > 0 {
+ if len(p.nth) == 0 {
+ ret = []Token{Token{text: &item.text, prefixLength: 0, trimLength: int32(item.text.TrimLength())}}
+ } else {
tokens := Tokenize(item.text, p.delimiter)
ret = Transform(tokens, p.nth)
- } else {
- ret = []Token{Token{text: item.text, prefixLength: 0, trimLength: item.text.TrimLength()}}
}
item.transformed = ret
return ret
}
func (p *Pattern) iter(pfun func(bool, bool, util.Chars, []rune) algo.Result,
- tokens []Token, caseSensitive bool, forward bool, pattern []rune) (Offset, int32) {
+ tokens []Token, caseSensitive bool, forward bool, pattern []rune) (Offset, int, int) {
for _, part := range tokens {
- prefixLength := int32(part.prefixLength)
- if res := pfun(caseSensitive, forward, part.text, pattern); res.Start >= 0 {
- sidx := res.Start + prefixLength
- eidx := res.End + prefixLength
- return Offset{sidx, eidx, int32(part.trimLength)}, res.Bonus
+ if res := pfun(caseSensitive, forward, *part.text, pattern); res.Start >= 0 {
+ sidx := int32(res.Start) + part.prefixLength
+ eidx := int32(res.End) + part.prefixLength
+ return Offset{sidx, eidx}, res.Bonus, int(part.trimLength)
}
}
- // TODO: math.MaxUint16
- return Offset{-1, -1, -1}, 0.0
+ return Offset{-1, -1}, 0, -1
}