Improve unpackString performance (#1011)
I'm not convinced this is really worth doing, but it does show a performance improvement. name old time/op new time/op delta UnpackString/Escaped-12 83.7ns ± 7% 78.2ns ± 3% -6.50% (p=0.000 n=10+9) UnpackString/Unescaped-12 57.8ns ± 9% 50.4ns ±13% -12.74% (p=0.000 n=10+10) name old alloc/op new alloc/op delta UnpackString/Escaped-12 48.0B ± 0% 32.0B ± 0% -33.33% (p=0.000 n=10+10) UnpackString/Unescaped-12 32.0B ± 0% 32.0B ± 0% ~ (all equal) name old allocs/op new allocs/op delta UnpackString/Escaped-12 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) UnpackString/Unescaped-12 1.00 ± 0% 1.00 ± 0% ~ (all equal)
This commit is contained in:
parent
ba5bfd0295
commit
b733ad8671
|
@ -265,12 +265,25 @@ func unpackString(msg []byte, off int) (string, int, error) {
|
|||
return "", off, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
l := int(msg[off])
|
||||
if off+l+1 > len(msg) {
|
||||
off++
|
||||
if off+l > len(msg) {
|
||||
return "", off, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
escapedLen := l
|
||||
for _, b := range msg[off : off+l] {
|
||||
switch {
|
||||
case b == '"' || b == '\\':
|
||||
escapedLen++
|
||||
case b < ' ' || b > '~': // unprintable
|
||||
escapedLen += 3 // escapeByte always returns four characters
|
||||
}
|
||||
}
|
||||
if escapedLen == l { // no escaping needed
|
||||
return string(msg[off : off+l]), off + l, nil
|
||||
}
|
||||
var s strings.Builder
|
||||
s.Grow(l)
|
||||
for _, b := range msg[off+1 : off+1+l] {
|
||||
s.Grow(escapedLen)
|
||||
for _, b := range msg[off : off+l] {
|
||||
switch {
|
||||
case b == '"' || b == '\\':
|
||||
s.WriteByte('\\')
|
||||
|
@ -281,7 +294,7 @@ func unpackString(msg []byte, off int) (string, int, error) {
|
|||
s.WriteByte(b)
|
||||
}
|
||||
}
|
||||
off += 1 + l
|
||||
off += l
|
||||
return s.String(), off, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ func TestUnpackString(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkUnpackString(b *testing.B) {
|
||||
b.Run("Escaped", func(b *testing.B) {
|
||||
msg := []byte("\x00abcdef\x0f\\\"ghi\x04mmm")
|
||||
msg[0] = byte(len(msg) - 1)
|
||||
|
||||
|
@ -135,4 +136,20 @@ func BenchmarkUnpackString(b *testing.B) {
|
|||
b.Errorf("expected %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
b.Run("Unescaped", func(b *testing.B) {
|
||||
msg := []byte("\x00large.example.com")
|
||||
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 := "large.example.com"; want != got {
|
||||
b.Errorf("expected %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue