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 (
|
||||
cachedOpcodeSets []*opcodeSet
|
||||
cachedOpcodeMap unsafe.Pointer // map[uintptr]*opcodeSet
|
||||
cachedDecoder []decoder
|
||||
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
||||
baseTypeAddr uintptr
|
||||
|
@ -66,7 +64,6 @@ func setupCodec() error {
|
|||
if addrRange > maxAcceptableTypeAddrRange {
|
||||
return fmt.Errorf("too big address range %d", addrRange)
|
||||
}
|
||||
cachedOpcodeSets = make([]*opcodeSet, addrRange)
|
||||
cachedDecoder = make([]decoder, addrRange)
|
||||
baseTypeAddr = min
|
||||
maxTypeAddr = max
|
||||
|
@ -77,22 +74,6 @@ func init() {
|
|||
_ = 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 {
|
||||
p := atomic.LoadPointer(&cachedDecoderMap)
|
||||
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
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
@ -8,6 +9,10 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||
)
|
||||
|
||||
func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, error) {
|
||||
decoderMap := loadDecoderMap()
|
||||
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"
|
||||
)
|
||||
|
||||
func compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
||||
func Compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
||||
if len(src) == 0 {
|
||||
return errors.ErrUnexpectedEndOfJSON("", 0)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package json
|
||||
package encoder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -10,9 +10,9 @@ func TestDumpOpcode(t *testing.T) {
|
|||
header := (*emptyInterface)(unsafe.Pointer(&v))
|
||||
typ := header.typ
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
codeSet, err := encodeCompileToGetCodeSet(typeptr)
|
||||
codeSet, err := CompileToGetCodeSet(typeptr)
|
||||
if err != nil {
|
||||
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)
|
||||
// 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 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}
|
||||
}
|
||||
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}
|
||||
}
|
||||
var indentBuf bytes.Buffer
|
||||
if err := encodeIndent(
|
||||
if err := Indent(
|
||||
&indentBuf,
|
||||
compactBuf.Bytes(),
|
||||
string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+indent+1),
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"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))
|
||||
indentNum := 0
|
||||
indentBytes := []byte(indentStr)
|
||||
|
|
6
json.go
6
json.go
|
@ -4,6 +4,8 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
// 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
|
||||
// insignificant space characters elided.
|
||||
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.
|
||||
|
@ -323,7 +325,7 @@ func Compact(dst *bytes.Buffer, src []byte) error {
|
|||
// For example, if src has no trailing spaces, neither will dst;
|
||||
// if src ends in a trailing newline, so will dst.
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue