mirror of https://github.com/golang/go.git
net: efficient text processing
Optimize IP.String, IPMask.String and ParseIP. benchmark old ns/op new ns/op delta BenchmarkParseIP 2216 1849 -16.56% BenchmarkIPString 7828 2486 -68.24% BenchmarkIPMaskString 3872 659 -82.98% LGTM=mikioh.mikioh, dave, bradfitz R=golang-codereviews, mikioh.mikioh, dave, bradfitz CC=golang-codereviews https://golang.org/cl/95750043
This commit is contained in:
parent
f837078c50
commit
f7c99f3377
|
|
@ -287,6 +287,7 @@ func (ip IP) String() string {
|
|||
if j > i && j-i > e1-e0 {
|
||||
e0 = i
|
||||
e1 = j
|
||||
i = j
|
||||
}
|
||||
}
|
||||
// The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
|
||||
|
|
@ -295,21 +296,23 @@ func (ip IP) String() string {
|
|||
e1 = -1
|
||||
}
|
||||
|
||||
const maxLen = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
|
||||
b := make([]byte, 0, maxLen)
|
||||
|
||||
// Print with possible :: in place of run of zeros
|
||||
var s string
|
||||
for i := 0; i < IPv6len; i += 2 {
|
||||
if i == e0 {
|
||||
s += "::"
|
||||
b = append(b, ':', ':')
|
||||
i = e1
|
||||
if i >= IPv6len {
|
||||
break
|
||||
}
|
||||
} else if i > 0 {
|
||||
s += ":"
|
||||
b = append(b, ':')
|
||||
}
|
||||
s += itox((uint(p[i])<<8)|uint(p[i+1]), 1)
|
||||
b = appendHex(b, (uint32(p[i])<<8)|uint32(p[i+1]))
|
||||
}
|
||||
return s
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// ipEmptyString is like ip.String except that it returns
|
||||
|
|
@ -419,14 +422,14 @@ func (m IPMask) Size() (ones, bits int) {
|
|||
|
||||
// String returns the hexadecimal form of m, with no punctuation.
|
||||
func (m IPMask) String() string {
|
||||
s := ""
|
||||
for _, b := range m {
|
||||
s += itox(uint(b), 2)
|
||||
}
|
||||
if len(s) == 0 {
|
||||
if len(m) == 0 {
|
||||
return "<nil>"
|
||||
}
|
||||
return s
|
||||
buf := make([]byte, len(m)*2)
|
||||
for i, b := range m {
|
||||
buf[i*2], buf[i*2+1] = hexDigit[b>>4], hexDigit[b&0xf]
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
|
||||
|
|
@ -646,11 +649,16 @@ func (e *ParseError) Error() string {
|
|||
// If s is not a valid textual representation of an IP address,
|
||||
// ParseIP returns nil.
|
||||
func ParseIP(s string) IP {
|
||||
if ip := parseIPv4(s); ip != nil {
|
||||
return ip
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '.':
|
||||
return parseIPv4(s)
|
||||
case ':':
|
||||
ip, _ := parseIPv6(s, false)
|
||||
return ip
|
||||
}
|
||||
}
|
||||
ip, _ := parseIPv6(s, false)
|
||||
return ip
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseCIDR parses s as a CIDR notation IP address and mask,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ func TestParseIP(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseIP(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tt := range parseIPTests {
|
||||
ParseIP(tt.in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 6339
|
||||
func TestMarshalEmptyIP(t *testing.T) {
|
||||
for _, in := range [][]byte{nil, []byte("")} {
|
||||
|
|
@ -91,6 +99,16 @@ func TestIPString(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkIPString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tt := range ipStringTests {
|
||||
if tt.in != nil {
|
||||
tt.in.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ipMaskTests = []struct {
|
||||
in IP
|
||||
mask IPMask
|
||||
|
|
@ -131,6 +149,14 @@ func TestIPMaskString(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkIPMaskString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tt := range ipMaskStringTests {
|
||||
tt.in.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var parseCIDRTests = []struct {
|
||||
in string
|
||||
ip IP
|
||||
|
|
|
|||
|
|
@ -210,18 +210,18 @@ func itod(i uint) string {
|
|||
return string(b[bp:])
|
||||
}
|
||||
|
||||
// Convert i to hexadecimal string.
|
||||
func itox(i uint, min int) string {
|
||||
// Assemble hexadecimal in reverse order.
|
||||
var b [32]byte
|
||||
bp := len(b)
|
||||
for ; i > 0 || min > 0; i /= 16 {
|
||||
bp--
|
||||
b[bp] = "0123456789abcdef"[byte(i%16)]
|
||||
min--
|
||||
// Convert i to a hexadecimal string. Leading zeros are not printed.
|
||||
func appendHex(dst []byte, i uint32) []byte {
|
||||
if i == 0 {
|
||||
return append(dst, '0')
|
||||
}
|
||||
|
||||
return string(b[bp:])
|
||||
for j := 7; j >= 0; j-- {
|
||||
v := i >> uint(j*4)
|
||||
if v > 0 {
|
||||
dst = append(dst, hexDigit[v&0xf])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Number of occurrences of b in s.
|
||||
|
|
|
|||
Loading…
Reference in New Issue