60 lines
950 B
Go
60 lines
950 B
Go
package qrcode
|
|
|
|
// kmp is variant of kmp algorithm to count the pattern been in
|
|
// src slice.
|
|
// DONE(@yeqown): implement this in generic way.
|
|
func kmp[v comparable](src, pattern []v, next []int) (count int) {
|
|
if next == nil {
|
|
next = kmpGetNext(pattern)
|
|
}
|
|
slen := len(src)
|
|
plen := len(pattern)
|
|
i := 0 // cursor of src
|
|
j := 0 // cursor of pattern
|
|
|
|
loop:
|
|
for i < slen && j < plen {
|
|
if j == -1 || src[i] == pattern[j] {
|
|
i++
|
|
j++
|
|
} else {
|
|
j = next[j]
|
|
}
|
|
}
|
|
|
|
if j == plen {
|
|
if i-j >= 0 {
|
|
count++
|
|
}
|
|
|
|
// reset cursor to count duplicate pattern.
|
|
// such as: "aaaa" and "aa", we want 3 rather than 2.
|
|
i -= plen - 1
|
|
j = 0
|
|
|
|
goto loop
|
|
}
|
|
|
|
return count
|
|
}
|
|
|
|
func kmpGetNext[v comparable](pattern []v) []int {
|
|
fail := make([]int, len(pattern))
|
|
fail[0] = -1
|
|
|
|
j := 0
|
|
k := -1
|
|
|
|
for j < len(pattern)-1 {
|
|
if k == -1 || pattern[j] == pattern[k] {
|
|
k++
|
|
j++
|
|
fail[j] = k
|
|
} else {
|
|
k = fail[k]
|
|
}
|
|
}
|
|
|
|
return fail
|
|
}
|