diff --git a/codec.go b/codec.go index 96b917a..8818bb5 100644 --- a/codec.go +++ b/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)) diff --git a/compact.go b/compact.go deleted file mode 100644 index 2e568eb..0000000 --- a/compact.go +++ /dev/null @@ -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 -} diff --git a/decode_compile.go b/decode_compile.go index e6ed018..8ec2fd0 100644 --- a/decode_compile.go +++ b/decode_compile.go @@ -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 { diff --git a/encode_compile.go b/encode_compile.go deleted file mode 100644 index fcb89cb..0000000 --- a/encode_compile.go +++ /dev/null @@ -1,1424 +0,0 @@ -package json - -import ( - "encoding" - "fmt" - "math" - "reflect" - "strings" - "unsafe" -) - -type compiledCode struct { - code *opcode - linked bool // whether recursive code already have linked - curLen uintptr - nextLen uintptr -} - -type opcodeSet struct { - code *opcode - codeLength int -} - -var ( - marshalJSONType = reflect.TypeOf((*Marshaler)(nil)).Elem() - marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() - jsonNumberType = reflect.TypeOf(Number("")) -) - -func encodeCompileToGetCodeSetSlowPath(typeptr uintptr) (*opcodeSet, error) { - opcodeMap := loadOpcodeMap() - if codeSet, exists := opcodeMap[typeptr]; exists { - 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, - } - storeOpcodeSet(typeptr, codeSet, opcodeMap) - return codeSet, nil -} - -func encodeCompileHead(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - - isPtr := false - orgType := typ - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - isPtr = true - } - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - if typ.Kind() == reflect.Map { - if isPtr { - return encodeCompilePtr(ctx.withType(rtype_ptrTo(typ))) - } - return encodeCompileMap(ctx.withType(typ)) - } else if typ.Kind() == reflect.Struct { - code, err := encodeCompileStruct(ctx.withType(typ), isPtr) - if err != nil { - return nil, err - } - encodeOptimizeStructEnd(code) - encodeLinkRecursiveCode(code) - return code, nil - } else if isPtr && typ.Implements(marshalTextType) { - typ = orgType - } - code, err := encodeCompile(ctx.withType(typ), isPtr) - if err != nil { - return nil, err - } - encodeOptimizeStructEnd(code) - encodeLinkRecursiveCode(code) - return code, nil -} - -func encodeLinkRecursiveCode(c *opcode) { - for code := c; code.op != opEnd && code.op != opStructFieldRecursiveEnd; { - switch code.op { - case opStructFieldRecursive, opStructFieldRecursivePtr: - if code.jmp.linked { - code = code.next - continue - } - code.jmp.code = copyOpcode(code.jmp.code) - c := code.jmp.code - c.end.next = newEndOp(&encodeCompileContext{}) - c.op = c.op.ptrHeadToHead() - - beforeLastCode := c.end - lastCode := beforeLastCode.next - - lastCode.idx = beforeLastCode.idx + uintptrSize - lastCode.elemIdx = lastCode.idx + uintptrSize - - // extend length to alloc slot for elemIdx - totalLength := uintptr(code.totalLength() + 1) - nextTotalLength := uintptr(c.totalLength() + 1) - - c.end.next.op = opStructFieldRecursiveEnd - - code.jmp.curLen = totalLength - code.jmp.nextLen = nextTotalLength - code.jmp.linked = true - - encodeLinkRecursiveCode(code.jmp.code) - code = code.next - continue - } - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - default: - code = code.next - } - } -} - -func encodeOptimizeStructEnd(c *opcode) { - for code := c; code.op != opEnd; { - if code.op == opStructFieldRecursive || code.op == opStructFieldRecursivePtr { - // ignore if exists recursive operation - return - } - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - default: - code = code.next - } - } - - for code := c; code.op != opEnd; { - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - case codeStructEnd: - switch code.op { - case opStructEnd: - prev := code.prevField - prevOp := prev.op.String() - if strings.Contains(prevOp, "Head") || - strings.Contains(prevOp, "Slice") || - strings.Contains(prevOp, "Array") || - strings.Contains(prevOp, "Map") || - strings.Contains(prevOp, "MarshalJSON") || - strings.Contains(prevOp, "MarshalText") { - // not exists field - code = code.next - break - } - if prev.op != prev.op.fieldToEnd() { - prev.op = prev.op.fieldToEnd() - prev.next = code.next - } - code = code.next - default: - code = code.next - } - default: - code = code.next - } - } -} - -func encodeImplementsMarshalJSON(typ *rtype) bool { - if !typ.Implements(marshalJSONType) { - return false - } - if typ.Kind() != reflect.Ptr { - return true - } - // type kind is reflect.Ptr - if !typ.Elem().Implements(marshalJSONType) { - return true - } - // needs to dereference - return false -} - -func encodeImplementsMarshalText(typ *rtype) bool { - if !typ.Implements(marshalTextType) { - return false - } - if typ.Kind() != reflect.Ptr { - return true - } - // type kind is reflect.Ptr - if !typ.Elem().Implements(marshalTextType) { - return true - } - // needs to dereference - return false -} - -func encodeCompile(ctx *encodeCompileContext, isPtr bool) (*opcode, error) { - typ := ctx.typ - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - switch typ.Kind() { - case reflect.Ptr: - return encodeCompilePtr(ctx) - case reflect.Slice: - elem := typ.Elem() - if elem.Kind() == reflect.Uint8 { - p := rtype_ptrTo(elem) - if !p.Implements(marshalJSONType) && !p.Implements(marshalTextType) { - return encodeCompileBytes(ctx) - } - } - return encodeCompileSlice(ctx) - case reflect.Array: - return encodeCompileArray(ctx) - case reflect.Map: - return encodeCompileMap(ctx) - case reflect.Struct: - return encodeCompileStruct(ctx, isPtr) - case reflect.Interface: - return encodeCompileInterface(ctx) - case reflect.Int: - return encodeCompileInt(ctx) - case reflect.Int8: - return encodeCompileInt8(ctx) - case reflect.Int16: - return encodeCompileInt16(ctx) - case reflect.Int32: - return encodeCompileInt32(ctx) - case reflect.Int64: - return encodeCompileInt64(ctx) - case reflect.Uint: - return encodeCompileUint(ctx) - case reflect.Uint8: - return encodeCompileUint8(ctx) - case reflect.Uint16: - return encodeCompileUint16(ctx) - case reflect.Uint32: - return encodeCompileUint32(ctx) - case reflect.Uint64: - return encodeCompileUint64(ctx) - case reflect.Uintptr: - return encodeCompileUint(ctx) - case reflect.Float32: - return encodeCompileFloat32(ctx) - case reflect.Float64: - return encodeCompileFloat64(ctx) - case reflect.String: - return encodeCompileString(ctx) - case reflect.Bool: - return encodeCompileBool(ctx) - } - return nil, &UnsupportedTypeError{Type: rtype2type(typ)} -} - -func encodeConvertPtrOp(code *opcode) opType { - ptrHeadOp := code.op.headToPtrHead() - if code.op != ptrHeadOp { - return ptrHeadOp - } - switch code.op { - case opInt: - return opIntPtr - case opUint: - return opUintPtr - case opFloat32: - return opFloat32Ptr - case opFloat64: - return opFloat64Ptr - case opString: - return opStringPtr - case opBool: - return opBoolPtr - case opBytes: - return opBytesPtr - case opArray: - return opArrayPtr - case opSlice: - return opSlicePtr - case opMap: - return opMapPtr - case opMarshalJSON: - return opMarshalJSONPtr - case opMarshalText: - return opMarshalTextPtr - case opInterface: - return opInterfacePtr - case opStructFieldRecursive: - return opStructFieldRecursivePtr - } - return code.op -} - -func encodeCompileKey(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - switch typ.Kind() { - case reflect.Ptr: - return encodeCompilePtr(ctx) - case reflect.Interface: - return encodeCompileInterface(ctx) - case reflect.String: - return encodeCompileString(ctx) - case reflect.Int: - return encodeCompileIntString(ctx) - case reflect.Int8: - return encodeCompileInt8String(ctx) - case reflect.Int16: - return encodeCompileInt16String(ctx) - case reflect.Int32: - return encodeCompileInt32String(ctx) - case reflect.Int64: - return encodeCompileInt64String(ctx) - case reflect.Uint: - return encodeCompileUintString(ctx) - case reflect.Uint8: - return encodeCompileUint8String(ctx) - case reflect.Uint16: - return encodeCompileUint16String(ctx) - case reflect.Uint32: - return encodeCompileUint32String(ctx) - case reflect.Uint64: - return encodeCompileUint64String(ctx) - case reflect.Uintptr: - return encodeCompileUintString(ctx) - } - return nil, &UnsupportedTypeError{Type: rtype2type(typ)} -} - -func encodeCompilePtr(ctx *encodeCompileContext) (*opcode, error) { - code, err := encodeCompile(ctx.withType(ctx.typ.Elem()), true) - if err != nil { - return nil, err - } - code.op = encodeConvertPtrOp(code) - code.ptrNum++ - return code, nil -} - -func encodeCompileMarshalJSON(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opMarshalJSON) - typ := ctx.typ - if !typ.Implements(marshalJSONType) && rtype_ptrTo(typ).Implements(marshalJSONType) { - code.addrForMarshaler = true - } - ctx.incIndex() - return code, nil -} - -func encodeCompileMarshalText(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opMarshalText) - typ := ctx.typ - if !typ.Implements(marshalTextType) && rtype_ptrTo(typ).Implements(marshalTextType) { - code.addrForMarshaler = true - } - ctx.incIndex() - return code, nil -} - -const intSize = 32 << (^uint(0) >> 63) - -func encodeCompileInt(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileInt8(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt16(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt32(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt64(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileUint8(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint16(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint32(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint64(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileIntString(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileInt8String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt16String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt32String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt64String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileUintString(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileUint8String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint16String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint32String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint64String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileFloat32(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opFloat32) - ctx.incIndex() - return code, nil -} - -func encodeCompileFloat64(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opFloat64) - ctx.incIndex() - return code, nil -} - -func encodeCompileString(ctx *encodeCompileContext) (*opcode, error) { - var op opType - if ctx.typ == type2rtype(jsonNumberType) { - op = opNumber - } else { - op = opString - } - code := newOpCode(ctx, op) - ctx.incIndex() - return code, nil -} - -func encodeCompileBool(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opBool) - ctx.incIndex() - return code, nil -} - -func encodeCompileBytes(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opBytes) - ctx.incIndex() - return code, nil -} - -func encodeCompileInterface(ctx *encodeCompileContext) (*opcode, error) { - code := newInterfaceCode(ctx) - ctx.incIndex() - return code, nil -} - -func encodeCompileSlice(ctx *encodeCompileContext) (*opcode, error) { - elem := ctx.typ.Elem() - size := elem.Size() - - header := newSliceHeaderCode(ctx) - ctx.incIndex() - - code, err := encodeCompileSliceElem(ctx.withType(elem).incIndent()) - if err != nil { - return nil, err - } - - // header => opcode => elem => end - // ^ | - // |________| - - elemCode := newSliceElemCode(ctx, header, size) - ctx.incIndex() - - end := newOpCode(ctx, opSliceEnd) - ctx.incIndex() - - header.elem = elemCode - header.end = end - header.next = code - code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode)) - elemCode.next = code - elemCode.end = end - return (*opcode)(unsafe.Pointer(header)), nil -} - -func encodeCompileSliceElem(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - switch { - case !typ.Implements(marshalJSONType) && rtype_ptrTo(typ).Implements(marshalJSONType): - return encodeCompileMarshalJSON(ctx) - case !typ.Implements(marshalTextType) && rtype_ptrTo(typ).Implements(marshalTextType): - return encodeCompileMarshalText(ctx) - default: - return encodeCompile(ctx, false) - } -} - -func encodeCompileArray(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - elem := typ.Elem() - alen := typ.Len() - size := elem.Size() - - header := newArrayHeaderCode(ctx, alen) - ctx.incIndex() - - code, err := encodeCompile(ctx.withType(elem).incIndent(), false) - if err != nil { - return nil, err - } - // header => opcode => elem => end - // ^ | - // |________| - - elemCode := newArrayElemCode(ctx, header, alen, size) - ctx.incIndex() - - end := newOpCode(ctx, opArrayEnd) - ctx.incIndex() - - header.elem = elemCode - header.end = end - header.next = code - code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode)) - elemCode.next = code - elemCode.end = end - return (*opcode)(unsafe.Pointer(header)), nil -} - -//go:linkname mapiterinit reflect.mapiterinit -//go:noescape -func mapiterinit(mapType *rtype, m unsafe.Pointer) unsafe.Pointer - -//go:linkname mapiterkey reflect.mapiterkey -//go:noescape -func mapiterkey(it unsafe.Pointer) unsafe.Pointer - -//go:linkname mapiternext reflect.mapiternext -//go:noescape -func mapiternext(it unsafe.Pointer) - -//go:linkname maplen reflect.maplen -//go:noescape -func maplen(m unsafe.Pointer) int - -func encodeCompileMap(ctx *encodeCompileContext) (*opcode, error) { - // header => code => value => code => key => code => value => code => end - // ^ | - // |_______________________| - ctx = ctx.incIndent() - header := newMapHeaderCode(ctx) - ctx.incIndex() - - typ := ctx.typ - keyType := ctx.typ.Key() - keyCode, err := encodeCompileKey(ctx.withType(keyType)) - if err != nil { - return nil, err - } - - value := newMapValueCode(ctx, header) - ctx.incIndex() - - valueCode, err := encodeCompileMapValue(ctx.withType(typ.Elem())) - if err != nil { - return nil, err - } - - key := newMapKeyCode(ctx, header) - ctx.incIndex() - - ctx = ctx.decIndent() - - header.mapKey = key - header.mapValue = value - - end := newMapEndCode(ctx, header) - ctx.incIndex() - - header.next = keyCode - keyCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(value)) - value.next = valueCode - valueCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(key)) - key.next = keyCode - - header.end = end - key.end = end - value.end = end - - return (*opcode)(unsafe.Pointer(header)), nil -} - -func encodeCompileMapValue(ctx *encodeCompileContext) (*opcode, error) { - switch ctx.typ.Kind() { - case reflect.Map: - return encodeCompilePtr(ctx.withType(rtype_ptrTo(ctx.typ))) - default: - return encodeCompile(ctx, false) - } -} - -func encodeTypeToHeaderType(code *opcode) opType { - switch code.op { - case opInt: - return opStructFieldHeadInt - case opIntPtr: - return opStructFieldHeadIntPtr - case opUint: - return opStructFieldHeadUint - case opUintPtr: - return opStructFieldHeadUintPtr - case opFloat32: - return opStructFieldHeadFloat32 - case opFloat32Ptr: - return opStructFieldHeadFloat32Ptr - case opFloat64: - return opStructFieldHeadFloat64 - case opFloat64Ptr: - return opStructFieldHeadFloat64Ptr - case opString: - return opStructFieldHeadString - case opStringPtr: - return opStructFieldHeadStringPtr - case opNumber: - return opStructFieldHeadNumber - case opNumberPtr: - return opStructFieldHeadNumberPtr - case opBool: - return opStructFieldHeadBool - case opBoolPtr: - return opStructFieldHeadBoolPtr - case opMap: - return opStructFieldHeadMap - case opMapPtr: - code.op = opMap - return opStructFieldHeadMapPtr - case opArray: - return opStructFieldHeadArray - case opArrayPtr: - code.op = opArray - return opStructFieldHeadArrayPtr - case opSlice: - return opStructFieldHeadSlice - case opSlicePtr: - code.op = opSlice - return opStructFieldHeadSlicePtr - case opMarshalJSON: - return opStructFieldHeadMarshalJSON - case opMarshalJSONPtr: - return opStructFieldHeadMarshalJSONPtr - case opMarshalText: - return opStructFieldHeadMarshalText - case opMarshalTextPtr: - return opStructFieldHeadMarshalTextPtr - } - return opStructFieldHead -} - -func encodeTypeToFieldType(code *opcode) opType { - switch code.op { - case opInt: - return opStructFieldInt - case opIntPtr: - return opStructFieldIntPtr - case opUint: - return opStructFieldUint - case opUintPtr: - return opStructFieldUintPtr - case opFloat32: - return opStructFieldFloat32 - case opFloat32Ptr: - return opStructFieldFloat32Ptr - case opFloat64: - return opStructFieldFloat64 - case opFloat64Ptr: - return opStructFieldFloat64Ptr - case opString: - return opStructFieldString - case opStringPtr: - return opStructFieldStringPtr - case opNumber: - return opStructFieldNumber - case opNumberPtr: - return opStructFieldNumberPtr - case opBool: - return opStructFieldBool - case opBoolPtr: - return opStructFieldBoolPtr - case opMap: - return opStructFieldMap - case opMapPtr: - code.op = opMap - return opStructFieldMapPtr - case opArray: - return opStructFieldArray - case opArrayPtr: - code.op = opArray - return opStructFieldArrayPtr - case opSlice: - return opStructFieldSlice - case opSlicePtr: - code.op = opSlice - return opStructFieldSlicePtr - case opMarshalJSON: - return opStructFieldMarshalJSON - case opMarshalJSONPtr: - return opStructFieldMarshalJSONPtr - case opMarshalText: - return opStructFieldMarshalText - case opMarshalTextPtr: - return opStructFieldMarshalTextPtr - } - return opStructField -} - -func encodeOptimizeStructHeader(code *opcode, tag *structTag) opType { - headType := encodeTypeToHeaderType(code) - switch { - case tag.isOmitEmpty: - headType = headType.headToOmitEmptyHead() - case tag.isString: - headType = headType.headToStringTagHead() - } - return headType -} - -func encodeOptimizeStructField(code *opcode, tag *structTag) opType { - fieldType := encodeTypeToFieldType(code) - switch { - case tag.isOmitEmpty: - fieldType = fieldType.fieldToOmitEmptyField() - case tag.isString: - fieldType = fieldType.fieldToStringTagField() - } - return fieldType -} - -func encodeRecursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode { - code := newRecursiveCode(ctx, jmp) - ctx.incIndex() - return code -} - -func encodeCompiledCode(ctx *encodeCompileContext) *opcode { - typ := ctx.typ - typeptr := uintptr(unsafe.Pointer(typ)) - if compiledCode, exists := ctx.structTypeToCompiledCode[typeptr]; exists { - return encodeRecursiveCode(ctx, compiledCode) - } - return nil -} - -func encodeStructHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode { - fieldCode.indent-- - op := encodeOptimizeStructHeader(valueCode, tag) - fieldCode.op = op - fieldCode.mask = valueCode.mask - fieldCode.rshiftNum = valueCode.rshiftNum - fieldCode.ptrNum = valueCode.ptrNum - switch op { - case opStructFieldHead, - opStructFieldHeadSlice, - opStructFieldHeadArray, - opStructFieldHeadMap, - opStructFieldHeadStruct, - opStructFieldHeadOmitEmpty, - opStructFieldHeadOmitEmptySlice, - opStructFieldHeadStringTagSlice, - opStructFieldHeadOmitEmptyArray, - opStructFieldHeadStringTagArray, - opStructFieldHeadOmitEmptyMap, - opStructFieldHeadStringTagMap, - opStructFieldHeadOmitEmptyStruct, - opStructFieldHeadStringTag: - return valueCode.beforeLastCode() - case opStructFieldHeadSlicePtr, - opStructFieldHeadOmitEmptySlicePtr, - opStructFieldHeadStringTagSlicePtr, - opStructFieldHeadArrayPtr, - opStructFieldHeadOmitEmptyArrayPtr, - opStructFieldHeadStringTagArrayPtr, - opStructFieldHeadMapPtr, - opStructFieldHeadOmitEmptyMapPtr, - opStructFieldHeadStringTagMapPtr: - return valueCode.beforeLastCode() - case opStructFieldHeadMarshalJSONPtr, - opStructFieldHeadOmitEmptyMarshalJSONPtr, - opStructFieldHeadStringTagMarshalJSONPtr, - opStructFieldHeadMarshalTextPtr, - opStructFieldHeadOmitEmptyMarshalTextPtr, - opStructFieldHeadStringTagMarshalTextPtr: - ctx.decOpcodeIndex() - return (*opcode)(unsafe.Pointer(fieldCode)) - } - ctx.decOpcodeIndex() - return (*opcode)(unsafe.Pointer(fieldCode)) -} - -func encodeStructField(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode { - code := (*opcode)(unsafe.Pointer(fieldCode)) - op := encodeOptimizeStructField(valueCode, tag) - fieldCode.op = op - fieldCode.ptrNum = valueCode.ptrNum - fieldCode.mask = valueCode.mask - fieldCode.rshiftNum = valueCode.rshiftNum - fieldCode.jmp = valueCode.jmp - switch op { - case opStructField, - opStructFieldSlice, - opStructFieldArray, - opStructFieldMap, - opStructFieldStruct, - opStructFieldOmitEmpty, - opStructFieldOmitEmptySlice, - opStructFieldStringTagSlice, - opStructFieldOmitEmptyArray, - opStructFieldStringTagArray, - opStructFieldOmitEmptyMap, - opStructFieldStringTagMap, - opStructFieldOmitEmptyStruct, - opStructFieldStringTag: - return valueCode.beforeLastCode() - case opStructFieldSlicePtr, - opStructFieldOmitEmptySlicePtr, - opStructFieldStringTagSlicePtr, - opStructFieldArrayPtr, - opStructFieldOmitEmptyArrayPtr, - opStructFieldStringTagArrayPtr, - opStructFieldMapPtr, - opStructFieldOmitEmptyMapPtr, - opStructFieldStringTagMapPtr: - return valueCode.beforeLastCode() - } - ctx.decIndex() - return code -} - -func encodeIsNotExistsField(head *opcode) bool { - if head == nil { - return false - } - if head.op != opStructFieldHead { - return false - } - if !head.anonymousHead { - return false - } - if head.next == nil { - return false - } - if head.nextField == nil { - return false - } - if head.nextField.op != opStructAnonymousEnd { - return false - } - if head.next.op == opStructAnonymousEnd { - return true - } - if head.next.op.codeType() != codeStructField { - return false - } - return encodeIsNotExistsField(head.next) -} - -func encodeOptimizeAnonymousFields(head *opcode) { - code := head - var prev *opcode - removedFields := map[*opcode]struct{}{} - for { - if code.op == opStructEnd { - break - } - if code.op == opStructField { - codeType := code.next.op.codeType() - if codeType == codeStructField { - if encodeIsNotExistsField(code.next) { - code.next = code.nextField - diff := code.next.displayIdx - code.displayIdx - for i := 0; i < diff; i++ { - code.next.decOpcodeIndex() - } - encodeLinkPrevToNextField(code, removedFields) - code = prev - } - } - } - prev = code - code = code.nextField - } -} - -type structFieldPair struct { - prevField *opcode - curField *opcode - isTaggedKey bool - linked bool -} - -func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode *opcode) map[string][]structFieldPair { - anonymousFields := map[string][]structFieldPair{} - f := valueCode - var prevAnonymousField *opcode - removedFields := map[*opcode]struct{}{} - for { - existsKey := tags.existsKey(f.displayKey) - isHeadOp := strings.Contains(f.op.String(), "Head") - if existsKey && strings.Contains(f.op.String(), "Recursive") { - // through - } else if isHeadOp && !f.anonymousHead { - if existsKey { - // TODO: need to remove this head - f.op = opStructFieldHead - f.anonymousKey = true - f.anonymousHead = true - } else if named == "" { - f.anonymousHead = true - } - } else if named == "" && f.op == opStructEnd { - f.op = opStructAnonymousEnd - } else if existsKey { - diff := f.nextField.displayIdx - f.displayIdx - for i := 0; i < diff; i++ { - f.nextField.decOpcodeIndex() - } - encodeLinkPrevToNextField(f, removedFields) - } - - if f.displayKey == "" { - if f.nextField == nil { - break - } - prevAnonymousField = f - f = f.nextField - continue - } - - key := fmt.Sprintf("%s.%s", named, f.displayKey) - anonymousFields[key] = append(anonymousFields[key], structFieldPair{ - prevField: prevAnonymousField, - curField: f, - isTaggedKey: f.isTaggedKey, - }) - if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { - for k, v := range encodeAnonymousFieldPairRecursively(named, f.next) { - anonymousFields[k] = append(anonymousFields[k], v...) - } - } - if f.nextField == nil { - break - } - prevAnonymousField = f - f = f.nextField - } - return anonymousFields -} - -func encodeAnonymousFieldPairRecursively(named string, valueCode *opcode) map[string][]structFieldPair { - anonymousFields := map[string][]structFieldPair{} - f := valueCode - var prevAnonymousField *opcode - for { - if f.displayKey != "" && f.anonymousHead { - key := fmt.Sprintf("%s.%s", named, f.displayKey) - anonymousFields[key] = append(anonymousFields[key], structFieldPair{ - prevField: prevAnonymousField, - curField: f, - isTaggedKey: f.isTaggedKey, - }) - if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { - for k, v := range encodeAnonymousFieldPairRecursively(named, f.next) { - anonymousFields[k] = append(anonymousFields[k], v...) - } - } - } - if f.nextField == nil { - break - } - prevAnonymousField = f - f = f.nextField - } - return anonymousFields -} - -func encodeOptimizeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) { - removedFields := map[*opcode]struct{}{} - for _, fieldPairs := range anonymousFields { - if len(fieldPairs) == 1 { - continue - } - // conflict anonymous fields - taggedPairs := []structFieldPair{} - for _, fieldPair := range fieldPairs { - if fieldPair.isTaggedKey { - taggedPairs = append(taggedPairs, fieldPair) - } else { - if !fieldPair.linked { - if fieldPair.prevField == nil { - // head operation - fieldPair.curField.op = opStructFieldHead - fieldPair.curField.anonymousHead = true - fieldPair.curField.anonymousKey = true - } else { - diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx - for i := 0; i < diff; i++ { - fieldPair.curField.nextField.decOpcodeIndex() - } - removedFields[fieldPair.curField] = struct{}{} - encodeLinkPrevToNextField(fieldPair.curField, removedFields) - } - fieldPair.linked = true - } - } - } - if len(taggedPairs) > 1 { - for _, fieldPair := range taggedPairs { - if !fieldPair.linked { - if fieldPair.prevField == nil { - // head operation - fieldPair.curField.op = opStructFieldHead - fieldPair.curField.anonymousHead = true - fieldPair.curField.anonymousKey = true - } else { - diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx - removedFields[fieldPair.curField] = struct{}{} - for i := 0; i < diff; i++ { - fieldPair.curField.nextField.decOpcodeIndex() - } - encodeLinkPrevToNextField(fieldPair.curField, removedFields) - } - fieldPair.linked = true - } - } - } else { - for _, fieldPair := range taggedPairs { - fieldPair.curField.isTaggedKey = false - } - } - } -} - -func encodeIsNilableType(typ *rtype) bool { - switch typ.Kind() { - case reflect.Ptr: - return true - case reflect.Interface: - return true - case reflect.Slice: - return true - case reflect.Map: - return true - default: - return false - } -} - -func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error) { - if code := encodeCompiledCode(ctx); code != nil { - return code, nil - } - typ := ctx.typ - typeptr := uintptr(unsafe.Pointer(typ)) - compiled := &compiledCode{} - ctx.structTypeToCompiledCode[typeptr] = compiled - // header => code => structField => code => end - // ^ | - // |__________| - fieldNum := typ.NumField() - indirect := ifaceIndir(typ) - fieldIdx := 0 - disableIndirectConversion := false - var ( - head *opcode - code *opcode - prevField *opcode - ) - ctx = ctx.incIndent() - tags := structTags{} - anonymousFields := map[string][]structFieldPair{} - for i := 0; i < fieldNum; i++ { - field := typ.Field(i) - if isIgnoredStructField(field) { - continue - } - tags = append(tags, structTagFromField(field)) - } - for i, tag := range tags { - field := tag.field - fieldType := type2rtype(field.Type) - fieldOpcodeIndex := ctx.opcodeIndex - fieldPtrIndex := ctx.ptrIndex - ctx.incIndex() - - nilcheck := true - addrForMarshaler := false - isIndirectSpecialCase := isPtr && i == 0 && fieldNum == 1 - isNilableType := encodeIsNilableType(fieldType) - - var valueCode *opcode - switch { - case isIndirectSpecialCase && !isNilableType && encodeIsPtrMarshalJSONType(fieldType): - // *struct{ field T } => struct { field *T } - // func (*T) MarshalJSON() ([]byte, error) - // move pointer position from head to first field - code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType))) - if err != nil { - return nil, err - } - valueCode = code - nilcheck = false - indirect = false - disableIndirectConversion = true - case isIndirectSpecialCase && !isNilableType && encodeIsPtrMarshalTextType(fieldType): - // *struct{ field T } => struct { field *T } - // func (*T) MarshalText() ([]byte, error) - // move pointer position from head to first field - code, err := encodeCompileMarshalText(ctx.withType(rtype_ptrTo(fieldType))) - if err != nil { - return nil, err - } - valueCode = code - nilcheck = false - indirect = false - disableIndirectConversion = true - case isPtr && encodeIsPtrMarshalJSONType(fieldType): - // *struct{ field T } - // func (*T) MarshalJSON() ([]byte, error) - code, err := encodeCompileMarshalJSON(ctx.withType(fieldType)) - if err != nil { - return nil, err - } - addrForMarshaler = true - nilcheck = false - valueCode = code - case isPtr && encodeIsPtrMarshalTextType(fieldType): - // *struct{ field T } - // func (*T) MarshalText() ([]byte, error) - code, err := encodeCompileMarshalText(ctx.withType(fieldType)) - if err != nil { - return nil, err - } - addrForMarshaler = true - nilcheck = false - valueCode = code - default: - code, err := encodeCompile(ctx.withType(fieldType), isPtr) - if err != nil { - return nil, err - } - valueCode = code - } - - if field.Anonymous { - tagKey := "" - if tag.isTaggedKey { - tagKey = tag.key - } - for k, v := range encodeAnonymousStructFieldPairMap(tags, tagKey, valueCode) { - anonymousFields[k] = append(anonymousFields[k], v...) - } - valueCode.decIndent() - - // fix issue144 - if !(isPtr && strings.Contains(valueCode.op.String(), "Marshal")) { - valueCode.indirect = indirect - } - } else { - valueCode.indirect = indirect - } - key := fmt.Sprintf(`"%s":`, tag.key) - escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key))) - fieldCode := &opcode{ - typ: valueCode.typ, - displayIdx: fieldOpcodeIndex, - idx: opcodeOffset(fieldPtrIndex), - next: valueCode, - indent: ctx.indent, - anonymousKey: field.Anonymous, - key: []byte(key), - escapedKey: []byte(escapedKey), - isTaggedKey: tag.isTaggedKey, - displayKey: tag.key, - offset: field.Offset, - indirect: indirect, - nilcheck: nilcheck, - addrForMarshaler: addrForMarshaler, - } - if fieldIdx == 0 { - fieldCode.headIdx = fieldCode.idx - code = encodeStructHeader(ctx, fieldCode, valueCode, tag) - head = fieldCode - prevField = fieldCode - } else { - fieldCode.headIdx = head.headIdx - code.next = fieldCode - code = encodeStructField(ctx, fieldCode, valueCode, tag) - prevField.nextField = fieldCode - fieldCode.prevField = prevField - prevField = fieldCode - } - fieldIdx++ - } - ctx = ctx.decIndent() - - structEndCode := &opcode{ - op: opStructEnd, - typ: nil, - indent: ctx.indent, - next: newEndOp(ctx), - } - - // no struct field - if head == nil { - head = &opcode{ - op: opStructFieldHead, - typ: typ, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - headIdx: opcodeOffset(ctx.ptrIndex), - indent: ctx.indent, - nextField: structEndCode, - } - structEndCode.prevField = head - ctx.incIndex() - code = head - } - - structEndCode.displayIdx = ctx.opcodeIndex - structEndCode.idx = opcodeOffset(ctx.ptrIndex) - ctx.incIndex() - - if prevField != nil && prevField.nextField == nil { - prevField.nextField = structEndCode - structEndCode.prevField = prevField - } - - head.end = structEndCode - code.next = structEndCode - encodeOptimizeConflictAnonymousFields(anonymousFields) - encodeOptimizeAnonymousFields(head) - ret := (*opcode)(unsafe.Pointer(head)) - compiled.code = ret - - delete(ctx.structTypeToCompiledCode, typeptr) - - if !disableIndirectConversion && !head.indirect && isPtr { - head.indirect = true - } - - return ret, nil -} - -func encodeIsPtrMarshalJSONType(typ *rtype) bool { - return !typ.Implements(marshalJSONType) && rtype_ptrTo(typ).Implements(marshalJSONType) -} - -func encodeIsPtrMarshalTextType(typ *rtype) bool { - return !typ.Implements(marshalTextType) && rtype_ptrTo(typ).Implements(marshalTextType) -} diff --git a/encode_compile_norace.go b/encode_compile_norace.go deleted file mode 100644 index 3305a5b..0000000 --- a/encode_compile_norace.go +++ /dev/null @@ -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 -} diff --git a/encode_compile_race.go b/encode_compile_race.go deleted file mode 100644 index decba6e..0000000 --- a/encode_compile_race.go +++ /dev/null @@ -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 -} diff --git a/encode_context.go b/encode_context.go deleted file mode 100644 index 9d45f1e..0000000 --- a/encode_context.go +++ /dev/null @@ -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) -} diff --git a/encode_int.go b/encode_int.go deleted file mode 100644 index 993b9d1..0000000 --- a/encode_int.go +++ /dev/null @@ -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:]...) -} diff --git a/encode_map112.go b/encode_map112.go deleted file mode 100644 index 99b4bdb..0000000 --- a/encode_map112.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !go1.13 - -package json - -import "unsafe" - -//go:linkname mapitervalue reflect.mapitervalue -func mapitervalue(it unsafe.Pointer) unsafe.Pointer diff --git a/encode_map113.go b/encode_map113.go deleted file mode 100644 index 48bbd6d..0000000 --- a/encode_map113.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build go1.13 - -package json - -import "unsafe" - -//go:linkname mapitervalue reflect.mapiterelem -func mapitervalue(it unsafe.Pointer) unsafe.Pointer diff --git a/encode_opcode.go b/encode_opcode.go deleted file mode 100644 index 1278f12..0000000 --- a/encode_opcode.go +++ /dev/null @@ -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, - } -} diff --git a/encode_optype.go b/encode_optype.go deleted file mode 100644 index 7e73479..0000000 --- a/encode_optype.go +++ /dev/null @@ -1,1186 +0,0 @@ -// Code generated by cmd/generator. DO NOT EDIT! -package json - -import ( - "strings" -) - -type codeType int - -const ( - codeOp codeType = 0 - codeArrayHead codeType = 1 - codeArrayElem codeType = 2 - codeSliceHead codeType = 3 - codeSliceElem codeType = 4 - codeMapHead codeType = 5 - codeMapKey codeType = 6 - codeMapValue codeType = 7 - codeMapEnd codeType = 8 - codeStructFieldRecursive codeType = 9 - codeStructField codeType = 10 - codeStructEnd codeType = 11 -) - -var opTypeStrings = [440]string{ - "End", - "Interface", - "Ptr", - "SliceElem", - "SliceEnd", - "ArrayElem", - "ArrayEnd", - "MapKey", - "MapValue", - "MapEnd", - "StructFieldRecursiveEnd", - "StructAnonymousEnd", - "Int", - "Uint", - "Float32", - "Float64", - "Bool", - "String", - "Bytes", - "Number", - "Array", - "Map", - "Slice", - "Struct", - "MarshalJSON", - "MarshalText", - "Recursive", - "IntString", - "UintString", - "IntPtr", - "UintPtr", - "Float32Ptr", - "Float64Ptr", - "BoolPtr", - "StringPtr", - "BytesPtr", - "NumberPtr", - "ArrayPtr", - "MapPtr", - "SlicePtr", - "MarshalJSONPtr", - "MarshalTextPtr", - "InterfacePtr", - "RecursivePtr", - "StructFieldHeadInt", - "StructFieldHeadOmitEmptyInt", - "StructFieldHeadStringTagInt", - "StructFieldPtrHeadInt", - "StructFieldPtrHeadOmitEmptyInt", - "StructFieldPtrHeadStringTagInt", - "StructFieldHeadUint", - "StructFieldHeadOmitEmptyUint", - "StructFieldHeadStringTagUint", - "StructFieldPtrHeadUint", - "StructFieldPtrHeadOmitEmptyUint", - "StructFieldPtrHeadStringTagUint", - "StructFieldHeadFloat32", - "StructFieldHeadOmitEmptyFloat32", - "StructFieldHeadStringTagFloat32", - "StructFieldPtrHeadFloat32", - "StructFieldPtrHeadOmitEmptyFloat32", - "StructFieldPtrHeadStringTagFloat32", - "StructFieldHeadFloat64", - "StructFieldHeadOmitEmptyFloat64", - "StructFieldHeadStringTagFloat64", - "StructFieldPtrHeadFloat64", - "StructFieldPtrHeadOmitEmptyFloat64", - "StructFieldPtrHeadStringTagFloat64", - "StructFieldHeadBool", - "StructFieldHeadOmitEmptyBool", - "StructFieldHeadStringTagBool", - "StructFieldPtrHeadBool", - "StructFieldPtrHeadOmitEmptyBool", - "StructFieldPtrHeadStringTagBool", - "StructFieldHeadString", - "StructFieldHeadOmitEmptyString", - "StructFieldHeadStringTagString", - "StructFieldPtrHeadString", - "StructFieldPtrHeadOmitEmptyString", - "StructFieldPtrHeadStringTagString", - "StructFieldHeadBytes", - "StructFieldHeadOmitEmptyBytes", - "StructFieldHeadStringTagBytes", - "StructFieldPtrHeadBytes", - "StructFieldPtrHeadOmitEmptyBytes", - "StructFieldPtrHeadStringTagBytes", - "StructFieldHeadNumber", - "StructFieldHeadOmitEmptyNumber", - "StructFieldHeadStringTagNumber", - "StructFieldPtrHeadNumber", - "StructFieldPtrHeadOmitEmptyNumber", - "StructFieldPtrHeadStringTagNumber", - "StructFieldHeadArray", - "StructFieldHeadOmitEmptyArray", - "StructFieldHeadStringTagArray", - "StructFieldPtrHeadArray", - "StructFieldPtrHeadOmitEmptyArray", - "StructFieldPtrHeadStringTagArray", - "StructFieldHeadMap", - "StructFieldHeadOmitEmptyMap", - "StructFieldHeadStringTagMap", - "StructFieldPtrHeadMap", - "StructFieldPtrHeadOmitEmptyMap", - "StructFieldPtrHeadStringTagMap", - "StructFieldHeadSlice", - "StructFieldHeadOmitEmptySlice", - "StructFieldHeadStringTagSlice", - "StructFieldPtrHeadSlice", - "StructFieldPtrHeadOmitEmptySlice", - "StructFieldPtrHeadStringTagSlice", - "StructFieldHeadStruct", - "StructFieldHeadOmitEmptyStruct", - "StructFieldHeadStringTagStruct", - "StructFieldPtrHeadStruct", - "StructFieldPtrHeadOmitEmptyStruct", - "StructFieldPtrHeadStringTagStruct", - "StructFieldHeadMarshalJSON", - "StructFieldHeadOmitEmptyMarshalJSON", - "StructFieldHeadStringTagMarshalJSON", - "StructFieldPtrHeadMarshalJSON", - "StructFieldPtrHeadOmitEmptyMarshalJSON", - "StructFieldPtrHeadStringTagMarshalJSON", - "StructFieldHeadMarshalText", - "StructFieldHeadOmitEmptyMarshalText", - "StructFieldHeadStringTagMarshalText", - "StructFieldPtrHeadMarshalText", - "StructFieldPtrHeadOmitEmptyMarshalText", - "StructFieldPtrHeadStringTagMarshalText", - "StructFieldHeadRecursive", - "StructFieldHeadOmitEmptyRecursive", - "StructFieldHeadStringTagRecursive", - "StructFieldPtrHeadRecursive", - "StructFieldPtrHeadOmitEmptyRecursive", - "StructFieldPtrHeadStringTagRecursive", - "StructFieldHeadIntString", - "StructFieldHeadOmitEmptyIntString", - "StructFieldHeadStringTagIntString", - "StructFieldPtrHeadIntString", - "StructFieldPtrHeadOmitEmptyIntString", - "StructFieldPtrHeadStringTagIntString", - "StructFieldHeadUintString", - "StructFieldHeadOmitEmptyUintString", - "StructFieldHeadStringTagUintString", - "StructFieldPtrHeadUintString", - "StructFieldPtrHeadOmitEmptyUintString", - "StructFieldPtrHeadStringTagUintString", - "StructFieldHeadIntPtr", - "StructFieldHeadOmitEmptyIntPtr", - "StructFieldHeadStringTagIntPtr", - "StructFieldPtrHeadIntPtr", - "StructFieldPtrHeadOmitEmptyIntPtr", - "StructFieldPtrHeadStringTagIntPtr", - "StructFieldHeadUintPtr", - "StructFieldHeadOmitEmptyUintPtr", - "StructFieldHeadStringTagUintPtr", - "StructFieldPtrHeadUintPtr", - "StructFieldPtrHeadOmitEmptyUintPtr", - "StructFieldPtrHeadStringTagUintPtr", - "StructFieldHeadFloat32Ptr", - "StructFieldHeadOmitEmptyFloat32Ptr", - "StructFieldHeadStringTagFloat32Ptr", - "StructFieldPtrHeadFloat32Ptr", - "StructFieldPtrHeadOmitEmptyFloat32Ptr", - "StructFieldPtrHeadStringTagFloat32Ptr", - "StructFieldHeadFloat64Ptr", - "StructFieldHeadOmitEmptyFloat64Ptr", - "StructFieldHeadStringTagFloat64Ptr", - "StructFieldPtrHeadFloat64Ptr", - "StructFieldPtrHeadOmitEmptyFloat64Ptr", - "StructFieldPtrHeadStringTagFloat64Ptr", - "StructFieldHeadBoolPtr", - "StructFieldHeadOmitEmptyBoolPtr", - "StructFieldHeadStringTagBoolPtr", - "StructFieldPtrHeadBoolPtr", - "StructFieldPtrHeadOmitEmptyBoolPtr", - "StructFieldPtrHeadStringTagBoolPtr", - "StructFieldHeadStringPtr", - "StructFieldHeadOmitEmptyStringPtr", - "StructFieldHeadStringTagStringPtr", - "StructFieldPtrHeadStringPtr", - "StructFieldPtrHeadOmitEmptyStringPtr", - "StructFieldPtrHeadStringTagStringPtr", - "StructFieldHeadBytesPtr", - "StructFieldHeadOmitEmptyBytesPtr", - "StructFieldHeadStringTagBytesPtr", - "StructFieldPtrHeadBytesPtr", - "StructFieldPtrHeadOmitEmptyBytesPtr", - "StructFieldPtrHeadStringTagBytesPtr", - "StructFieldHeadNumberPtr", - "StructFieldHeadOmitEmptyNumberPtr", - "StructFieldHeadStringTagNumberPtr", - "StructFieldPtrHeadNumberPtr", - "StructFieldPtrHeadOmitEmptyNumberPtr", - "StructFieldPtrHeadStringTagNumberPtr", - "StructFieldHeadArrayPtr", - "StructFieldHeadOmitEmptyArrayPtr", - "StructFieldHeadStringTagArrayPtr", - "StructFieldPtrHeadArrayPtr", - "StructFieldPtrHeadOmitEmptyArrayPtr", - "StructFieldPtrHeadStringTagArrayPtr", - "StructFieldHeadMapPtr", - "StructFieldHeadOmitEmptyMapPtr", - "StructFieldHeadStringTagMapPtr", - "StructFieldPtrHeadMapPtr", - "StructFieldPtrHeadOmitEmptyMapPtr", - "StructFieldPtrHeadStringTagMapPtr", - "StructFieldHeadSlicePtr", - "StructFieldHeadOmitEmptySlicePtr", - "StructFieldHeadStringTagSlicePtr", - "StructFieldPtrHeadSlicePtr", - "StructFieldPtrHeadOmitEmptySlicePtr", - "StructFieldPtrHeadStringTagSlicePtr", - "StructFieldHeadMarshalJSONPtr", - "StructFieldHeadOmitEmptyMarshalJSONPtr", - "StructFieldHeadStringTagMarshalJSONPtr", - "StructFieldPtrHeadMarshalJSONPtr", - "StructFieldPtrHeadOmitEmptyMarshalJSONPtr", - "StructFieldPtrHeadStringTagMarshalJSONPtr", - "StructFieldHeadMarshalTextPtr", - "StructFieldHeadOmitEmptyMarshalTextPtr", - "StructFieldHeadStringTagMarshalTextPtr", - "StructFieldPtrHeadMarshalTextPtr", - "StructFieldPtrHeadOmitEmptyMarshalTextPtr", - "StructFieldPtrHeadStringTagMarshalTextPtr", - "StructFieldHeadInterfacePtr", - "StructFieldHeadOmitEmptyInterfacePtr", - "StructFieldHeadStringTagInterfacePtr", - "StructFieldPtrHeadInterfacePtr", - "StructFieldPtrHeadOmitEmptyInterfacePtr", - "StructFieldPtrHeadStringTagInterfacePtr", - "StructFieldHeadRecursivePtr", - "StructFieldHeadOmitEmptyRecursivePtr", - "StructFieldHeadStringTagRecursivePtr", - "StructFieldPtrHeadRecursivePtr", - "StructFieldPtrHeadOmitEmptyRecursivePtr", - "StructFieldPtrHeadStringTagRecursivePtr", - "StructFieldHead", - "StructFieldHeadOmitEmpty", - "StructFieldHeadStringTag", - "StructFieldPtrHead", - "StructFieldPtrHeadOmitEmpty", - "StructFieldPtrHeadStringTag", - "StructFieldInt", - "StructFieldOmitEmptyInt", - "StructFieldStringTagInt", - "StructFieldUint", - "StructFieldOmitEmptyUint", - "StructFieldStringTagUint", - "StructFieldFloat32", - "StructFieldOmitEmptyFloat32", - "StructFieldStringTagFloat32", - "StructFieldFloat64", - "StructFieldOmitEmptyFloat64", - "StructFieldStringTagFloat64", - "StructFieldBool", - "StructFieldOmitEmptyBool", - "StructFieldStringTagBool", - "StructFieldString", - "StructFieldOmitEmptyString", - "StructFieldStringTagString", - "StructFieldBytes", - "StructFieldOmitEmptyBytes", - "StructFieldStringTagBytes", - "StructFieldNumber", - "StructFieldOmitEmptyNumber", - "StructFieldStringTagNumber", - "StructFieldArray", - "StructFieldOmitEmptyArray", - "StructFieldStringTagArray", - "StructFieldMap", - "StructFieldOmitEmptyMap", - "StructFieldStringTagMap", - "StructFieldSlice", - "StructFieldOmitEmptySlice", - "StructFieldStringTagSlice", - "StructFieldStruct", - "StructFieldOmitEmptyStruct", - "StructFieldStringTagStruct", - "StructFieldMarshalJSON", - "StructFieldOmitEmptyMarshalJSON", - "StructFieldStringTagMarshalJSON", - "StructFieldMarshalText", - "StructFieldOmitEmptyMarshalText", - "StructFieldStringTagMarshalText", - "StructFieldRecursive", - "StructFieldOmitEmptyRecursive", - "StructFieldStringTagRecursive", - "StructFieldIntString", - "StructFieldOmitEmptyIntString", - "StructFieldStringTagIntString", - "StructFieldUintString", - "StructFieldOmitEmptyUintString", - "StructFieldStringTagUintString", - "StructFieldIntPtr", - "StructFieldOmitEmptyIntPtr", - "StructFieldStringTagIntPtr", - "StructFieldUintPtr", - "StructFieldOmitEmptyUintPtr", - "StructFieldStringTagUintPtr", - "StructFieldFloat32Ptr", - "StructFieldOmitEmptyFloat32Ptr", - "StructFieldStringTagFloat32Ptr", - "StructFieldFloat64Ptr", - "StructFieldOmitEmptyFloat64Ptr", - "StructFieldStringTagFloat64Ptr", - "StructFieldBoolPtr", - "StructFieldOmitEmptyBoolPtr", - "StructFieldStringTagBoolPtr", - "StructFieldStringPtr", - "StructFieldOmitEmptyStringPtr", - "StructFieldStringTagStringPtr", - "StructFieldBytesPtr", - "StructFieldOmitEmptyBytesPtr", - "StructFieldStringTagBytesPtr", - "StructFieldNumberPtr", - "StructFieldOmitEmptyNumberPtr", - "StructFieldStringTagNumberPtr", - "StructFieldArrayPtr", - "StructFieldOmitEmptyArrayPtr", - "StructFieldStringTagArrayPtr", - "StructFieldMapPtr", - "StructFieldOmitEmptyMapPtr", - "StructFieldStringTagMapPtr", - "StructFieldSlicePtr", - "StructFieldOmitEmptySlicePtr", - "StructFieldStringTagSlicePtr", - "StructFieldMarshalJSONPtr", - "StructFieldOmitEmptyMarshalJSONPtr", - "StructFieldStringTagMarshalJSONPtr", - "StructFieldMarshalTextPtr", - "StructFieldOmitEmptyMarshalTextPtr", - "StructFieldStringTagMarshalTextPtr", - "StructFieldInterfacePtr", - "StructFieldOmitEmptyInterfacePtr", - "StructFieldStringTagInterfacePtr", - "StructFieldRecursivePtr", - "StructFieldOmitEmptyRecursivePtr", - "StructFieldStringTagRecursivePtr", - "StructField", - "StructFieldOmitEmpty", - "StructFieldStringTag", - "StructEndInt", - "StructEndOmitEmptyInt", - "StructEndStringTagInt", - "StructEndUint", - "StructEndOmitEmptyUint", - "StructEndStringTagUint", - "StructEndFloat32", - "StructEndOmitEmptyFloat32", - "StructEndStringTagFloat32", - "StructEndFloat64", - "StructEndOmitEmptyFloat64", - "StructEndStringTagFloat64", - "StructEndBool", - "StructEndOmitEmptyBool", - "StructEndStringTagBool", - "StructEndString", - "StructEndOmitEmptyString", - "StructEndStringTagString", - "StructEndBytes", - "StructEndOmitEmptyBytes", - "StructEndStringTagBytes", - "StructEndNumber", - "StructEndOmitEmptyNumber", - "StructEndStringTagNumber", - "StructEndArray", - "StructEndOmitEmptyArray", - "StructEndStringTagArray", - "StructEndMap", - "StructEndOmitEmptyMap", - "StructEndStringTagMap", - "StructEndSlice", - "StructEndOmitEmptySlice", - "StructEndStringTagSlice", - "StructEndStruct", - "StructEndOmitEmptyStruct", - "StructEndStringTagStruct", - "StructEndMarshalJSON", - "StructEndOmitEmptyMarshalJSON", - "StructEndStringTagMarshalJSON", - "StructEndMarshalText", - "StructEndOmitEmptyMarshalText", - "StructEndStringTagMarshalText", - "StructEndRecursive", - "StructEndOmitEmptyRecursive", - "StructEndStringTagRecursive", - "StructEndIntString", - "StructEndOmitEmptyIntString", - "StructEndStringTagIntString", - "StructEndUintString", - "StructEndOmitEmptyUintString", - "StructEndStringTagUintString", - "StructEndIntPtr", - "StructEndOmitEmptyIntPtr", - "StructEndStringTagIntPtr", - "StructEndUintPtr", - "StructEndOmitEmptyUintPtr", - "StructEndStringTagUintPtr", - "StructEndFloat32Ptr", - "StructEndOmitEmptyFloat32Ptr", - "StructEndStringTagFloat32Ptr", - "StructEndFloat64Ptr", - "StructEndOmitEmptyFloat64Ptr", - "StructEndStringTagFloat64Ptr", - "StructEndBoolPtr", - "StructEndOmitEmptyBoolPtr", - "StructEndStringTagBoolPtr", - "StructEndStringPtr", - "StructEndOmitEmptyStringPtr", - "StructEndStringTagStringPtr", - "StructEndBytesPtr", - "StructEndOmitEmptyBytesPtr", - "StructEndStringTagBytesPtr", - "StructEndNumberPtr", - "StructEndOmitEmptyNumberPtr", - "StructEndStringTagNumberPtr", - "StructEndArrayPtr", - "StructEndOmitEmptyArrayPtr", - "StructEndStringTagArrayPtr", - "StructEndMapPtr", - "StructEndOmitEmptyMapPtr", - "StructEndStringTagMapPtr", - "StructEndSlicePtr", - "StructEndOmitEmptySlicePtr", - "StructEndStringTagSlicePtr", - "StructEndMarshalJSONPtr", - "StructEndOmitEmptyMarshalJSONPtr", - "StructEndStringTagMarshalJSONPtr", - "StructEndMarshalTextPtr", - "StructEndOmitEmptyMarshalTextPtr", - "StructEndStringTagMarshalTextPtr", - "StructEndInterfacePtr", - "StructEndOmitEmptyInterfacePtr", - "StructEndStringTagInterfacePtr", - "StructEndRecursivePtr", - "StructEndOmitEmptyRecursivePtr", - "StructEndStringTagRecursivePtr", - "StructEnd", - "StructEndOmitEmpty", - "StructEndStringTag", -} - -type opType int - -const ( - opEnd opType = 0 - opInterface opType = 1 - opPtr opType = 2 - opSliceElem opType = 3 - opSliceEnd opType = 4 - opArrayElem opType = 5 - opArrayEnd opType = 6 - opMapKey opType = 7 - opMapValue opType = 8 - opMapEnd opType = 9 - opStructFieldRecursiveEnd opType = 10 - opStructAnonymousEnd opType = 11 - opInt opType = 12 - opUint opType = 13 - opFloat32 opType = 14 - opFloat64 opType = 15 - opBool opType = 16 - opString opType = 17 - opBytes opType = 18 - opNumber opType = 19 - opArray opType = 20 - opMap opType = 21 - opSlice opType = 22 - opStruct opType = 23 - opMarshalJSON opType = 24 - opMarshalText opType = 25 - opRecursive opType = 26 - opIntString opType = 27 - opUintString opType = 28 - opIntPtr opType = 29 - opUintPtr opType = 30 - opFloat32Ptr opType = 31 - opFloat64Ptr opType = 32 - opBoolPtr opType = 33 - opStringPtr opType = 34 - opBytesPtr opType = 35 - opNumberPtr opType = 36 - opArrayPtr opType = 37 - opMapPtr opType = 38 - opSlicePtr opType = 39 - opMarshalJSONPtr opType = 40 - opMarshalTextPtr opType = 41 - opInterfacePtr opType = 42 - opRecursivePtr opType = 43 - opStructFieldHeadInt opType = 44 - opStructFieldHeadOmitEmptyInt opType = 45 - opStructFieldHeadStringTagInt opType = 46 - opStructFieldPtrHeadInt opType = 47 - opStructFieldPtrHeadOmitEmptyInt opType = 48 - opStructFieldPtrHeadStringTagInt opType = 49 - opStructFieldHeadUint opType = 50 - opStructFieldHeadOmitEmptyUint opType = 51 - opStructFieldHeadStringTagUint opType = 52 - opStructFieldPtrHeadUint opType = 53 - opStructFieldPtrHeadOmitEmptyUint opType = 54 - opStructFieldPtrHeadStringTagUint opType = 55 - opStructFieldHeadFloat32 opType = 56 - opStructFieldHeadOmitEmptyFloat32 opType = 57 - opStructFieldHeadStringTagFloat32 opType = 58 - opStructFieldPtrHeadFloat32 opType = 59 - opStructFieldPtrHeadOmitEmptyFloat32 opType = 60 - opStructFieldPtrHeadStringTagFloat32 opType = 61 - opStructFieldHeadFloat64 opType = 62 - opStructFieldHeadOmitEmptyFloat64 opType = 63 - opStructFieldHeadStringTagFloat64 opType = 64 - opStructFieldPtrHeadFloat64 opType = 65 - opStructFieldPtrHeadOmitEmptyFloat64 opType = 66 - opStructFieldPtrHeadStringTagFloat64 opType = 67 - opStructFieldHeadBool opType = 68 - opStructFieldHeadOmitEmptyBool opType = 69 - opStructFieldHeadStringTagBool opType = 70 - opStructFieldPtrHeadBool opType = 71 - opStructFieldPtrHeadOmitEmptyBool opType = 72 - opStructFieldPtrHeadStringTagBool opType = 73 - opStructFieldHeadString opType = 74 - opStructFieldHeadOmitEmptyString opType = 75 - opStructFieldHeadStringTagString opType = 76 - opStructFieldPtrHeadString opType = 77 - opStructFieldPtrHeadOmitEmptyString opType = 78 - opStructFieldPtrHeadStringTagString opType = 79 - opStructFieldHeadBytes opType = 80 - opStructFieldHeadOmitEmptyBytes opType = 81 - opStructFieldHeadStringTagBytes opType = 82 - opStructFieldPtrHeadBytes opType = 83 - opStructFieldPtrHeadOmitEmptyBytes opType = 84 - opStructFieldPtrHeadStringTagBytes opType = 85 - opStructFieldHeadNumber opType = 86 - opStructFieldHeadOmitEmptyNumber opType = 87 - opStructFieldHeadStringTagNumber opType = 88 - opStructFieldPtrHeadNumber opType = 89 - opStructFieldPtrHeadOmitEmptyNumber opType = 90 - opStructFieldPtrHeadStringTagNumber opType = 91 - opStructFieldHeadArray opType = 92 - opStructFieldHeadOmitEmptyArray opType = 93 - opStructFieldHeadStringTagArray opType = 94 - opStructFieldPtrHeadArray opType = 95 - opStructFieldPtrHeadOmitEmptyArray opType = 96 - opStructFieldPtrHeadStringTagArray opType = 97 - opStructFieldHeadMap opType = 98 - opStructFieldHeadOmitEmptyMap opType = 99 - opStructFieldHeadStringTagMap opType = 100 - opStructFieldPtrHeadMap opType = 101 - opStructFieldPtrHeadOmitEmptyMap opType = 102 - opStructFieldPtrHeadStringTagMap opType = 103 - opStructFieldHeadSlice opType = 104 - opStructFieldHeadOmitEmptySlice opType = 105 - opStructFieldHeadStringTagSlice opType = 106 - opStructFieldPtrHeadSlice opType = 107 - opStructFieldPtrHeadOmitEmptySlice opType = 108 - opStructFieldPtrHeadStringTagSlice opType = 109 - opStructFieldHeadStruct opType = 110 - opStructFieldHeadOmitEmptyStruct opType = 111 - opStructFieldHeadStringTagStruct opType = 112 - opStructFieldPtrHeadStruct opType = 113 - opStructFieldPtrHeadOmitEmptyStruct opType = 114 - opStructFieldPtrHeadStringTagStruct opType = 115 - opStructFieldHeadMarshalJSON opType = 116 - opStructFieldHeadOmitEmptyMarshalJSON opType = 117 - opStructFieldHeadStringTagMarshalJSON opType = 118 - opStructFieldPtrHeadMarshalJSON opType = 119 - opStructFieldPtrHeadOmitEmptyMarshalJSON opType = 120 - opStructFieldPtrHeadStringTagMarshalJSON opType = 121 - opStructFieldHeadMarshalText opType = 122 - opStructFieldHeadOmitEmptyMarshalText opType = 123 - opStructFieldHeadStringTagMarshalText opType = 124 - opStructFieldPtrHeadMarshalText opType = 125 - opStructFieldPtrHeadOmitEmptyMarshalText opType = 126 - opStructFieldPtrHeadStringTagMarshalText opType = 127 - opStructFieldHeadRecursive opType = 128 - opStructFieldHeadOmitEmptyRecursive opType = 129 - opStructFieldHeadStringTagRecursive opType = 130 - opStructFieldPtrHeadRecursive opType = 131 - opStructFieldPtrHeadOmitEmptyRecursive opType = 132 - opStructFieldPtrHeadStringTagRecursive opType = 133 - opStructFieldHeadIntString opType = 134 - opStructFieldHeadOmitEmptyIntString opType = 135 - opStructFieldHeadStringTagIntString opType = 136 - opStructFieldPtrHeadIntString opType = 137 - opStructFieldPtrHeadOmitEmptyIntString opType = 138 - opStructFieldPtrHeadStringTagIntString opType = 139 - opStructFieldHeadUintString opType = 140 - opStructFieldHeadOmitEmptyUintString opType = 141 - opStructFieldHeadStringTagUintString opType = 142 - opStructFieldPtrHeadUintString opType = 143 - opStructFieldPtrHeadOmitEmptyUintString opType = 144 - opStructFieldPtrHeadStringTagUintString opType = 145 - opStructFieldHeadIntPtr opType = 146 - opStructFieldHeadOmitEmptyIntPtr opType = 147 - opStructFieldHeadStringTagIntPtr opType = 148 - opStructFieldPtrHeadIntPtr opType = 149 - opStructFieldPtrHeadOmitEmptyIntPtr opType = 150 - opStructFieldPtrHeadStringTagIntPtr opType = 151 - opStructFieldHeadUintPtr opType = 152 - opStructFieldHeadOmitEmptyUintPtr opType = 153 - opStructFieldHeadStringTagUintPtr opType = 154 - opStructFieldPtrHeadUintPtr opType = 155 - opStructFieldPtrHeadOmitEmptyUintPtr opType = 156 - opStructFieldPtrHeadStringTagUintPtr opType = 157 - opStructFieldHeadFloat32Ptr opType = 158 - opStructFieldHeadOmitEmptyFloat32Ptr opType = 159 - opStructFieldHeadStringTagFloat32Ptr opType = 160 - opStructFieldPtrHeadFloat32Ptr opType = 161 - opStructFieldPtrHeadOmitEmptyFloat32Ptr opType = 162 - opStructFieldPtrHeadStringTagFloat32Ptr opType = 163 - opStructFieldHeadFloat64Ptr opType = 164 - opStructFieldHeadOmitEmptyFloat64Ptr opType = 165 - opStructFieldHeadStringTagFloat64Ptr opType = 166 - opStructFieldPtrHeadFloat64Ptr opType = 167 - opStructFieldPtrHeadOmitEmptyFloat64Ptr opType = 168 - opStructFieldPtrHeadStringTagFloat64Ptr opType = 169 - opStructFieldHeadBoolPtr opType = 170 - opStructFieldHeadOmitEmptyBoolPtr opType = 171 - opStructFieldHeadStringTagBoolPtr opType = 172 - opStructFieldPtrHeadBoolPtr opType = 173 - opStructFieldPtrHeadOmitEmptyBoolPtr opType = 174 - opStructFieldPtrHeadStringTagBoolPtr opType = 175 - opStructFieldHeadStringPtr opType = 176 - opStructFieldHeadOmitEmptyStringPtr opType = 177 - opStructFieldHeadStringTagStringPtr opType = 178 - opStructFieldPtrHeadStringPtr opType = 179 - opStructFieldPtrHeadOmitEmptyStringPtr opType = 180 - opStructFieldPtrHeadStringTagStringPtr opType = 181 - opStructFieldHeadBytesPtr opType = 182 - opStructFieldHeadOmitEmptyBytesPtr opType = 183 - opStructFieldHeadStringTagBytesPtr opType = 184 - opStructFieldPtrHeadBytesPtr opType = 185 - opStructFieldPtrHeadOmitEmptyBytesPtr opType = 186 - opStructFieldPtrHeadStringTagBytesPtr opType = 187 - opStructFieldHeadNumberPtr opType = 188 - opStructFieldHeadOmitEmptyNumberPtr opType = 189 - opStructFieldHeadStringTagNumberPtr opType = 190 - opStructFieldPtrHeadNumberPtr opType = 191 - opStructFieldPtrHeadOmitEmptyNumberPtr opType = 192 - opStructFieldPtrHeadStringTagNumberPtr opType = 193 - opStructFieldHeadArrayPtr opType = 194 - opStructFieldHeadOmitEmptyArrayPtr opType = 195 - opStructFieldHeadStringTagArrayPtr opType = 196 - opStructFieldPtrHeadArrayPtr opType = 197 - opStructFieldPtrHeadOmitEmptyArrayPtr opType = 198 - opStructFieldPtrHeadStringTagArrayPtr opType = 199 - opStructFieldHeadMapPtr opType = 200 - opStructFieldHeadOmitEmptyMapPtr opType = 201 - opStructFieldHeadStringTagMapPtr opType = 202 - opStructFieldPtrHeadMapPtr opType = 203 - opStructFieldPtrHeadOmitEmptyMapPtr opType = 204 - opStructFieldPtrHeadStringTagMapPtr opType = 205 - opStructFieldHeadSlicePtr opType = 206 - opStructFieldHeadOmitEmptySlicePtr opType = 207 - opStructFieldHeadStringTagSlicePtr opType = 208 - opStructFieldPtrHeadSlicePtr opType = 209 - opStructFieldPtrHeadOmitEmptySlicePtr opType = 210 - opStructFieldPtrHeadStringTagSlicePtr opType = 211 - opStructFieldHeadMarshalJSONPtr opType = 212 - opStructFieldHeadOmitEmptyMarshalJSONPtr opType = 213 - opStructFieldHeadStringTagMarshalJSONPtr opType = 214 - opStructFieldPtrHeadMarshalJSONPtr opType = 215 - opStructFieldPtrHeadOmitEmptyMarshalJSONPtr opType = 216 - opStructFieldPtrHeadStringTagMarshalJSONPtr opType = 217 - opStructFieldHeadMarshalTextPtr opType = 218 - opStructFieldHeadOmitEmptyMarshalTextPtr opType = 219 - opStructFieldHeadStringTagMarshalTextPtr opType = 220 - opStructFieldPtrHeadMarshalTextPtr opType = 221 - opStructFieldPtrHeadOmitEmptyMarshalTextPtr opType = 222 - opStructFieldPtrHeadStringTagMarshalTextPtr opType = 223 - opStructFieldHeadInterfacePtr opType = 224 - opStructFieldHeadOmitEmptyInterfacePtr opType = 225 - opStructFieldHeadStringTagInterfacePtr opType = 226 - opStructFieldPtrHeadInterfacePtr opType = 227 - opStructFieldPtrHeadOmitEmptyInterfacePtr opType = 228 - opStructFieldPtrHeadStringTagInterfacePtr opType = 229 - opStructFieldHeadRecursivePtr opType = 230 - opStructFieldHeadOmitEmptyRecursivePtr opType = 231 - opStructFieldHeadStringTagRecursivePtr opType = 232 - opStructFieldPtrHeadRecursivePtr opType = 233 - opStructFieldPtrHeadOmitEmptyRecursivePtr opType = 234 - opStructFieldPtrHeadStringTagRecursivePtr opType = 235 - opStructFieldHead opType = 236 - opStructFieldHeadOmitEmpty opType = 237 - opStructFieldHeadStringTag opType = 238 - opStructFieldPtrHead opType = 239 - opStructFieldPtrHeadOmitEmpty opType = 240 - opStructFieldPtrHeadStringTag opType = 241 - opStructFieldInt opType = 242 - opStructFieldOmitEmptyInt opType = 243 - opStructFieldStringTagInt opType = 244 - opStructFieldUint opType = 245 - opStructFieldOmitEmptyUint opType = 246 - opStructFieldStringTagUint opType = 247 - opStructFieldFloat32 opType = 248 - opStructFieldOmitEmptyFloat32 opType = 249 - opStructFieldStringTagFloat32 opType = 250 - opStructFieldFloat64 opType = 251 - opStructFieldOmitEmptyFloat64 opType = 252 - opStructFieldStringTagFloat64 opType = 253 - opStructFieldBool opType = 254 - opStructFieldOmitEmptyBool opType = 255 - opStructFieldStringTagBool opType = 256 - opStructFieldString opType = 257 - opStructFieldOmitEmptyString opType = 258 - opStructFieldStringTagString opType = 259 - opStructFieldBytes opType = 260 - opStructFieldOmitEmptyBytes opType = 261 - opStructFieldStringTagBytes opType = 262 - opStructFieldNumber opType = 263 - opStructFieldOmitEmptyNumber opType = 264 - opStructFieldStringTagNumber opType = 265 - opStructFieldArray opType = 266 - opStructFieldOmitEmptyArray opType = 267 - opStructFieldStringTagArray opType = 268 - opStructFieldMap opType = 269 - opStructFieldOmitEmptyMap opType = 270 - opStructFieldStringTagMap opType = 271 - opStructFieldSlice opType = 272 - opStructFieldOmitEmptySlice opType = 273 - opStructFieldStringTagSlice opType = 274 - opStructFieldStruct opType = 275 - opStructFieldOmitEmptyStruct opType = 276 - opStructFieldStringTagStruct opType = 277 - opStructFieldMarshalJSON opType = 278 - opStructFieldOmitEmptyMarshalJSON opType = 279 - opStructFieldStringTagMarshalJSON opType = 280 - opStructFieldMarshalText opType = 281 - opStructFieldOmitEmptyMarshalText opType = 282 - opStructFieldStringTagMarshalText opType = 283 - opStructFieldRecursive opType = 284 - opStructFieldOmitEmptyRecursive opType = 285 - opStructFieldStringTagRecursive opType = 286 - opStructFieldIntString opType = 287 - opStructFieldOmitEmptyIntString opType = 288 - opStructFieldStringTagIntString opType = 289 - opStructFieldUintString opType = 290 - opStructFieldOmitEmptyUintString opType = 291 - opStructFieldStringTagUintString opType = 292 - opStructFieldIntPtr opType = 293 - opStructFieldOmitEmptyIntPtr opType = 294 - opStructFieldStringTagIntPtr opType = 295 - opStructFieldUintPtr opType = 296 - opStructFieldOmitEmptyUintPtr opType = 297 - opStructFieldStringTagUintPtr opType = 298 - opStructFieldFloat32Ptr opType = 299 - opStructFieldOmitEmptyFloat32Ptr opType = 300 - opStructFieldStringTagFloat32Ptr opType = 301 - opStructFieldFloat64Ptr opType = 302 - opStructFieldOmitEmptyFloat64Ptr opType = 303 - opStructFieldStringTagFloat64Ptr opType = 304 - opStructFieldBoolPtr opType = 305 - opStructFieldOmitEmptyBoolPtr opType = 306 - opStructFieldStringTagBoolPtr opType = 307 - opStructFieldStringPtr opType = 308 - opStructFieldOmitEmptyStringPtr opType = 309 - opStructFieldStringTagStringPtr opType = 310 - opStructFieldBytesPtr opType = 311 - opStructFieldOmitEmptyBytesPtr opType = 312 - opStructFieldStringTagBytesPtr opType = 313 - opStructFieldNumberPtr opType = 314 - opStructFieldOmitEmptyNumberPtr opType = 315 - opStructFieldStringTagNumberPtr opType = 316 - opStructFieldArrayPtr opType = 317 - opStructFieldOmitEmptyArrayPtr opType = 318 - opStructFieldStringTagArrayPtr opType = 319 - opStructFieldMapPtr opType = 320 - opStructFieldOmitEmptyMapPtr opType = 321 - opStructFieldStringTagMapPtr opType = 322 - opStructFieldSlicePtr opType = 323 - opStructFieldOmitEmptySlicePtr opType = 324 - opStructFieldStringTagSlicePtr opType = 325 - opStructFieldMarshalJSONPtr opType = 326 - opStructFieldOmitEmptyMarshalJSONPtr opType = 327 - opStructFieldStringTagMarshalJSONPtr opType = 328 - opStructFieldMarshalTextPtr opType = 329 - opStructFieldOmitEmptyMarshalTextPtr opType = 330 - opStructFieldStringTagMarshalTextPtr opType = 331 - opStructFieldInterfacePtr opType = 332 - opStructFieldOmitEmptyInterfacePtr opType = 333 - opStructFieldStringTagInterfacePtr opType = 334 - opStructFieldRecursivePtr opType = 335 - opStructFieldOmitEmptyRecursivePtr opType = 336 - opStructFieldStringTagRecursivePtr opType = 337 - opStructField opType = 338 - opStructFieldOmitEmpty opType = 339 - opStructFieldStringTag opType = 340 - opStructEndInt opType = 341 - opStructEndOmitEmptyInt opType = 342 - opStructEndStringTagInt opType = 343 - opStructEndUint opType = 344 - opStructEndOmitEmptyUint opType = 345 - opStructEndStringTagUint opType = 346 - opStructEndFloat32 opType = 347 - opStructEndOmitEmptyFloat32 opType = 348 - opStructEndStringTagFloat32 opType = 349 - opStructEndFloat64 opType = 350 - opStructEndOmitEmptyFloat64 opType = 351 - opStructEndStringTagFloat64 opType = 352 - opStructEndBool opType = 353 - opStructEndOmitEmptyBool opType = 354 - opStructEndStringTagBool opType = 355 - opStructEndString opType = 356 - opStructEndOmitEmptyString opType = 357 - opStructEndStringTagString opType = 358 - opStructEndBytes opType = 359 - opStructEndOmitEmptyBytes opType = 360 - opStructEndStringTagBytes opType = 361 - opStructEndNumber opType = 362 - opStructEndOmitEmptyNumber opType = 363 - opStructEndStringTagNumber opType = 364 - opStructEndArray opType = 365 - opStructEndOmitEmptyArray opType = 366 - opStructEndStringTagArray opType = 367 - opStructEndMap opType = 368 - opStructEndOmitEmptyMap opType = 369 - opStructEndStringTagMap opType = 370 - opStructEndSlice opType = 371 - opStructEndOmitEmptySlice opType = 372 - opStructEndStringTagSlice opType = 373 - opStructEndStruct opType = 374 - opStructEndOmitEmptyStruct opType = 375 - opStructEndStringTagStruct opType = 376 - opStructEndMarshalJSON opType = 377 - opStructEndOmitEmptyMarshalJSON opType = 378 - opStructEndStringTagMarshalJSON opType = 379 - opStructEndMarshalText opType = 380 - opStructEndOmitEmptyMarshalText opType = 381 - opStructEndStringTagMarshalText opType = 382 - opStructEndRecursive opType = 383 - opStructEndOmitEmptyRecursive opType = 384 - opStructEndStringTagRecursive opType = 385 - opStructEndIntString opType = 386 - opStructEndOmitEmptyIntString opType = 387 - opStructEndStringTagIntString opType = 388 - opStructEndUintString opType = 389 - opStructEndOmitEmptyUintString opType = 390 - opStructEndStringTagUintString opType = 391 - opStructEndIntPtr opType = 392 - opStructEndOmitEmptyIntPtr opType = 393 - opStructEndStringTagIntPtr opType = 394 - opStructEndUintPtr opType = 395 - opStructEndOmitEmptyUintPtr opType = 396 - opStructEndStringTagUintPtr opType = 397 - opStructEndFloat32Ptr opType = 398 - opStructEndOmitEmptyFloat32Ptr opType = 399 - opStructEndStringTagFloat32Ptr opType = 400 - opStructEndFloat64Ptr opType = 401 - opStructEndOmitEmptyFloat64Ptr opType = 402 - opStructEndStringTagFloat64Ptr opType = 403 - opStructEndBoolPtr opType = 404 - opStructEndOmitEmptyBoolPtr opType = 405 - opStructEndStringTagBoolPtr opType = 406 - opStructEndStringPtr opType = 407 - opStructEndOmitEmptyStringPtr opType = 408 - opStructEndStringTagStringPtr opType = 409 - opStructEndBytesPtr opType = 410 - opStructEndOmitEmptyBytesPtr opType = 411 - opStructEndStringTagBytesPtr opType = 412 - opStructEndNumberPtr opType = 413 - opStructEndOmitEmptyNumberPtr opType = 414 - opStructEndStringTagNumberPtr opType = 415 - opStructEndArrayPtr opType = 416 - opStructEndOmitEmptyArrayPtr opType = 417 - opStructEndStringTagArrayPtr opType = 418 - opStructEndMapPtr opType = 419 - opStructEndOmitEmptyMapPtr opType = 420 - opStructEndStringTagMapPtr opType = 421 - opStructEndSlicePtr opType = 422 - opStructEndOmitEmptySlicePtr opType = 423 - opStructEndStringTagSlicePtr opType = 424 - opStructEndMarshalJSONPtr opType = 425 - opStructEndOmitEmptyMarshalJSONPtr opType = 426 - opStructEndStringTagMarshalJSONPtr opType = 427 - opStructEndMarshalTextPtr opType = 428 - opStructEndOmitEmptyMarshalTextPtr opType = 429 - opStructEndStringTagMarshalTextPtr opType = 430 - opStructEndInterfacePtr opType = 431 - opStructEndOmitEmptyInterfacePtr opType = 432 - opStructEndStringTagInterfacePtr opType = 433 - opStructEndRecursivePtr opType = 434 - opStructEndOmitEmptyRecursivePtr opType = 435 - opStructEndStringTagRecursivePtr opType = 436 - opStructEnd opType = 437 - opStructEndOmitEmpty opType = 438 - opStructEndStringTag opType = 439 -) - -func (t opType) String() string { - if int(t) >= 440 { - return "" - } - return opTypeStrings[int(t)] -} - -func (t opType) codeType() codeType { - if strings.Contains(t.String(), "Struct") { - if strings.Contains(t.String(), "End") { - return codeStructEnd - } - return codeStructField - } - if t.String() == "Array" || t.String() == "ArrayPtr" { - return codeArrayHead - } - if strings.Contains(t.String(), "ArrayElem") { - return codeArrayElem - } - if t.String() == "Slice" || t.String() == "SlicePtr" { - return codeSliceHead - } - if strings.Contains(t.String(), "SliceElem") { - return codeSliceElem - } - if t.String() == "Map" || t.String() == "MapPtr" { - return codeMapHead - } - if strings.Contains(t.String(), "MapKey") { - return codeMapKey - } - if strings.Contains(t.String(), "MapValue") { - return codeMapValue - } - if strings.Contains(t.String(), "MapEnd") { - return codeMapEnd - } - - return codeOp -} - -func (t opType) headToPtrHead() opType { - if strings.Index(t.String(), "PtrHead") > 0 { - return t - } - - idx := strings.Index(t.String(), "Field") - if idx == -1 { - return t - } - suffix := "Ptr" + t.String()[idx+len("Field"):] - - const toPtrOffset = 3 - if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) { - return opType(int(t) + toPtrOffset) - } - return t -} - -func (t opType) headToOmitEmptyHead() opType { - const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) - } - - return t -} - -func (t opType) headToStringTagHead() opType { - const toStringTagOffset = 2 - if strings.Contains(opType(int(t)+toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) - } - return t -} - -func (t opType) ptrHeadToHead() opType { - idx := strings.Index(t.String(), "Ptr") - if idx == -1 { - return t - } - suffix := t.String()[idx+len("Ptr"):] - - const toPtrOffset = 3 - if strings.Contains(opType(int(t)-toPtrOffset).String(), suffix) { - return opType(int(t) - toPtrOffset) - } - return t -} - -func (t opType) fieldToEnd() opType { - switch t { - case opStructFieldInt: - return opStructEndInt - case opStructFieldOmitEmptyInt: - return opStructEndOmitEmptyInt - case opStructFieldStringTagInt: - return opStructEndStringTagInt - case opStructFieldUint: - return opStructEndUint - case opStructFieldOmitEmptyUint: - return opStructEndOmitEmptyUint - case opStructFieldStringTagUint: - return opStructEndStringTagUint - case opStructFieldFloat32: - return opStructEndFloat32 - case opStructFieldOmitEmptyFloat32: - return opStructEndOmitEmptyFloat32 - case opStructFieldStringTagFloat32: - return opStructEndStringTagFloat32 - case opStructFieldFloat64: - return opStructEndFloat64 - case opStructFieldOmitEmptyFloat64: - return opStructEndOmitEmptyFloat64 - case opStructFieldStringTagFloat64: - return opStructEndStringTagFloat64 - case opStructFieldBool: - return opStructEndBool - case opStructFieldOmitEmptyBool: - return opStructEndOmitEmptyBool - case opStructFieldStringTagBool: - return opStructEndStringTagBool - case opStructFieldString: - return opStructEndString - case opStructFieldOmitEmptyString: - return opStructEndOmitEmptyString - case opStructFieldStringTagString: - return opStructEndStringTagString - case opStructFieldBytes: - return opStructEndBytes - case opStructFieldOmitEmptyBytes: - return opStructEndOmitEmptyBytes - case opStructFieldStringTagBytes: - return opStructEndStringTagBytes - case opStructFieldNumber: - return opStructEndNumber - case opStructFieldOmitEmptyNumber: - return opStructEndOmitEmptyNumber - case opStructFieldStringTagNumber: - return opStructEndStringTagNumber - case opStructFieldMarshalJSON: - return opStructEndMarshalJSON - case opStructFieldOmitEmptyMarshalJSON: - return opStructEndOmitEmptyMarshalJSON - case opStructFieldStringTagMarshalJSON: - return opStructEndStringTagMarshalJSON - case opStructFieldMarshalText: - return opStructEndMarshalText - case opStructFieldOmitEmptyMarshalText: - return opStructEndOmitEmptyMarshalText - case opStructFieldStringTagMarshalText: - return opStructEndStringTagMarshalText - case opStructFieldIntString: - return opStructEndIntString - case opStructFieldOmitEmptyIntString: - return opStructEndOmitEmptyIntString - case opStructFieldStringTagIntString: - return opStructEndStringTagIntString - case opStructFieldUintString: - return opStructEndUintString - case opStructFieldOmitEmptyUintString: - return opStructEndOmitEmptyUintString - case opStructFieldStringTagUintString: - return opStructEndStringTagUintString - case opStructFieldIntPtr: - return opStructEndIntPtr - case opStructFieldOmitEmptyIntPtr: - return opStructEndOmitEmptyIntPtr - case opStructFieldStringTagIntPtr: - return opStructEndStringTagIntPtr - case opStructFieldUintPtr: - return opStructEndUintPtr - case opStructFieldOmitEmptyUintPtr: - return opStructEndOmitEmptyUintPtr - case opStructFieldStringTagUintPtr: - return opStructEndStringTagUintPtr - case opStructFieldFloat32Ptr: - return opStructEndFloat32Ptr - case opStructFieldOmitEmptyFloat32Ptr: - return opStructEndOmitEmptyFloat32Ptr - case opStructFieldStringTagFloat32Ptr: - return opStructEndStringTagFloat32Ptr - case opStructFieldFloat64Ptr: - return opStructEndFloat64Ptr - case opStructFieldOmitEmptyFloat64Ptr: - return opStructEndOmitEmptyFloat64Ptr - case opStructFieldStringTagFloat64Ptr: - return opStructEndStringTagFloat64Ptr - case opStructFieldBoolPtr: - return opStructEndBoolPtr - case opStructFieldOmitEmptyBoolPtr: - return opStructEndOmitEmptyBoolPtr - case opStructFieldStringTagBoolPtr: - return opStructEndStringTagBoolPtr - case opStructFieldStringPtr: - return opStructEndStringPtr - case opStructFieldOmitEmptyStringPtr: - return opStructEndOmitEmptyStringPtr - case opStructFieldStringTagStringPtr: - return opStructEndStringTagStringPtr - case opStructFieldBytesPtr: - return opStructEndBytesPtr - case opStructFieldOmitEmptyBytesPtr: - return opStructEndOmitEmptyBytesPtr - case opStructFieldStringTagBytesPtr: - return opStructEndStringTagBytesPtr - case opStructFieldNumberPtr: - return opStructEndNumberPtr - case opStructFieldOmitEmptyNumberPtr: - return opStructEndOmitEmptyNumberPtr - case opStructFieldStringTagNumberPtr: - return opStructEndStringTagNumberPtr - case opStructFieldArrayPtr: - return opStructEndArrayPtr - case opStructFieldOmitEmptyArrayPtr: - return opStructEndOmitEmptyArrayPtr - case opStructFieldStringTagArrayPtr: - return opStructEndStringTagArrayPtr - case opStructFieldMapPtr: - return opStructEndMapPtr - case opStructFieldOmitEmptyMapPtr: - return opStructEndOmitEmptyMapPtr - case opStructFieldStringTagMapPtr: - return opStructEndStringTagMapPtr - case opStructFieldSlicePtr: - return opStructEndSlicePtr - case opStructFieldOmitEmptySlicePtr: - return opStructEndOmitEmptySlicePtr - case opStructFieldStringTagSlicePtr: - return opStructEndStringTagSlicePtr - case opStructFieldMarshalJSONPtr: - return opStructEndMarshalJSONPtr - case opStructFieldOmitEmptyMarshalJSONPtr: - return opStructEndOmitEmptyMarshalJSONPtr - case opStructFieldStringTagMarshalJSONPtr: - return opStructEndStringTagMarshalJSONPtr - case opStructFieldMarshalTextPtr: - return opStructEndMarshalTextPtr - case opStructFieldOmitEmptyMarshalTextPtr: - return opStructEndOmitEmptyMarshalTextPtr - case opStructFieldStringTagMarshalTextPtr: - return opStructEndStringTagMarshalTextPtr - case opStructFieldInterfacePtr: - return opStructEndInterfacePtr - case opStructFieldOmitEmptyInterfacePtr: - return opStructEndOmitEmptyInterfacePtr - case opStructFieldStringTagInterfacePtr: - return opStructEndStringTagInterfacePtr - case opStructFieldRecursivePtr: - return opStructEndRecursivePtr - case opStructFieldOmitEmptyRecursivePtr: - return opStructEndOmitEmptyRecursivePtr - case opStructFieldStringTagRecursivePtr: - return opStructEndStringTagRecursivePtr - } - return t -} - -func (t opType) fieldToOmitEmptyField() opType { - const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) - } - return t -} - -func (t opType) fieldToStringTagField() opType { - const toStringTagOffset = 2 - if strings.Contains(opType(int(t)+toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) - } - return t -} diff --git a/encode_string.go b/encode_string.go deleted file mode 100644 index 7797101..0000000 --- a/encode_string.go +++ /dev/null @@ -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:]...), '"') -} diff --git a/encode_vm.go b/encode_vm.go deleted file mode 100644 index 3893ce1..0000000 --- a/encode_vm.go +++ /dev/null @@ -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, - } -} diff --git a/internal/encoder/compact.go b/internal/encoder/compact.go index e5c5793..cf3f7fa 100644 --- a/internal/encoder/compact.go +++ b/internal/encoder/compact.go @@ -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) } diff --git a/encode_opcode_test.go b/internal/encoder/encode_opcode_test.go similarity index 73% rename from encode_opcode_test.go rename to internal/encoder/encode_opcode_test.go index 96d3a3d..d37d747 100644 --- a/encode_opcode_test.go +++ b/internal/encoder/encode_opcode_test.go @@ -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() } diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index b8baf49..ad9ced5 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -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), diff --git a/internal/encoder/indent.go b/internal/encoder/indent.go index ac76159..fba4519 100644 --- a/internal/encoder/indent.go +++ b/internal/encoder/indent.go @@ -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) diff --git a/json.go b/json.go index d4a92d6..3ebba68 100644 --- a/json.go +++ b/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