1
0
mirror of https://github.com/json-iterator/go.git synced 2025-05-13 21:36:29 +02:00

use reflect2 decode slice

This commit is contained in:
Tao Wen 2018-02-19 14:18:42 +08:00
parent cbc1786a76
commit 29604bf5c3
4 changed files with 34 additions and 62 deletions

View File

@ -34,7 +34,7 @@ type Any interface {
type baseAny struct{} type baseAny struct{}
func (any *baseAny) Get(path ...interface{}) Any { func (any *baseAny) Get(path ...interface{}) Any {
return &invalidAny{baseAny{}, fmt.Errorf("Get %v from simple value", path)} return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)}
} }
func (any *baseAny) Size() int { func (any *baseAny) Size() int {

View File

@ -14,7 +14,7 @@ func (any *stringAny) Get(path ...interface{}) Any {
if len(path) == 0 { if len(path) == 0 {
return any return any
} }
return &invalidAny{baseAny{}, fmt.Errorf("Get %v from simple value", path)} return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)}
} }
func (any *stringAny) Parse() *Iterator { func (any *stringAny) Parse() *Iterator {

View File

@ -10,7 +10,8 @@ import (
func decoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { func decoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder {
decoder := decoderOfType(cfg, prefix+"[slice]->", typ.Elem()) decoder := decoderOfType(cfg, prefix+"[slice]->", typ.Elem())
return &sliceDecoder{typ, typ.Elem(), decoder} sliceType := reflect2.Type2(typ).(*reflect2.UnsafeSliceType)
return &sliceDecoder{sliceType, decoder}
} }
func encoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { func encoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder {
@ -35,10 +36,10 @@ func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
return return
} }
stream.WriteArrayStart() stream.WriteArrayStart()
encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGet(ptr, 0), stream) encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream)
for i := 1; i < length; i++ { for i := 1; i < length; i++ {
stream.WriteMore() stream.WriteMore()
elemPtr := encoder.sliceType.UnsafeGet(ptr, i) elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i)
encoder.elemEncoder.Encode(elemPtr, stream) encoder.elemEncoder.Encode(elemPtr, stream)
} }
stream.WriteArrayEnd() stream.WriteArrayEnd()
@ -53,8 +54,7 @@ func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
} }
type sliceDecoder struct { type sliceDecoder struct {
sliceType reflect.Type sliceType *reflect2.UnsafeSliceType
elemType reflect.Type
elemDecoder ValDecoder elemDecoder ValDecoder
} }
@ -73,64 +73,36 @@ func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
} }
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
slice := (*sliceHeader)(ptr) c := iter.nextToken()
if iter.ReadNil() { sliceType := decoder.sliceType
slice.Len = 0 if c == 'n' {
slice.Cap = 0 iter.skipThreeBytes('u', 'l', 'l')
slice.Data = nil sliceType.UnsafeSetNil(ptr)
return return
} }
reuseSlice(slice, decoder.sliceType, 4) if c != '[' {
slice.Len = 0 iter.ReportError("decode array", "expect [ or n, but found "+string([]byte{c}))
offset := uintptr(0)
iter.ReadArrayCB(func(iter *Iterator) bool {
growOne(slice, decoder.sliceType, decoder.elemType)
decoder.elemDecoder.Decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
offset += decoder.elemType.Size()
return true
})
}
// grow grows the slice s so that it can hold extra more values, allocating
// more capacity if needed. It also returns the old and new slice lengths.
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
newLen := slice.Len + 1
if newLen <= slice.Cap {
slice.Len = newLen
return return
} }
newCap := slice.Cap c = iter.nextToken()
if newCap == 0 { if c == ']' {
newCap = 1 sliceType.Set(ptr, sliceType.UnsafeNew())
} else { return
for newCap < newLen { }
if slice.Len < 1024 { iter.unreadByte()
newCap += newCap sliceType.UnsafeGrow(ptr, 1)
} else { elemPtr := sliceType.UnsafeGetIndex(ptr, 0)
newCap += newCap / 4 decoder.elemDecoder.Decode(elemPtr, iter)
} length := 1
} for c = iter.nextToken(); c == ','; c = iter.nextToken() {
} idx := length
newVal := reflect.MakeSlice(sliceType, newLen, newCap).Interface() length += 1
newValPtr := extractInterface(newVal).word sliceType.UnsafeGrow(ptr, length)
dst := (*sliceHeader)(newValPtr).Data elemPtr = sliceType.UnsafeGetIndex(ptr, idx)
// copy old array into new array decoder.elemDecoder.Decode(elemPtr, iter)
originalBytesCount := slice.Len * int(elementType.Size()) }
srcSliceHeader := (unsafe.Pointer)(&sliceHeader{slice.Data, originalBytesCount, originalBytesCount}) if c != ']' {
dstSliceHeader := (unsafe.Pointer)(&sliceHeader{dst, originalBytesCount, originalBytesCount}) iter.ReportError("decode array", "expect ], but found "+string([]byte{c}))
copy(*(*[]byte)(dstSliceHeader), *(*[]byte)(srcSliceHeader))
slice.Data = dst
slice.Len = newLen
slice.Cap = newCap
}
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
if expectedCap <= slice.Cap {
return return
} }
newVal := reflect.MakeSlice(sliceType, 0, expectedCap).Interface()
newValPtr := extractInterface(newVal).word
dst := (*sliceHeader)(newValPtr).Data
slice.Data = dst
slice.Cap = expectedCap
} }

View File

@ -74,7 +74,7 @@ func init() {
(*[]jsonMarshaler)(nil), (*[]jsonMarshaler)(nil),
(*[]jsonMarshalerMap)(nil), (*[]jsonMarshalerMap)(nil),
(*[]textMarshaler)(nil), (*[]textMarshaler)(nil),
selectedSymmetricCase{(*[]textMarshalerMap)(nil)}, (*[]textMarshalerMap)(nil),
) )
} }