Skip to content

Commit ae68a91

Browse files
committed
encoding/json: remove unnecessary isValidNumber call
The decoder called this function to check numbers being decoded into a json.Number. However, these can't be quoted as strings, so the tokenizer has already verified they are valid JSON numbers. Verified this by adding a test with such an input. As expected, it produces a syntax error, not the fmt.Errorf - that line could never execute. Since the only remaining non-test caller of isvalidnumber is in encode.go, move the function there. This change should slightly reduce the amount of work when decoding into json.Number, though that isn't very common nor part of any current benchmarks. Change-Id: I67a1723deb3d18d5b542d6dd35f3ae56a43f23eb Reviewed-on: https://go-review.googlesource.com/c/go/+/184817 Run-TryBot: Daniel Martí <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent b9bf2f5 commit ae68a91

File tree

3 files changed

+63
-63
lines changed

3 files changed

+63
-63
lines changed

src/encoding/json/decode.go

Lines changed: 2 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -199,66 +199,6 @@ func (n Number) Int64() (int64, error) {
199199
return strconv.ParseInt(string(n), 10, 64)
200200
}
201201

202-
// isValidNumber reports whether s is a valid JSON number literal.
203-
func isValidNumber(s string) bool {
204-
// This function implements the JSON numbers grammar.
205-
// See https://tools.ietf.org/html/rfc7159#section-6
206-
// and https://json.org/number.gif
207-
208-
if s == "" {
209-
return false
210-
}
211-
212-
// Optional -
213-
if s[0] == '-' {
214-
s = s[1:]
215-
if s == "" {
216-
return false
217-
}
218-
}
219-
220-
// Digits
221-
switch {
222-
default:
223-
return false
224-
225-
case s[0] == '0':
226-
s = s[1:]
227-
228-
case '1' <= s[0] && s[0] <= '9':
229-
s = s[1:]
230-
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
231-
s = s[1:]
232-
}
233-
}
234-
235-
// . followed by 1 or more digits.
236-
if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
237-
s = s[2:]
238-
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
239-
s = s[1:]
240-
}
241-
}
242-
243-
// e or E followed by an optional - or + and
244-
// 1 or more digits.
245-
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
246-
s = s[1:]
247-
if s[0] == '+' || s[0] == '-' {
248-
s = s[1:]
249-
if s == "" {
250-
return false
251-
}
252-
}
253-
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
254-
s = s[1:]
255-
}
256-
}
257-
258-
// Make sure we are at the end.
259-
return s == ""
260-
}
261-
262202
// decodeState represents the state while decoding a JSON value.
263203
type decodeState struct {
264204
data []byte
@@ -1027,10 +967,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
1027967
switch v.Kind() {
1028968
default:
1029969
if v.Kind() == reflect.String && v.Type() == numberType {
970+
// s must be a valid number, because it's
971+
// already been tokenized.
1030972
v.SetString(s)
1031-
if !isValidNumber(s) {
1032-
return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)
1033-
}
1034973
break
1035974
}
1036975
if fromQuoted {

src/encoding/json/decode_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ var unmarshalTests = []unmarshalTest{
448448
{in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},
449449
{in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
450450
{in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}},
451+
{in: `{"F3": -}`, ptr: new(V), out: V{F3: Number("-")}, err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}},
451452

452453
// raw value errors
453454
{in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},

src/encoding/json/encode.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,66 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
611611
}
612612
}
613613

614+
// isValidNumber reports whether s is a valid JSON number literal.
615+
func isValidNumber(s string) bool {
616+
// This function implements the JSON numbers grammar.
617+
// See https://tools.ietf.org/html/rfc7159#section-6
618+
// and https://json.org/number.gif
619+
620+
if s == "" {
621+
return false
622+
}
623+
624+
// Optional -
625+
if s[0] == '-' {
626+
s = s[1:]
627+
if s == "" {
628+
return false
629+
}
630+
}
631+
632+
// Digits
633+
switch {
634+
default:
635+
return false
636+
637+
case s[0] == '0':
638+
s = s[1:]
639+
640+
case '1' <= s[0] && s[0] <= '9':
641+
s = s[1:]
642+
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
643+
s = s[1:]
644+
}
645+
}
646+
647+
// . followed by 1 or more digits.
648+
if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
649+
s = s[2:]
650+
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
651+
s = s[1:]
652+
}
653+
}
654+
655+
// e or E followed by an optional - or + and
656+
// 1 or more digits.
657+
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
658+
s = s[1:]
659+
if s[0] == '+' || s[0] == '-' {
660+
s = s[1:]
661+
if s == "" {
662+
return false
663+
}
664+
}
665+
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
666+
s = s[1:]
667+
}
668+
}
669+
670+
// Make sure we are at the end.
671+
return s == ""
672+
}
673+
614674
func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) {
615675
if v.IsNil() {
616676
e.WriteString("null")

0 commit comments

Comments
 (0)