Skip to content
This repository has been archived by the owner on Oct 17, 2018. It is now read-only.

Replace strings with byte slices for filters #23

Merged
merged 3 commits into from
Mar 28, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 61 additions & 55 deletions filters/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"bytes"
"errors"
"fmt"
"strings"
)

var (
Expand Down Expand Up @@ -60,21 +59,24 @@ const (
multiRangeStartChar = '{'
multiRangeEndChar = '}'
invalidNestedChars = "?[{"
multiRangeSplit = ","
)

var (
multiRangeSplit = []byte(",")
)

// Filter matches a string against certain conditions
type Filter interface {
fmt.Stringer

// Matches returns true if the conditions are met
Matches(val string) bool
Matches(val []byte) bool
}

// NewFilter supports startsWith, endsWith, contains and a single wildcard
// along with negation and glob matching support
// TODO(martinm): Provide more detailed error messages
func NewFilter(pattern string) (Filter, error) {
func NewFilter(pattern []byte) (Filter, error) {
if len(pattern) == 0 {
return newEqualityFilter(pattern), nil
}
Expand All @@ -98,8 +100,10 @@ func NewFilter(pattern string) (Filter, error) {

// newWildcardFilter creates a filter that segments the pattern based
// on wildcards, creating a rangeFilter for each segment
func newWildcardFilter(pattern string) (Filter, error) {
wIdx := strings.IndexRune(pattern, wildcardChar)
func newWildcardFilter(pattern []byte) (Filter, error) {
wIdx := bytes.IndexRune(pattern, wildcardChar)

// TODO(r): use utf8 to take into account size of rune in byte slice

if wIdx == -1 {
// No wildcards
Expand All @@ -116,7 +120,7 @@ func newWildcardFilter(pattern string) (Filter, error) {
return newRangeFilter(pattern[:len(pattern)-1], false, start)
}

secondWIdx := strings.IndexRune(pattern[wIdx+1:], wildcardChar)
secondWIdx := bytes.IndexRune(pattern[wIdx+1:], wildcardChar)
if secondWIdx == -1 {
if wIdx == 0 {
// Single wildcard at start
Expand Down Expand Up @@ -147,7 +151,7 @@ func newWildcardFilter(pattern string) (Filter, error) {

// newRangeFilter creates a filter that checks for ranges (? or [] or {}) and segments
// the pattern into a multiple chain filters based on ranges found
func newRangeFilter(pattern string, backwards bool, seg chainSegment) (Filter, error) {
func newRangeFilter(pattern []byte, backwards bool, seg chainSegment) (Filter, error) {
var filters []chainFilter
eqIdx := -1
for i := 0; i < len(pattern); i++ {
Expand All @@ -159,7 +163,7 @@ func newRangeFilter(pattern string, backwards bool, seg chainSegment) (Filter, e
eqIdx = -1
}

endIdx := strings.IndexRune(pattern[i+1:], singleRangeEndChar)
endIdx := bytes.IndexRune(pattern[i+1:], singleRangeEndChar)
if endIdx == -1 {
return nil, errInvalidFilterPattern
}
Expand All @@ -179,7 +183,7 @@ func newRangeFilter(pattern string, backwards bool, seg chainSegment) (Filter, e
eqIdx = -1
}

endIdx := strings.IndexRune(pattern[i+1:], multiRangeEndChar)
endIdx := bytes.IndexRune(pattern[i+1:], multiRangeEndChar)
if endIdx == -1 {
return nil, errInvalidFilterPattern
}
Expand Down Expand Up @@ -218,44 +222,44 @@ type allowFilter struct{}

func newAllowFilter() Filter { return allowAllFilter }
func (f allowFilter) String() string { return "All" }
func (f allowFilter) Matches(val string) bool { return true }
func (f allowFilter) Matches(val []byte) bool { return true }

// equalityFilter is a filter that matches exact values
type equalityFilter struct {
pattern string
pattern []byte
}

func newEqualityFilter(pattern string) Filter {
func newEqualityFilter(pattern []byte) Filter {
return &equalityFilter{pattern: pattern}
}

func (f *equalityFilter) String() string {
return "Equals(\"" + f.pattern + "\")"
return "Equals(\"" + string(f.pattern) + "\")"
}

func (f *equalityFilter) Matches(val string) bool {
return f.pattern == val
func (f *equalityFilter) Matches(val []byte) bool {
return bytes.Equal(f.pattern, val)
}

// containsFilter is a filter that performs contains matches
type containsFilter struct {
pattern string
pattern []byte
}

func newContainsFilter(pattern string) (Filter, error) {
if strings.ContainsAny(pattern, invalidNestedChars) {
func newContainsFilter(pattern []byte) (Filter, error) {
if bytes.ContainsAny(pattern, invalidNestedChars) {
return nil, errInvalidFilterPattern
}

return &containsFilter{pattern: pattern}, nil
}

func (f *containsFilter) String() string {
return "Contains(\"" + f.pattern + "\")"
return "Contains(\"" + string(f.pattern) + "\")"
}

func (f *containsFilter) Matches(val string) bool {
return strings.Contains(val, f.pattern)
func (f *containsFilter) Matches(val []byte) bool {
return bytes.Contains(val, f.pattern)
}

// negationFilter is a filter that matches the opposite of the provided filter
Expand All @@ -271,7 +275,7 @@ func (f *negationFilter) String() string {
return "Not(" + f.filter.String() + ")"
}

func (f *negationFilter) Matches(val string) bool {
func (f *negationFilter) Matches(val []byte) bool {
return !f.filter.Matches(val)
}

Expand Down Expand Up @@ -300,7 +304,7 @@ func (f *multiFilter) String() string {
return buf.String()
}

func (f *multiFilter) Matches(val string) bool {
func (f *multiFilter) Matches(val []byte) bool {
if len(f.filters) == 0 {
return true
}
Expand All @@ -324,34 +328,34 @@ func (f *multiFilter) Matches(val string) bool {
type chainFilter interface {
fmt.Stringer

matches(val string) (string, bool)
matches(val []byte) ([]byte, bool)
}

// equalityChainFilter is a filter that performs equality string matches
// from either the front or back of the string
type equalityChainFilter struct {
pattern string
pattern []byte
backwards bool
}

func newEqualityChainFilter(pattern string, backwards bool) chainFilter {
func newEqualityChainFilter(pattern []byte, backwards bool) chainFilter {
return &equalityChainFilter{pattern: pattern, backwards: backwards}
}

func (f *equalityChainFilter) String() string {
return "Equals(\"" + f.pattern + "\")"
return "Equals(\"" + string(f.pattern) + "\")"
}

func (f *equalityChainFilter) matches(val string) (string, bool) {
if f.backwards && strings.HasSuffix(val, f.pattern) {
func (f *equalityChainFilter) matches(val []byte) ([]byte, bool) {
if f.backwards && bytes.HasSuffix(val, f.pattern) {
return val[:len(val)-len(f.pattern)], true
}

if !f.backwards && strings.HasPrefix(val, f.pattern) {
if !f.backwards && bytes.HasPrefix(val, f.pattern) {
return val[len(f.pattern):], true
}

return "", false
return nil, false
}

// singleAnyCharFilter is a filter that allows any one char
Expand All @@ -369,9 +373,9 @@ func newSingleAnyCharFilter(backwards bool) chainFilter {

func (f *singleAnyCharFilter) String() string { return "AnyChar" }

func (f *singleAnyCharFilter) matches(val string) (string, bool) {
func (f *singleAnyCharFilter) matches(val []byte) ([]byte, bool) {
if len(val) == 0 {
return "", false
return nil, false
}

if f.backwards {
Expand All @@ -383,7 +387,7 @@ func (f *singleAnyCharFilter) matches(val string) (string, bool) {

// newSingleRangeFilter creates a filter that performs range matching
// on a single char
func newSingleRangeFilter(pattern string, backwards bool) (chainFilter, error) {
func newSingleRangeFilter(pattern []byte, backwards bool) (chainFilter, error) {
if len(pattern) == 0 {
return nil, errInvalidFilterPattern
}
Expand All @@ -401,7 +405,7 @@ func newSingleRangeFilter(pattern string, backwards bool) (chainFilter, error) {
return nil, errInvalidFilterPattern
}

patterns := make([]string, 0, len(pattern)%3)
patterns := make([][]byte, 0, len(pattern)%3)
for i := 0; i < len(pattern); i += 3 {
if pattern[i+1] != rangeChar || pattern[i] > pattern[i+2] {
return nil, errInvalidFilterPattern
Expand All @@ -419,7 +423,7 @@ func newSingleRangeFilter(pattern string, backwards bool) (chainFilter, error) {
// singleRangeFilter is a filter that performs a single character match against
// a range of chars given in a range format eg. [a-z]
type singleRangeFilter struct {
patterns []string
patterns [][]byte
backwards bool
negate bool
}
Expand All @@ -431,12 +435,14 @@ func (f *singleRangeFilter) String() string {
negateSuffix = ")"
}

return negatePrefix + "Range(\"" + strings.Join(f.patterns, " "+string(Disjunction)+" ") + "\")" + negateSuffix
return negatePrefix + "Range(\"" +
string(bytes.Join(f.patterns, []byte(fmt.Sprintf(" %s ", Disjunction)))) +
"\")" + negateSuffix
}

func (f *singleRangeFilter) matches(val string) (string, bool) {
func (f *singleRangeFilter) matches(val []byte) ([]byte, bool) {
if len(val) == 0 {
return "", false
return nil, false
}

match := false
Expand Down Expand Up @@ -464,7 +470,7 @@ func (f *singleRangeFilter) matches(val string) (string, bool) {
// singleCharSetFilter is a filter that performs a single character match against
// a set of chars given explicity eg. [abcdefg]
type singleCharSetFilter struct {
pattern string
pattern []byte
backwards bool
negate bool
}
Expand All @@ -476,12 +482,12 @@ func (f *singleCharSetFilter) String() string {
negateSuffix = ")"
}

return negatePrefix + "Range(\"" + f.pattern + "\")" + negateSuffix
return negatePrefix + "Range(\"" + string(f.pattern) + "\")" + negateSuffix
}

func (f *singleCharSetFilter) matches(val string) (string, bool) {
func (f *singleCharSetFilter) matches(val []byte) ([]byte, bool) {
if len(val) == 0 {
return "", false
return nil, false
}

match := false
Expand Down Expand Up @@ -511,41 +517,41 @@ func (f *singleCharSetFilter) matches(val string) (string, bool) {
// multiCharRangeFilter is a filter that performs matches against multiple sets of chars
// eg. {abc,defg}
type multiCharSequenceFilter struct {
patterns []string
patterns [][]byte
backwards bool
}

func newMultiCharSequenceFilter(patterns string, backwards bool) (chainFilter, error) {
func newMultiCharSequenceFilter(patterns []byte, backwards bool) (chainFilter, error) {
if len(patterns) == 0 {
return nil, errInvalidFilterPattern
}

return &multiCharSequenceFilter{
patterns: strings.Split(patterns, multiRangeSplit),
patterns: bytes.Split(patterns, multiRangeSplit),
backwards: backwards,
}, nil
}

func (f *multiCharSequenceFilter) String() string {
return "Range(\"" + strings.Join(f.patterns, multiRangeSplit) + "\")"
return "Range(\"" + string(bytes.Join(f.patterns, multiRangeSplit)) + "\")"
}

func (f *multiCharSequenceFilter) matches(val string) (string, bool) {
func (f *multiCharSequenceFilter) matches(val []byte) ([]byte, bool) {
if len(val) == 0 {
return "", false
return nil, false
}

for _, pattern := range f.patterns {
if f.backwards && strings.HasSuffix(val, pattern) {
if f.backwards && bytes.HasSuffix(val, pattern) {
return val[:len(val)-len(pattern)], true
}

if !f.backwards && strings.HasPrefix(val, pattern) {
if !f.backwards && bytes.HasPrefix(val, pattern) {
return val[len(pattern):], true
}
}

return "", false
return nil, false
}

// multiChainFilter chains multiple chainFilters together with &&
Expand Down Expand Up @@ -586,7 +592,7 @@ func (f *multiChainFilter) String() string {
return buf.String()
}

func (f *multiChainFilter) Matches(val string) bool {
func (f *multiChainFilter) Matches(val []byte) bool {
if len(f.filters) == 0 {
return true
}
Expand All @@ -609,7 +615,7 @@ func (f *multiChainFilter) Matches(val string) bool {
}
}

if f.seg == middle && val != "" {
if f.seg == middle && len(val) != 0 {
// chain was middle segment and some value was left over at end of chain
return false
}
Expand Down
Loading