1
0
mirror of https://github.com/golang/go synced 2024-11-21 22:34:48 -07:00

encoding/json: reduce the number of allocations when decoding in streaming mode (Token API)

When the scanner is used by the Token API it always resets the state before so that the scanner behaves as if it was parsing a top-level value,
which causes it to allocate and set the 'err' field because the following character is not a space. This error value is completely unnecessary
because it's dropped by the next invocation of readValue().

Fixes #56299
This commit is contained in:
Dmitry Panov 2022-10-18 20:17:11 +00:00
parent 4fb35d6cee
commit 9d4e68dd1a
2 changed files with 17 additions and 0 deletions

View File

@ -73,6 +73,9 @@ type scanner struct {
// Reached end of top-level value.
endTop bool
// The scanner is used in streaming mode (i.e. by the Token API)
inStream bool
// Stack of what we're in the middle of - array values, object keys, object values.
parseState []int
@ -280,6 +283,15 @@ func stateEndValue(s *scanner, c byte) int {
n := len(s.parseState)
if n == 0 {
// Completed top-level before the current byte.
if s.inStream {
// If used in streaming mode (i.e. by the Token API) do not allocate and set s.err in case the next
// character is non-space (which stateEndTop() would do). The error would be discarded anyway at the next
// call to readValue().
if s.err != nil {
return scanError
}
return scanEnd
}
s.step = stateEndTop
s.endTop = true
return stateEndTop(s, c)

View File

@ -369,6 +369,11 @@ func (d Delim) String() string {
// to mark the start and end of arrays and objects.
// Commas and colons are elided.
func (dec *Decoder) Token() (Token, error) {
dec.scan.inStream = true
defer func() {
dec.scan.inStream = false
}()
for {
c, err := dec.peek()
if err != nil {