From 6ebda5a7bc8c1f5611e41cc63a769bd9afc14592 Mon Sep 17 00:00:00 2001 From: Oleg Zaytsev Date: Wed, 8 May 2024 17:05:27 +0200 Subject: [PATCH] Optimize Matcher.String() Signed-off-by: Oleg Zaytsev --- model/labels/matcher.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/model/labels/matcher.go b/model/labels/matcher.go index 291eac1c7..ce9e42471 100644 --- a/model/labels/matcher.go +++ b/model/labels/matcher.go @@ -14,7 +14,8 @@ package labels import ( - "fmt" + "strconv" + "unsafe" ) // MatchType is an enum for label matching types. @@ -78,10 +79,20 @@ func MustNewMatcher(mt MatchType, name, val string) *Matcher { } func (m *Matcher) String() string { - if !m.shouldQuoteName() { - return fmt.Sprintf("%s%s%q", m.Name, m.Type, m.Value) + const quote = 1 + const matcher = 2 + // As we're not on go1.22 yet and we don't have the new fancy AvailableBuffer method on strings.Builder, + // we'll use a plain byte slice and then do the unsafe conversion to string just like strings.Builder does. + // We pre-allocate pessimistically for quoting the label name, and optimistically for not having to escape any quotes. + b := make([]byte, 0, quote+len(m.Name)+quote+matcher+quote+len(m.Value)+quote) + if m.shouldQuoteName() { + b = strconv.AppendQuote(b, m.Name) + } else { + b = append(b, m.Name...) } - return fmt.Sprintf("%q%s%q", m.Name, m.Type, m.Value) + b = append(b, m.Type.String()...) + b = strconv.AppendQuote(b, m.Value) + return *((*string)(unsafe.Pointer(&b))) } func (m *Matcher) shouldQuoteName() bool {