From d2e2596b72d32dffc4c205f6438e036eb8303f53 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Wed, 8 Dec 2021 15:11:28 +1000 Subject: [PATCH] Speed up parseInt and parseUint (#112) There's no need to check for possible overflow before we handle each byte of input. We can just handle the next byte and then check whether overflow occurred. --- json/parse.go | 58 ++++++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/json/parse.go b/json/parse.go index 8f5bd95..acf1a08 100644 --- a/json/parse.go +++ b/json/parse.go @@ -131,33 +131,22 @@ func (d decoder) parseInt(b []byte, t reflect.Type) (int64, []byte, error) { count++ } else { - const max = math.MaxInt64 - const lim = max / 10 - if len(b) > 1 && b[0] == '0' && '0' <= b[1] && b[1] <= '9' { return 0, b, syntaxError(b, "invalid leading character '0' in integer") } - for _, c := range b { - if !(c >= '0' && c <= '9') { - if count == 0 { - b, err := d.inputError(b, t) - return 0, b, err - } - break - } - x := int64(c - '0') - - if value > lim { - return 0, b, unmarshalOverflow(b, t) - } - - if value *= 10; value > (max - x) { + for ; count < len(b) && b[count] >= '0' && b[count] <= '9'; count++ { + x := int64(b[count] - '0') + next := value*10 + x + if next < value { return 0, b, unmarshalOverflow(b, t) } + value = next + } - value += x - count++ + if count == 0 { + b, err := d.inputError(b, t) + return 0, b, err } } @@ -177,9 +166,6 @@ func (d decoder) parseInt(b []byte, t reflect.Type) (int64, []byte, error) { // parseUint is like parseInt but for unsigned integers. func (d decoder) parseUint(b []byte, t reflect.Type) (uint64, []byte, error) { - const max = math.MaxUint64 - const lim = max / 10 - var value uint64 var count int @@ -191,26 +177,18 @@ func (d decoder) parseUint(b []byte, t reflect.Type) (uint64, []byte, error) { return 0, b, syntaxError(b, "invalid leading character '0' in integer") } - for _, c := range b { - if !(c >= '0' && c <= '9') { - if count == 0 { - b, err := d.inputError(b, t) - return 0, b, err - } - break - } - x := uint64(c - '0') - - if value > lim { - return 0, b, unmarshalOverflow(b, t) - } - - if value *= 10; value > (max - x) { + for ; count < len(b) && b[count] >= '0' && b[count] <= '9'; count++ { + x := uint64(b[count] - '0') + next := value*10 + x + if next < value { return 0, b, unmarshalOverflow(b, t) } + value = next + } - value += x - count++ + if count == 0 { + b, err := d.inputError(b, t) + return 0, b, err } if count < len(b) {