matchergroup_substr.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package strmatcher
  2. import (
  3. "sort"
  4. "strings"
  5. )
  6. // SubstrMatcherGroup is implementation of MatcherGroup,
  7. // It is simply implmeneted to comply with the priority specification of Substr matchers.
  8. type SubstrMatcherGroup struct {
  9. patterns []string
  10. values []uint32
  11. }
  12. // AddSubstrMatcher implements MatcherGroupForSubstr.AddSubstrMatcher.
  13. func (g *SubstrMatcherGroup) AddSubstrMatcher(matcher SubstrMatcher, value uint32) {
  14. g.patterns = append(g.patterns, matcher.Pattern())
  15. g.values = append(g.values, value)
  16. }
  17. // Match implements MatcherGroup.Match.
  18. func (g *SubstrMatcherGroup) Match(input string) []uint32 {
  19. var result []uint32
  20. for i, pattern := range g.patterns {
  21. for j := strings.LastIndex(input, pattern); j != -1; j = strings.LastIndex(input[:j], pattern) {
  22. result = append(result, uint32(j)<<16|uint32(i)&0xffff) // uint32: position (higher 16 bit) | patternIdx (lower 16 bit)
  23. }
  24. }
  25. // sort.Slice will trigger allocation no matter what input is. See https://github.com/golang/go/issues/17332
  26. // We optimize the sorting by length to prevent memory allocation as possible.
  27. switch len(result) {
  28. case 0:
  29. return nil
  30. case 1:
  31. // No need to sort
  32. case 2:
  33. // Do a simple swap if unsorted
  34. if result[0] > result[1] {
  35. result[0], result[1] = result[1], result[0]
  36. }
  37. default:
  38. // Sort the match results in dictionary order, so that:
  39. // 1. Pattern matched at smaller position (meaning matched further) takes precedence.
  40. // 2. When patterns matched at same position, pattern with smaller index (meaning inserted early) takes precedence.
  41. sort.Slice(result, func(i, j int) bool { return result[i] < result[j] })
  42. }
  43. for i, entry := range result {
  44. result[i] = g.values[entry&0xffff] // Get pattern value from its index (the lower 16 bit)
  45. }
  46. return result
  47. }
  48. // MatchAny implements MatcherGroup.MatchAny.
  49. func (g *SubstrMatcherGroup) MatchAny(input string) bool {
  50. for _, pattern := range g.patterns {
  51. if strings.Contains(input, pattern) {
  52. return true
  53. }
  54. }
  55. return false
  56. }