types: improve the performance of sprintName by ~30% and halve allocs (#1008)

```
benchmark                                          old ns/op     new ns/op     delta
BenchmarkSprintName-12                             174           117           -32.76%

benchmark                                          old allocs     new allocs     delta
BenchmarkSprintName-12                             2              1              -50.00%

benchmark                                          old bytes     new bytes     delta
BenchmarkSprintName-12                             48            32            -33.33%
```
This commit is contained in:
Charlie Vieth 2019-09-23 02:17:00 -04:00 committed by Miek Gieben
parent 9578caeab0
commit e393768b85
2 changed files with 48 additions and 18 deletions

View File

@ -438,25 +438,54 @@ func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
func sprintName(s string) string {
var dst strings.Builder
dst.Grow(len(s))
for i := 0; i < len(s); {
if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
dst.WriteString(s[i : i+2])
if dst.Len() != 0 {
dst.WriteString(s[i : i+2])
}
i += 2
continue
}
b, n := nextByte(s, i)
switch {
case n == 0:
i++ // dangling back slash
case b == '.':
dst.WriteByte('.')
if n == 0 {
i++
continue
}
if b == '.' {
if dst.Len() != 0 {
dst.WriteByte('.')
}
i += n
continue
}
switch b {
case ' ', '\'', '@', ';', '(', ')', '"', '\\': // additional chars to escape
if dst.Len() == 0 {
dst.Grow(len(s) * 2)
dst.WriteString(s[:i])
}
dst.WriteByte('\\')
dst.WriteByte(b)
default:
writeDomainNameByte(&dst, b)
if ' ' <= b && b <= '~' {
if dst.Len() != 0 {
dst.WriteByte(b)
}
} else {
if dst.Len() == 0 {
dst.Grow(len(s) * 2)
dst.WriteString(s[:i])
}
dst.WriteString(escapeByte(b))
}
}
i += n
}
if dst.Len() == 0 {
return s
}
return dst.String()
}
@ -510,16 +539,6 @@ func sprintTxt(txt []string) string {
return out.String()
}
func writeDomainNameByte(s *strings.Builder, b byte) {
switch b {
case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
s.WriteByte('\\')
s.WriteByte(b)
default:
writeTXTStringByte(s, b)
}
}
func writeTXTStringByte(s *strings.Builder, b byte) {
switch {
case b == '"' || b == '\\':

View File

@ -133,6 +133,16 @@ func BenchmarkSprintName(b *testing.B) {
}
}
func BenchmarkSprintName_NoEscape(b *testing.B) {
for n := 0; n < b.N; n++ {
got := sprintName("large.example.com")
if want := "large.example.com"; got != want {
b.Fatalf("expected %q, got %q", got, want)
}
}
}
func BenchmarkSprintTxtOctet(b *testing.B) {
for n := 0; n < b.N; n++ {
got := sprintTxtOctet("abc\\.def\007\"\127@\255\x05\xef\\")
@ -149,6 +159,7 @@ func BenchmarkSprintTxt(b *testing.B) {
"example.com",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
got := sprintTxt(txt)