mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-26 06:04:05 -08:00
Merge pull request #15210 from bboreham/faster-lowercase
FastRegexMatcher: use stack memory for lowercase copy of string
This commit is contained in:
commit
49999b8a90
|
@ -802,7 +802,7 @@ type equalMultiStringMapMatcher struct {
|
|||
|
||||
func (m *equalMultiStringMapMatcher) add(s string) {
|
||||
if !m.caseSensitive {
|
||||
s = toNormalisedLower(s)
|
||||
s = toNormalisedLower(s, nil) // Don't pass a stack buffer here - it will always escape to heap.
|
||||
}
|
||||
|
||||
m.values[s] = struct{}{}
|
||||
|
@ -840,15 +840,24 @@ func (m *equalMultiStringMapMatcher) setMatches() []string {
|
|||
}
|
||||
|
||||
func (m *equalMultiStringMapMatcher) Matches(s string) bool {
|
||||
if !m.caseSensitive {
|
||||
s = toNormalisedLower(s)
|
||||
if len(m.values) > 0 {
|
||||
sNorm := s
|
||||
var a [32]byte
|
||||
if !m.caseSensitive {
|
||||
sNorm = toNormalisedLower(s, a[:])
|
||||
}
|
||||
if _, ok := m.values[sNorm]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := m.values[s]; ok {
|
||||
return true
|
||||
}
|
||||
if m.minPrefixLen > 0 && len(s) >= m.minPrefixLen {
|
||||
for _, matcher := range m.prefixes[s[:m.minPrefixLen]] {
|
||||
prefix := s[:m.minPrefixLen]
|
||||
var a [32]byte
|
||||
if !m.caseSensitive {
|
||||
prefix = toNormalisedLower(s[:m.minPrefixLen], a[:])
|
||||
}
|
||||
for _, matcher := range m.prefixes[prefix] {
|
||||
if matcher.Matches(s) {
|
||||
return true
|
||||
}
|
||||
|
@ -859,22 +868,37 @@ func (m *equalMultiStringMapMatcher) Matches(s string) bool {
|
|||
|
||||
// toNormalisedLower normalise the input string using "Unicode Normalization Form D" and then convert
|
||||
// it to lower case.
|
||||
func toNormalisedLower(s string) string {
|
||||
var buf []byte
|
||||
func toNormalisedLower(s string, a []byte) string {
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c >= utf8.RuneSelf {
|
||||
return strings.Map(unicode.ToLower, norm.NFKD.String(s))
|
||||
}
|
||||
if 'A' <= c && c <= 'Z' {
|
||||
if buf == nil {
|
||||
buf = []byte(s)
|
||||
}
|
||||
buf[i] = c + 'a' - 'A'
|
||||
return toNormalisedLowerSlow(s, i, a)
|
||||
}
|
||||
}
|
||||
if buf == nil {
|
||||
return s
|
||||
return s
|
||||
}
|
||||
|
||||
// toNormalisedLowerSlow is split from toNormalisedLower because having a call
|
||||
// to `copy` slows it down even when it is not called.
|
||||
func toNormalisedLowerSlow(s string, i int, a []byte) string {
|
||||
var buf []byte
|
||||
if cap(a) > len(s) {
|
||||
buf = a[:len(s)]
|
||||
copy(buf, s)
|
||||
} else {
|
||||
buf = []byte(s)
|
||||
}
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c >= utf8.RuneSelf {
|
||||
return strings.Map(unicode.ToLower, norm.NFKD.String(s))
|
||||
}
|
||||
if 'A' <= c && c <= 'Z' {
|
||||
buf[i] = c + 'a' - 'A'
|
||||
}
|
||||
}
|
||||
return yoloString(buf)
|
||||
}
|
||||
|
|
|
@ -333,7 +333,8 @@ func BenchmarkToNormalizedLower(b *testing.B) {
|
|||
}
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
toNormalisedLower(inputs[n%len(inputs)])
|
||||
var a [256]byte
|
||||
toNormalisedLower(inputs[n%len(inputs)], a[:])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1390,6 +1391,6 @@ func TestToNormalisedLower(t *testing.T) {
|
|||
"ſſAſſa": "ssassa",
|
||||
}
|
||||
for input, expectedOutput := range testCases {
|
||||
require.Equal(t, expectedOutput, toNormalisedLower(input))
|
||||
require.Equal(t, expectedOutput, toNormalisedLower(input, nil))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue