| 285 | } |
| 286 | |
| 287 | func stringFixedDistanceCharFilter(ch rune, distance, minRequiredLength int) StringPrefixFilter { |
| 288 | if distance < 0 { |
| 289 | return nil |
| 290 | } |
| 291 | |
| 292 | return func(input string, startAt int) (candidateByteIndex int, ok bool) { |
| 293 | if !hasMinRequiredBytes(input, startAt, minRequiredLength) { |
| 294 | return 0, false |
| 295 | } |
| 296 | |
| 297 | searchAt := startAt |
| 298 | for { |
| 299 | offset := strings.IndexRune(input[searchAt:], ch) |
| 300 | if offset < 0 { |
| 301 | return 0, false |
| 302 | } |
| 303 | byteIndex := searchAt + offset |
| 304 | candidateByteIndex, ok := stringFixedDistanceCandidateStart(input, startAt, byteIndex, distance) |
| 305 | if ok && hasMinRequiredBytes(input, candidateByteIndex, minRequiredLength) { |
| 306 | return candidateByteIndex, true |
| 307 | } |
| 308 | if ok { |
| 309 | return 0, false |
| 310 | } |
| 311 | _, size := utf8.DecodeRuneInString(input[byteIndex:]) |
| 312 | if size == 0 { |
| 313 | return 0, false |
| 314 | } |
| 315 | searchAt = byteIndex + size |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | func stringFixedDistanceStringFilter(literal string, distance, minRequiredLength int) StringPrefixFilter { |
| 321 | if literal == "" || distance < 0 || len(literal) > maxStringFilterLiteralLen { |