From 02b962186be4ed9597df5fc526ef85b2e66cf55b Mon Sep 17 00:00:00 2001 From: Shulhan Date: Fri, 26 Aug 2022 21:48:21 +0700 Subject: encoding/json: optimize isValidNumber function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use an index instead of reslicing the string because reslicing a string updates both the data and length fields instead of just the one index variable. Benchmark result, name old time/op new time/op delta NumberIsValid-8 19.0ns ± 0% 14.5ns ± 1% -23.70% (p=0.008 n=5+5) name old alloc/op new alloc/op delta NumberIsValid-8 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta NumberIsValid-8 0.00 0.00 ~ (all equal) Change-Id: I4698c5db134998f83ff47fb3add6a04ba6ec3aa0 --- src/encoding/json/encode.go | 50 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'src/encoding/json/encode.go') diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 9d59b0ff2b..da936173da 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -652,14 +652,20 @@ func isValidNumber(s string) bool { // See https://tools.ietf.org/html/rfc7159#section-6 // and https://www.json.org/img/number.png - if s == "" { + if len(s) == 0 { return false } + // We use an index instead of reslicing the string because + // reslicing a string updates both the data and length fields + // instead of just the one index variable. + + var i int + // Optional - - if s[0] == '-' { - s = s[1:] - if s == "" { + if s[i] == '-' { + i++ + if len(s) == i { return false } } @@ -669,41 +675,41 @@ func isValidNumber(s string) bool { default: return false - case s[0] == '0': - s = s[1:] + case s[i] == '0': + i++ - case '1' <= s[0] && s[0] <= '9': - s = s[1:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] + case '1' <= s[i] && s[i] <= '9': + i++ + for len(s) > i && '0' <= s[i] && s[i] <= '9' { + i++ } } // . followed by 1 or more digits. - if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { - s = s[2:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] + if len(s)-i >= 2 && s[i] == '.' && '0' <= s[i+1] && s[i+1] <= '9' { + i += 2 + for len(s) > i && '0' <= s[i] && s[i] <= '9' { + i++ } } // 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:] - if s[0] == '+' || s[0] == '-' { - s = s[1:] - if s == "" { + if len(s)-i >= 2 && (s[i] == 'e' || s[i] == 'E') { + i++ + if s[i] == '+' || s[i] == '-' { + i++ + if len(s) == i { return false } } - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] + for len(s) > i && '0' <= s[i] && s[i] <= '9' { + i++ } } // Make sure we are at the end. - return s == "" + return len(s) == i } func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) { -- cgit v1.3