feat: dont compile regex matcher if we know its a literal (#12434)
labels: dont compile regex matcher if we know its a literal Signed-off-by: Michael Hoffmann <mhoffm@posteo.de> Co-authored-by: Sharad <sharadgaur@gmail.com>
This commit is contained in:
parent
4268feb9d7
commit
344c8ff97c
|
@ -102,12 +102,12 @@ func TestInverse(t *testing.T) {
|
||||||
expected: &Matcher{Type: MatchEqual, Name: "name2", Value: "value2"},
|
expected: &Matcher{Type: MatchEqual, Name: "name2", Value: "value2"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
matcher: &Matcher{Type: MatchRegexp, Name: "name3", Value: "value3"},
|
matcher: &Matcher{Type: MatchRegexp, Name: "name3", Value: "value3.*"},
|
||||||
expected: &Matcher{Type: MatchNotRegexp, Name: "name3", Value: "value3"},
|
expected: &Matcher{Type: MatchNotRegexp, Name: "name3", Value: "value3.*"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
matcher: &Matcher{Type: MatchNotRegexp, Name: "name4", Value: "value4"},
|
matcher: &Matcher{Type: MatchNotRegexp, Name: "name4", Value: "value4.*"},
|
||||||
expected: &Matcher{Type: MatchRegexp, Name: "name4", Value: "value4"},
|
expected: &Matcher{Type: MatchRegexp, Name: "name4", Value: "value4.*"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,3 +123,13 @@ func BenchmarkMatchType_String(b *testing.B) {
|
||||||
_ = MatchType(i % int(MatchNotRegexp+1)).String()
|
_ = MatchType(i % int(MatchNotRegexp+1)).String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewMatcher(b *testing.B) {
|
||||||
|
b.Run("regex matcher with literal", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i <= b.N; i++ {
|
||||||
|
NewMatcher(MatchRegexp, "foo", "bar")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -25,9 +25,16 @@ type FastRegexMatcher struct {
|
||||||
prefix string
|
prefix string
|
||||||
suffix string
|
suffix string
|
||||||
contains string
|
contains string
|
||||||
|
|
||||||
|
// shortcut for literals
|
||||||
|
literal bool
|
||||||
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) {
|
func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) {
|
||||||
|
if isLiteral(v) {
|
||||||
|
return &FastRegexMatcher{literal: true, value: v}, nil
|
||||||
|
}
|
||||||
re, err := regexp.Compile("^(?:" + v + ")$")
|
re, err := regexp.Compile("^(?:" + v + ")$")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -50,6 +57,9 @@ func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FastRegexMatcher) MatchString(s string) bool {
|
func (m *FastRegexMatcher) MatchString(s string) bool {
|
||||||
|
if m.literal {
|
||||||
|
return s == m.value
|
||||||
|
}
|
||||||
if m.prefix != "" && !strings.HasPrefix(s, m.prefix) {
|
if m.prefix != "" && !strings.HasPrefix(s, m.prefix) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -63,9 +73,16 @@ func (m *FastRegexMatcher) MatchString(s string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FastRegexMatcher) GetRegexString() string {
|
func (m *FastRegexMatcher) GetRegexString() string {
|
||||||
|
if m.literal {
|
||||||
|
return m.value
|
||||||
|
}
|
||||||
return m.re.String()
|
return m.re.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isLiteral(re string) bool {
|
||||||
|
return regexp.QuoteMeta(re) == re
|
||||||
|
}
|
||||||
|
|
||||||
// optimizeConcatRegex returns literal prefix/suffix text that can be safely
|
// optimizeConcatRegex returns literal prefix/suffix text that can be safely
|
||||||
// checked against the label value before running the regexp matcher.
|
// checked against the label value before running the regexp matcher.
|
||||||
func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) {
|
func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) {
|
||||||
|
|
Loading…
Reference in New Issue