I tried:
strconv.Quote()
strconv.AppendQuote() (weird that this is faster than Quote)
fmt.Sprintf("%q")
scanning for !IsPrint() + bytes.Buffer
scanning for !IsPrint() + strings.Builder (sad that this is not faster than Buffer)
scanning for !IsPrint() + string addition
```
$ go test -benchtime=5s -bench='XX' ./benchmark/
goos: linux
goarch: amd64
pkg:
github.com/go-logr/logr/benchmarkcpu: Intel(R) Xeon(R) W-2135 CPU @ 3.70GHz
BenchmarkXXQuote-6 23233543 258.5 ns/op
BenchmarkXXAppendQuote-6 24370812 207.7 ns/op
BenchmarkXXSprintf-6 18040070 335.2 ns/op
BenchmarkXXScanBuffer-6 47154340 117.4 ns/op
BenchmarkXXScanBuilder-6 42295635 141.9 ns/op
BenchmarkXXScanAdd-6 43635146 137.5 ns/op
PASS
ok
github.com/go-logr/logr/benchmark 35.926s
```
code:
```
//go:noinline
func foo(s string) {
_ = s
}
func prettyBuffer(s string) string {
if needsEscape(s) {
return strconv.Quote(s)
}
b := bytes.NewBuffer(make([]byte, 0, 1024))
b.WriteByte('"')
b.WriteString(s)
b.WriteByte('"')
return b.String()
}
func prettyBuilder(s string) string {
if needsEscape(s) {
return strconv.Quote(s)
}
b := strings.Builder{}
b.WriteByte('"')
b.WriteString(s)
b.WriteByte('"')
return b.String()
}
func prettyAdd(s string) string {
if needsEscape(s) {
return strconv.Quote(s)
}
return `"` + s + `"`
}
// needsEscape determines whether the input string needs to be escaped or not,
// without doing any allocations.
func needsEscape(s string) bool {
for _, r := range s {
if !strconv.IsPrint(r) || r == '\\' || r == '"' {
return true
}
}
return false
}
func BenchmarkXXQuote(b *testing.B) {
in := "a string with no specials"
for i := 0; i < b.N; i++ {
out := strconv.Quote(in)
foo(out)
}
}
func BenchmarkXXAppendQuote(b *testing.B) {
in := "a string with no specials"
for i := 0; i < b.N; i++ {
out := strconv.AppendQuote(make([]byte, 0, 1024), in)
foo(string(out))
}
}
func BenchmarkXXSprintf(b *testing.B) {
in := "a string with no specials"
for i := 0; i < b.N; i++ {
out := fmt.Sprintf("%q", in)
foo(out)
}
}
func BenchmarkXXScanBuffer(b *testing.B) {
in := "a string with no specials"
for i := 0; i < b.N; i++ {
out := prettyBuffer(in)
foo(out)
}
}
func BenchmarkXXScanBuilder(b *testing.B) {
in := "a string with no specials"
for i := 0; i < b.N; i++ {
out := prettyBuilder(in)
foo(out)
}
}
func BenchmarkXXScanAdd(b *testing.B) {
in := "a string with no specials"
for i := 0; i < b.N; i++ {
out := prettyAdd(in)
foo(out)
}
}
```