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 {
|
func sprintName(s string) string {
|
||||||
var dst strings.Builder
|
var dst strings.Builder
|
||||||
dst.Grow(len(s))
|
|
||||||
for i := 0; i < len(s); {
|
for i := 0; i < len(s); {
|
||||||
if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
|
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
|
i += 2
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
b, n := nextByte(s, i)
|
b, n := nextByte(s, i)
|
||||||
switch {
|
if n == 0 {
|
||||||
case n == 0:
|
i++
|
||||||
i++ // dangling back slash
|
continue
|
||||||
case b == '.':
|
}
|
||||||
dst.WriteByte('.')
|
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:
|
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
|
i += n
|
||||||
}
|
}
|
||||||
|
if dst.Len() == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
return dst.String()
|
return dst.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,16 +539,6 @@ func sprintTxt(txt []string) string {
|
||||||
return out.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) {
|
func writeTXTStringByte(s *strings.Builder, b byte) {
|
||||||
switch {
|
switch {
|
||||||
case b == '"' || b == '\\':
|
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) {
|
func BenchmarkSprintTxtOctet(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
got := sprintTxtOctet("abc\\.def\007\"\127@\255\x05\xef\\")
|
got := sprintTxtOctet("abc\\.def\007\"\127@\255\x05\xef\\")
|
||||||
|
@ -149,6 +159,7 @@ func BenchmarkSprintTxt(b *testing.B) {
|
||||||
"example.com",
|
"example.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
got := sprintTxt(txt)
|
got := sprintTxt(txt)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue