mirror of https://github.com/goccy/go-json.git
Merge pull request #310 from goccy/feature/improve-map-encoding-performance
Improve map encoding performance
This commit is contained in:
commit
5686ae09f7
|
@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
break
|
||||
}
|
||||
b = appendStructHead(ctx, b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapiterinit(code.Type, uptr, &mapCtx.Iter)
|
||||
store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
mapCtx.Start = len(b)
|
||||
mapCtx.First = len(b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
case encoder.OpMapKey:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
idx := mapCtx.Idx
|
||||
idx++
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
if idx < mapCtx.Len {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Idx = int(idx)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
if idx < length {
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
|
||||
if idx < mapCtx.Len {
|
||||
mapCtx.Idx = int(idx)
|
||||
mapCtx.Start = len(b)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
|
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendColon(ctx, b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
|
||||
mapCtx.Start = len(b)
|
||||
}
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
value := mapitervalue(iter)
|
||||
value := mapitervalue(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(value))
|
||||
mapiternext(iter)
|
||||
mapiternext(&mapCtx.Iter)
|
||||
code = code.Next
|
||||
case encoder.OpMapEnd:
|
||||
// this operation only used by sorted map.
|
||||
length := int(load(ctxptr, code.Length))
|
||||
ptr := load(ctxptr, code.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
pos := mapCtx.Pos
|
||||
for i := 0; i < length; i++ {
|
||||
startKey := pos[i*2]
|
||||
startValue := pos[i*2+1]
|
||||
var endValue int
|
||||
if i+1 < length {
|
||||
endValue = pos[i*2+2]
|
||||
} else {
|
||||
endValue = len(b)
|
||||
}
|
||||
mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{
|
||||
Key: b[startKey:startValue],
|
||||
Value: b[startValue:endValue],
|
||||
})
|
||||
}
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = b[:mapCtx.First]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
|
|
|
@ -222,33 +222,54 @@ func (m *Mapslice) Swap(i, j int) {
|
|||
m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
|
||||
}
|
||||
|
||||
//nolint:structcheck,unused
|
||||
type mapIter struct {
|
||||
key unsafe.Pointer
|
||||
elem unsafe.Pointer
|
||||
t unsafe.Pointer
|
||||
h unsafe.Pointer
|
||||
buckets unsafe.Pointer
|
||||
bptr unsafe.Pointer
|
||||
overflow unsafe.Pointer
|
||||
oldoverflow unsafe.Pointer
|
||||
startBucket uintptr
|
||||
offset uint8
|
||||
wrapped bool
|
||||
B uint8
|
||||
i uint8
|
||||
bucket uintptr
|
||||
checkBucket uintptr
|
||||
}
|
||||
|
||||
type MapContext struct {
|
||||
Pos []int
|
||||
Start int
|
||||
First int
|
||||
Idx int
|
||||
Slice *Mapslice
|
||||
Buf []byte
|
||||
Len int
|
||||
Iter mapIter
|
||||
}
|
||||
|
||||
var mapContextPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &MapContext{}
|
||||
return &MapContext{
|
||||
Slice: &Mapslice{},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func NewMapContext(mapLen int) *MapContext {
|
||||
ctx := mapContextPool.Get().(*MapContext)
|
||||
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)
|
||||
if len(ctx.Slice.Items) < mapLen {
|
||||
ctx.Slice.Items = make([]MapItem, mapLen)
|
||||
} else {
|
||||
ctx.Pos = ctx.Pos[:0]
|
||||
ctx.Slice.Items = ctx.Slice.Items[:0]
|
||||
ctx.Slice.Items = ctx.Slice.Items[:mapLen]
|
||||
}
|
||||
ctx.Buf = ctx.Buf[:0]
|
||||
ctx.Iter = mapIter{}
|
||||
ctx.Idx = 0
|
||||
ctx.Len = mapLen
|
||||
return ctx
|
||||
}
|
||||
|
||||
|
@ -256,17 +277,17 @@ func ReleaseMapContext(c *MapContext) {
|
|||
mapContextPool.Put(c)
|
||||
}
|
||||
|
||||
//go:linkname MapIterInit reflect.mapiterinit
|
||||
//go:linkname MapIterInit runtime.mapiterinit
|
||||
//go:noescape
|
||||
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter)
|
||||
|
||||
//go:linkname MapIterKey reflect.mapiterkey
|
||||
//go:noescape
|
||||
func MapIterKey(it unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterKey(it *mapIter) unsafe.Pointer
|
||||
|
||||
//go:linkname MapIterNext reflect.mapiternext
|
||||
//go:noescape
|
||||
func MapIterNext(it unsafe.Pointer)
|
||||
func MapIterNext(it *mapIter)
|
||||
|
||||
//go:linkname MapLen reflect.maplen
|
||||
//go:noescape
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !go1.13
|
||||
// +build !go1.13
|
||||
|
||||
package encoder
|
||||
|
@ -5,4 +6,4 @@ package encoder
|
|||
import "unsafe"
|
||||
|
||||
//go:linkname MapIterValue reflect.mapitervalue
|
||||
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterValue(it *mapIter) unsafe.Pointer
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build go1.13
|
||||
// +build go1.13
|
||||
|
||||
package encoder
|
||||
|
@ -5,4 +6,4 @@ package encoder
|
|||
import "unsafe"
|
||||
|
||||
//go:linkname MapIterValue reflect.mapiterelem
|
||||
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterValue(it *mapIter) unsafe.Pointer
|
||||
|
|
|
@ -39,10 +39,8 @@ type Opcode struct {
|
|||
|
||||
Type *runtime.Type // go type
|
||||
Jmp *CompiledCode // for recursive call
|
||||
ElemIdx uint32 // offset to access array/slice/map elem
|
||||
Length uint32 // offset to access slice/map length or array length
|
||||
MapIter uint32 // offset to access map iterator
|
||||
MapPos uint32 // offset to access position list for sorted map
|
||||
ElemIdx uint32 // offset to access array/slice elem
|
||||
Length uint32 // offset to access slice length or array length
|
||||
Indent uint32 // indent number
|
||||
Size uint32 // array/slice elem size
|
||||
DisplayIdx uint32 // opcode index
|
||||
|
@ -91,8 +89,6 @@ func (c *Opcode) MaxIdx() uint32 {
|
|||
c.Idx,
|
||||
c.ElemIdx,
|
||||
c.Length,
|
||||
c.MapIter,
|
||||
c.MapPos,
|
||||
c.Size,
|
||||
} {
|
||||
if max < value {
|
||||
|
@ -341,8 +337,6 @@ func copyOpcode(code *Opcode) *Opcode {
|
|||
DisplayKey: c.DisplayKey,
|
||||
ElemIdx: c.ElemIdx,
|
||||
Length: c.Length,
|
||||
MapIter: c.MapIter,
|
||||
MapPos: c.MapPos,
|
||||
Size: c.Size,
|
||||
Indent: c.Indent,
|
||||
Jmp: c.Jmp,
|
||||
|
@ -448,26 +442,21 @@ func (c *Opcode) dumpHead(code *Opcode) string {
|
|||
|
||||
func (c *Opcode) dumpMapHead(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
code.Idx/uintptrSize,
|
||||
code.ElemIdx/uintptrSize,
|
||||
code.Length/uintptrSize,
|
||||
code.MapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Opcode) dumpMapEnd(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%03d]%s%s ([idx:%d][mapPos:%d][length:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
code.Idx/uintptrSize,
|
||||
code.MapPos/uintptrSize,
|
||||
code.Length/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -504,25 +493,21 @@ func (c *Opcode) dumpField(code *Opcode) string {
|
|||
|
||||
func (c *Opcode) dumpKey(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(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(
|
||||
`[%03d]%s%s ([idx:%d][mapIter:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
code.Idx/uintptrSize,
|
||||
code.MapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -629,19 +614,11 @@ func newArrayElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, leng
|
|||
func newMapHeaderCode(ctx *compileContext, typ *runtime.Type) *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,
|
||||
Type: typ,
|
||||
Idx: idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: elemIdx,
|
||||
Length: length,
|
||||
MapIter: mapIter,
|
||||
Indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
@ -650,11 +627,8 @@ func newMapKeyCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode
|
|||
return &Opcode{
|
||||
Op: OpMapKey,
|
||||
Type: typ,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: head.ElemIdx,
|
||||
Length: head.Length,
|
||||
MapIter: head.MapIter,
|
||||
Indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
@ -663,28 +637,20 @@ func newMapValueCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opco
|
|||
return &Opcode{
|
||||
Op: OpMapValue,
|
||||
Type: typ,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: head.ElemIdx,
|
||||
Length: head.Length,
|
||||
MapIter: head.MapIter,
|
||||
Indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func newMapEndCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
|
||||
mapPos := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
return &Opcode{
|
||||
Op: OpMapEnd,
|
||||
Type: typ,
|
||||
Idx: idx,
|
||||
Next: newEndOp(ctx, typ),
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
Length: head.Length,
|
||||
MapPos: mapPos,
|
||||
Indent: ctx.indent,
|
||||
Next: newEndOp(ctx, typ),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
break
|
||||
}
|
||||
b = appendStructHead(ctx, b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapiterinit(code.Type, uptr, &mapCtx.Iter)
|
||||
store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
mapCtx.Start = len(b)
|
||||
mapCtx.First = len(b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
case encoder.OpMapKey:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
idx := mapCtx.Idx
|
||||
idx++
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
if idx < mapCtx.Len {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Idx = int(idx)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
if idx < length {
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
|
||||
if idx < mapCtx.Len {
|
||||
mapCtx.Idx = int(idx)
|
||||
mapCtx.Start = len(b)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
|
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendColon(ctx, b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
|
||||
mapCtx.Start = len(b)
|
||||
}
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
value := mapitervalue(iter)
|
||||
value := mapitervalue(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(value))
|
||||
mapiternext(iter)
|
||||
mapiternext(&mapCtx.Iter)
|
||||
code = code.Next
|
||||
case encoder.OpMapEnd:
|
||||
// this operation only used by sorted map.
|
||||
length := int(load(ctxptr, code.Length))
|
||||
ptr := load(ctxptr, code.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
pos := mapCtx.Pos
|
||||
for i := 0; i < length; i++ {
|
||||
startKey := pos[i*2]
|
||||
startValue := pos[i*2+1]
|
||||
var endValue int
|
||||
if i+1 < length {
|
||||
endValue = pos[i*2+2]
|
||||
} else {
|
||||
endValue = len(b)
|
||||
}
|
||||
mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{
|
||||
Key: b[startKey:startValue],
|
||||
Value: b[startValue:endValue],
|
||||
})
|
||||
}
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = b[:mapCtx.First]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
|
|
|
@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
break
|
||||
}
|
||||
b = appendStructHead(ctx, b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapiterinit(code.Type, uptr, &mapCtx.Iter)
|
||||
store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
mapCtx.Start = len(b)
|
||||
mapCtx.First = len(b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
case encoder.OpMapKey:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
idx := mapCtx.Idx
|
||||
idx++
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
if idx < mapCtx.Len {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Idx = int(idx)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
if idx < length {
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
|
||||
if idx < mapCtx.Len {
|
||||
mapCtx.Idx = int(idx)
|
||||
mapCtx.Start = len(b)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
|
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendColon(ctx, b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
|
||||
mapCtx.Start = len(b)
|
||||
}
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
value := mapitervalue(iter)
|
||||
value := mapitervalue(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(value))
|
||||
mapiternext(iter)
|
||||
mapiternext(&mapCtx.Iter)
|
||||
code = code.Next
|
||||
case encoder.OpMapEnd:
|
||||
// this operation only used by sorted map.
|
||||
length := int(load(ctxptr, code.Length))
|
||||
ptr := load(ctxptr, code.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
pos := mapCtx.Pos
|
||||
for i := 0; i < length; i++ {
|
||||
startKey := pos[i*2]
|
||||
startValue := pos[i*2+1]
|
||||
var endValue int
|
||||
if i+1 < length {
|
||||
endValue = pos[i*2+2]
|
||||
} else {
|
||||
endValue = len(b)
|
||||
}
|
||||
mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{
|
||||
Key: b[startKey:startValue],
|
||||
Value: b[startValue:endValue],
|
||||
})
|
||||
}
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = b[:mapCtx.First]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
|
|
|
@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
break
|
||||
}
|
||||
b = appendStructHead(ctx, b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapiterinit(code.Type, uptr, &mapCtx.Iter)
|
||||
store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
mapCtx.Start = len(b)
|
||||
mapCtx.First = len(b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
case encoder.OpMapKey:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
idx := mapCtx.Idx
|
||||
idx++
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
if idx < mapCtx.Len {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Idx = int(idx)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
if idx < length {
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
|
||||
if idx < mapCtx.Len {
|
||||
mapCtx.Idx = int(idx)
|
||||
mapCtx.Start = len(b)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
|
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendColon(ctx, b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
|
||||
mapCtx.Start = len(b)
|
||||
}
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
value := mapitervalue(iter)
|
||||
value := mapitervalue(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(value))
|
||||
mapiternext(iter)
|
||||
mapiternext(&mapCtx.Iter)
|
||||
code = code.Next
|
||||
case encoder.OpMapEnd:
|
||||
// this operation only used by sorted map.
|
||||
length := int(load(ctxptr, code.Length))
|
||||
ptr := load(ctxptr, code.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
pos := mapCtx.Pos
|
||||
for i := 0; i < length; i++ {
|
||||
startKey := pos[i*2]
|
||||
startValue := pos[i*2+1]
|
||||
var endValue int
|
||||
if i+1 < length {
|
||||
endValue = pos[i*2+2]
|
||||
} else {
|
||||
endValue = len(b)
|
||||
}
|
||||
mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{
|
||||
Key: b[startKey:startValue],
|
||||
Value: b[startValue:endValue],
|
||||
})
|
||||
}
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = b[:mapCtx.First]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
|
|
|
@ -403,48 +403,41 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
break
|
||||
}
|
||||
b = appendStructHead(ctx, b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapiterinit(code.Type, uptr, &mapCtx.Iter)
|
||||
store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
mapCtx := encoder.NewMapContext(mlen)
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
mapCtx.Start = len(b)
|
||||
mapCtx.First = len(b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
case encoder.OpMapKey:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
idx := mapCtx.Idx
|
||||
idx++
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
if idx < mapCtx.Len {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Idx = int(idx)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
if idx < length {
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)]
|
||||
if idx < mapCtx.Len {
|
||||
mapCtx.Idx = int(idx)
|
||||
mapCtx.Start = len(b)
|
||||
key := mapiterkey(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
|
@ -452,46 +445,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 {
|
||||
b = appendColon(ctx, b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)]
|
||||
mapCtx.Start = len(b)
|
||||
}
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
value := mapitervalue(iter)
|
||||
value := mapitervalue(&mapCtx.Iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(value))
|
||||
mapiternext(iter)
|
||||
mapiternext(&mapCtx.Iter)
|
||||
code = code.Next
|
||||
case encoder.OpMapEnd:
|
||||
// this operation only used by sorted map.
|
||||
length := int(load(ctxptr, code.Length))
|
||||
ptr := load(ctxptr, code.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
pos := mapCtx.Pos
|
||||
for i := 0; i < length; i++ {
|
||||
startKey := pos[i*2]
|
||||
startValue := pos[i*2+1]
|
||||
var endValue int
|
||||
if i+1 < length {
|
||||
endValue = pos[i*2+2]
|
||||
} else {
|
||||
endValue = len(b)
|
||||
}
|
||||
mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{
|
||||
Key: b[startKey:startValue],
|
||||
Value: b[startValue:endValue],
|
||||
})
|
||||
}
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx)))
|
||||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = b[:mapCtx.First]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
encoder.ReleaseMapContext(mapCtx)
|
||||
|
|
|
@ -11,8 +11,8 @@ func TestOpcodeSize(t *testing.T) {
|
|||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
if uintptrSize == 8 {
|
||||
size := unsafe.Sizeof(encoder.Opcode{})
|
||||
if size != 120 {
|
||||
t.Fatalf("unexpected opcode size: expected 120bytes but got %dbytes", size)
|
||||
if size != 112 {
|
||||
t.Fatalf("unexpected opcode size: expected 112bytes but got %dbytes", size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue