mirror of https://github.com/goccy/go-json.git
feat: improve performance when a payload contains escape sequence
This commit is contained in:
parent
116e62dc84
commit
4bd7d2399f
|
@ -1,6 +1,7 @@
|
||||||
package decoder
|
package decoder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"reflect"
|
"reflect"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
|
@ -308,49 +309,30 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
|
||||||
cursor++
|
cursor++
|
||||||
start := cursor
|
start := cursor
|
||||||
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
|
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
|
||||||
|
escaped := 0
|
||||||
for {
|
for {
|
||||||
switch char(b, cursor) {
|
switch char(b, cursor) {
|
||||||
case '\\':
|
case '\\':
|
||||||
|
escaped++
|
||||||
cursor++
|
cursor++
|
||||||
switch char(b, cursor) {
|
switch char(b, cursor) {
|
||||||
case '"':
|
case '"', '\\', '/', 'b', 'f', 'n', 'r', 't':
|
||||||
buf[cursor] = '"'
|
cursor++
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case '\\':
|
|
||||||
buf[cursor] = '\\'
|
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case '/':
|
|
||||||
buf[cursor] = '/'
|
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case 'b':
|
|
||||||
buf[cursor] = '\b'
|
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case 'f':
|
|
||||||
buf[cursor] = '\f'
|
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case 'n':
|
|
||||||
buf[cursor] = '\n'
|
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case 'r':
|
|
||||||
buf[cursor] = '\r'
|
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case 't':
|
|
||||||
buf[cursor] = '\t'
|
|
||||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
|
||||||
case 'u':
|
case 'u':
|
||||||
buflen := int64(len(buf))
|
buflen := int64(len(buf))
|
||||||
if cursor+5 >= buflen {
|
if cursor+5 >= buflen {
|
||||||
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
||||||
}
|
}
|
||||||
code := unicodeToRune(buf[cursor+1 : cursor+5])
|
cursor += 5
|
||||||
unicode := []byte(string(code))
|
|
||||||
buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...)
|
|
||||||
default:
|
default:
|
||||||
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
case '"':
|
case '"':
|
||||||
literal := buf[start:cursor]
|
literal := buf[start:cursor]
|
||||||
|
if escaped > 0 {
|
||||||
|
literal = literal[:unescapeString(literal, escaped)]
|
||||||
|
}
|
||||||
cursor++
|
cursor++
|
||||||
return literal, cursor, nil
|
return literal, cursor, nil
|
||||||
case nul:
|
case nul:
|
||||||
|
@ -369,3 +351,33 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var unescapeMap = [256]byte{
|
||||||
|
'"': '"',
|
||||||
|
'\\': '\\',
|
||||||
|
'/': '/',
|
||||||
|
'b': '\b',
|
||||||
|
'f': '\f',
|
||||||
|
'n': '\n',
|
||||||
|
'r': '\r',
|
||||||
|
't': '\t',
|
||||||
|
}
|
||||||
|
|
||||||
|
func unescapeString(buf []byte, escaped int) int {
|
||||||
|
cursor := 0
|
||||||
|
for i := 0; i < escaped; i++ {
|
||||||
|
cursor += bytes.IndexByte(buf[cursor:], '\\')
|
||||||
|
c := buf[cursor+1]
|
||||||
|
if c == 'u' {
|
||||||
|
code := unicodeToRune(buf[cursor+2 : cursor+6])
|
||||||
|
unicode := []byte(string(code))
|
||||||
|
buf = append(append(buf[:cursor], unicode...), buf[cursor+6:]...)
|
||||||
|
cursor += len(unicode)
|
||||||
|
} else {
|
||||||
|
buf[cursor+1] = unescapeMap[c]
|
||||||
|
buf = append(buf[:cursor], buf[cursor+1:]...)
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(buf)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue