diff --git a/staging/src/k8s.io/apimachinery/pkg/labels/selector.go b/staging/src/k8s.io/apimachinery/pkg/labels/selector.go index e5f1a8264038..ab12f7c2f32d 100644 --- a/staging/src/k8s.io/apimachinery/pkg/labels/selector.go +++ b/staging/src/k8s.io/apimachinery/pkg/labels/selector.go @@ -17,7 +17,6 @@ limitations under the License. package labels import ( - "bytes" "fmt" "sort" "strconv" @@ -274,48 +273,55 @@ func (s internalSelector) Empty() bool { // Requirement. If called on an invalid Requirement, an error is // returned. See NewRequirement for creating a valid Requirement. func (r *Requirement) String() string { - var buffer bytes.Buffer + var sb strings.Builder + sb.Grow( + // length of r.key + len(r.key) + + // length of 'r.operator' + 2 spaces for the worst case ('in' and 'notin') + len(r.operator) + 2 + + // length of 'r.strValues' slice times. Heuristically 5 chars per word + +5*len(r.strValues)) if r.operator == selection.DoesNotExist { - buffer.WriteString("!") + sb.WriteString("!") } - buffer.WriteString(r.key) + sb.WriteString(r.key) switch r.operator { case selection.Equals: - buffer.WriteString("=") + sb.WriteString("=") case selection.DoubleEquals: - buffer.WriteString("==") + sb.WriteString("==") case selection.NotEquals: - buffer.WriteString("!=") + sb.WriteString("!=") case selection.In: - buffer.WriteString(" in ") + sb.WriteString(" in ") case selection.NotIn: - buffer.WriteString(" notin ") + sb.WriteString(" notin ") case selection.GreaterThan: - buffer.WriteString(">") + sb.WriteString(">") case selection.LessThan: - buffer.WriteString("<") + sb.WriteString("<") case selection.Exists, selection.DoesNotExist: - return buffer.String() + return sb.String() } switch r.operator { case selection.In, selection.NotIn: - buffer.WriteString("(") + sb.WriteString("(") } if len(r.strValues) == 1 { - buffer.WriteString(r.strValues[0]) + sb.WriteString(r.strValues[0]) } else { // only > 1 since == 0 prohibited by NewRequirement // normalizes value order on output, without mutating the in-memory selector representation // also avoids normalization when it is not required, and ensures we do not mutate shared data - buffer.WriteString(strings.Join(safeSort(r.strValues), ",")) + sb.WriteString(strings.Join(safeSort(r.strValues), ",")) } switch r.operator { case selection.In, selection.NotIn: - buffer.WriteString(")") + sb.WriteString(")") } - return buffer.String() + return sb.String() } // safeSort sorts input strings without modification diff --git a/staging/src/k8s.io/apimachinery/pkg/labels/selector_test.go b/staging/src/k8s.io/apimachinery/pkg/labels/selector_test.go index aa3fb2e54bcb..f2cb7f8941a8 100644 --- a/staging/src/k8s.io/apimachinery/pkg/labels/selector_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/labels/selector_test.go @@ -738,3 +738,21 @@ func TestValidatedSelectorFromSet(t *testing.T) { } } } + +func BenchmarkRequirementString(b *testing.B) { + r := Requirement{ + key: "environment", + operator: selection.NotIn, + strValues: []string{ + "dev", + }, + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + if r.String() != "environment notin (dev)" { + b.Errorf("Unexpected Requirement string") + } + } +} diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/http.go b/staging/src/k8s.io/apimachinery/pkg/util/net/http.go index ba63d02df69a..567a294e26c3 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/net/http.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/http.go @@ -693,7 +693,7 @@ func parseQuotedString(quotedString string) (string, string, error) { var remainder string escaping := false closedQuote := false - result := &bytes.Buffer{} + result := &strings.Builder{} loop: for i := 0; i < len(quotedString); i++ { b := quotedString[i] diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go b/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go index a43161b88b76..9411bfa7ddf7 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go @@ -1107,3 +1107,21 @@ func TestPingTimeoutSeconds(t *testing.T) { } reset() } + +func Benchmark_ParseQuotedString(b *testing.B) { + str := `"The quick brown" fox jumps over the lazy dog` + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + quoted, remainder, err := parseQuotedString(str) + if err != nil { + b.Errorf("Unexpected error %s", err) + } + if quoted != "The quick brown" { + b.Errorf("Unexpected quoted string %s", quoted) + } + if remainder != "fox jumps over the lazy dog" { + b.Errorf("Unexpected remainder string %s", quoted) + } + } +}