// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package match import ( "bytes" "fmt" "reflect" "strings" "unsafe" ) type equalsMatcher struct { s string bs []byte } type substringMatcher struct { s string bs []byte } type altSubstringMatcher struct { literals [][]byte } type oneOfMatcher struct { literals [][]byte } type prefixMatcher struct { s []byte } type altPrefixMatcher struct { literals [][]byte } type prefixNumDate struct { minLen int prefix []byte digits []int seps [][]byte suffix []byte } type emptyStringMatcher struct{} type emptyWhiteStringMatcher struct{} type matchAny struct{} func (m *equalsMatcher) MatchString(s string) bool { return m.s == s } func (m *equalsMatcher) Match(bs []byte) bool { return bytes.Equal(bs, m.bs) } func (m *equalsMatcher) String() string { return fmt.Sprintf("", m.s) } func (m *substringMatcher) MatchString(s string) bool { return strings.Contains(s, m.s) } func (m *substringMatcher) Match(bs []byte) bool { return bytes.Contains(bs, m.bs) } func (m *substringMatcher) String() string { return fmt.Sprintf("", m.s) } func (m *altSubstringMatcher) MatchString(s string) bool { return m.Match(stringToBytes(s)) } func (m *altSubstringMatcher) Match(in []byte) bool { for _, literal := range m.literals { if bytes.Contains(in, literal) { return true } } return false } func (m *altSubstringMatcher) String() string { return fmt.Sprintf("", bytes.Join(m.literals, []byte(","))) } func (m *oneOfMatcher) MatchString(s string) bool { return m.Match(stringToBytes(s)) } func (m *oneOfMatcher) Match(in []byte) bool { for _, literal := range m.literals { if bytes.Equal(in, literal) { return true } } return false } func (m *oneOfMatcher) String() string { return fmt.Sprintf("", bytes.Join(m.literals, []byte(","))) } func (m *prefixMatcher) MatchString(s string) bool { return len(s) >= len(m.s) && s[0:len(m.s)] == string(m.s) } func (m *prefixMatcher) Match(bs []byte) bool { return len(bs) >= len(m.s) && bytes.Equal(bs[0:len(m.s)], m.s) } func (m *prefixMatcher) String() string { return fmt.Sprintf("", string(m.s)) } func (m *altPrefixMatcher) MatchString(in string) bool { for _, s := range m.literals { if len(in) >= len(s) && in[0:len(s)] == string(s) { return true } } return false } func (m *altPrefixMatcher) Match(bs []byte) bool { for _, s := range m.literals { if len(bs) >= len(s) && bytes.Equal(bs[0:len(s)], s) { return true } } return false } func (m *altPrefixMatcher) String() string { return fmt.Sprintf("", bytes.Join(m.literals, []byte(","))) } func (m *prefixNumDate) MatchString(in string) bool { return m.Match(stringToBytes(in)) } func (m *prefixNumDate) Match(in []byte) bool { if len(in) < m.minLen { return false } pos := 0 if m.prefix != nil { end := len(m.prefix) if !bytes.Equal(in[0:end], m.prefix) { return false } pos += end } for cnt := m.digits[0]; cnt > 0; cnt-- { v := in[pos] pos++ if !('0' <= v && v <= '9') { return false } } for i := 1; i < len(m.digits); i++ { sep := m.seps[i-1] if !bytes.Equal(in[pos:pos+len(sep)], sep) { return false } pos += len(sep) for cnt := m.digits[i]; cnt > 0; cnt-- { v := in[pos] pos++ if !('0' <= v && v <= '9') { return false } } } if sfx := m.suffix; len(sfx) > 0 { if !bytes.HasPrefix(in[pos:], sfx) { return false } } return true } func (m *prefixNumDate) String() string { return "" } func (m *emptyStringMatcher) MatchString(s string) bool { return len(s) == 0 } func (m *emptyStringMatcher) Match(bs []byte) bool { return len(bs) == 0 } func (m *emptyStringMatcher) String() string { return "" } func (m *emptyWhiteStringMatcher) MatchString(s string) bool { for _, r := range s { if !(r == 0x9 || r == 0xa || r == 0xc || r == 0xd || r == 0x20 || r == '\t') { return false } } return true } func (m *emptyWhiteStringMatcher) Match(bs []byte) bool { for _, r := range bytesToString(bs) { if !(r == 0x9 || r == 0xa || r == 0xc || r == 0xd || r == 0x20 || r == '\t') { return false } } return true } func (m *emptyWhiteStringMatcher) String() string { return "" } func (m *matchAny) Match(_ []byte) bool { return true } func (m *matchAny) MatchString(_ string) bool { return true } func (m *matchAny) String() string { return "" } func bytesToString(b []byte) string { bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) sh := reflect.StringHeader{Data: bh.Data, Len: bh.Len} return *(*string)(unsafe.Pointer(&sh)) } func stringToBytes(s string) []byte { sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) bh := reflect.SliceHeader{Data: sh.Data, Len: sh.Len, Cap: sh.Len} return *(*[]byte)(unsafe.Pointer(&bh)) }