diff --git a/coverage_test.go b/coverage_test.go index 43f194e..5ff342e 100644 --- a/coverage_test.go +++ b/coverage_test.go @@ -14,6 +14,27 @@ func int8ptr(v int8) *int8 { return &v } +func headIntPtrNilNotRoot() interface{} { + v := struct { + A struct { + A *int `json:"a"` + } + }{} + return v +} + +func ptrHeadIntNotRoot() interface{} { + v := struct { + A *struct { + A int `json:"a"` + } + }{A: new(struct { + A int `json:"a"` + })} + v.A.A = 1 + return v +} + func TestCoverage(t *testing.T) { tests := []struct { name string @@ -21,44 +42,78 @@ func TestCoverage(t *testing.T) { data interface{} }{ { - name: "IntHead", + name: "HeadIntZero", + expected: `{"a":0}`, + data: struct { + A int `json:"a"` + }{}, + }, + { + name: "HeadInt", expected: `{"a":1}`, data: struct { A int `json:"a"` }{A: 1}, }, { - name: "IntPtrHead", + name: "HeadIntPtr", expected: `{"a":1}`, data: struct { A *int `json:"a"` }{A: intptr(1)}, }, - /* - { - name: "IntPtrNilHead", - expected: `{"a":null}`, - data: struct { - A *int `json:"a"` - }{A: nil}, - }, - */ { - name: "PtrIntHead", + name: "HeadIntPtrNil", + expected: `{"a":null}`, + data: struct { + A *int `json:"a"` + }{A: nil}, + }, + { + name: "PtrHeadIntZero", + expected: `{"a":0}`, + data: &struct { + A int `json:"a"` + }{}, + }, + { + name: "PtrHeadInt", expected: `{"a":1}`, data: &struct { A int `json:"a"` }{A: 1}, }, { - name: "PtrIntPtrHead", + name: "PtrHeadIntPtr", expected: `{"a":1}`, data: &struct { A *int `json:"a"` }{A: intptr(1)}, }, { - name: "IntField", + name: "PtrHeadIntPtrNil", + expected: `{"a":null}`, + data: &struct { + A *int `json:"a"` + }{A: nil}, + }, + { + name: "PtrHeadIntNil", + expected: `null`, + data: (*struct { + A *int `json:"a"` + })(nil), + }, + { + name: "HeadIntZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: struct { + A int `json:"a"` + B int `json:"b"` + }{}, + }, + { + name: "HeadIntMultiFields", expected: `{"a":1,"b":2}`, data: struct { A int `json:"a"` @@ -66,13 +121,232 @@ func TestCoverage(t *testing.T) { }{A: 1, B: 2}, }, { - name: "IntPtrField", + name: "HeadIntPtrMultiFields", expected: `{"a":1,"b":2}`, data: struct { A *int `json:"a"` B *int `json:"b"` }{A: intptr(1), B: intptr(2)}, }, + { + name: "HeadIntPtrNilMultiFieldsd", + expected: `{"a":null,"b":null}`, + data: struct { + A *int `json:"a"` + B *int `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadIntZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: &struct { + A int `json:"a"` + B int `json:"b"` + }{}, + }, + { + name: "PtrHeadIntMultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A int `json:"a"` + B int `json:"b"` + }{A: 1, B: 2}, + }, + { + name: "PtrHeadIntPtrMultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A *int `json:"a"` + B *int `json:"b"` + }{A: intptr(1), B: intptr(2)}, + }, + { + name: "PtrHeadIntPtrNilMultiFields", + expected: `{"a":null,"b":null}`, + data: &struct { + A *int `json:"a"` + B *int `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadIntNilMultiFields", + expected: `null`, + data: (*struct { + A *int `json:"a"` + B *int `json:"b"` + })(nil), + }, + + { + name: "HeadIntZeroNotRoot", + expected: `{"A":{"a":0}}`, + data: struct { + A struct { + A int `json:"a"` + } + }{}, + }, + { + name: "HeadIntNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A struct { + A int `json:"a"` + } + }{A: struct { + A int `json:"a"` + }{A: 1}}, + }, + { + name: "HeadIntPtrNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A struct { + A *int `json:"a"` + } + }{A: struct { + A *int `json:"a"` + }{intptr(1)}}, + }, + /* + { + name: "HeadIntPtrNilNotRoot", + expected: `{"A":{"a":null}}`, + data: struct { + A struct { + A *int `json:"a"` + } + }{}, + }, + { + name: "PtrHeadIntZeroNotRoot", + expected: `{"A":{"a":0}}`, + data: struct { + A *struct { + A int `json:"a"` + } + }{A: new(struct { + A int `json:"a"` + })}, + }, + { + name: "PtrHeadIntNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A *struct { + A int `json:"a"` + } + }{A: &(struct { + A int `json:"a"` + }{A: 1})}, + }, + { + name: "PtrHeadIntPtrNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A *struct { + A *int `json:"a"` + } + }{A: &(struct { + A *int `json:"a"` + }{A: intptr(1)})}, + }, + { + name: "PtrHeadIntPtrNilNotRoot", + expected: `{"A":{"a":null}}`, + data: struct { + A *struct { + A *int `json:"a"` + } + }{A: &(struct { + A *int `json:"a"` + }{A: nil})}, + }, + */ + /* + { + name: "PtrHeadIntNilNotRoot", + expected: `{"A":null}`, + data: struct { + A *struct { + A *int `json:"a"` + } + }{A: nil}, + }, + */ + { + name: "HeadIntZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: struct { + A int `json:"a"` + B int `json:"b"` + }{}, + }, + { + name: "HeadIntMultiFields", + expected: `{"a":1,"b":2}`, + data: struct { + A int `json:"a"` + B int `json:"b"` + }{A: 1, B: 2}, + }, + { + name: "HeadIntPtrMultiFields", + expected: `{"a":1,"b":2}`, + data: struct { + A *int `json:"a"` + B *int `json:"b"` + }{A: intptr(1), B: intptr(2)}, + }, + { + name: "HeadIntPtrNilMultiFieldsd", + expected: `{"a":null,"b":null}`, + data: struct { + A *int `json:"a"` + B *int `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadIntZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: &struct { + A int `json:"a"` + B int `json:"b"` + }{}, + }, + { + name: "PtrHeadIntMultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A int `json:"a"` + B int `json:"b"` + }{A: 1, B: 2}, + }, + { + name: "PtrHeadIntPtrMultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A *int `json:"a"` + B *int `json:"b"` + }{A: intptr(1), B: intptr(2)}, + }, + { + name: "PtrHeadIntPtrNilMultiFields", + expected: `{"a":null,"b":null}`, + data: &struct { + A *int `json:"a"` + B *int `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadIntNilMultiFields", + expected: `null`, + data: (*struct { + A *int `json:"a"` + B *int `json:"b"` + })(nil), + }, + { name: "Int8Head", expected: `{"a":1}`, @@ -133,10 +407,10 @@ func TestCoverage(t *testing.T) { enc := NewEncoder(&buf) enc.SetEscapeHTML(htmlEscape) if err := enc.Encode(test.data); err != nil { - t.Fatalf("%s(htmlEscape:%T): %s: %s", test.name, htmlEscape, test.expected, err) + t.Errorf("%s(htmlEscape:%T): %s: %s", test.name, htmlEscape, test.expected, err) } if strings.TrimRight(buf.String(), "\n") != test.expected { - t.Fatalf("%s(htmlEscape:%T): expected %q but got %q", test.name, htmlEscape, test.expected, buf.String()) + t.Errorf("%s(htmlEscape:%T): expected %q but got %q", test.name, htmlEscape, test.expected, buf.String()) } } } diff --git a/encode_compile.go b/encode_compile.go index 0721cec..e40092f 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -536,126 +536,251 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode, return (*opcode)(unsafe.Pointer(header)), nil } -func (e *Encoder) typeToHeaderType(ctx *encodeCompileContext, code *opcode) opType { - switch code.op { - case opPtr: - ptrNum := 1 - c := code - ctx.decIndex() - for { - if code.next.op == opPtr { - ptrNum++ - code = code.next - ctx.decIndex() +func (e *Encoder) typeToHeaderType(ctx *encodeCompileContext, code *opcode, isOnlyPtrField bool) opType { + if isOnlyPtrField { + // 1. pointer struct + primitive type field + // 2. struct + primitive pointer type field + switch code.op { + case opPtr: + ptrNum := 1 + c := code + ctx.decIndex() + for { + if code.next.op == opPtr { + ptrNum++ + code = code.next + ctx.decIndex() + } + break } - break + c.ptrNum = ptrNum + if ptrNum > 1 { + switch code.next.op { + case opInt: + return opStructFieldHeadIntNPtrOnly + case opInt8: + return opStructFieldHeadInt8NPtrOnly + case opInt16: + return opStructFieldHeadInt16NPtrOnly + case opInt32: + return opStructFieldHeadInt32NPtrOnly + case opInt64: + return opStructFieldHeadInt64NPtrOnly + case opUint: + return opStructFieldHeadUintNPtrOnly + case opUint8: + return opStructFieldHeadUint8NPtrOnly + case opUint16: + return opStructFieldHeadUint16NPtrOnly + case opUint32: + return opStructFieldHeadUint32NPtrOnly + case opUint64: + return opStructFieldHeadUint64NPtrOnly + case opFloat32: + return opStructFieldHeadFloat32NPtrOnly + case opFloat64: + return opStructFieldHeadFloat64NPtrOnly + case opString: + return opStructFieldHeadStringNPtrOnly + case opBool: + return opStructFieldHeadBoolNPtrOnly + } + } else { + switch code.next.op { + case opInt: + return opStructFieldHeadIntPtrOnly + case opInt8: + return opStructFieldHeadInt8PtrOnly + case opInt16: + return opStructFieldHeadInt16PtrOnly + case opInt32: + return opStructFieldHeadInt32PtrOnly + case opInt64: + return opStructFieldHeadInt64PtrOnly + case opUint: + return opStructFieldHeadUintPtrOnly + case opUint8: + return opStructFieldHeadUint8PtrOnly + case opUint16: + return opStructFieldHeadUint16PtrOnly + case opUint32: + return opStructFieldHeadUint32PtrOnly + case opUint64: + return opStructFieldHeadUint64PtrOnly + case opFloat32: + return opStructFieldHeadFloat32PtrOnly + case opFloat64: + return opStructFieldHeadFloat64PtrOnly + case opString: + return opStructFieldHeadStringPtrOnly + case opBool: + return opStructFieldHeadBoolPtrOnly + } + } + case opInt: + return opStructFieldHeadIntOnly + case opInt8: + return opStructFieldHeadInt8Only + case opInt16: + return opStructFieldHeadInt16Only + case opInt32: + return opStructFieldHeadInt32Only + case opInt64: + return opStructFieldHeadInt64Only + case opUint: + return opStructFieldHeadUintOnly + case opUint8: + return opStructFieldHeadUint8Only + case opUint16: + return opStructFieldHeadUint16Only + case opUint32: + return opStructFieldHeadUint32Only + case opUint64: + return opStructFieldHeadUint64Only + case opFloat32: + return opStructFieldHeadFloat32Only + case opFloat64: + return opStructFieldHeadFloat64Only + case opString: + return opStructFieldHeadStringOnly + case opBool: + return opStructFieldHeadBoolOnly + case opMapHead: + return opStructFieldHeadMap + case opMapHeadLoad: + return opStructFieldHeadMapLoad + case opArrayHead: + return opStructFieldHeadArray + case opSliceHead: + return opStructFieldHeadSlice + case opStructFieldHead: + return opStructFieldHeadStruct + case opMarshalJSON: + return opStructFieldHeadMarshalJSON + case opMarshalText: + return opStructFieldHeadMarshalText } - c.ptrNum = ptrNum - if ptrNum > 1 { - switch code.next.op { - case opInt: - return opStructFieldHeadIntNPtr - case opInt8: - return opStructFieldHeadInt8NPtr - case opInt16: - return opStructFieldHeadInt16NPtr - case opInt32: - return opStructFieldHeadInt32NPtr - case opInt64: - return opStructFieldHeadInt64NPtr - case opUint: - return opStructFieldHeadUintNPtr - case opUint8: - return opStructFieldHeadUint8NPtr - case opUint16: - return opStructFieldHeadUint16NPtr - case opUint32: - return opStructFieldHeadUint32NPtr - case opUint64: - return opStructFieldHeadUint64NPtr - case opFloat32: - return opStructFieldHeadFloat32NPtr - case opFloat64: - return opStructFieldHeadFloat64NPtr - case opString: - return opStructFieldHeadStringNPtr - case opBool: - return opStructFieldHeadBoolNPtr + } else { + switch code.op { + case opPtr: + ptrNum := 1 + c := code + ctx.decIndex() + for { + if code.next.op == opPtr { + ptrNum++ + code = code.next + ctx.decIndex() + } + break } - } else { - switch code.next.op { - case opInt: - return opStructFieldHeadIntPtr - case opInt8: - return opStructFieldHeadInt8Ptr - case opInt16: - return opStructFieldHeadInt16Ptr - case opInt32: - return opStructFieldHeadInt32Ptr - case opInt64: - return opStructFieldHeadInt64Ptr - case opUint: - return opStructFieldHeadUintPtr - case opUint8: - return opStructFieldHeadUint8Ptr - case opUint16: - return opStructFieldHeadUint16Ptr - case opUint32: - return opStructFieldHeadUint32Ptr - case opUint64: - return opStructFieldHeadUint64Ptr - case opFloat32: - return opStructFieldHeadFloat32Ptr - case opFloat64: - return opStructFieldHeadFloat64Ptr - case opString: - return opStructFieldHeadStringPtr - case opBool: - return opStructFieldHeadBoolPtr + c.ptrNum = ptrNum + if ptrNum > 1 { + switch code.next.op { + case opInt: + return opStructFieldHeadIntNPtr + case opInt8: + return opStructFieldHeadInt8NPtr + case opInt16: + return opStructFieldHeadInt16NPtr + case opInt32: + return opStructFieldHeadInt32NPtr + case opInt64: + return opStructFieldHeadInt64NPtr + case opUint: + return opStructFieldHeadUintNPtr + case opUint8: + return opStructFieldHeadUint8NPtr + case opUint16: + return opStructFieldHeadUint16NPtr + case opUint32: + return opStructFieldHeadUint32NPtr + case opUint64: + return opStructFieldHeadUint64NPtr + case opFloat32: + return opStructFieldHeadFloat32NPtr + case opFloat64: + return opStructFieldHeadFloat64NPtr + case opString: + return opStructFieldHeadStringNPtr + case opBool: + return opStructFieldHeadBoolNPtr + } + } else { + switch code.next.op { + case opInt: + return opStructFieldHeadIntPtr + case opInt8: + return opStructFieldHeadInt8Ptr + case opInt16: + return opStructFieldHeadInt16Ptr + case opInt32: + return opStructFieldHeadInt32Ptr + case opInt64: + return opStructFieldHeadInt64Ptr + case opUint: + return opStructFieldHeadUintPtr + case opUint8: + return opStructFieldHeadUint8Ptr + case opUint16: + return opStructFieldHeadUint16Ptr + case opUint32: + return opStructFieldHeadUint32Ptr + case opUint64: + return opStructFieldHeadUint64Ptr + case opFloat32: + return opStructFieldHeadFloat32Ptr + case opFloat64: + return opStructFieldHeadFloat64Ptr + case opString: + return opStructFieldHeadStringPtr + case opBool: + return opStructFieldHeadBoolPtr + } } + case opInt: + return opStructFieldHeadInt + case opInt8: + return opStructFieldHeadInt8 + case opInt16: + return opStructFieldHeadInt16 + case opInt32: + return opStructFieldHeadInt32 + case opInt64: + return opStructFieldHeadInt64 + case opUint: + return opStructFieldHeadUint + case opUint8: + return opStructFieldHeadUint8 + case opUint16: + return opStructFieldHeadUint16 + case opUint32: + return opStructFieldHeadUint32 + case opUint64: + return opStructFieldHeadUint64 + case opFloat32: + return opStructFieldHeadFloat32 + case opFloat64: + return opStructFieldHeadFloat64 + case opString: + return opStructFieldHeadString + case opBool: + return opStructFieldHeadBool + case opMapHead: + return opStructFieldHeadMap + case opMapHeadLoad: + return opStructFieldHeadMapLoad + case opArrayHead: + return opStructFieldHeadArray + case opSliceHead: + return opStructFieldHeadSlice + case opStructFieldHead: + return opStructFieldHeadStruct + case opMarshalJSON: + return opStructFieldHeadMarshalJSON + case opMarshalText: + return opStructFieldHeadMarshalText } - case opInt: - return opStructFieldHeadInt - case opInt8: - return opStructFieldHeadInt8 - case opInt16: - return opStructFieldHeadInt16 - case opInt32: - return opStructFieldHeadInt32 - case opInt64: - return opStructFieldHeadInt64 - case opUint: - return opStructFieldHeadUint - case opUint8: - return opStructFieldHeadUint8 - case opUint16: - return opStructFieldHeadUint16 - case opUint32: - return opStructFieldHeadUint32 - case opUint64: - return opStructFieldHeadUint64 - case opFloat32: - return opStructFieldHeadFloat32 - case opFloat64: - return opStructFieldHeadFloat64 - case opString: - return opStructFieldHeadString - case opBool: - return opStructFieldHeadBool - case opMapHead: - return opStructFieldHeadMap - case opMapHeadLoad: - return opStructFieldHeadMapLoad - case opArrayHead: - return opStructFieldHeadArray - case opSliceHead: - return opStructFieldHeadSlice - case opStructFieldHead: - return opStructFieldHeadStruct - case opMarshalJSON: - return opStructFieldHeadMarshalJSON - case opMarshalText: - return opStructFieldHeadMarshalText } return opStructFieldHead } @@ -784,8 +909,8 @@ func (e *Encoder) typeToFieldType(ctx *encodeCompileContext, code *opcode) opTyp return opStructField } -func (e *Encoder) optimizeStructHeader(ctx *encodeCompileContext, code *opcode, tag *structTag) opType { - headType := e.typeToHeaderType(ctx, code) +func (e *Encoder) optimizeStructHeader(ctx *encodeCompileContext, code *opcode, tag *structTag, isOnlyPtrField bool) opType { + headType := e.typeToHeaderType(ctx, code, isOnlyPtrField) switch { case tag.isOmitEmpty: headType = headType.headToOmitEmptyHead() @@ -821,9 +946,9 @@ func (e *Encoder) compiledCode(ctx *encodeCompileContext) *opcode { return nil } -func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode { +func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag, isOnlyPtrField bool) *opcode { fieldCode.indent-- - op := e.optimizeStructHeader(ctx, valueCode, tag) + op := e.optimizeStructHeader(ctx, valueCode, tag, isOnlyPtrField) fieldCode.op = op fieldCode.ptrNum = valueCode.ptrNum switch op { @@ -1103,17 +1228,10 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, } } - if fieldNum == 1 && valueCode.op == opPtr && !isPtr { - // if field number is one and primitive pointer type, - // it should encode as **not** pointer . - switch valueCode.next.op { - case opInt, opInt8, opInt16, opInt32, opInt64, - opUint, opUint8, opUint16, opUint32, opUint64, - opFloat32, opFloat64, opBool, opString, opBytes: - valueCode = valueCode.next - ctx.decOpcodeIndex() - } - } + // if field number is one and primitive pointer type, + // it should encode as special opcode. + isOnlyPtrField := fieldNum == 1 && (valueCode.op == opPtr && !isPtr || valueCode.op != opPtr && isPtr) + key := fmt.Sprintf(`"%s":`, tag.key) escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key))) fieldCode := &opcode{ @@ -1131,7 +1249,7 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, } if fieldIdx == 0 { fieldCode.headIdx = fieldCode.idx - code = e.structHeader(ctx, fieldCode, valueCode, tag) + code = e.structHeader(ctx, fieldCode, valueCode, tag, isOnlyPtrField) head = fieldCode prevField = fieldCode } else { diff --git a/encode_vm.go b/encode_vm.go index 391b826..83f6eea 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -1236,6 +1236,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte code = code.next store(ctxptr, code.idx, ptr) } + case opStructFieldPtrHeadIntOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + fallthrough + case opStructFieldHeadIntOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + b = appendInt(b, int64(e.ptrToInt(p))) + b = encodeComma(b) + code = code.next case opStructFieldPtrHeadInt: p := load(ctxptr, code.idx) if p == 0 { @@ -1247,22 +1263,28 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte store(ctxptr, code.idx, e.ptrToPtr(p)) fallthrough case opStructFieldHeadInt: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - if code.op == opStructFieldPtrHeadInt { - b = encodeNull(b) - b = encodeComma(b) - } else { - b = append(b, '{', '}', ',') - } - code = code.end.next - } else { - b = append(b, '{') - b = append(b, code.key...) - b = appendInt(b, int64(e.ptrToInt(ptr+code.offset))) + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + b = appendInt(b, int64(e.ptrToInt(p+code.offset))) + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrHeadIntOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) b = encodeComma(b) - code = code.next + code = code.end.next + break } + fallthrough + case opStructEscapedFieldHeadIntOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = appendInt(b, int64(e.ptrToInt(p))) + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadInt: p := load(ctxptr, code.idx) if p == 0 { @@ -1274,22 +1296,33 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte store(ctxptr, code.idx, e.ptrToPtr(p)) fallthrough case opStructEscapedFieldHeadInt: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - if code.op == opStructEscapedFieldPtrHeadInt { - b = encodeNull(b) - b = encodeComma(b) - } else { - b = append(b, '{', '}', ',') - } - code = code.end.next - } else { - b = append(b, '{') - b = append(b, code.escapedKey...) - b = appendInt(b, int64(e.ptrToInt(ptr+code.offset))) + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = appendInt(b, int64(e.ptrToInt(p+code.offset))) + b = encodeComma(b) + code = code.next + case opStructFieldPtrHeadIntPtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) b = encodeComma(b) - code = code.next + code = code.end.next + break } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructFieldHeadIntPtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt(p+code.offset))) + } + b = encodeComma(b) + code = code.next case opStructFieldPtrHeadIntPtr: p := load(ctxptr, code.idx) if p == 0 { @@ -1304,16 +1337,38 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte p := load(ctxptr, code.idx) if p == 0 { b = encodeNull(b) + b = encodeComma(b) code = code.end.next + break + } + b = append(b, '{') + b = append(b, code.key...) + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) } else { - b = append(b, '{') - b = append(b, code.key...) - p = e.ptrToPtr(p) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, int64(e.ptrToInt(p+code.offset))) - } + b = appendInt(b, int64(e.ptrToInt(p+code.offset))) + } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrHeadIntPtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructEscapedFieldHeadIntPtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt(p+code.offset))) } b = encodeComma(b) code = code.next @@ -1331,19 +1386,20 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte p := load(ctxptr, code.idx) if p == 0 { b = encodeNull(b) + b = encodeComma(b) code = code.end.next + break + } + b = append(b, '{') + b = append(b, code.escapedKey...) + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) } else { - b = append(b, '{') - b = append(b, code.escapedKey...) - p = e.ptrToPtr(p) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, int64(e.ptrToInt(p+code.offset))) - } - code = code.next + b = appendInt(b, int64(e.ptrToInt(p+code.offset))) } b = encodeComma(b) + code = code.next case opStructFieldHeadIntNPtr: p := load(ctxptr, code.idx) if p == 0 { @@ -1413,6 +1469,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructFieldPtrHeadInt8Only: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + fallthrough + case opStructFieldHeadInt8Only: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + b = appendInt(b, int64(e.ptrToInt8(p))) + b = encodeComma(b) + code = code.next case opStructFieldPtrHeadInt8: p := load(ctxptr, code.idx) if p == 0 { @@ -1440,6 +1512,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructEscapedFieldPtrHeadInt8Only: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + fallthrough + case opStructEscapedFieldHeadInt8Only: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = appendInt(b, int64(e.ptrToInt8(p))) + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadInt8: p := load(ctxptr, code.idx) if p == 0 { @@ -1467,6 +1555,27 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructFieldPtrHeadInt8PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructFieldHeadInt8PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt8(p))) + } + b = encodeComma(b) + code = code.next case opStructFieldPtrHeadInt8Ptr: p := load(ctxptr, code.idx) if p == 0 { @@ -1494,6 +1603,27 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte code = code.next } b = encodeComma(b) + case opStructEscapedFieldPtrHeadInt8PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructEscapedFieldHeadInt8PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt8(p))) + } + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadInt8Ptr: p := load(ctxptr, code.idx) if p == 0 { @@ -2390,6 +2520,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructEscapedFieldPtrHeadEscapedStringOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + fallthrough + case opStructEscapedFieldHeadEscapedStringOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = encodeEscapedString(b, e.ptrToString(p)) + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadEscapedString: p := load(ctxptr, code.idx) if p == 0 { @@ -2470,6 +2616,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructEscapedFieldPtrHeadBoolOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + fallthrough + case opStructEscapedFieldHeadBoolOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = encodeBool(b, e.ptrToBool(p)) + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadBool: p := load(ctxptr, code.idx) if p == 0 { @@ -3827,6 +3989,24 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte code = code.next } } + case opStructEscapedFieldPtrHeadOmitEmptyIntOnly: + ptr := load(ctxptr, code.idx) + if ptr != 0 { + store(ctxptr, code.idx, e.ptrToPtr(ptr)) + } + fallthrough + case opStructEscapedFieldHeadOmitEmptyIntOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + v := e.ptrToInt(p) + if v == 0 { + code = code.nextField + } else { + b = append(b, code.escapedKey...) + b = appendInt(b, int64(v)) + b = encodeComma(b) + code = code.next + } case opStructEscapedFieldPtrHeadOmitEmptyInt: ptr := load(ctxptr, code.idx) if ptr != 0 { @@ -6782,6 +6962,22 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + + case opStructEscapedFieldPtrHeadStringTagInt64PtrOnly: + ptr := load(ctxptr, code.idx) + if ptr != 0 { + store(ctxptr, code.idx, e.ptrToPtr(ptr)) + } + fallthrough + case opStructEscapedFieldHeadStringTagInt64PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = append(b, '"') + b = appendInt(b, e.ptrToInt64(p)) + b = append(b, '"') + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadStringTagInt64: ptr := load(ctxptr, code.idx) if ptr != 0 { @@ -7496,6 +7692,21 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructEscapedFieldPtrHeadStringTagBoolOnly: + ptr := load(ctxptr, code.idx) + if ptr != 0 { + store(ctxptr, code.idx, e.ptrToPtr(ptr)) + } + fallthrough + case opStructEscapedFieldHeadStringTagBoolOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = append(b, '"') + b = encodeBool(b, e.ptrToBool(p)) + b = append(b, '"') + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadStringTagBool: ptr := load(ctxptr, code.idx) if ptr != 0 {