forked from TrueCloudLab/restic
filter: Reduce redundant path and pattern splitting
A single call to filter.List will split the path only once and also split each search pattern only once and use it for both match and childMatch. name old time/op new time/op delta FilterPatterns/Relative-4 62.1ms ±15% 30.3ms ±10% -51.22% (p=0.000 n=9+10) FilterPatterns/Absolute-4 111ms ±10% 49ms ± 3% -56.08% (p=0.000 n=10+8) FilterPatterns/Wildcard-4 393ms ±15% 345ms ± 9% -12.30% (p=0.000 n=10+10) FilterPatterns/ManyNoMatch-4 10.0s ± 3% 3.9s ± 2% -60.53% (p=0.000 n=10+9) name old alloc/op new alloc/op delta FilterPatterns/Relative-4 16.4MB ± 0% 4.6MB ± 0% -71.76% (p=0.000 n=10+9) FilterPatterns/Absolute-4 31.4MB ± 0% 8.5MB ± 0% -72.77% (p=0.000 n=9+10) FilterPatterns/Wildcard-4 168MB ± 0% 146MB ± 0% -13.19% (p=0.000 n=10+9) FilterPatterns/ManyNoMatch-4 3.23GB ± 0% 0.91GB ± 0% -71.96% (p=0.000 n=10+9) name old allocs/op new allocs/op delta FilterPatterns/Relative-4 178k ± 0% 67k ± 0% -62.50% (p=0.000 n=10+10) FilterPatterns/Absolute-4 266k ± 0% 89k ± 0% -66.67% (p=0.000 n=10+10) FilterPatterns/Wildcard-4 1.87M ± 0% 1.70M ± 0% -9.47% (p=0.000 n=10+10) FilterPatterns/ManyNoMatch-4 17.7M ± 0% 4.5M ± 0% -74.87% (p=0.000 n=9+10)
This commit is contained in:
parent
e73c281142
commit
b8eacd1364
1 changed files with 45 additions and 26 deletions
|
@ -11,6 +11,32 @@ import (
|
||||||
// second argument.
|
// second argument.
|
||||||
var ErrBadString = errors.New("filter.Match: string is empty")
|
var ErrBadString = errors.New("filter.Match: string is empty")
|
||||||
|
|
||||||
|
type filterPattern []string
|
||||||
|
|
||||||
|
func prepareStr(str string) ([]string, error) {
|
||||||
|
if str == "" {
|
||||||
|
return nil, ErrBadString
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert file path separator to '/'
|
||||||
|
if filepath.Separator != '/' {
|
||||||
|
str = strings.Replace(str, string(filepath.Separator), "/", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Split(str, "/"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func preparePattern(pattern string) filterPattern {
|
||||||
|
pattern = filepath.Clean(pattern)
|
||||||
|
|
||||||
|
// convert file path separator to '/'
|
||||||
|
if filepath.Separator != '/' {
|
||||||
|
pattern = strings.Replace(pattern, string(filepath.Separator), "/", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Split(pattern, "/")
|
||||||
|
}
|
||||||
|
|
||||||
// Match returns true if str matches the pattern. When the pattern is
|
// Match returns true if str matches the pattern. When the pattern is
|
||||||
// malformed, filepath.ErrBadPattern is returned. The empty pattern matches
|
// malformed, filepath.ErrBadPattern is returned. The empty pattern matches
|
||||||
// everything, when str is the empty string ErrBadString is returned.
|
// everything, when str is the empty string ErrBadString is returned.
|
||||||
|
@ -26,21 +52,13 @@ func Match(pattern, str string) (matched bool, err error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern = filepath.Clean(pattern)
|
patterns := preparePattern(pattern)
|
||||||
|
strs, err := prepareStr(str)
|
||||||
|
|
||||||
if str == "" {
|
if err != nil {
|
||||||
return false, ErrBadString
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert file path separator to '/'
|
|
||||||
if filepath.Separator != '/' {
|
|
||||||
pattern = strings.Replace(pattern, string(filepath.Separator), "/", -1)
|
|
||||||
str = strings.Replace(str, string(filepath.Separator), "/", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
patterns := strings.Split(pattern, "/")
|
|
||||||
strs := strings.Split(str, "/")
|
|
||||||
|
|
||||||
return match(patterns, strs)
|
return match(patterns, strs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,21 +77,13 @@ func ChildMatch(pattern, str string) (matched bool, err error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern = filepath.Clean(pattern)
|
patterns := preparePattern(pattern)
|
||||||
|
strs, err := prepareStr(str)
|
||||||
|
|
||||||
if str == "" {
|
if err != nil {
|
||||||
return false, ErrBadString
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert file path separator to '/'
|
|
||||||
if filepath.Separator != '/' {
|
|
||||||
pattern = strings.Replace(pattern, string(filepath.Separator), "/", -1)
|
|
||||||
str = strings.Replace(str, string(filepath.Separator), "/", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
patterns := strings.Split(pattern, "/")
|
|
||||||
strs := strings.Split(str, "/")
|
|
||||||
|
|
||||||
return childMatch(patterns, strs)
|
return childMatch(patterns, strs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,17 +172,26 @@ func match(patterns, strs []string) (matched bool, err error) {
|
||||||
// List returns true if str matches one of the patterns. Empty patterns are
|
// List returns true if str matches one of the patterns. Empty patterns are
|
||||||
// ignored.
|
// ignored.
|
||||||
func List(patterns []string, str string) (matched bool, childMayMatch bool, err error) {
|
func List(patterns []string, str string) (matched bool, childMayMatch bool, err error) {
|
||||||
|
if len(patterns) == 0 {
|
||||||
|
return false, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
strs, err := prepareStr(str)
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
for _, pat := range patterns {
|
for _, pat := range patterns {
|
||||||
if pat == "" {
|
if pat == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := Match(pat, str)
|
pats := preparePattern(pat)
|
||||||
|
m, err := match(pats, strs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := ChildMatch(pat, str)
|
c, err := childMatch(pats, strs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue