mirror of https://github.com/goccy/go-json.git
Remove unnecessary files
This commit is contained in:
parent
9cbe7b3991
commit
4db967f28d
19
codec.go
19
codec.go
|
@ -12,8 +12,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cachedOpcodeSets []*opcodeSet
|
|
||||||
cachedOpcodeMap unsafe.Pointer // map[uintptr]*opcodeSet
|
|
||||||
cachedDecoder []decoder
|
cachedDecoder []decoder
|
||||||
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
||||||
baseTypeAddr uintptr
|
baseTypeAddr uintptr
|
||||||
|
@ -66,7 +64,6 @@ func setupCodec() error {
|
||||||
if addrRange > maxAcceptableTypeAddrRange {
|
if addrRange > maxAcceptableTypeAddrRange {
|
||||||
return fmt.Errorf("too big address range %d", addrRange)
|
return fmt.Errorf("too big address range %d", addrRange)
|
||||||
}
|
}
|
||||||
cachedOpcodeSets = make([]*opcodeSet, addrRange)
|
|
||||||
cachedDecoder = make([]decoder, addrRange)
|
cachedDecoder = make([]decoder, addrRange)
|
||||||
baseTypeAddr = min
|
baseTypeAddr = min
|
||||||
maxTypeAddr = max
|
maxTypeAddr = max
|
||||||
|
@ -77,22 +74,6 @@ func init() {
|
||||||
_ = setupCodec()
|
_ = setupCodec()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadOpcodeMap() map[uintptr]*opcodeSet {
|
|
||||||
p := atomic.LoadPointer(&cachedOpcodeMap)
|
|
||||||
return *(*map[uintptr]*opcodeSet)(unsafe.Pointer(&p))
|
|
||||||
}
|
|
||||||
|
|
||||||
func storeOpcodeSet(typ uintptr, set *opcodeSet, m map[uintptr]*opcodeSet) {
|
|
||||||
newOpcodeMap := make(map[uintptr]*opcodeSet, len(m)+1)
|
|
||||||
newOpcodeMap[typ] = set
|
|
||||||
|
|
||||||
for k, v := range m {
|
|
||||||
newOpcodeMap[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.StorePointer(&cachedOpcodeMap, *(*unsafe.Pointer)(unsafe.Pointer(&newOpcodeMap)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadDecoderMap() map[uintptr]decoder {
|
func loadDecoderMap() map[uintptr]decoder {
|
||||||
p := atomic.LoadPointer(&cachedDecoderMap)
|
p := atomic.LoadPointer(&cachedDecoderMap)
|
||||||
return *(*map[uintptr]decoder)(unsafe.Pointer(&p))
|
return *(*map[uintptr]decoder)(unsafe.Pointer(&p))
|
||||||
|
|
54
compact.go
54
compact.go
|
@ -1,54 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
func compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
|
||||||
if len(src) == 0 {
|
|
||||||
return errUnexpectedEndOfJSON("", 0)
|
|
||||||
}
|
|
||||||
length := len(src)
|
|
||||||
for cursor := 0; cursor < length; cursor++ {
|
|
||||||
c := src[cursor]
|
|
||||||
switch c {
|
|
||||||
case ' ', '\t', '\n', '\r':
|
|
||||||
continue
|
|
||||||
case '"':
|
|
||||||
if err := dst.WriteByte(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
cursor++
|
|
||||||
c := src[cursor]
|
|
||||||
if escape && (c == '<' || c == '>' || c == '&') {
|
|
||||||
if _, err := dst.WriteString(`\u00`); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := dst.Write([]byte{hex[c>>4], hex[c&0xF]}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if err := dst.WriteByte(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch c {
|
|
||||||
case '\\':
|
|
||||||
cursor++
|
|
||||||
if err := dst.WriteByte(src[cursor]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case '"':
|
|
||||||
goto LOOP_END
|
|
||||||
case nul:
|
|
||||||
return errUnexpectedEndOfJSON("string", int64(length))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if err := dst.WriteByte(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOOP_END:
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
package json
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -8,6 +9,10 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||||
|
)
|
||||||
|
|
||||||
func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, error) {
|
func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, error) {
|
||||||
decoderMap := loadDecoderMap()
|
decoderMap := loadDecoderMap()
|
||||||
if dec, exists := decoderMap[typeptr]; exists {
|
if dec, exists := decoderMap[typeptr]; exists {
|
||||||
|
|
1424
encode_compile.go
1424
encode_compile.go
File diff suppressed because it is too large
Load Diff
|
@ -1,34 +0,0 @@
|
||||||
// +build !race
|
|
||||||
|
|
||||||
package json
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
|
||||||
if typeptr > maxTypeAddr {
|
|
||||||
return encodeCompileToGetCodeSetSlowPath(typeptr)
|
|
||||||
}
|
|
||||||
index := typeptr - baseTypeAddr
|
|
||||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
|
||||||
return codeSet, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// noescape trick for header.typ ( reflect.*rtype )
|
|
||||||
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
|
|
||||||
|
|
||||||
code, err := encodeCompileHead(&encodeCompileContext{
|
|
||||||
typ: copiedType,
|
|
||||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
code = copyOpcode(code)
|
|
||||||
codeLength := code.totalLength()
|
|
||||||
codeSet := &opcodeSet{
|
|
||||||
code: code,
|
|
||||||
codeLength: codeLength,
|
|
||||||
}
|
|
||||||
cachedOpcodeSets[index] = codeSet
|
|
||||||
return codeSet, nil
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// +build race
|
|
||||||
|
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var setsMu sync.RWMutex
|
|
||||||
|
|
||||||
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
|
||||||
if typeptr > maxTypeAddr {
|
|
||||||
return encodeCompileToGetCodeSetSlowPath(typeptr)
|
|
||||||
}
|
|
||||||
index := typeptr - baseTypeAddr
|
|
||||||
setsMu.RLock()
|
|
||||||
if codeSet := cachedOpcodeSets[index]; 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,
|
|
||||||
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[index] = codeSet
|
|
||||||
setsMu.Unlock()
|
|
||||||
return codeSet, nil
|
|
||||||
}
|
|
|
@ -1,164 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"sync"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mapItem struct {
|
|
||||||
key []byte
|
|
||||||
value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type mapslice struct {
|
|
||||||
items []mapItem
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mapslice) Len() int {
|
|
||||||
return len(m.items)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mapslice) Less(i, j int) bool {
|
|
||||||
return bytes.Compare(m.items[i].key, m.items[j].key) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mapslice) Swap(i, j int) {
|
|
||||||
m.items[i], m.items[j] = m.items[j], m.items[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
type encodeMapContext struct {
|
|
||||||
pos []int
|
|
||||||
slice *mapslice
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var mapContextPool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return &encodeMapContext{}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMapContext(mapLen int) *encodeMapContext {
|
|
||||||
ctx := mapContextPool.Get().(*encodeMapContext)
|
|
||||||
if ctx.slice == nil {
|
|
||||||
ctx.slice = &mapslice{
|
|
||||||
items: make([]mapItem, 0, mapLen),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cap(ctx.pos) < (mapLen*2 + 1) {
|
|
||||||
ctx.pos = make([]int, 0, mapLen*2+1)
|
|
||||||
ctx.slice.items = make([]mapItem, 0, mapLen)
|
|
||||||
} else {
|
|
||||||
ctx.pos = ctx.pos[:0]
|
|
||||||
ctx.slice.items = ctx.slice.items[:0]
|
|
||||||
}
|
|
||||||
ctx.buf = ctx.buf[:0]
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func releaseMapContext(c *encodeMapContext) {
|
|
||||||
mapContextPool.Put(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
type encodeCompileContext struct {
|
|
||||||
typ *rtype
|
|
||||||
opcodeIndex int
|
|
||||||
ptrIndex int
|
|
||||||
indent int
|
|
||||||
structTypeToCompiledCode map[uintptr]*compiledCode
|
|
||||||
|
|
||||||
parent *encodeCompileContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) context() *encodeCompileContext {
|
|
||||||
return &encodeCompileContext{
|
|
||||||
typ: c.typ,
|
|
||||||
opcodeIndex: c.opcodeIndex,
|
|
||||||
ptrIndex: c.ptrIndex,
|
|
||||||
indent: c.indent,
|
|
||||||
structTypeToCompiledCode: c.structTypeToCompiledCode,
|
|
||||||
parent: c,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) withType(typ *rtype) *encodeCompileContext {
|
|
||||||
ctx := c.context()
|
|
||||||
ctx.typ = typ
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) incIndent() *encodeCompileContext {
|
|
||||||
ctx := c.context()
|
|
||||||
ctx.indent++
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) decIndent() *encodeCompileContext {
|
|
||||||
ctx := c.context()
|
|
||||||
ctx.indent--
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) incIndex() {
|
|
||||||
c.incOpcodeIndex()
|
|
||||||
c.incPtrIndex()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) decIndex() {
|
|
||||||
c.decOpcodeIndex()
|
|
||||||
c.decPtrIndex()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) incOpcodeIndex() {
|
|
||||||
c.opcodeIndex++
|
|
||||||
if c.parent != nil {
|
|
||||||
c.parent.incOpcodeIndex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) decOpcodeIndex() {
|
|
||||||
c.opcodeIndex--
|
|
||||||
if c.parent != nil {
|
|
||||||
c.parent.decOpcodeIndex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) incPtrIndex() {
|
|
||||||
c.ptrIndex++
|
|
||||||
if c.parent != nil {
|
|
||||||
c.parent.incPtrIndex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeCompileContext) decPtrIndex() {
|
|
||||||
c.ptrIndex--
|
|
||||||
if c.parent != nil {
|
|
||||||
c.parent.decPtrIndex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type encodeRuntimeContext struct {
|
|
||||||
buf []byte
|
|
||||||
ptrs []uintptr
|
|
||||||
keepRefs []unsafe.Pointer
|
|
||||||
seenPtr []uintptr
|
|
||||||
baseIndent int
|
|
||||||
prefix []byte
|
|
||||||
indentStr []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeRuntimeContext) init(p uintptr, codelen int) {
|
|
||||||
if len(c.ptrs) < codelen {
|
|
||||||
c.ptrs = make([]uintptr, codelen)
|
|
||||||
}
|
|
||||||
c.ptrs[0] = p
|
|
||||||
c.keepRefs = c.keepRefs[:0]
|
|
||||||
c.seenPtr = c.seenPtr[:0]
|
|
||||||
c.baseIndent = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *encodeRuntimeContext) ptr() uintptr {
|
|
||||||
header := (*sliceHeader)(unsafe.Pointer(&c.ptrs))
|
|
||||||
return uintptr(header.data)
|
|
||||||
}
|
|
124
encode_int.go
124
encode_int.go
|
@ -1,124 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var endianness int
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var b [2]byte
|
|
||||||
*(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD)
|
|
||||||
|
|
||||||
switch b[0] {
|
|
||||||
case 0xCD:
|
|
||||||
endianness = 0 // LE
|
|
||||||
case 0xAB:
|
|
||||||
endianness = 1 // BE
|
|
||||||
default:
|
|
||||||
panic("could not determine endianness")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// "00010203...96979899" cast to []uint16
|
|
||||||
var intLELookup = [100]uint16{
|
|
||||||
0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
|
|
||||||
0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
|
|
||||||
0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
|
|
||||||
0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933,
|
|
||||||
0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934,
|
|
||||||
0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935,
|
|
||||||
0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936,
|
|
||||||
0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
|
|
||||||
0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
|
|
||||||
0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939,
|
|
||||||
}
|
|
||||||
|
|
||||||
var intBELookup = [100]uint16{
|
|
||||||
0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039,
|
|
||||||
0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139,
|
|
||||||
0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239,
|
|
||||||
0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339,
|
|
||||||
0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439,
|
|
||||||
0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539,
|
|
||||||
0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639,
|
|
||||||
0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739,
|
|
||||||
0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839,
|
|
||||||
0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939,
|
|
||||||
}
|
|
||||||
|
|
||||||
var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup}
|
|
||||||
|
|
||||||
func appendInt(out []byte, u64 uint64, code *opcode) []byte {
|
|
||||||
n := u64 & code.mask
|
|
||||||
negative := (u64>>code.rshiftNum)&1 == 1
|
|
||||||
if !negative {
|
|
||||||
if n < 10 {
|
|
||||||
return append(out, byte(n+'0'))
|
|
||||||
} else if n < 100 {
|
|
||||||
u := intLELookup[n]
|
|
||||||
return append(out, byte(u), byte(u>>8))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
n = -n & code.mask
|
|
||||||
}
|
|
||||||
|
|
||||||
lookup := intLookup[endianness]
|
|
||||||
|
|
||||||
var b [22]byte
|
|
||||||
u := (*[11]uint16)(unsafe.Pointer(&b))
|
|
||||||
i := 11
|
|
||||||
|
|
||||||
for n >= 100 {
|
|
||||||
j := n % 100
|
|
||||||
n /= 100
|
|
||||||
i--
|
|
||||||
u[i] = lookup[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
i--
|
|
||||||
u[i] = lookup[n]
|
|
||||||
|
|
||||||
i *= 2 // convert to byte index
|
|
||||||
if n < 10 {
|
|
||||||
i++ // remove leading zero
|
|
||||||
}
|
|
||||||
if negative {
|
|
||||||
i--
|
|
||||||
b[i] = '-'
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(out, b[i:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendUint(out []byte, u64 uint64, code *opcode) []byte {
|
|
||||||
n := u64 & code.mask
|
|
||||||
if n < 10 {
|
|
||||||
return append(out, byte(n+'0'))
|
|
||||||
} else if n < 100 {
|
|
||||||
u := intLELookup[n]
|
|
||||||
return append(out, byte(u), byte(u>>8))
|
|
||||||
}
|
|
||||||
|
|
||||||
lookup := intLookup[endianness]
|
|
||||||
|
|
||||||
var b [22]byte
|
|
||||||
u := (*[11]uint16)(unsafe.Pointer(&b))
|
|
||||||
i := 11
|
|
||||||
|
|
||||||
for n >= 100 {
|
|
||||||
j := n % 100
|
|
||||||
n /= 100
|
|
||||||
i--
|
|
||||||
u[i] = lookup[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
i--
|
|
||||||
u[i] = lookup[n]
|
|
||||||
|
|
||||||
i *= 2 // convert to byte index
|
|
||||||
if n < 10 {
|
|
||||||
i++ // remove leading zero
|
|
||||||
}
|
|
||||||
return append(out, b[i:]...)
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
// +build !go1.13
|
|
||||||
|
|
||||||
package json
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
//go:linkname mapitervalue reflect.mapitervalue
|
|
||||||
func mapitervalue(it unsafe.Pointer) unsafe.Pointer
|
|
|
@ -1,8 +0,0 @@
|
||||||
// +build go1.13
|
|
||||||
|
|
||||||
package json
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
//go:linkname mapitervalue reflect.mapiterelem
|
|
||||||
func mapitervalue(it unsafe.Pointer) unsafe.Pointer
|
|
512
encode_opcode.go
512
encode_opcode.go
|
@ -1,512 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const uintptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
|
|
||||||
|
|
||||||
type opcode struct {
|
|
||||||
op opType // operation type
|
|
||||||
typ *rtype // go type
|
|
||||||
displayIdx int // opcode index
|
|
||||||
key []byte // struct field key
|
|
||||||
escapedKey []byte // struct field key ( HTML escaped )
|
|
||||||
ptrNum int // pointer number: e.g. double pointer is 2.
|
|
||||||
displayKey string // key text to display
|
|
||||||
isTaggedKey bool // whether tagged key
|
|
||||||
anonymousKey bool // whether anonymous key
|
|
||||||
anonymousHead bool // whether anonymous head or not
|
|
||||||
indirect bool // whether indirect or not
|
|
||||||
nilcheck bool // whether needs to nilcheck or not
|
|
||||||
addrForMarshaler bool // whether needs to addr for marshaler or not
|
|
||||||
rshiftNum uint8 // use to take bit for judging whether negative integer or not
|
|
||||||
mask uint64 // mask for number
|
|
||||||
indent int // indent number
|
|
||||||
|
|
||||||
idx uintptr // offset to access ptr
|
|
||||||
headIdx uintptr // offset to access slice/struct head
|
|
||||||
elemIdx uintptr // offset to access array/slice/map elem
|
|
||||||
length uintptr // offset to access slice/map length or array length
|
|
||||||
mapIter uintptr // offset to access map iterator
|
|
||||||
mapPos uintptr // offset to access position list for sorted map
|
|
||||||
offset uintptr // offset size from struct header
|
|
||||||
size uintptr // array/slice elem size
|
|
||||||
|
|
||||||
mapKey *opcode // map key
|
|
||||||
mapValue *opcode // map value
|
|
||||||
elem *opcode // array/slice elem
|
|
||||||
end *opcode // array/slice/struct/map end
|
|
||||||
prevField *opcode // prev struct field
|
|
||||||
nextField *opcode // next struct field
|
|
||||||
next *opcode // next opcode
|
|
||||||
jmp *compiledCode // for recursive call
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOpCode(ctx *encodeCompileContext, op opType) *opcode {
|
|
||||||
return newOpCodeWithNext(ctx, op, newEndOp(ctx))
|
|
||||||
}
|
|
||||||
|
|
||||||
func opcodeOffset(idx int) uintptr {
|
|
||||||
return uintptr(idx) * uintptrSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyOpcode(code *opcode) *opcode {
|
|
||||||
codeMap := map[uintptr]*opcode{}
|
|
||||||
return code.copy(codeMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
|
|
||||||
return &opcode{
|
|
||||||
op: op,
|
|
||||||
typ: ctx.typ,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
indent: ctx.indent,
|
|
||||||
idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
next: next,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEndOp(ctx *encodeCompileContext) *opcode {
|
|
||||||
return newOpCodeWithNext(ctx, opEnd, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
||||||
if c == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
addr := uintptr(unsafe.Pointer(c))
|
|
||||||
if code, exists := codeMap[addr]; exists {
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
copied := &opcode{
|
|
||||||
op: c.op,
|
|
||||||
typ: c.typ,
|
|
||||||
displayIdx: c.displayIdx,
|
|
||||||
key: c.key,
|
|
||||||
escapedKey: c.escapedKey,
|
|
||||||
displayKey: c.displayKey,
|
|
||||||
ptrNum: c.ptrNum,
|
|
||||||
mask: c.mask,
|
|
||||||
rshiftNum: c.rshiftNum,
|
|
||||||
isTaggedKey: c.isTaggedKey,
|
|
||||||
anonymousKey: c.anonymousKey,
|
|
||||||
anonymousHead: c.anonymousHead,
|
|
||||||
indirect: c.indirect,
|
|
||||||
nilcheck: c.nilcheck,
|
|
||||||
addrForMarshaler: c.addrForMarshaler,
|
|
||||||
indent: c.indent,
|
|
||||||
idx: c.idx,
|
|
||||||
headIdx: c.headIdx,
|
|
||||||
elemIdx: c.elemIdx,
|
|
||||||
length: c.length,
|
|
||||||
mapIter: c.mapIter,
|
|
||||||
mapPos: c.mapPos,
|
|
||||||
offset: c.offset,
|
|
||||||
size: c.size,
|
|
||||||
}
|
|
||||||
codeMap[addr] = copied
|
|
||||||
copied.mapKey = c.mapKey.copy(codeMap)
|
|
||||||
copied.mapValue = c.mapValue.copy(codeMap)
|
|
||||||
copied.elem = c.elem.copy(codeMap)
|
|
||||||
copied.end = c.end.copy(codeMap)
|
|
||||||
copied.prevField = c.prevField.copy(codeMap)
|
|
||||||
copied.nextField = c.nextField.copy(codeMap)
|
|
||||||
copied.next = c.next.copy(codeMap)
|
|
||||||
copied.jmp = c.jmp
|
|
||||||
return copied
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) beforeLastCode() *opcode {
|
|
||||||
code := c
|
|
||||||
for {
|
|
||||||
var nextCode *opcode
|
|
||||||
switch code.op.codeType() {
|
|
||||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
||||||
nextCode = code.end
|
|
||||||
default:
|
|
||||||
nextCode = code.next
|
|
||||||
}
|
|
||||||
if nextCode.op == opEnd {
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
code = nextCode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) totalLength() int {
|
|
||||||
var idx int
|
|
||||||
for code := c; code.op != opEnd; {
|
|
||||||
idx = int(code.idx / uintptrSize)
|
|
||||||
if code.op == opStructFieldRecursiveEnd {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
switch code.op.codeType() {
|
|
||||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
||||||
code = code.end
|
|
||||||
default:
|
|
||||||
code = code.next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return idx + 2 // opEnd + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) decOpcodeIndex() {
|
|
||||||
for code := c; code.op != opEnd; {
|
|
||||||
code.displayIdx--
|
|
||||||
code.idx -= uintptrSize
|
|
||||||
if code.headIdx > 0 {
|
|
||||||
code.headIdx -= uintptrSize
|
|
||||||
}
|
|
||||||
if code.elemIdx > 0 {
|
|
||||||
code.elemIdx -= uintptrSize
|
|
||||||
}
|
|
||||||
if code.mapIter > 0 {
|
|
||||||
code.mapIter -= uintptrSize
|
|
||||||
}
|
|
||||||
if code.length > 0 && code.op.codeType() != codeArrayHead && code.op.codeType() != codeArrayElem {
|
|
||||||
code.length -= uintptrSize
|
|
||||||
}
|
|
||||||
switch code.op.codeType() {
|
|
||||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
||||||
code = code.end
|
|
||||||
default:
|
|
||||||
code = code.next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) decIndent() {
|
|
||||||
for code := c; code.op != opEnd; {
|
|
||||||
code.indent--
|
|
||||||
switch code.op.codeType() {
|
|
||||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
||||||
code = code.end
|
|
||||||
default:
|
|
||||||
code = code.next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dumpHead(code *opcode) string {
|
|
||||||
var length uintptr
|
|
||||||
if code.op.codeType() == codeArrayHead {
|
|
||||||
length = code.length
|
|
||||||
} else {
|
|
||||||
length = code.length / uintptrSize
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d])`,
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
code.headIdx/uintptrSize,
|
|
||||||
code.elemIdx/uintptrSize,
|
|
||||||
length,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dumpMapHead(code *opcode) string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
code.headIdx/uintptrSize,
|
|
||||||
code.elemIdx/uintptrSize,
|
|
||||||
code.length/uintptrSize,
|
|
||||||
code.mapIter/uintptrSize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dumpMapEnd(code *opcode) string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`,
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
code.mapPos/uintptrSize,
|
|
||||||
code.length/uintptrSize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dumpElem(code *opcode) string {
|
|
||||||
var length uintptr
|
|
||||||
if code.op.codeType() == codeArrayElem {
|
|
||||||
length = code.length
|
|
||||||
} else {
|
|
||||||
length = code.length / uintptrSize
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][size:%d])`,
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
code.headIdx/uintptrSize,
|
|
||||||
code.elemIdx/uintptrSize,
|
|
||||||
length,
|
|
||||||
code.size,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dumpField(code *opcode) string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`[%d]%s%s ([idx:%d][key:%s][offset:%d][headIdx:%d])`,
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
code.displayKey,
|
|
||||||
code.offset,
|
|
||||||
code.headIdx/uintptrSize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dumpKey(code *opcode) string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
code.elemIdx/uintptrSize,
|
|
||||||
code.length/uintptrSize,
|
|
||||||
code.mapIter/uintptrSize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dumpValue(code *opcode) string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`[%d]%s%s ([idx:%d][mapIter:%d])`,
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
code.mapIter/uintptrSize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *opcode) dump() string {
|
|
||||||
codes := []string{}
|
|
||||||
for code := c; code.op != opEnd; {
|
|
||||||
switch code.op.codeType() {
|
|
||||||
case codeSliceHead:
|
|
||||||
codes = append(codes, c.dumpHead(code))
|
|
||||||
code = code.next
|
|
||||||
case codeMapHead:
|
|
||||||
codes = append(codes, c.dumpMapHead(code))
|
|
||||||
code = code.next
|
|
||||||
case codeArrayElem, codeSliceElem:
|
|
||||||
codes = append(codes, c.dumpElem(code))
|
|
||||||
code = code.end
|
|
||||||
case codeMapKey:
|
|
||||||
codes = append(codes, c.dumpKey(code))
|
|
||||||
code = code.end
|
|
||||||
case codeMapValue:
|
|
||||||
codes = append(codes, c.dumpValue(code))
|
|
||||||
code = code.next
|
|
||||||
case codeMapEnd:
|
|
||||||
codes = append(codes, c.dumpMapEnd(code))
|
|
||||||
code = code.next
|
|
||||||
case codeStructField:
|
|
||||||
codes = append(codes, c.dumpField(code))
|
|
||||||
code = code.next
|
|
||||||
case codeStructEnd:
|
|
||||||
codes = append(codes, c.dumpField(code))
|
|
||||||
code = code.next
|
|
||||||
default:
|
|
||||||
codes = append(codes, fmt.Sprintf(
|
|
||||||
"[%d]%s%s ([idx:%d])",
|
|
||||||
code.displayIdx,
|
|
||||||
strings.Repeat("-", code.indent),
|
|
||||||
code.op,
|
|
||||||
code.idx/uintptrSize,
|
|
||||||
))
|
|
||||||
code = code.next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(codes, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func prevField(code *opcode, removedFields map[*opcode]struct{}) *opcode {
|
|
||||||
if _, exists := removedFields[code]; exists {
|
|
||||||
return prevField(code.prevField, removedFields)
|
|
||||||
}
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
|
|
||||||
func nextField(code *opcode, removedFields map[*opcode]struct{}) *opcode {
|
|
||||||
if _, exists := removedFields[code]; exists {
|
|
||||||
return nextField(code.nextField, removedFields)
|
|
||||||
}
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeLinkPrevToNextField(cur *opcode, removedFields map[*opcode]struct{}) {
|
|
||||||
prev := prevField(cur.prevField, removedFields)
|
|
||||||
prev.nextField = nextField(cur.nextField, removedFields)
|
|
||||||
code := prev
|
|
||||||
fcode := cur
|
|
||||||
for {
|
|
||||||
var nextCode *opcode
|
|
||||||
switch code.op.codeType() {
|
|
||||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
||||||
nextCode = code.end
|
|
||||||
default:
|
|
||||||
nextCode = code.next
|
|
||||||
}
|
|
||||||
if nextCode == fcode {
|
|
||||||
code.next = fcode.next
|
|
||||||
break
|
|
||||||
} else if nextCode.op == opEnd {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
code = nextCode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSliceHeaderCode(ctx *encodeCompileContext) *opcode {
|
|
||||||
idx := opcodeOffset(ctx.ptrIndex)
|
|
||||||
ctx.incPtrIndex()
|
|
||||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
||||||
ctx.incPtrIndex()
|
|
||||||
length := opcodeOffset(ctx.ptrIndex)
|
|
||||||
return &opcode{
|
|
||||||
op: opSlice,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: idx,
|
|
||||||
headIdx: idx,
|
|
||||||
elemIdx: elemIdx,
|
|
||||||
length: length,
|
|
||||||
indent: ctx.indent,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSliceElemCode(ctx *encodeCompileContext, head *opcode, size uintptr) *opcode {
|
|
||||||
return &opcode{
|
|
||||||
op: opSliceElem,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
headIdx: head.idx,
|
|
||||||
elemIdx: head.elemIdx,
|
|
||||||
length: head.length,
|
|
||||||
indent: ctx.indent,
|
|
||||||
size: size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *opcode {
|
|
||||||
idx := opcodeOffset(ctx.ptrIndex)
|
|
||||||
ctx.incPtrIndex()
|
|
||||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
||||||
return &opcode{
|
|
||||||
op: opArray,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: idx,
|
|
||||||
headIdx: idx,
|
|
||||||
elemIdx: elemIdx,
|
|
||||||
indent: ctx.indent,
|
|
||||||
length: uintptr(alen),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newArrayElemCode(ctx *encodeCompileContext, head *opcode, length int, size uintptr) *opcode {
|
|
||||||
return &opcode{
|
|
||||||
op: opArrayElem,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
elemIdx: head.elemIdx,
|
|
||||||
headIdx: head.headIdx,
|
|
||||||
length: uintptr(length),
|
|
||||||
indent: ctx.indent,
|
|
||||||
size: size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMapHeaderCode(ctx *encodeCompileContext) *opcode {
|
|
||||||
idx := opcodeOffset(ctx.ptrIndex)
|
|
||||||
ctx.incPtrIndex()
|
|
||||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
||||||
ctx.incPtrIndex()
|
|
||||||
length := opcodeOffset(ctx.ptrIndex)
|
|
||||||
ctx.incPtrIndex()
|
|
||||||
mapIter := opcodeOffset(ctx.ptrIndex)
|
|
||||||
return &opcode{
|
|
||||||
op: opMap,
|
|
||||||
typ: ctx.typ,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: idx,
|
|
||||||
elemIdx: elemIdx,
|
|
||||||
length: length,
|
|
||||||
mapIter: mapIter,
|
|
||||||
indent: ctx.indent,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMapKeyCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
|
||||||
return &opcode{
|
|
||||||
op: opMapKey,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
elemIdx: head.elemIdx,
|
|
||||||
length: head.length,
|
|
||||||
mapIter: head.mapIter,
|
|
||||||
indent: ctx.indent,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMapValueCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
|
||||||
return &opcode{
|
|
||||||
op: opMapValue,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
elemIdx: head.elemIdx,
|
|
||||||
length: head.length,
|
|
||||||
mapIter: head.mapIter,
|
|
||||||
indent: ctx.indent,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMapEndCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
|
||||||
mapPos := opcodeOffset(ctx.ptrIndex)
|
|
||||||
ctx.incPtrIndex()
|
|
||||||
idx := opcodeOffset(ctx.ptrIndex)
|
|
||||||
return &opcode{
|
|
||||||
op: opMapEnd,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: idx,
|
|
||||||
length: head.length,
|
|
||||||
mapPos: mapPos,
|
|
||||||
indent: ctx.indent,
|
|
||||||
next: newEndOp(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newInterfaceCode(ctx *encodeCompileContext) *opcode {
|
|
||||||
return &opcode{
|
|
||||||
op: opInterface,
|
|
||||||
typ: ctx.typ,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
indent: ctx.indent,
|
|
||||||
next: newEndOp(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRecursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode {
|
|
||||||
return &opcode{
|
|
||||||
op: opStructFieldRecursive,
|
|
||||||
typ: ctx.typ,
|
|
||||||
displayIdx: ctx.opcodeIndex,
|
|
||||||
idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
indent: ctx.indent,
|
|
||||||
next: newEndOp(ctx),
|
|
||||||
jmp: jmp,
|
|
||||||
}
|
|
||||||
}
|
|
1186
encode_optype.go
1186
encode_optype.go
File diff suppressed because it is too large
Load Diff
637
encode_string.go
637
encode_string.go
|
@ -1,637 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/bits"
|
|
||||||
"reflect"
|
|
||||||
"unicode/utf8"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
lsb = 0x0101010101010101
|
|
||||||
msb = 0x8080808080808080
|
|
||||||
)
|
|
||||||
|
|
||||||
var needEscapeWithHTML = [256]bool{
|
|
||||||
'"': true,
|
|
||||||
'&': true,
|
|
||||||
'<': true,
|
|
||||||
'>': true,
|
|
||||||
'\\': true,
|
|
||||||
0x00: true,
|
|
||||||
0x01: true,
|
|
||||||
0x02: true,
|
|
||||||
0x03: true,
|
|
||||||
0x04: true,
|
|
||||||
0x05: true,
|
|
||||||
0x06: true,
|
|
||||||
0x07: true,
|
|
||||||
0x08: true,
|
|
||||||
0x09: true,
|
|
||||||
0x0a: true,
|
|
||||||
0x0b: true,
|
|
||||||
0x0c: true,
|
|
||||||
0x0d: true,
|
|
||||||
0x0e: true,
|
|
||||||
0x0f: true,
|
|
||||||
0x10: true,
|
|
||||||
0x11: true,
|
|
||||||
0x12: true,
|
|
||||||
0x13: true,
|
|
||||||
0x14: true,
|
|
||||||
0x15: true,
|
|
||||||
0x16: true,
|
|
||||||
0x17: true,
|
|
||||||
0x18: true,
|
|
||||||
0x19: true,
|
|
||||||
0x1a: true,
|
|
||||||
0x1b: true,
|
|
||||||
0x1c: true,
|
|
||||||
0x1d: true,
|
|
||||||
0x1e: true,
|
|
||||||
0x1f: true,
|
|
||||||
/* 0x20 - 0x7f */
|
|
||||||
0x80: true,
|
|
||||||
0x81: true,
|
|
||||||
0x82: true,
|
|
||||||
0x83: true,
|
|
||||||
0x84: true,
|
|
||||||
0x85: true,
|
|
||||||
0x86: true,
|
|
||||||
0x87: true,
|
|
||||||
0x88: true,
|
|
||||||
0x89: true,
|
|
||||||
0x8a: true,
|
|
||||||
0x8b: true,
|
|
||||||
0x8c: true,
|
|
||||||
0x8d: true,
|
|
||||||
0x8e: true,
|
|
||||||
0x8f: true,
|
|
||||||
0x90: true,
|
|
||||||
0x91: true,
|
|
||||||
0x92: true,
|
|
||||||
0x93: true,
|
|
||||||
0x94: true,
|
|
||||||
0x95: true,
|
|
||||||
0x96: true,
|
|
||||||
0x97: true,
|
|
||||||
0x98: true,
|
|
||||||
0x99: true,
|
|
||||||
0x9a: true,
|
|
||||||
0x9b: true,
|
|
||||||
0x9c: true,
|
|
||||||
0x9d: true,
|
|
||||||
0x9e: true,
|
|
||||||
0x9f: true,
|
|
||||||
0xa0: true,
|
|
||||||
0xa1: true,
|
|
||||||
0xa2: true,
|
|
||||||
0xa3: true,
|
|
||||||
0xa4: true,
|
|
||||||
0xa5: true,
|
|
||||||
0xa6: true,
|
|
||||||
0xa7: true,
|
|
||||||
0xa8: true,
|
|
||||||
0xa9: true,
|
|
||||||
0xaa: true,
|
|
||||||
0xab: true,
|
|
||||||
0xac: true,
|
|
||||||
0xad: true,
|
|
||||||
0xae: true,
|
|
||||||
0xaf: true,
|
|
||||||
0xb0: true,
|
|
||||||
0xb1: true,
|
|
||||||
0xb2: true,
|
|
||||||
0xb3: true,
|
|
||||||
0xb4: true,
|
|
||||||
0xb5: true,
|
|
||||||
0xb6: true,
|
|
||||||
0xb7: true,
|
|
||||||
0xb8: true,
|
|
||||||
0xb9: true,
|
|
||||||
0xba: true,
|
|
||||||
0xbb: true,
|
|
||||||
0xbc: true,
|
|
||||||
0xbd: true,
|
|
||||||
0xbe: true,
|
|
||||||
0xbf: true,
|
|
||||||
0xc0: true,
|
|
||||||
0xc1: true,
|
|
||||||
0xc2: true,
|
|
||||||
0xc3: true,
|
|
||||||
0xc4: true,
|
|
||||||
0xc5: true,
|
|
||||||
0xc6: true,
|
|
||||||
0xc7: true,
|
|
||||||
0xc8: true,
|
|
||||||
0xc9: true,
|
|
||||||
0xca: true,
|
|
||||||
0xcb: true,
|
|
||||||
0xcc: true,
|
|
||||||
0xcd: true,
|
|
||||||
0xce: true,
|
|
||||||
0xcf: true,
|
|
||||||
0xd0: true,
|
|
||||||
0xd1: true,
|
|
||||||
0xd2: true,
|
|
||||||
0xd3: true,
|
|
||||||
0xd4: true,
|
|
||||||
0xd5: true,
|
|
||||||
0xd6: true,
|
|
||||||
0xd7: true,
|
|
||||||
0xd8: true,
|
|
||||||
0xd9: true,
|
|
||||||
0xda: true,
|
|
||||||
0xdb: true,
|
|
||||||
0xdc: true,
|
|
||||||
0xdd: true,
|
|
||||||
0xde: true,
|
|
||||||
0xdf: true,
|
|
||||||
0xe0: true,
|
|
||||||
0xe1: true,
|
|
||||||
0xe2: true,
|
|
||||||
0xe3: true,
|
|
||||||
0xe4: true,
|
|
||||||
0xe5: true,
|
|
||||||
0xe6: true,
|
|
||||||
0xe7: true,
|
|
||||||
0xe8: true,
|
|
||||||
0xe9: true,
|
|
||||||
0xea: true,
|
|
||||||
0xeb: true,
|
|
||||||
0xec: true,
|
|
||||||
0xed: true,
|
|
||||||
0xee: true,
|
|
||||||
0xef: true,
|
|
||||||
0xf0: true,
|
|
||||||
0xf1: true,
|
|
||||||
0xf2: true,
|
|
||||||
0xf3: true,
|
|
||||||
0xf4: true,
|
|
||||||
0xf5: true,
|
|
||||||
0xf6: true,
|
|
||||||
0xf7: true,
|
|
||||||
0xf8: true,
|
|
||||||
0xf9: true,
|
|
||||||
0xfa: true,
|
|
||||||
0xfb: true,
|
|
||||||
0xfc: true,
|
|
||||||
0xfd: true,
|
|
||||||
0xfe: true,
|
|
||||||
0xff: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var needEscape = [256]bool{
|
|
||||||
'"': true,
|
|
||||||
'\\': true,
|
|
||||||
0x00: true,
|
|
||||||
0x01: true,
|
|
||||||
0x02: true,
|
|
||||||
0x03: true,
|
|
||||||
0x04: true,
|
|
||||||
0x05: true,
|
|
||||||
0x06: true,
|
|
||||||
0x07: true,
|
|
||||||
0x08: true,
|
|
||||||
0x09: true,
|
|
||||||
0x0a: true,
|
|
||||||
0x0b: true,
|
|
||||||
0x0c: true,
|
|
||||||
0x0d: true,
|
|
||||||
0x0e: true,
|
|
||||||
0x0f: true,
|
|
||||||
0x10: true,
|
|
||||||
0x11: true,
|
|
||||||
0x12: true,
|
|
||||||
0x13: true,
|
|
||||||
0x14: true,
|
|
||||||
0x15: true,
|
|
||||||
0x16: true,
|
|
||||||
0x17: true,
|
|
||||||
0x18: true,
|
|
||||||
0x19: true,
|
|
||||||
0x1a: true,
|
|
||||||
0x1b: true,
|
|
||||||
0x1c: true,
|
|
||||||
0x1d: true,
|
|
||||||
0x1e: true,
|
|
||||||
0x1f: true,
|
|
||||||
/* 0x20 - 0x7f */
|
|
||||||
0x80: true,
|
|
||||||
0x81: true,
|
|
||||||
0x82: true,
|
|
||||||
0x83: true,
|
|
||||||
0x84: true,
|
|
||||||
0x85: true,
|
|
||||||
0x86: true,
|
|
||||||
0x87: true,
|
|
||||||
0x88: true,
|
|
||||||
0x89: true,
|
|
||||||
0x8a: true,
|
|
||||||
0x8b: true,
|
|
||||||
0x8c: true,
|
|
||||||
0x8d: true,
|
|
||||||
0x8e: true,
|
|
||||||
0x8f: true,
|
|
||||||
0x90: true,
|
|
||||||
0x91: true,
|
|
||||||
0x92: true,
|
|
||||||
0x93: true,
|
|
||||||
0x94: true,
|
|
||||||
0x95: true,
|
|
||||||
0x96: true,
|
|
||||||
0x97: true,
|
|
||||||
0x98: true,
|
|
||||||
0x99: true,
|
|
||||||
0x9a: true,
|
|
||||||
0x9b: true,
|
|
||||||
0x9c: true,
|
|
||||||
0x9d: true,
|
|
||||||
0x9e: true,
|
|
||||||
0x9f: true,
|
|
||||||
0xa0: true,
|
|
||||||
0xa1: true,
|
|
||||||
0xa2: true,
|
|
||||||
0xa3: true,
|
|
||||||
0xa4: true,
|
|
||||||
0xa5: true,
|
|
||||||
0xa6: true,
|
|
||||||
0xa7: true,
|
|
||||||
0xa8: true,
|
|
||||||
0xa9: true,
|
|
||||||
0xaa: true,
|
|
||||||
0xab: true,
|
|
||||||
0xac: true,
|
|
||||||
0xad: true,
|
|
||||||
0xae: true,
|
|
||||||
0xaf: true,
|
|
||||||
0xb0: true,
|
|
||||||
0xb1: true,
|
|
||||||
0xb2: true,
|
|
||||||
0xb3: true,
|
|
||||||
0xb4: true,
|
|
||||||
0xb5: true,
|
|
||||||
0xb6: true,
|
|
||||||
0xb7: true,
|
|
||||||
0xb8: true,
|
|
||||||
0xb9: true,
|
|
||||||
0xba: true,
|
|
||||||
0xbb: true,
|
|
||||||
0xbc: true,
|
|
||||||
0xbd: true,
|
|
||||||
0xbe: true,
|
|
||||||
0xbf: true,
|
|
||||||
0xc0: true,
|
|
||||||
0xc1: true,
|
|
||||||
0xc2: true,
|
|
||||||
0xc3: true,
|
|
||||||
0xc4: true,
|
|
||||||
0xc5: true,
|
|
||||||
0xc6: true,
|
|
||||||
0xc7: true,
|
|
||||||
0xc8: true,
|
|
||||||
0xc9: true,
|
|
||||||
0xca: true,
|
|
||||||
0xcb: true,
|
|
||||||
0xcc: true,
|
|
||||||
0xcd: true,
|
|
||||||
0xce: true,
|
|
||||||
0xcf: true,
|
|
||||||
0xd0: true,
|
|
||||||
0xd1: true,
|
|
||||||
0xd2: true,
|
|
||||||
0xd3: true,
|
|
||||||
0xd4: true,
|
|
||||||
0xd5: true,
|
|
||||||
0xd6: true,
|
|
||||||
0xd7: true,
|
|
||||||
0xd8: true,
|
|
||||||
0xd9: true,
|
|
||||||
0xda: true,
|
|
||||||
0xdb: true,
|
|
||||||
0xdc: true,
|
|
||||||
0xdd: true,
|
|
||||||
0xde: true,
|
|
||||||
0xdf: true,
|
|
||||||
0xe0: true,
|
|
||||||
0xe1: true,
|
|
||||||
0xe2: true,
|
|
||||||
0xe3: true,
|
|
||||||
0xe4: true,
|
|
||||||
0xe5: true,
|
|
||||||
0xe6: true,
|
|
||||||
0xe7: true,
|
|
||||||
0xe8: true,
|
|
||||||
0xe9: true,
|
|
||||||
0xea: true,
|
|
||||||
0xeb: true,
|
|
||||||
0xec: true,
|
|
||||||
0xed: true,
|
|
||||||
0xee: true,
|
|
||||||
0xef: true,
|
|
||||||
0xf0: true,
|
|
||||||
0xf1: true,
|
|
||||||
0xf2: true,
|
|
||||||
0xf3: true,
|
|
||||||
0xf4: true,
|
|
||||||
0xf5: true,
|
|
||||||
0xf6: true,
|
|
||||||
0xf7: true,
|
|
||||||
0xf8: true,
|
|
||||||
0xf9: true,
|
|
||||||
0xfa: true,
|
|
||||||
0xfb: true,
|
|
||||||
0xfc: true,
|
|
||||||
0xfd: true,
|
|
||||||
0xfe: true,
|
|
||||||
0xff: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var hex = "0123456789abcdef"
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// If no chars in `s` require escaping, the return value is -1.
|
|
||||||
func escapeIndex(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 | below(n, 0x20) | contains(n, '"') | contains(n, '\\')
|
|
||||||
if (mask & msb) != 0 {
|
|
||||||
return bits.TrailingZeros64(mask&msb) / 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
valLen := len(s)
|
|
||||||
for i := len(chunks) * 8; i < valLen; i++ {
|
|
||||||
if needEscape[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
|
|
||||||
// 0x80.
|
|
||||||
func below(n uint64, b byte) uint64 {
|
|
||||||
return n - expand(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// contains returns a mask that can be used to determine if any of the
|
|
||||||
// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then
|
|
||||||
// that byte is equal to `b`. The result is only valid if `b`, and each
|
|
||||||
// byte in `n`, is below 0x80.
|
|
||||||
func contains(n uint64, b byte) uint64 {
|
|
||||||
return (n ^ expand(b)) - lsb
|
|
||||||
}
|
|
||||||
|
|
||||||
// expand puts the specified byte into each of the 8 bytes of a uint64.
|
|
||||||
func expand(b byte) uint64 {
|
|
||||||
return lsb * uint64(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
//nolint:govet
|
|
||||||
func stringToUint64Slice(s string) []uint64 {
|
|
||||||
return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{
|
|
||||||
Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data,
|
|
||||||
Len: len(s) / 8,
|
|
||||||
Cap: len(s) / 8,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeEscapedString(buf []byte, s string) []byte {
|
|
||||||
valLen := len(s)
|
|
||||||
if valLen == 0 {
|
|
||||||
return append(buf, `""`...)
|
|
||||||
}
|
|
||||||
buf = append(buf, '"')
|
|
||||||
var (
|
|
||||||
i, j int
|
|
||||||
)
|
|
||||||
if valLen >= 8 {
|
|
||||||
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 {
|
|
||||||
j = bits.TrailingZeros64(mask&msb) / 8
|
|
||||||
goto ESCAPE_END
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := len(chunks) * 8; i < valLen; i++ {
|
|
||||||
if needEscapeWithHTML[s[i]] {
|
|
||||||
j = i
|
|
||||||
goto ESCAPE_END
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no found any escape characters.
|
|
||||||
return append(append(buf, s...), '"')
|
|
||||||
}
|
|
||||||
ESCAPE_END:
|
|
||||||
for j < valLen {
|
|
||||||
c := s[j]
|
|
||||||
|
|
||||||
if !needEscapeWithHTML[c] {
|
|
||||||
// fast path: most of the time, printable ascii characters are used
|
|
||||||
j++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch c {
|
|
||||||
case '\\', '"':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', c)
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '\n':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', 'n')
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', 'r')
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '\t':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', 't')
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '<', '>', '&':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\u00`...)
|
|
||||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
|
||||||
if c < 0x20 {
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\u00`...)
|
|
||||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
r, size := utf8.DecodeRuneInString(s[j:])
|
|
||||||
|
|
||||||
if r == utf8.RuneError && size == 1 {
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\ufffd`...)
|
|
||||||
i = j + size
|
|
||||||
j = j + size
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r {
|
|
||||||
case '\u2028', '\u2029':
|
|
||||||
// U+2028 is LINE SEPARATOR.
|
|
||||||
// U+2029 is PARAGRAPH SEPARATOR.
|
|
||||||
// They are both technically valid characters in JSON strings,
|
|
||||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
|
||||||
// and can lead to security holes there. It is valid JSON to
|
|
||||||
// escape them, so we do so unconditionally.
|
|
||||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\u202`...)
|
|
||||||
buf = append(buf, hex[r&0xF])
|
|
||||||
i = j + size
|
|
||||||
j = j + size
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
j += size
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(append(buf, s[i:]...), '"')
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeNoEscapedString(buf []byte, s string) []byte {
|
|
||||||
valLen := len(s)
|
|
||||||
if valLen == 0 {
|
|
||||||
return append(buf, `""`...)
|
|
||||||
}
|
|
||||||
buf = append(buf, '"')
|
|
||||||
var escapeIdx int
|
|
||||||
if valLen >= 8 {
|
|
||||||
if escapeIdx = escapeIndex(s); escapeIdx < 0 {
|
|
||||||
return append(append(buf, s...), '"')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i := 0
|
|
||||||
j := escapeIdx
|
|
||||||
for j < valLen {
|
|
||||||
c := s[j]
|
|
||||||
|
|
||||||
if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' {
|
|
||||||
// fast path: most of the time, printable ascii characters are used
|
|
||||||
j++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch c {
|
|
||||||
case '\\', '"':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', c)
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '\n':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', 'n')
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', 'r')
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '\t':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, '\\', 't')
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
case '<', '>', '&':
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\u00`...)
|
|
||||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
|
||||||
if c < 0x20 {
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\u00`...)
|
|
||||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
|
||||||
i = j + 1
|
|
||||||
j = j + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
r, size := utf8.DecodeRuneInString(s[j:])
|
|
||||||
|
|
||||||
if r == utf8.RuneError && size == 1 {
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\ufffd`...)
|
|
||||||
i = j + size
|
|
||||||
j = j + size
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r {
|
|
||||||
case '\u2028', '\u2029':
|
|
||||||
// U+2028 is LINE SEPARATOR.
|
|
||||||
// U+2029 is PARAGRAPH SEPARATOR.
|
|
||||||
// They are both technically valid characters in JSON strings,
|
|
||||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
|
||||||
// and can lead to security holes there. It is valid JSON to
|
|
||||||
// escape them, so we do so unconditionally.
|
|
||||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
|
||||||
buf = append(buf, s[i:j]...)
|
|
||||||
buf = append(buf, `\u202`...)
|
|
||||||
buf = append(buf, hex[r&0xF])
|
|
||||||
i = j + size
|
|
||||||
j = j + size
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
j += size
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(append(buf, s[i:]...), '"')
|
|
||||||
}
|
|
66
encode_vm.go
66
encode_vm.go
|
@ -1,66 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const startDetectingCyclesAfter = 1000
|
|
||||||
|
|
||||||
func load(base uintptr, idx uintptr) uintptr {
|
|
||||||
addr := base + idx
|
|
||||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
|
||||||
}
|
|
||||||
|
|
||||||
func store(base uintptr, idx uintptr, p uintptr) {
|
|
||||||
addr := base + idx
|
|
||||||
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
|
||||||
func ptrToNumber(p uintptr) Number { return **(**Number)(unsafe.Pointer(&p)) }
|
|
||||||
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
|
||||||
func ptrToSlice(p uintptr) *sliceHeader { return *(**sliceHeader)(unsafe.Pointer(&p)) }
|
|
||||||
func ptrToPtr(p uintptr) uintptr {
|
|
||||||
return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
|
|
||||||
}
|
|
||||||
func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
|
|
||||||
return *(*unsafe.Pointer)(unsafe.Pointer(&p))
|
|
||||||
}
|
|
||||||
func ptrToInterface(code *opcode, p uintptr) interface{} {
|
|
||||||
return *(*interface{})(unsafe.Pointer(&emptyInterface{
|
|
||||||
typ: code.typ,
|
|
||||||
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
func errUnsupportedValue(code *opcode, ptr uintptr) *UnsupportedValueError {
|
|
||||||
v := *(*interface{})(unsafe.Pointer(&emptyInterface{
|
|
||||||
typ: code.typ,
|
|
||||||
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)),
|
|
||||||
}))
|
|
||||||
return &UnsupportedValueError{
|
|
||||||
Value: reflect.ValueOf(v),
|
|
||||||
Str: fmt.Sprintf("encountered a cycle via %s", code.typ),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errUnsupportedFloat(v float64) *UnsupportedValueError {
|
|
||||||
return &UnsupportedValueError{
|
|
||||||
Value: reflect.ValueOf(v),
|
|
||||||
Str: strconv.FormatFloat(v, 'g', -1, 64),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errMarshalerWithCode(code *opcode, err error) *MarshalerError {
|
|
||||||
return &MarshalerError{
|
|
||||||
Type: rtype2type(code.typ),
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/goccy/go-json/internal/errors"
|
"github.com/goccy/go-json/internal/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
func Compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
||||||
if len(src) == 0 {
|
if len(src) == 0 {
|
||||||
return errors.ErrUnexpectedEndOfJSON("", 0)
|
return errors.ErrUnexpectedEndOfJSON("", 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package json
|
package encoder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -10,9 +10,9 @@ func TestDumpOpcode(t *testing.T) {
|
||||||
header := (*emptyInterface)(unsafe.Pointer(&v))
|
header := (*emptyInterface)(unsafe.Pointer(&v))
|
||||||
typ := header.typ
|
typ := header.typ
|
||||||
typeptr := uintptr(unsafe.Pointer(typ))
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
codeSet, err := encodeCompileToGetCodeSet(typeptr)
|
codeSet, err := CompileToGetCodeSet(typeptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
codeSet.code.dump()
|
codeSet.Code.Dump()
|
||||||
}
|
}
|
|
@ -434,7 +434,7 @@ func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]by
|
||||||
}
|
}
|
||||||
buf := bytes.NewBuffer(b)
|
buf := bytes.NewBuffer(b)
|
||||||
// TODO: we should validate buffer with `compact`
|
// TODO: we should validate buffer with `compact`
|
||||||
if err := compact(buf, bb, escape); err != nil {
|
if err := Compact(buf, bb, escape); err != nil {
|
||||||
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
}
|
}
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
|
@ -461,11 +461,11 @@ func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v inte
|
||||||
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
}
|
}
|
||||||
var compactBuf bytes.Buffer
|
var compactBuf bytes.Buffer
|
||||||
if err := compact(&compactBuf, bb, escape); err != nil {
|
if err := Compact(&compactBuf, bb, escape); err != nil {
|
||||||
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
}
|
}
|
||||||
var indentBuf bytes.Buffer
|
var indentBuf bytes.Buffer
|
||||||
if err := encodeIndent(
|
if err := Indent(
|
||||||
&indentBuf,
|
&indentBuf,
|
||||||
compactBuf.Bytes(),
|
compactBuf.Bytes(),
|
||||||
string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+indent+1),
|
string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+indent+1),
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/goccy/go-json/internal/errors"
|
"github.com/goccy/go-json/internal/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func encodeIndent(dst *bytes.Buffer, src []byte, prefix, indentStr string) error {
|
func Indent(dst *bytes.Buffer, src []byte, prefix, indentStr string) error {
|
||||||
length := int64(len(src))
|
length := int64(len(src))
|
||||||
indentNum := 0
|
indentNum := 0
|
||||||
indentBytes := []byte(indentStr)
|
indentBytes := []byte(indentStr)
|
||||||
|
|
6
json.go
6
json.go
|
@ -4,6 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Marshaler is the interface implemented by types that
|
// Marshaler is the interface implemented by types that
|
||||||
|
@ -308,7 +310,7 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error {
|
||||||
// Compact appends to dst the JSON-encoded src with
|
// Compact appends to dst the JSON-encoded src with
|
||||||
// insignificant space characters elided.
|
// insignificant space characters elided.
|
||||||
func Compact(dst *bytes.Buffer, src []byte) error {
|
func Compact(dst *bytes.Buffer, src []byte) error {
|
||||||
return compact(dst, src, false)
|
return encoder.Compact(dst, src, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indent appends to dst an indented form of the JSON-encoded src.
|
// Indent appends to dst an indented form of the JSON-encoded src.
|
||||||
|
@ -323,7 +325,7 @@ func Compact(dst *bytes.Buffer, src []byte) error {
|
||||||
// For example, if src has no trailing spaces, neither will dst;
|
// For example, if src has no trailing spaces, neither will dst;
|
||||||
// if src ends in a trailing newline, so will dst.
|
// if src ends in a trailing newline, so will dst.
|
||||||
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
|
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
|
||||||
return encodeWithIndent(dst, src, prefix, indent)
|
return encoder.Indent(dst, src, prefix, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
|
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
|
||||||
|
|
Loading…
Reference in New Issue