forked from mirror/go-json
Reuse slice instance for decoding
This commit is contained in:
parent
4f979d764e
commit
bc23c32f1a
|
@ -3,6 +3,7 @@ package json
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ type sliceDecoder struct {
|
||||||
elemType *rtype
|
elemType *rtype
|
||||||
valueDecoder decoder
|
valueDecoder decoder
|
||||||
size uintptr
|
size uintptr
|
||||||
|
arrayPool sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder {
|
func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder {
|
||||||
|
@ -17,7 +19,27 @@ func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder {
|
||||||
valueDecoder: dec,
|
valueDecoder: dec,
|
||||||
elemType: elemType,
|
elemType: elemType,
|
||||||
size: size,
|
size: size,
|
||||||
|
arrayPool: sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
cap := 2
|
||||||
|
return &reflect.SliceHeader{
|
||||||
|
Data: uintptr(newArray(elemType, cap)),
|
||||||
|
Len: 0,
|
||||||
|
Cap: cap,
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *sliceDecoder) newSlice() *reflect.SliceHeader {
|
||||||
|
slice := d.arrayPool.Get().(*reflect.SliceHeader)
|
||||||
|
slice.Len = 0
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *sliceDecoder) releaseSlice(p *reflect.SliceHeader) {
|
||||||
|
d.arrayPool.Put(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname copySlice reflect.typedslicecopy
|
//go:linkname copySlice reflect.typedslicecopy
|
||||||
|
@ -34,8 +56,9 @@ func (d *sliceDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) {
|
||||||
continue
|
continue
|
||||||
case '[':
|
case '[':
|
||||||
idx := 0
|
idx := 0
|
||||||
cap := 2
|
slice := d.newSlice()
|
||||||
data := uintptr(newArray(d.elemType, cap))
|
cap := slice.Cap
|
||||||
|
data := slice.Data
|
||||||
for {
|
for {
|
||||||
cursor++
|
cursor++
|
||||||
if cap <= idx {
|
if cap <= idx {
|
||||||
|
@ -53,17 +76,27 @@ func (d *sliceDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) {
|
||||||
cursor = skipWhiteSpace(buf, cursor)
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
switch buf[cursor] {
|
switch buf[cursor] {
|
||||||
case ']':
|
case ']':
|
||||||
*(*reflect.SliceHeader)(unsafe.Pointer(p)) = reflect.SliceHeader{
|
slice.Cap = cap
|
||||||
Data: data,
|
slice.Len = idx + 1
|
||||||
|
slice.Data = data
|
||||||
|
dstCap := idx + 1
|
||||||
|
dst := reflect.SliceHeader{
|
||||||
|
Data: uintptr(newArray(d.elemType, dstCap)),
|
||||||
Len: idx + 1,
|
Len: idx + 1,
|
||||||
Cap: cap,
|
Cap: dstCap,
|
||||||
}
|
}
|
||||||
|
copySlice(d.elemType, dst, *slice)
|
||||||
|
*(*reflect.SliceHeader)(unsafe.Pointer(p)) = dst
|
||||||
|
d.releaseSlice(slice)
|
||||||
cursor++
|
cursor++
|
||||||
return cursor, nil
|
return cursor, nil
|
||||||
case ',':
|
case ',':
|
||||||
idx++
|
idx++
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
|
slice.Cap = cap
|
||||||
|
slice.Data = data
|
||||||
|
d.releaseSlice(slice)
|
||||||
return 0, errors.New("syntax error slice")
|
return 0, errors.New("syntax error slice")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue