forked from mirror/go-json
Merge branch 'master' into golangci-lint
This commit is contained in:
commit
5f9f30fc8e
|
@ -1,4 +1,7 @@
|
|||
run:
|
||||
skip-files:
|
||||
- encode_optype.go
|
||||
- ".*_test\\.go$"
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
|
@ -9,6 +12,7 @@ linters-settings:
|
|||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- dogsled
|
||||
- dupl
|
||||
- exhaustive
|
||||
- exhaustivestruct
|
||||
|
@ -35,6 +39,12 @@ linters:
|
|||
- testpackage
|
||||
- thelper
|
||||
- wrapcheck
|
||||
- interfacer
|
||||
- lll
|
||||
- nakedret
|
||||
- nestif
|
||||
- nlreturn
|
||||
- testpackage
|
||||
- wsl
|
||||
|
||||
issues:
|
||||
|
@ -48,10 +58,12 @@ issues:
|
|||
text: "don't use an underscore in package name"
|
||||
linters:
|
||||
- golint
|
||||
- path: rtype.go
|
||||
linters:
|
||||
- golint
|
||||
|
||||
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||
max-issues-per-linter: 0
|
||||
|
||||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||
max-same-issues: 0
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ type decoder interface {
|
|||
|
||||
type Decoder struct {
|
||||
s *stream
|
||||
disallowUnknownFields bool
|
||||
structTypeToDecoder map[uintptr]decoder
|
||||
}
|
||||
|
||||
|
@ -240,11 +239,12 @@ func (d *Decoder) Token() (Token, error) {
|
|||
if s.read() {
|
||||
continue
|
||||
}
|
||||
return nil, io.EOF
|
||||
goto END
|
||||
default:
|
||||
return nil, errInvalidCharacter(s.char(), "token", s.totalOffset())
|
||||
}
|
||||
}
|
||||
END:
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,6 @@ func (d *bytesDecoder) decodeBinary(buf []byte, cursor int64, p unsafe.Pointer)
|
|||
}
|
||||
cursor++
|
||||
}
|
||||
return nil, 0, errUnexpectedEndOfJSON("[]byte", cursor)
|
||||
case '[':
|
||||
if d.sliceDecoder == nil {
|
||||
return nil, 0, &UnmarshalTypeError{
|
||||
|
|
|
@ -309,7 +309,7 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod
|
|||
// recursive definition
|
||||
continue
|
||||
}
|
||||
d.removeConflictFields(fieldMap, conflictedMap, stDec, uintptr(field.Offset))
|
||||
d.removeConflictFields(fieldMap, conflictedMap, stDec, field.Offset)
|
||||
} else if pdec, ok := dec.(*ptrDecoder); ok {
|
||||
contentDec := pdec.contentDecoder()
|
||||
if pdec.typ == typ {
|
||||
|
@ -326,7 +326,7 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod
|
|||
if !exists {
|
||||
fieldSet := &structFieldSet{
|
||||
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
|
||||
offset: uintptr(field.Offset),
|
||||
offset: field.Offset,
|
||||
isTaggedKey: v.isTaggedKey,
|
||||
}
|
||||
fieldMap[k] = fieldSet
|
||||
|
@ -347,7 +347,7 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod
|
|||
if v.isTaggedKey {
|
||||
fieldSet := &structFieldSet{
|
||||
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
|
||||
offset: uintptr(field.Offset),
|
||||
offset: field.Offset,
|
||||
isTaggedKey: v.isTaggedKey,
|
||||
}
|
||||
fieldMap[k] = fieldSet
|
||||
|
|
|
@ -142,5 +142,4 @@ func skipValue(buf []byte, cursor int64) (int64, error) {
|
|||
}
|
||||
cursor++
|
||||
}
|
||||
return cursor, errUnexpectedEndOfJSON("value of object", cursor)
|
||||
}
|
||||
|
|
|
@ -149,7 +149,6 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error)
|
|||
return nil, 0, d.typeError([]byte{buf[cursor]}, cursor)
|
||||
}
|
||||
}
|
||||
return nil, 0, errUnexpectedEndOfJSON("number(integer)", cursor)
|
||||
}
|
||||
|
||||
func (d *intDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
|
||||
|
|
|
@ -143,7 +143,6 @@ func (d *interfaceDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
|
|||
}
|
||||
s.cursor++
|
||||
}
|
||||
return errUnexpectedEndOfJSON("string", s.totalOffset())
|
||||
case 't':
|
||||
if err := trueBytes(s); err != nil {
|
||||
return err
|
||||
|
@ -229,7 +228,6 @@ func (d *interfaceDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (i
|
|||
}
|
||||
cursor++
|
||||
}
|
||||
return 0, errUnexpectedEndOfJSON("string", cursor)
|
||||
case 't':
|
||||
if cursor+3 >= int64(len(buf)) {
|
||||
return 0, errUnexpectedEndOfJSON("bool(true)", cursor)
|
||||
|
|
|
@ -94,7 +94,6 @@ func (d *mapDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
|
|||
return errExpected("comma after object value", s.totalOffset())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, error) {
|
||||
|
@ -151,7 +150,6 @@ func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64,
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cursor = valueCursor
|
||||
mapassign(d.mapType, mapValue, unsafe.Pointer(&key), unsafe.Pointer(&value))
|
||||
cursor = skipWhiteSpace(buf, valueCursor)
|
||||
if buf[cursor] == '}' {
|
||||
|
|
|
@ -28,6 +28,7 @@ func (d *ptrDecoder) contentDecoder() decoder {
|
|||
return dec.contentDecoder()
|
||||
}
|
||||
|
||||
//nolint:golint
|
||||
//go:linkname unsafe_New reflect.unsafe_New
|
||||
func unsafe_New(*rtype) unsafe.Pointer
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ type stream struct {
|
|||
r io.Reader
|
||||
offset int64
|
||||
cursor int64
|
||||
readPos int64
|
||||
allRead bool
|
||||
useNumber bool
|
||||
disallowUnknownFields bool
|
||||
|
@ -200,5 +199,4 @@ func (s *stream) skipValue() error {
|
|||
}
|
||||
s.cursor++
|
||||
}
|
||||
return errUnexpectedEndOfJSON("value of object", s.offset)
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ RETRY:
|
|||
return nil
|
||||
}
|
||||
|
||||
//nolint:deadcode,unused
|
||||
func appendCoerceInvalidUTF8(b []byte, s []byte) []byte {
|
||||
c := [4]byte{}
|
||||
|
||||
|
@ -298,7 +299,6 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
|
|||
}
|
||||
cursor++
|
||||
}
|
||||
return nil, 0, errUnexpectedEndOfJSON("string", cursor)
|
||||
case 'n':
|
||||
buflen := int64(len(buf))
|
||||
if cursor+3 >= buflen {
|
||||
|
|
|
@ -93,7 +93,6 @@ func (d *structDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
|
|||
}
|
||||
s.cursor++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *structDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, error) {
|
||||
|
|
|
@ -70,12 +70,12 @@ func (d *uintDecoder) decodeStreamByte(s *stream) ([]byte, error) {
|
|||
}
|
||||
num := s.buf[start:s.cursor]
|
||||
return num, nil
|
||||
default:
|
||||
return nil, d.typeError([]byte{s.char()}, s.totalOffset())
|
||||
case nul:
|
||||
if s.read() {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
return nil, d.typeError([]byte{s.char()}, s.totalOffset())
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
10
encode.go
10
encode.go
|
@ -128,7 +128,7 @@ func (e *Encoder) SetIndent(prefix, indent string) {
|
|||
func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||
ctx := takeEncodeRuntimeContext()
|
||||
|
||||
buf, err := encode(ctx, v, EncodeOptionHTMLEscape)
|
||||
buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape)
|
||||
if err != nil {
|
||||
releaseEncodeRuntimeContext(ctx)
|
||||
return nil, err
|
||||
|
@ -149,7 +149,7 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
|
|||
func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||
ctx := takeEncodeRuntimeContext()
|
||||
|
||||
buf, err := encodeNoEscape(ctx, v, EncodeOptionHTMLEscape)
|
||||
buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape)
|
||||
if err != nil {
|
||||
releaseEncodeRuntimeContext(ctx)
|
||||
return nil, err
|
||||
|
@ -170,7 +170,7 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
|
|||
func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) {
|
||||
ctx := takeEncodeRuntimeContext()
|
||||
|
||||
buf, err := encodeIndent(ctx, v, prefix, indent, EncodeOptionHTMLEscape)
|
||||
buf, err := encodeIndent(ctx, v, prefix, indent, opt|EncodeOptionHTMLEscape)
|
||||
if err != nil {
|
||||
releaseEncodeRuntimeContext(ctx)
|
||||
return nil, err
|
||||
|
@ -320,10 +320,6 @@ func encodeBool(b []byte, v bool) []byte {
|
|||
return append(b, "false"...)
|
||||
}
|
||||
|
||||
func encodeBytes(dst []byte, src []byte) []byte {
|
||||
return append(dst, src...)
|
||||
}
|
||||
|
||||
func encodeNull(b []byte) []byte {
|
||||
return append(b, "null"...)
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ var (
|
|||
cachedOpcode unsafe.Pointer // map[uintptr]*opcodeSet
|
||||
baseTypeAddr uintptr
|
||||
cachedOpcodeSets []*opcodeSet
|
||||
existsCachedOpcodeSets bool
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -72,7 +73,7 @@ func setupOpcodeSets() error {
|
|||
}
|
||||
}
|
||||
}
|
||||
addrRange := uintptr(max) - uintptr(min)
|
||||
addrRange := max - min
|
||||
if addrRange == 0 {
|
||||
return fmt.Errorf("failed to get address range of types")
|
||||
}
|
||||
|
@ -80,43 +81,13 @@ func setupOpcodeSets() error {
|
|||
return fmt.Errorf("too big address range %d", addrRange)
|
||||
}
|
||||
cachedOpcodeSets = make([]*opcodeSet, addrRange)
|
||||
existsCachedOpcodeSets = true
|
||||
baseTypeAddr = min
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
if err := setupOpcodeSets(); err != nil {
|
||||
// fallback to slow path
|
||||
}
|
||||
}
|
||||
|
||||
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
||||
if cachedOpcodeSets == nil {
|
||||
return encodeCompileToGetCodeSetSlowPath(typeptr)
|
||||
}
|
||||
if codeSet := cachedOpcodeSets[typeptr-baseTypeAddr]; codeSet != nil {
|
||||
return codeSet, nil
|
||||
}
|
||||
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
|
||||
|
||||
code, err := encodeCompileHead(&encodeCompileContext{
|
||||
typ: copiedType,
|
||||
root: true,
|
||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code = copyOpcode(code)
|
||||
codeLength := code.totalLength()
|
||||
codeSet := &opcodeSet{
|
||||
code: code,
|
||||
codeLength: codeLength,
|
||||
}
|
||||
cachedOpcodeSets[int(typeptr-baseTypeAddr)] = codeSet
|
||||
return codeSet, nil
|
||||
_ = setupOpcodeSets()
|
||||
}
|
||||
|
||||
func encodeCompileToGetCodeSetSlowPath(typeptr uintptr) (*opcodeSet, error) {
|
||||
|
@ -799,6 +770,7 @@ func encodeTypeToHeaderType(ctx *encodeCompileContext, code *opcode) opType {
|
|||
ptrNum++
|
||||
code = code.next
|
||||
ctx.decIndex()
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
@ -923,6 +895,7 @@ func encodeTypeToFieldType(ctx *encodeCompileContext, code *opcode) opType {
|
|||
ptrNum++
|
||||
code = code.next
|
||||
ctx.decIndex()
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
@ -1182,7 +1155,7 @@ type structFieldPair struct {
|
|||
linked bool
|
||||
}
|
||||
|
||||
func encodeAnonymousStructFieldPairMap(typ *rtype, tags structTags, named string, valueCode *opcode) map[string][]structFieldPair {
|
||||
func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode *opcode) map[string][]structFieldPair {
|
||||
anonymousFields := map[string][]structFieldPair{}
|
||||
f := valueCode
|
||||
var prevAnonymousField *opcode
|
||||
|
@ -1224,7 +1197,7 @@ func encodeAnonymousStructFieldPairMap(typ *rtype, tags structTags, named string
|
|||
isTaggedKey: f.isTaggedKey,
|
||||
})
|
||||
if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField {
|
||||
for k, v := range encodeAnonymousStructFieldPairMap(typ, tags, named, f.next) {
|
||||
for k, v := range encodeAnonymousStructFieldPairMap(tags, named, f.next) {
|
||||
anonymousFields[k] = append(anonymousFields[k], v...)
|
||||
}
|
||||
}
|
||||
|
@ -1350,7 +1323,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
|||
if tag.isTaggedKey {
|
||||
tagKey = tag.key
|
||||
}
|
||||
for k, v := range encodeAnonymousStructFieldPairMap(typ, tags, tagKey, valueCode) {
|
||||
for k, v := range encodeAnonymousStructFieldPairMap(tags, tagKey, valueCode) {
|
||||
anonymousFields[k] = append(anonymousFields[k], v...)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// +build !race
|
||||
|
||||
package json
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
||||
if !existsCachedOpcodeSets {
|
||||
return encodeCompileToGetCodeSetSlowPath(typeptr)
|
||||
}
|
||||
if codeSet := cachedOpcodeSets[typeptr-baseTypeAddr]; codeSet != nil {
|
||||
return codeSet, nil
|
||||
}
|
||||
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
|
||||
|
||||
code, err := encodeCompileHead(&encodeCompileContext{
|
||||
typ: copiedType,
|
||||
root: true,
|
||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code = copyOpcode(code)
|
||||
codeLength := code.totalLength()
|
||||
codeSet := &opcodeSet{
|
||||
code: code,
|
||||
codeLength: codeLength,
|
||||
}
|
||||
cachedOpcodeSets[int(typeptr-baseTypeAddr)] = codeSet
|
||||
return codeSet, nil
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// +build race
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var setsMu sync.RWMutex
|
||||
|
||||
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
||||
if !existsCachedOpcodeSets {
|
||||
return encodeCompileToGetCodeSetSlowPath(typeptr)
|
||||
}
|
||||
setsMu.RLock()
|
||||
if codeSet := cachedOpcodeSets[typeptr-baseTypeAddr]; codeSet != nil {
|
||||
setsMu.RUnlock()
|
||||
return codeSet, nil
|
||||
}
|
||||
setsMu.RUnlock()
|
||||
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
|
||||
|
||||
code, err := encodeCompileHead(&encodeCompileContext{
|
||||
typ: copiedType,
|
||||
root: true,
|
||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code = copyOpcode(code)
|
||||
codeLength := code.totalLength()
|
||||
codeSet := &opcodeSet{
|
||||
code: code,
|
||||
codeLength: codeLength,
|
||||
}
|
||||
setsMu.Lock()
|
||||
cachedOpcodeSets[int(typeptr-baseTypeAddr)] = codeSet
|
||||
setsMu.Unlock()
|
||||
return codeSet, nil
|
||||
}
|
|
@ -28,7 +28,6 @@ func (m *mapslice) Swap(i, j int) {
|
|||
}
|
||||
|
||||
type encodeMapContext struct {
|
||||
iter unsafe.Pointer
|
||||
pos []int
|
||||
slice *mapslice
|
||||
buf []byte
|
||||
|
|
|
@ -124,7 +124,6 @@ func (c *opcode) beforeLastCode() *opcode {
|
|||
}
|
||||
code = nextCode
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *opcode) totalLength() int {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func TestDumpOpcode(t *testing.T) {
|
||||
var v interface{} = 1
|
||||
header := (*interfaceHeader)(unsafe.Pointer(&v))
|
||||
typ := header.typ
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
codeSet, err := encodeCompileToGetCodeSet(typeptr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
codeSet.code.dump()
|
||||
}
|
371
encode_string.go
371
encode_string.go
|
@ -347,345 +347,6 @@ var needEscape = [256]bool{
|
|||
0xff: true,
|
||||
}
|
||||
|
||||
// htmlSafeSet holds the value true if the ASCII character with the given
|
||||
// array position can be safely represented inside a JSON string, embedded
|
||||
// inside of HTML <script> tags, without any additional escaping.
|
||||
//
|
||||
// All values are true except for the ASCII control characters (0-31), the
|
||||
// double quote ("), the backslash character ("\"), HTML opening and closing
|
||||
// tags ("<" and ">"), and the ampersand ("&").
|
||||
var htmlSafeSet = [256]bool{
|
||||
' ': true,
|
||||
'!': true,
|
||||
'"': false,
|
||||
'#': true,
|
||||
'$': true,
|
||||
'%': true,
|
||||
'&': false,
|
||||
'\'': true,
|
||||
'(': true,
|
||||
')': true,
|
||||
'*': true,
|
||||
'+': true,
|
||||
',': true,
|
||||
'-': true,
|
||||
'.': true,
|
||||
'/': true,
|
||||
'0': true,
|
||||
'1': true,
|
||||
'2': true,
|
||||
'3': true,
|
||||
'4': true,
|
||||
'5': true,
|
||||
'6': true,
|
||||
'7': true,
|
||||
'8': true,
|
||||
'9': true,
|
||||
':': true,
|
||||
';': true,
|
||||
'<': false,
|
||||
'=': true,
|
||||
'>': false,
|
||||
'?': true,
|
||||
'@': true,
|
||||
'A': true,
|
||||
'B': true,
|
||||
'C': true,
|
||||
'D': true,
|
||||
'E': true,
|
||||
'F': true,
|
||||
'G': true,
|
||||
'H': true,
|
||||
'I': true,
|
||||
'J': true,
|
||||
'K': true,
|
||||
'L': true,
|
||||
'M': true,
|
||||
'N': true,
|
||||
'O': true,
|
||||
'P': true,
|
||||
'Q': true,
|
||||
'R': true,
|
||||
'S': true,
|
||||
'T': true,
|
||||
'U': true,
|
||||
'V': true,
|
||||
'W': true,
|
||||
'X': true,
|
||||
'Y': true,
|
||||
'Z': true,
|
||||
'[': true,
|
||||
'\\': false,
|
||||
']': true,
|
||||
'^': true,
|
||||
'_': true,
|
||||
'`': true,
|
||||
'a': true,
|
||||
'b': true,
|
||||
'c': true,
|
||||
'd': true,
|
||||
'e': true,
|
||||
'f': true,
|
||||
'g': true,
|
||||
'h': true,
|
||||
'i': true,
|
||||
'j': true,
|
||||
'k': true,
|
||||
'l': true,
|
||||
'm': true,
|
||||
'n': true,
|
||||
'o': true,
|
||||
'p': true,
|
||||
'q': true,
|
||||
'r': true,
|
||||
's': true,
|
||||
't': true,
|
||||
'u': true,
|
||||
'v': true,
|
||||
'w': true,
|
||||
'x': true,
|
||||
'y': true,
|
||||
'z': true,
|
||||
'{': true,
|
||||
'|': true,
|
||||
'}': true,
|
||||
'~': true,
|
||||
'\u007f': true,
|
||||
0x80: false,
|
||||
0x81: false,
|
||||
0x82: false,
|
||||
0x83: false,
|
||||
0x84: false,
|
||||
0x85: false,
|
||||
0x86: false,
|
||||
0x87: false,
|
||||
0x88: false,
|
||||
0x89: false,
|
||||
0x8a: false,
|
||||
0x8b: false,
|
||||
0x8c: false,
|
||||
0x8d: false,
|
||||
0x8e: false,
|
||||
0x8f: false,
|
||||
0x90: false,
|
||||
0x91: false,
|
||||
0x92: false,
|
||||
0x93: false,
|
||||
0x94: false,
|
||||
0x95: false,
|
||||
0x96: false,
|
||||
0x97: false,
|
||||
0x98: false,
|
||||
0x99: false,
|
||||
0x9a: false,
|
||||
0x9b: false,
|
||||
0x9c: false,
|
||||
0x9d: false,
|
||||
0x9e: false,
|
||||
0x9f: false,
|
||||
0xa0: false,
|
||||
0xa1: false,
|
||||
0xa2: false,
|
||||
0xa3: false,
|
||||
0xa4: false,
|
||||
0xa5: false,
|
||||
0xa6: false,
|
||||
0xa7: false,
|
||||
0xa8: false,
|
||||
0xa9: false,
|
||||
0xaa: false,
|
||||
0xab: false,
|
||||
0xac: false,
|
||||
0xad: false,
|
||||
0xae: false,
|
||||
0xaf: false,
|
||||
0xb0: false,
|
||||
0xb1: false,
|
||||
0xb2: false,
|
||||
0xb3: false,
|
||||
0xb4: false,
|
||||
0xb5: false,
|
||||
0xb6: false,
|
||||
0xb7: false,
|
||||
0xb8: false,
|
||||
0xb9: false,
|
||||
0xba: false,
|
||||
0xbb: false,
|
||||
0xbc: false,
|
||||
0xbd: false,
|
||||
0xbe: false,
|
||||
0xbf: false,
|
||||
0xc0: false,
|
||||
0xc1: false,
|
||||
0xc2: false,
|
||||
0xc3: false,
|
||||
0xc4: false,
|
||||
0xc5: false,
|
||||
0xc6: false,
|
||||
0xc7: false,
|
||||
0xc8: false,
|
||||
0xc9: false,
|
||||
0xca: false,
|
||||
0xcb: false,
|
||||
0xcc: false,
|
||||
0xcd: false,
|
||||
0xce: false,
|
||||
0xcf: false,
|
||||
0xd0: false,
|
||||
0xd1: false,
|
||||
0xd2: false,
|
||||
0xd3: false,
|
||||
0xd4: false,
|
||||
0xd5: false,
|
||||
0xd6: false,
|
||||
0xd7: false,
|
||||
0xd8: false,
|
||||
0xd9: false,
|
||||
0xda: false,
|
||||
0xdb: false,
|
||||
0xdc: false,
|
||||
0xdd: false,
|
||||
0xde: false,
|
||||
0xdf: false,
|
||||
0xe0: false,
|
||||
0xe1: false,
|
||||
0xe2: false,
|
||||
0xe3: false,
|
||||
0xe4: false,
|
||||
0xe5: false,
|
||||
0xe6: false,
|
||||
0xe7: false,
|
||||
0xe8: false,
|
||||
0xe9: false,
|
||||
0xea: false,
|
||||
0xeb: false,
|
||||
0xec: false,
|
||||
0xed: false,
|
||||
0xee: false,
|
||||
0xef: false,
|
||||
0xf0: false,
|
||||
0xf1: false,
|
||||
0xf2: false,
|
||||
0xf3: false,
|
||||
0xf4: false,
|
||||
0xf5: false,
|
||||
0xf6: false,
|
||||
0xf7: false,
|
||||
0xf8: false,
|
||||
0xf9: false,
|
||||
0xfa: false,
|
||||
0xfb: false,
|
||||
0xfc: false,
|
||||
0xfd: false,
|
||||
0xfe: false,
|
||||
0xff: false,
|
||||
}
|
||||
|
||||
// safeSet holds the value true if the ASCII character with the given array
|
||||
// position can be represented inside a JSON string without any further
|
||||
// escaping.
|
||||
//
|
||||
// All values are true except for the ASCII control characters (0-31), the
|
||||
// double quote ("), and the backslash character ("\").
|
||||
var safeSet = [utf8.RuneSelf]bool{
|
||||
' ': true,
|
||||
'!': true,
|
||||
'"': false,
|
||||
'#': true,
|
||||
'$': true,
|
||||
'%': true,
|
||||
'&': true,
|
||||
'\'': true,
|
||||
'(': true,
|
||||
')': true,
|
||||
'*': true,
|
||||
'+': true,
|
||||
',': true,
|
||||
'-': true,
|
||||
'.': true,
|
||||
'/': true,
|
||||
'0': true,
|
||||
'1': true,
|
||||
'2': true,
|
||||
'3': true,
|
||||
'4': true,
|
||||
'5': true,
|
||||
'6': true,
|
||||
'7': true,
|
||||
'8': true,
|
||||
'9': true,
|
||||
':': true,
|
||||
';': true,
|
||||
'<': true,
|
||||
'=': true,
|
||||
'>': true,
|
||||
'?': true,
|
||||
'@': true,
|
||||
'A': true,
|
||||
'B': true,
|
||||
'C': true,
|
||||
'D': true,
|
||||
'E': true,
|
||||
'F': true,
|
||||
'G': true,
|
||||
'H': true,
|
||||
'I': true,
|
||||
'J': true,
|
||||
'K': true,
|
||||
'L': true,
|
||||
'M': true,
|
||||
'N': true,
|
||||
'O': true,
|
||||
'P': true,
|
||||
'Q': true,
|
||||
'R': true,
|
||||
'S': true,
|
||||
'T': true,
|
||||
'U': true,
|
||||
'V': true,
|
||||
'W': true,
|
||||
'X': true,
|
||||
'Y': true,
|
||||
'Z': true,
|
||||
'[': true,
|
||||
'\\': false,
|
||||
']': true,
|
||||
'^': true,
|
||||
'_': true,
|
||||
'`': true,
|
||||
'a': true,
|
||||
'b': true,
|
||||
'c': true,
|
||||
'd': true,
|
||||
'e': true,
|
||||
'f': true,
|
||||
'g': true,
|
||||
'h': true,
|
||||
'i': true,
|
||||
'j': true,
|
||||
'k': true,
|
||||
'l': true,
|
||||
'm': true,
|
||||
'n': true,
|
||||
'o': true,
|
||||
'p': true,
|
||||
'q': true,
|
||||
'r': true,
|
||||
's': true,
|
||||
't': true,
|
||||
'u': true,
|
||||
'v': true,
|
||||
'w': true,
|
||||
'x': true,
|
||||
'y': true,
|
||||
'z': true,
|
||||
'{': true,
|
||||
'|': true,
|
||||
'}': true,
|
||||
'~': true,
|
||||
'\u007f': true,
|
||||
}
|
||||
|
||||
var hex = "0123456789abcdef"
|
||||
|
||||
// escapeIndex finds the index of the first char in `s` that requires escaping.
|
||||
|
@ -714,38 +375,6 @@ func escapeIndex(s string) int {
|
|||
return -1
|
||||
}
|
||||
|
||||
// escapeIndex finds the index of the first char in `s` that requires escaping.
|
||||
// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if
|
||||
// it includes a double quote or backslash.
|
||||
// Also, the chars <, > and & require escaping.
|
||||
// If no chars in `s` require escaping, the return value is -1.
|
||||
func escapeIndexWithHTMLEscape(s string) int {
|
||||
chunks := stringToUint64Slice(s)
|
||||
for _, n := range chunks {
|
||||
// combine masks before checking for the MSB of each byte. We include
|
||||
// `n` in the mask to check whether any of the *input* byte MSBs were
|
||||
// set (i.e. the byte was outside the ASCII range).
|
||||
mask := n | (n - (lsb * 0x20)) |
|
||||
((n ^ (lsb * '"')) - lsb) |
|
||||
((n ^ (lsb * '\\')) - lsb) |
|
||||
((n ^ (lsb * '<')) - lsb) |
|
||||
((n ^ (lsb * '>')) - lsb) |
|
||||
((n ^ (lsb * '&')) - lsb)
|
||||
if (mask & msb) != 0 {
|
||||
return bits.TrailingZeros64(mask&msb) / 8
|
||||
}
|
||||
}
|
||||
|
||||
valLen := len(s)
|
||||
for i := len(chunks) * 8; i < valLen; i++ {
|
||||
if needEscapeWithHTML[s[i]] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// below return a mask that can be used to determine if any of the bytes
|
||||
// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was
|
||||
// below `b`. The result is only valid if `b`, and each byte in `n`, is below
|
||||
|
|
|
@ -37,7 +37,6 @@ func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)
|
|||
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||
func ptrToByte(p uintptr) byte { return **(**byte)(unsafe.Pointer(&p)) }
|
||||
func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
||||
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
||||
func ptrToSlice(p uintptr) *sliceHeader { return *(**sliceHeader)(unsafe.Pointer(&p)) }
|
||||
|
@ -7637,7 +7636,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
ptr := load(ctxptr, code.headIdx)
|
||||
b = append(b, code.key...)
|
||||
b = append(b, '"')
|
||||
b = appendUint(b, uint64(ptrToUint64(ptr+code.offset)))
|
||||
b = appendUint(b, ptrToUint64(ptr+code.offset))
|
||||
b = append(b, '"')
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
|
|
|
@ -7588,7 +7588,7 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
|
|||
ptr := load(ctxptr, code.headIdx)
|
||||
b = append(b, code.escapedKey...)
|
||||
b = append(b, '"')
|
||||
b = appendUint(b, uint64(ptrToUint64(ptr+code.offset)))
|
||||
b = appendUint(b, ptrToUint64(ptr+code.offset))
|
||||
b = append(b, '"')
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
|
@ -7801,6 +7801,15 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
|
|||
ptr := load(ctxptr, code.headIdx)
|
||||
b = append(b, code.escapedKey...)
|
||||
p := ptr + code.offset
|
||||
if code.typ.Kind() == reflect.Ptr {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.next
|
||||
break
|
||||
}
|
||||
v := ptrToInterface(code, p)
|
||||
bb, err := v.(Marshaler).MarshalJSON()
|
||||
if err != nil {
|
||||
|
@ -7816,11 +7825,14 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
|
|||
case opStructFieldOmitEmptyMarshalJSON:
|
||||
ptr := load(ctxptr, code.headIdx)
|
||||
p := ptr + code.offset
|
||||
if code.typ.Kind() == reflect.Ptr && code.typ.Elem().Implements(marshalJSONType) {
|
||||
if code.typ.Kind() == reflect.Ptr {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
if p == 0 {
|
||||
code = code.next
|
||||
break
|
||||
}
|
||||
v := ptrToInterface(code, p)
|
||||
if v != nil && p != 0 {
|
||||
bb, err := v.(Marshaler).MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, errMarshaler(code, err)
|
||||
|
@ -7832,7 +7844,6 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
|
|||
}
|
||||
b = buf.Bytes()
|
||||
b = encodeComma(b)
|
||||
}
|
||||
code = code.next
|
||||
case opStructFieldStringTagMarshalJSON:
|
||||
ptr := load(ctxptr, code.headIdx)
|
||||
|
@ -9256,8 +9267,21 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
|
|||
case opStructEndOmitEmptyMarshalJSON:
|
||||
ptr := load(ctxptr, code.headIdx)
|
||||
p := ptr + code.offset
|
||||
if code.typ.Kind() == reflect.Ptr {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
if p == 0 {
|
||||
last := len(b) - 1
|
||||
if b[last] == ',' {
|
||||
b[last] = '}'
|
||||
b = encodeComma(b)
|
||||
} else {
|
||||
b = appendStructEnd(b)
|
||||
}
|
||||
code = code.next
|
||||
break
|
||||
}
|
||||
v := ptrToInterface(code, p)
|
||||
if v != nil && (code.typ.Kind() != reflect.Ptr || ptrToPtr(p) != 0) {
|
||||
bb, err := v.(Marshaler).MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, errMarshaler(code, err)
|
||||
|
@ -9269,15 +9293,6 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
|
|||
}
|
||||
b = buf.Bytes()
|
||||
b = appendStructEnd(b)
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
if b[last] == ',' {
|
||||
b[last] = '}'
|
||||
b = encodeComma(b)
|
||||
} else {
|
||||
b = appendStructEnd(b)
|
||||
}
|
||||
}
|
||||
code = code.next
|
||||
case opStructEndStringTagMarshalJSON:
|
||||
ptr := load(ctxptr, code.headIdx)
|
||||
|
|
|
@ -29,7 +29,7 @@ func encodeWithIndent(dst *bytes.Buffer, src []byte, prefix, indentStr string) e
|
|||
case '"':
|
||||
goto LOOP_END
|
||||
case nul:
|
||||
return errUnexpectedEndOfJSON("string", int64(length))
|
||||
return errUnexpectedEndOfJSON("string", length)
|
||||
}
|
||||
}
|
||||
case '{':
|
||||
|
|
|
@ -22,10 +22,7 @@ func isIgnoredStructField(field reflect.StructField) bool {
|
|||
}
|
||||
}
|
||||
tag := getTag(field)
|
||||
if tag == "-" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return tag == "-"
|
||||
}
|
||||
|
||||
type structTag struct {
|
||||
|
|
Loading…
Reference in New Issue