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/benchmark
cpu: 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)
    }
}

```


On Thu, Oct 14, 2021 at 1:52 AM roger peppe <rogpe...@gmail.com> wrote:

> On Thu, 14 Oct 2021 at 04:58, 'Tim Hockin' via golang-nuts <
> golang-nuts@googlegroups.com> wrote:
>
>> Thanks for confirming.  I wrote that function and erased a good bit of
>> the overhead.
>>
>> bytes.Buffer for the no-escapes path and strconv.Quote otherwise.
>>
>
> Could you not use strconv.AppendQuote and get the advantage without
> needing the extra scan?
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAO_RewbrDW55pD74hO6eCTgUEGZh7-46_z7RC3FWonrpnypwHw%40mail.gmail.com.

Reply via email to