filter: Parse filter patterns only once

name                          old time/op    new time/op    delta
FilterPatterns/Relative-4       30.3ms ±10%    23.6ms ±20%  -22.12%  (p=0.000 n=10+10)
FilterPatterns/Absolute-4       49.0ms ± 3%    32.3ms ± 8%  -33.94%  (p=0.000 n=8+10)
FilterPatterns/Wildcard-4        345ms ± 9%     334ms ±17%     ~     (p=0.315 n=10+10)
FilterPatterns/ManyNoMatch-4     3.93s ± 2%     0.71s ± 7%  -81.98%  (p=0.000 n=9+10)

name                          old alloc/op   new alloc/op   delta
FilterPatterns/Relative-4       4.63MB ± 0%    3.57MB ± 0%  -22.98%  (p=0.000 n=9+9)
FilterPatterns/Absolute-4       8.54MB ± 0%    3.57MB ± 0%  -58.20%  (p=0.000 n=10+10)
FilterPatterns/Wildcard-4        146MB ± 0%     141MB ± 0%   -2.93%  (p=0.000 n=9+9)
FilterPatterns/ManyNoMatch-4     907MB ± 0%       4MB ± 0%  -99.61%  (p=0.000 n=9+9)

name                          old allocs/op  new allocs/op  delta
FilterPatterns/Relative-4        66.6k ± 0%     22.2k ± 0%  -66.67%  (p=0.000 n=10+10)
FilterPatterns/Absolute-4        88.7k ± 0%     22.2k ± 0%  -75.00%  (p=0.000 n=10+10)
FilterPatterns/Wildcard-4        1.70M ± 0%     1.63M ± 0%   -3.92%  (p=0.000 n=10+10)
FilterPatterns/ManyNoMatch-4     4.46M ± 0%     0.02M ± 0%  -99.50%  (p=0.000 n=10+10)
This commit is contained in:
Michael Eischer 2020-10-07 14:39:51 +02:00
parent b8eacd1364
commit 375c2a56de
4 changed files with 50 additions and 34 deletions

View file

@ -11,7 +11,8 @@ import (
// second argument.
var ErrBadString = errors.New("filter.Match: string is empty")
type filterPattern []string
// Pattern represents a preparsed filter pattern
type Pattern []string
func prepareStr(str string) ([]string, error) {
if str == "" {
@ -26,7 +27,7 @@ func prepareStr(str string) ([]string, error) {
return strings.Split(str, "/"), nil
}
func preparePattern(pattern string) filterPattern {
func preparePattern(pattern string) Pattern {
pattern = filepath.Clean(pattern)
// convert file path separator to '/'
@ -87,7 +88,7 @@ func ChildMatch(pattern, str string) (matched bool, err error) {
return childMatch(patterns, strs)
}
func childMatch(patterns, strs []string) (matched bool, err error) {
func childMatch(patterns Pattern, strs []string) (matched bool, err error) {
if patterns[0] != "" {
// relative pattern can always be nested down
return true, nil
@ -109,7 +110,7 @@ func childMatch(patterns, strs []string) (matched bool, err error) {
return match(patterns[0:l], strs)
}
func hasDoubleWildcard(list []string) (ok bool, pos int) {
func hasDoubleWildcard(list Pattern) (ok bool, pos int) {
for i, item := range list {
if item == "**" {
return true, i
@ -119,11 +120,11 @@ func hasDoubleWildcard(list []string) (ok bool, pos int) {
return false, 0
}
func match(patterns, strs []string) (matched bool, err error) {
func match(patterns Pattern, strs []string) (matched bool, err error) {
if ok, pos := hasDoubleWildcard(patterns); ok {
// gradually expand '**' into separate wildcards
for i := 0; i <= len(strs)-len(patterns)+1; i++ {
newPat := make([]string, pos)
newPat := make(Pattern, pos)
copy(newPat, patterns[:pos])
for k := 0; k < i; k++ {
newPat = append(newPat, "*")
@ -169,9 +170,22 @@ func match(patterns, strs []string) (matched bool, err error) {
return false, nil
}
// List returns true if str matches one of the patterns. Empty patterns are
// ignored.
func List(patterns []string, str string) (matched bool, childMayMatch bool, err error) {
// ParsePatterns prepares a list of patterns for use with List.
func ParsePatterns(patterns []string) []Pattern {
patpat := make([]Pattern, 0)
for _, pat := range patterns {
if pat == "" {
continue
}
pats := preparePattern(pat)
patpat = append(patpat, pats)
}
return patpat
}
// List returns true if str matches one of the patterns. Empty patterns are ignored.
func List(patterns []Pattern, str string) (matched bool, childMayMatch bool, err error) {
if len(patterns) == 0 {
return false, false, nil
}
@ -181,17 +195,12 @@ func List(patterns []string, str string) (matched bool, childMayMatch bool, err
return false, false, err
}
for _, pat := range patterns {
if pat == "" {
continue
}
pats := preparePattern(pat)
m, err := match(pats, strs)
m, err := match(pat, strs)
if err != nil {
return false, false, err
}
c, err := childMatch(pats, strs)
c, err := childMatch(pat, strs)
if err != nil {
return false, false, err
}