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