From 8db3345c2fe5551a7cbc838ddef009813cdeec41 Mon Sep 17 00:00:00 2001
From: Junegunn Choi <junegunn.c@gmail.com>
Date: Sun, 30 Jul 2017 18:15:02 +0900
Subject: [PATCH] Optimize exact match by applying the same trick for fuzzy
 match

---
 src/algo/algo.go | 62 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 19 deletions(-)

diff --git a/src/algo/algo.go b/src/algo/algo.go
index a2f0f2b4..7a6dad32 100644
--- a/src/algo/algo.go
+++ b/src/algo/algo.go
@@ -274,6 +274,41 @@ func trySkip(input *util.Chars, caseSensitive bool, b byte, from int) int {
 	return from + idx
 }
 
+func isAscii(runes []rune) bool {
+	for _, r := range runes {
+		if r >= utf8.RuneSelf {
+			return false
+		}
+	}
+	return true
+}
+
+func asciiFuzzyIndex(input *util.Chars, pattern []rune, caseSensitive bool) int {
+	// Can't determine
+	if !input.IsBytes() {
+		return 0
+	}
+
+	// Not possible
+	if !isAscii(pattern) {
+		return -1
+	}
+
+	firstIdx, idx := 0, 0
+	for pidx := 0; pidx < len(pattern); pidx++ {
+		idx = trySkip(input, caseSensitive, byte(pattern[pidx]), idx)
+		if idx < 0 {
+			return -1
+		}
+		if pidx == 0 && idx > 0 {
+			// Step back to find the right bonus point
+			firstIdx = idx - 1
+		}
+		idx++
+	}
+	return firstIdx
+}
+
 func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
 	// Assume that pattern is given in lowercase if case-insensitive.
 	// First check if there's a match and calculate bonus for each position.
@@ -302,30 +337,15 @@ func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input util.C
 	offset32, T := alloc32(offset32, slab, N, false)
 
 	// Phase 1. Optimized search for ASCII string
-	firstIdx := 0
-	if input.IsBytes() {
-		idx := 0
-		for pidx := 0; pidx < M; pidx++ {
-			// Not possible
-			if pattern[pidx] >= utf8.RuneSelf {
-				return Result{-1, -1, 0}, nil
-			}
-			idx = trySkip(&input, caseSensitive, byte(pattern[pidx]), idx)
-			if idx < 0 {
-				return Result{-1, -1, 0}, nil
-			}
-			if pidx == 0 && idx > 0 {
-				// Step back to find the right bonus point
-				firstIdx = idx - 1
-			}
-			idx++
-		}
+	idx := asciiFuzzyIndex(&input, pattern, caseSensitive)
+	if idx < 0 {
+		return Result{-1, -1, 0}, nil
 	}
 
 	// Phase 2. Calculate bonus for each point
 	pidx, lastIdx, prevClass := 0, 0, charNonWord
 	input.CopyRunes(T)
-	for idx := firstIdx; idx < N; idx++ {
+	for ; idx < N; idx++ {
 		char := T[idx]
 		var class charClass
 		if char <= unicode.MaxASCII {
@@ -657,6 +677,10 @@ func ExactMatchNaive(caseSensitive bool, normalize bool, forward bool, text util
 		return Result{-1, -1, 0}, nil
 	}
 
+	if asciiFuzzyIndex(&text, pattern, caseSensitive) < 0 {
+		return Result{-1, -1, 0}, nil
+	}
+
 	// For simplicity, only look at the bonus at the first character position
 	pidx := 0
 	bestPos, bonus, bestBonus := -1, int16(0), int16(-1)
-- 
GitLab