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:
parent
9578caeab0
commit
e393768b85
55
types.go
55
types.go
|
@ -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 == '\\':
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue