mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-02-21 00:39:54 +00:00
internal/encoding/json: improve Value.Int,Uint by reducing allocations
parseNumber does not need to construct new slices for numberParts, it simply needs to reference the correct subset from the input. normalizeToString may need to allocate but only if there's a positive exponent. name old time/op new time/op delta Float-4 308ns ± 0% 291ns ± 0% ~ (p=1.000 n=1+1) Int-4 498ns ± 0% 341ns ± 0% ~ (p=1.000 n=1+1) String-4 262ns ± 0% 250ns ± 0% ~ (p=1.000 n=1+1) Bool-4 212ns ± 0% 210ns ± 0% ~ (p=1.000 n=1+1) name old alloc/op new alloc/op delta Float-4 48.0B ± 0% 48.0B ± 0% ~ (all equal) Int-4 160B ± 0% 99B ± 0% ~ (p=1.000 n=1+1) String-4 176B ± 0% 176B ± 0% ~ (all equal) Bool-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta Float-4 1.00 ± 0% 1.00 ± 0% ~ (all equal) Int-4 9.00 ± 0% 4.00 ± 0% ~ (p=1.000 n=1+1) String-4 3.00 ± 0% 3.00 ± 0% ~ (all equal) Bool-4 0.00 0.00 ~ (all equal) Change-Id: If083e18a5914b15e794d34722cbb6539cbd73a53 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170788 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
parent
4686e239b6
commit
8fa64d98d8
@ -127,7 +127,7 @@ type numberParts struct {
|
||||
|
||||
// parseNumber constructs numberParts from given []byte. The logic here is
|
||||
// similar to consumeNumber above with the difference of having to construct
|
||||
// numberParts.
|
||||
// numberParts. The slice fields in numberParts are subslices of the input.
|
||||
func parseNumber(input []byte) (numberParts, bool) {
|
||||
var neg bool
|
||||
var intp []byte
|
||||
@ -155,12 +155,14 @@ func parseNumber(input []byte) (numberParts, bool) {
|
||||
s = s[1:]
|
||||
|
||||
case '1' <= s[0] && s[0] <= '9':
|
||||
intp = append(intp, s[0])
|
||||
intp = s
|
||||
n := 1
|
||||
s = s[1:]
|
||||
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
||||
intp = append(intp, s[0])
|
||||
s = s[1:]
|
||||
n++
|
||||
}
|
||||
intp = intp[:n]
|
||||
|
||||
default:
|
||||
return numberParts{}, false
|
||||
@ -168,29 +170,34 @@ func parseNumber(input []byte) (numberParts, bool) {
|
||||
|
||||
// . followed by 1 or more digits.
|
||||
if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
|
||||
frac = append(frac, s[1])
|
||||
frac = s[1:]
|
||||
n := 1
|
||||
s = s[2:]
|
||||
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
||||
frac = append(frac, s[0])
|
||||
s = s[1:]
|
||||
n++
|
||||
}
|
||||
frac = frac[:n]
|
||||
}
|
||||
|
||||
// e or E followed by an optional - or + and
|
||||
// 1 or more digits.
|
||||
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
|
||||
s = s[1:]
|
||||
exp = s
|
||||
n := 0
|
||||
if s[0] == '+' || s[0] == '-' {
|
||||
exp = append(exp, s[0])
|
||||
s = s[1:]
|
||||
n++
|
||||
if len(s) == 0 {
|
||||
return numberParts{}, false
|
||||
}
|
||||
}
|
||||
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
||||
exp = append(exp, s[0])
|
||||
s = s[1:]
|
||||
n++
|
||||
}
|
||||
exp = exp[:n]
|
||||
}
|
||||
|
||||
return numberParts{
|
||||
@ -205,8 +212,7 @@ func parseNumber(input []byte) (numberParts, bool) {
|
||||
// E-notation for given numberParts. It will return false if it is not an
|
||||
// integer or if the exponent exceeds than max/min int value.
|
||||
func normalizeToIntString(n numberParts) (string, bool) {
|
||||
num := n.intp
|
||||
intpSize := len(num)
|
||||
intpSize := len(n.intp)
|
||||
fracSize := len(n.frac)
|
||||
|
||||
if intpSize == 0 && fracSize == 0 {
|
||||
@ -222,16 +228,19 @@ func normalizeToIntString(n numberParts) (string, bool) {
|
||||
exp = int(i)
|
||||
}
|
||||
|
||||
var num []byte
|
||||
if exp >= 0 {
|
||||
// For positive E, shift fraction digits into integer part and also pad
|
||||
// with zeroes as needed.
|
||||
|
||||
// If there are more digits in fraction than the E value, then number is
|
||||
// not an integer.
|
||||
// If there are more digits in fraction than the E value, then the
|
||||
// number is not an integer.
|
||||
if fracSize > exp {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Set cap to make a copy of integer part when appended.
|
||||
num = n.intp[:len(n.intp):len(n.intp)]
|
||||
num = append(num, n.frac...)
|
||||
for i := 0; i < exp-fracSize; i++ {
|
||||
num = append(num, '0')
|
||||
@ -240,18 +249,21 @@ func normalizeToIntString(n numberParts) (string, bool) {
|
||||
} else {
|
||||
// For negative E, shift digits in integer part out.
|
||||
|
||||
// If there are any fractions to begin with, then number is not an
|
||||
// integer.
|
||||
// If there are fractions, then the number is not an integer.
|
||||
if fracSize > 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// index is where the decimal point will be after adjusting for negative
|
||||
// exponent.
|
||||
index := intpSize + exp
|
||||
if index < 0 {
|
||||
return "", false
|
||||
}
|
||||
// If any of the digits being shifted out is non-zero, then number is
|
||||
// not an integer.
|
||||
|
||||
num = n.intp
|
||||
// If any of the digits being shifted to the right of the decimal point
|
||||
// is non-zero, then the number is not an integer.
|
||||
for i := index; i < intpSize; i++ {
|
||||
if num[i] != '0' {
|
||||
return "", false
|
||||
|
Loading…
x
Reference in New Issue
Block a user