Use strings.Builder in unpackString (#746)

* Add test case and benchmark for unpackString helper

* Use strings.Builder in unpackString
This commit is contained in:
Tom Thorogood 2018-09-23 19:51:14 +09:30 committed by Miek Gieben
parent f4db2ca6ed
commit 5debfeec63
2 changed files with 47 additions and 18 deletions

View File

@ -7,6 +7,7 @@ import (
"encoding/hex"
"net"
"strconv"
"strings"
)
// helper functions called from the generated zmsg.go
@ -267,29 +268,27 @@ func unpackString(msg []byte, off int) (string, int, error) {
if off+l+1 > len(msg) {
return "", off, &Error{err: "overflow unpacking txt"}
}
s := make([]byte, 0, l)
var s strings.Builder
s.Grow(l)
for _, b := range msg[off+1 : off+1+l] {
switch b {
case '"', '\\':
s = append(s, '\\', b)
default:
if b < 32 || b > 127 { // unprintable
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s = append(s, '\\')
for i := 0; i < 3-len(bufs); i++ {
s = append(s, '0')
}
for _, r := range bufs {
s = append(s, r)
}
} else {
s = append(s, b)
switch {
case b == '"' || b == '\\':
s.WriteByte('\\')
s.WriteByte(b)
case b < 32 || b > 127: // unprintable
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s.WriteByte('\\')
for i := len(bufs); i < 3; i++ {
s.WriteByte('0')
}
s.Write(bufs)
default:
s.WriteByte(b)
}
}
off += 1 + l
return string(s), off, nil
return s.String(), off, nil
}
func packString(s string, msg []byte, off int) (int, error) {

View File

@ -106,3 +106,33 @@ func TestPackDataNsec(t *testing.T) {
})
}
}
func TestUnpackString(t *testing.T) {
msg := []byte("\x00abcdef\x0f\\\"ghi\x04mmm")
msg[0] = byte(len(msg) - 1)
got, _, err := unpackString(msg, 0)
if err != nil {
t.Fatal(err)
}
if want := `abcdef\015\\\"ghi\004mmm`; want != got {
t.Errorf("expected %q, got %q", want, got)
}
}
func BenchmarkUnpackString(b *testing.B) {
msg := []byte("\x00abcdef\x0f\\\"ghi\x04mmm")
msg[0] = byte(len(msg) - 1)
for n := 0; n < b.N; n++ {
got, _, err := unpackString(msg, 0)
if err != nil {
b.Fatal(err)
}
if want := `abcdef\015\\\"ghi\004mmm`; want != got {
b.Errorf("expected %q, got %q", want, got)
}
}
}