Commit 1ca10de3 authored by Rui Ueyama's avatar Rui Ueyama

strings: reduce allocation in byteStringReplacer.WriteString

Use WriteString instead of allocating a byte slice as a
buffer. This was a TODO.

benchmark               old ns/op    new ns/op    delta
BenchmarkWriteString        40139        19991  -50.20%

LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/107190044
parent 57964db3
......@@ -511,48 +511,32 @@ func (r *byteStringReplacer) Replace(s string) string {
return string(buf)
}
// WriteString maintains one buffer that's at most 32KB. The bytes in
// s are enumerated and the buffer is filled. If it reaches its
// capacity or a byte has a replacement, the buffer is flushed to w.
func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err error) {
// TODO(bradfitz): use io.WriteString with slices of s instead.
bufsize := 32 << 10
if len(s) < bufsize {
bufsize = len(s)
}
buf := make([]byte, bufsize)
bi := buf[:0]
sw := getStringWriter(w)
last := 0
for i := 0; i < len(s); i++ {
b := s[i]
var new []byte
if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
new = r.new[b]
} else {
bi = append(bi, b)
}
if len(bi) == cap(bi) || (len(bi) > 0 && len(new) > 0) {
nw, err := w.Write(bi)
n += nw
if err != nil {
return n, err
}
bi = buf[:0]
if r.old[b>>5]&uint32(1<<(b&31)) == 0 {
continue
}
if len(new) > 0 {
nw, err := w.Write(new)
if last != i {
nw, err := sw.WriteString(s[last:i])
n += nw
if err != nil {
return n, err
}
}
}
if len(bi) > 0 {
nw, err := w.Write(bi)
last = i + 1
nw, err := w.Write(r.new[b])
n += nw
if err != nil {
return n, err
}
}
return n, nil
if last != len(s) {
var nw int
nw, err = sw.WriteString(s[last:])
n += nw
}
return
}
......@@ -480,6 +480,15 @@ func BenchmarkHTMLEscapeOld(b *testing.B) {
}
}
func BenchmarkWriteString(b *testing.B) {
str := Repeat("I <3 to escape HTML & other text too.", 100)
buf := new(bytes.Buffer)
for i := 0; i < b.N; i++ {
htmlEscaper.WriteString(buf, str)
buf.Reset()
}
}
// BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces.
func BenchmarkByteByteReplaces(b *testing.B) {
str := Repeat("a", 100) + Repeat("b", 100)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment