Optimize map operation

This commit is contained in:
Masaaki Goshima 2021-01-25 13:10:07 +09:00
parent 0be236361a
commit 02797daba4
4 changed files with 82 additions and 103 deletions

View File

@ -378,11 +378,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) (
store(ctxptr, code.length, uintptr(mlen)) store(ctxptr, code.length, uintptr(mlen))
store(ctxptr, code.mapIter, uintptr(iter)) store(ctxptr, code.mapIter, uintptr(iter))
if !e.unorderedMap { if !e.unorderedMap {
pos := make([]int, 0, mlen) mapCtx := newMapContext(mlen)
pos = append(pos, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
posPtr := unsafe.Pointer(&pos) ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx))
ctx.keepRefs = append(ctx.keepRefs, posPtr) store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.end.mapPos, uintptr(posPtr))
} }
key := mapiterkey(iter) key := mapiterkey(iter)
store(ctxptr, code.next.idx, uintptr(key)) store(ctxptr, code.next.idx, uintptr(key))
@ -419,11 +418,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) (
key := mapiterkey(iter) key := mapiterkey(iter)
store(ctxptr, code.next.idx, uintptr(key)) store(ctxptr, code.next.idx, uintptr(key))
if !e.unorderedMap { if !e.unorderedMap {
pos := make([]int, 0, mlen) mapCtx := newMapContext(mlen)
pos = append(pos, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
posPtr := unsafe.Pointer(&pos) ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx))
ctx.keepRefs = append(ctx.keepRefs, posPtr) store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.end.mapPos, uintptr(posPtr))
} }
code = code.next code = code.next
} else { } else {
@ -451,8 +449,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) (
} }
} else { } else {
ptr := load(ctxptr, code.end.mapPos) ptr := load(ctxptr, code.end.mapPos)
posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
*posPtr = append(*posPtr, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
if idx < length { if idx < length {
ptr := load(ctxptr, code.mapIter) ptr := load(ctxptr, code.mapIter)
iter := e.ptrToUnsafePtr(ptr) iter := e.ptrToUnsafePtr(ptr)
@ -470,8 +468,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) (
b[last] = ':' b[last] = ':'
} else { } else {
ptr := load(ctxptr, code.end.mapPos) ptr := load(ctxptr, code.end.mapPos)
posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
*posPtr = append(*posPtr, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
} }
ptr := load(ctxptr, code.mapIter) ptr := load(ctxptr, code.mapIter)
iter := e.ptrToUnsafePtr(ptr) iter := e.ptrToUnsafePtr(ptr)
@ -482,14 +480,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) (
case opMapEnd: case opMapEnd:
// this operation only used by sorted map. // this operation only used by sorted map.
length := int(load(ctxptr, code.length)) length := int(load(ctxptr, code.length))
type mapKV struct {
key string
value string
}
kvs := make([]mapKV, 0, length)
ptr := load(ctxptr, code.mapPos) ptr := load(ctxptr, code.mapPos)
posPtr := e.ptrToUnsafePtr(ptr) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
pos := *(*[]int)(posPtr) pos := mapCtx.pos
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
startKey := pos[i*2] startKey := pos[i*2]
startValue := pos[i*2+1] startValue := pos[i*2+1]
@ -499,25 +492,24 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) (
} else { } else {
endValue = len(b) endValue = len(b)
} }
kvs = append(kvs, mapKV{ mapCtx.slice.items = append(mapCtx.slice.items, mapItem{
key: string(b[startKey:startValue]), key: b[startKey:startValue],
value: string(b[startValue:endValue]), value: b[startValue:endValue],
}) })
} }
sort.Slice(kvs, func(i, j int) bool { sort.Sort(mapCtx.slice)
return kvs[i].key < kvs[j].key buf := mapCtx.buf
}) for _, item := range mapCtx.slice.items {
buf := b[pos[0]:] buf = append(buf, item.key...)
buf = buf[:0]
for _, kv := range kvs {
buf = append(buf, []byte(kv.key)...)
buf[len(buf)-1] = ':' buf[len(buf)-1] = ':'
buf = append(buf, []byte(kv.value)...) buf = append(buf, item.value...)
} }
buf[len(buf)-1] = '}' buf[len(buf)-1] = '}'
buf = append(buf, ',') buf = append(buf, ',')
b = b[:pos[0]] b = b[:pos[0]]
b = append(b, buf...) b = append(b, buf...)
mapCtx.buf = buf
releaseMapContext(mapCtx)
code = code.next code = code.next
case opStructFieldPtrAnonymousHeadRecursive: case opStructFieldPtrAnonymousHeadRecursive:
store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx)))

View File

@ -460,15 +460,17 @@ func (e *Encoder) runEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcod
}) })
} }
sort.Sort(mapCtx.slice) sort.Sort(mapCtx.slice)
buf := mapCtx.buf
for _, item := range mapCtx.slice.items { for _, item := range mapCtx.slice.items {
mapCtx.buf = append(mapCtx.buf, item.key...) buf = append(buf, item.key...)
mapCtx.buf[len(mapCtx.buf)-1] = ':' buf[len(buf)-1] = ':'
mapCtx.buf = append(mapCtx.buf, item.value...) buf = append(buf, item.value...)
} }
mapCtx.buf[len(mapCtx.buf)-1] = '}' buf[len(buf)-1] = '}'
mapCtx.buf = append(mapCtx.buf, ',') buf = append(buf, ',')
b = b[:pos[0]] b = b[:pos[0]]
b = append(b, mapCtx.buf...) b = append(b, buf...)
mapCtx.buf = buf
releaseMapContext(mapCtx) releaseMapContext(mapCtx)
code = code.next code = code.next
case opStructFieldPtrAnonymousHeadRecursive: case opStructFieldPtrAnonymousHeadRecursive:

View File

@ -405,11 +405,10 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet
store(ctxptr, code.mapIter, uintptr(iter)) store(ctxptr, code.mapIter, uintptr(iter))
if !e.unorderedMap { if !e.unorderedMap {
pos := make([]int, 0, mlen) mapCtx := newMapContext(mlen)
pos = append(pos, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
posPtr := unsafe.Pointer(&pos) ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx))
ctx.keepRefs = append(ctx.keepRefs, posPtr) store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.end.mapPos, uintptr(posPtr))
} else { } else {
b = e.encodeIndent(b, code.next.indent) b = e.encodeIndent(b, code.next.indent)
} }
@ -452,11 +451,10 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet
store(ctxptr, code.next.idx, uintptr(key)) store(ctxptr, code.next.idx, uintptr(key))
if !e.unorderedMap { if !e.unorderedMap {
pos := make([]int, 0, mlen) mapCtx := newMapContext(mlen)
pos = append(pos, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
posPtr := unsafe.Pointer(&pos) ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx))
ctx.keepRefs = append(ctx.keepRefs, posPtr) store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.end.mapPos, uintptr(posPtr))
} else { } else {
b = e.encodeIndent(b, code.next.indent) b = e.encodeIndent(b, code.next.indent)
} }
@ -490,8 +488,8 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet
} }
} else { } else {
ptr := load(ctxptr, code.end.mapPos) ptr := load(ctxptr, code.end.mapPos)
posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
*posPtr = append(*posPtr, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
if idx < length { if idx < length {
ptr := load(ctxptr, code.mapIter) ptr := load(ctxptr, code.mapIter)
iter := e.ptrToUnsafePtr(ptr) iter := e.ptrToUnsafePtr(ptr)
@ -508,8 +506,8 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet
b = append(b, ':', ' ') b = append(b, ':', ' ')
} else { } else {
ptr := load(ctxptr, code.end.mapPos) ptr := load(ctxptr, code.end.mapPos)
posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
*posPtr = append(*posPtr, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
} }
ptr := load(ctxptr, code.mapIter) ptr := load(ctxptr, code.mapIter)
iter := e.ptrToUnsafePtr(ptr) iter := e.ptrToUnsafePtr(ptr)
@ -520,13 +518,9 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet
case opMapEnd: case opMapEnd:
// this operation only used by sorted map // this operation only used by sorted map
length := int(load(ctxptr, code.length)) length := int(load(ctxptr, code.length))
type mapKV struct {
key string
value string
}
kvs := make([]mapKV, 0, length)
ptr := load(ctxptr, code.mapPos) ptr := load(ctxptr, code.mapPos)
pos := *(*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
pos := mapCtx.pos
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
startKey := pos[i*2] startKey := pos[i*2]
startValue := pos[i*2+1] startValue := pos[i*2+1]
@ -536,33 +530,31 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet
} else { } else {
endValue = len(b) endValue = len(b)
} }
kvs = append(kvs, mapKV{ mapCtx.slice.items = append(mapCtx.slice.items, mapItem{
key: string(b[startKey:startValue]), key: b[startKey:startValue],
value: string(b[startValue:endValue]), value: b[startValue:endValue],
}) })
} }
sort.Slice(kvs, func(i, j int) bool { sort.Sort(mapCtx.slice)
return kvs[i].key < kvs[j].key buf := mapCtx.buf
}) for _, item := range mapCtx.slice.items {
buf := b[pos[0]:]
buf = buf[:0]
for _, kv := range kvs {
buf = append(buf, e.prefix...) buf = append(buf, e.prefix...)
buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent+1)...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent+1)...)
buf = append(buf, item.key...)
buf = append(buf, []byte(kv.key)...)
buf[len(buf)-2] = ':' buf[len(buf)-2] = ':'
buf[len(buf)-1] = ' ' buf[len(buf)-1] = ' '
buf = append(buf, []byte(kv.value)...) buf = append(buf, item.value...)
} }
buf = buf[:len(buf)-2] buf = buf[:len(buf)-2]
buf = append(buf, '\n') buf = append(buf, '\n')
buf = append(buf, e.prefix...) buf = append(buf, e.prefix...)
buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent)...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent)...)
buf = append(buf, '}', ',', '\n') buf = append(buf, '}', ',', '\n')
b = b[:pos[0]] b = b[:pos[0]]
b = append(b, buf...) b = append(b, buf...)
mapCtx.buf = buf
releaseMapContext(mapCtx)
code = code.next code = code.next
case opStructFieldPtrHead: case opStructFieldPtrHead:
p := load(ctxptr, code.idx) p := load(ctxptr, code.idx)

View File

@ -405,11 +405,10 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
store(ctxptr, code.mapIter, uintptr(iter)) store(ctxptr, code.mapIter, uintptr(iter))
if !e.unorderedMap { if !e.unorderedMap {
pos := make([]int, 0, mlen) mapCtx := newMapContext(mlen)
pos = append(pos, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
posPtr := unsafe.Pointer(&pos) ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx))
ctx.keepRefs = append(ctx.keepRefs, posPtr) store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.end.mapPos, uintptr(posPtr))
} else { } else {
b = e.encodeIndent(b, code.next.indent) b = e.encodeIndent(b, code.next.indent)
} }
@ -452,11 +451,10 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
store(ctxptr, code.next.idx, uintptr(key)) store(ctxptr, code.next.idx, uintptr(key))
if !e.unorderedMap { if !e.unorderedMap {
pos := make([]int, 0, mlen) mapCtx := newMapContext(mlen)
pos = append(pos, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
posPtr := unsafe.Pointer(&pos) ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx))
ctx.keepRefs = append(ctx.keepRefs, posPtr) store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx)))
store(ctxptr, code.end.mapPos, uintptr(posPtr))
} else { } else {
b = e.encodeIndent(b, code.next.indent) b = e.encodeIndent(b, code.next.indent)
} }
@ -490,8 +488,8 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
} }
} else { } else {
ptr := load(ctxptr, code.end.mapPos) ptr := load(ctxptr, code.end.mapPos)
posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
*posPtr = append(*posPtr, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
if idx < length { if idx < length {
ptr := load(ctxptr, code.mapIter) ptr := load(ctxptr, code.mapIter)
iter := e.ptrToUnsafePtr(ptr) iter := e.ptrToUnsafePtr(ptr)
@ -508,8 +506,8 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
b = append(b, ':', ' ') b = append(b, ':', ' ')
} else { } else {
ptr := load(ctxptr, code.end.mapPos) ptr := load(ctxptr, code.end.mapPos)
posPtr := (*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
*posPtr = append(*posPtr, len(b)) mapCtx.pos = append(mapCtx.pos, len(b))
} }
ptr := load(ctxptr, code.mapIter) ptr := load(ctxptr, code.mapIter)
iter := e.ptrToUnsafePtr(ptr) iter := e.ptrToUnsafePtr(ptr)
@ -520,13 +518,9 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
case opMapEnd: case opMapEnd:
// this operation only used by sorted map // this operation only used by sorted map
length := int(load(ctxptr, code.length)) length := int(load(ctxptr, code.length))
type mapKV struct {
key string
value string
}
kvs := make([]mapKV, 0, length)
ptr := load(ctxptr, code.mapPos) ptr := load(ctxptr, code.mapPos)
pos := *(*[]int)(*(*unsafe.Pointer)(unsafe.Pointer(&ptr))) mapCtx := (*encodeMapContext)(e.ptrToUnsafePtr(ptr))
pos := mapCtx.pos
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
startKey := pos[i*2] startKey := pos[i*2]
startValue := pos[i*2+1] startValue := pos[i*2+1]
@ -536,32 +530,31 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
} else { } else {
endValue = len(b) endValue = len(b)
} }
kvs = append(kvs, mapKV{ mapCtx.slice.items = append(mapCtx.slice.items, mapItem{
key: string(b[startKey:startValue]), key: b[startKey:startValue],
value: string(b[startValue:endValue]), value: b[startValue:endValue],
}) })
} }
sort.Slice(kvs, func(i, j int) bool { sort.Sort(mapCtx.slice)
return kvs[i].key < kvs[j].key buf := mapCtx.buf
}) for _, item := range mapCtx.slice.items {
buf := b[pos[0]:]
buf = buf[:0]
for _, kv := range kvs {
buf = append(buf, e.prefix...) buf = append(buf, e.prefix...)
buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent+1)...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent+1)...)
buf = append(buf, item.key...)
buf = append(buf, []byte(kv.key)...)
buf[len(buf)-2] = ':' buf[len(buf)-2] = ':'
buf[len(buf)-1] = ' ' buf[len(buf)-1] = ' '
buf = append(buf, []byte(kv.value)...) buf = append(buf, item.value...)
} }
buf = buf[:len(buf)-2] buf = buf[:len(buf)-2]
buf = append(buf, '\n') buf = append(buf, '\n')
buf = append(buf, e.prefix...) buf = append(buf, e.prefix...)
buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent)...) buf = append(buf, bytes.Repeat(e.indentStr, e.baseIndent+code.indent)...)
buf = append(buf, '}', ',', '\n') buf = append(buf, '}', ',', '\n')
b = b[:pos[0]] b = b[:pos[0]]
b = append(b, buf...) b = append(b, buf...)
mapCtx.buf = buf
releaseMapContext(mapCtx)
code = code.next code = code.next
case opStructFieldPtrHead: case opStructFieldPtrHead:
p := load(ctxptr, code.idx) p := load(ctxptr, code.idx)