mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-12-22 18:17:52 -05:00
f494df2567
[common/strmatcher] Implement Match and MatchAny for all MatcherGroup and IndexMatcher
62 lines
2.0 KiB
Go
62 lines
2.0 KiB
Go
package strmatcher
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// SubstrMatcherGroup is implementation of MatcherGroup,
|
|
// It is simply implmeneted to comply with the priority specification of Substr matchers.
|
|
type SubstrMatcherGroup struct {
|
|
patterns []string
|
|
values []uint32
|
|
}
|
|
|
|
// AddSubstrMatcher implements MatcherGroupForSubstr.AddSubstrMatcher.
|
|
func (g *SubstrMatcherGroup) AddSubstrMatcher(matcher SubstrMatcher, value uint32) {
|
|
g.patterns = append(g.patterns, matcher.Pattern())
|
|
g.values = append(g.values, value)
|
|
}
|
|
|
|
// Match implements MatcherGroup.Match.
|
|
func (g *SubstrMatcherGroup) Match(input string) []uint32 {
|
|
var result []uint32
|
|
for i, pattern := range g.patterns {
|
|
for j := strings.LastIndex(input, pattern); j != -1; j = strings.LastIndex(input[:j], pattern) {
|
|
result = append(result, uint32(j)<<16|uint32(i)&0xffff) // uint32: position (higher 16 bit) | patternIdx (lower 16 bit)
|
|
}
|
|
}
|
|
// sort.Slice will trigger allocation no matter what input is. See https://github.com/golang/go/issues/17332
|
|
// We optimize the sorting by length to prevent memory allocation as possible.
|
|
switch len(result) {
|
|
case 0:
|
|
return nil
|
|
case 1:
|
|
// No need to sort
|
|
case 2:
|
|
// Do a simple swap if unsorted
|
|
if result[0] > result[1] {
|
|
result[0], result[1] = result[1], result[0]
|
|
}
|
|
default:
|
|
// Sort the match results in dictionary order, so that:
|
|
// 1. Pattern matched at smaller position (meaning matched further) takes precedence.
|
|
// 2. When patterns matched at same position, pattern with smaller index (meaning inserted early) takes precedence.
|
|
sort.Slice(result, func(i, j int) bool { return result[i] < result[j] })
|
|
}
|
|
for i, entry := range result {
|
|
result[i] = g.values[entry&0xffff] // Get pattern value from its index (the lower 16 bit)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// MatchAny implements MatcherGroup.MatchAny.
|
|
func (g *SubstrMatcherGroup) MatchAny(input string) bool {
|
|
for _, pattern := range g.patterns {
|
|
if strings.Contains(input, pattern) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|