From 29604bf5c38441608973058fcc5fcb798e24b0df Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Mon, 19 Feb 2018 14:18:42 +0800 Subject: [PATCH] use reflect2 decode slice --- feature_any.go | 2 +- feature_any_string.go | 2 +- feature_reflect_slice.go | 90 ++++++++++++++-------------------------- type_tests/slice_test.go | 2 +- 4 files changed, 34 insertions(+), 62 deletions(-) diff --git a/feature_any.go b/feature_any.go index 0eeb8f6..e57dff2 100644 --- a/feature_any.go +++ b/feature_any.go @@ -34,7 +34,7 @@ type Any interface { type baseAny struct{} 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 { diff --git a/feature_any_string.go b/feature_any_string.go index abf060b..a4b93c7 100644 --- a/feature_any_string.go +++ b/feature_any_string.go @@ -14,7 +14,7 @@ func (any *stringAny) Get(path ...interface{}) Any { if len(path) == 0 { 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 { diff --git a/feature_reflect_slice.go b/feature_reflect_slice.go index 4060852..bb3958c 100644 --- a/feature_reflect_slice.go +++ b/feature_reflect_slice.go @@ -10,7 +10,8 @@ import ( func decoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { 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 { @@ -35,10 +36,10 @@ func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { return } 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++ { stream.WriteMore() - elemPtr := encoder.sliceType.UnsafeGet(ptr, i) + elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i) encoder.elemEncoder.Encode(elemPtr, stream) } stream.WriteArrayEnd() @@ -53,8 +54,7 @@ func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { } type sliceDecoder struct { - sliceType reflect.Type - elemType reflect.Type + sliceType *reflect2.UnsafeSliceType elemDecoder ValDecoder } @@ -73,64 +73,36 @@ func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { } func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { - slice := (*sliceHeader)(ptr) - if iter.ReadNil() { - slice.Len = 0 - slice.Cap = 0 - slice.Data = nil + c := iter.nextToken() + sliceType := decoder.sliceType + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + sliceType.UnsafeSetNil(ptr) return } - reuseSlice(slice, decoder.sliceType, 4) - slice.Len = 0 - 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 + if c != '[' { + iter.ReportError("decode array", "expect [ or n, but found "+string([]byte{c})) return } - newCap := slice.Cap - if newCap == 0 { - newCap = 1 - } else { - for newCap < newLen { - if slice.Len < 1024 { - newCap += newCap - } else { - newCap += newCap / 4 - } - } - } - newVal := reflect.MakeSlice(sliceType, newLen, newCap).Interface() - newValPtr := extractInterface(newVal).word - dst := (*sliceHeader)(newValPtr).Data - // copy old array into new array - originalBytesCount := slice.Len * int(elementType.Size()) - srcSliceHeader := (unsafe.Pointer)(&sliceHeader{slice.Data, originalBytesCount, originalBytesCount}) - dstSliceHeader := (unsafe.Pointer)(&sliceHeader{dst, originalBytesCount, originalBytesCount}) - 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 { + c = iter.nextToken() + if c == ']' { + sliceType.Set(ptr, sliceType.UnsafeNew()) + return + } + iter.unreadByte() + sliceType.UnsafeGrow(ptr, 1) + elemPtr := sliceType.UnsafeGetIndex(ptr, 0) + decoder.elemDecoder.Decode(elemPtr, iter) + length := 1 + for c = iter.nextToken(); c == ','; c = iter.nextToken() { + idx := length + length += 1 + sliceType.UnsafeGrow(ptr, length) + elemPtr = sliceType.UnsafeGetIndex(ptr, idx) + decoder.elemDecoder.Decode(elemPtr, iter) + } + if c != ']' { + iter.ReportError("decode array", "expect ], but found "+string([]byte{c})) return } - newVal := reflect.MakeSlice(sliceType, 0, expectedCap).Interface() - newValPtr := extractInterface(newVal).word - dst := (*sliceHeader)(newValPtr).Data - slice.Data = dst - slice.Cap = expectedCap } diff --git a/type_tests/slice_test.go b/type_tests/slice_test.go index cb1d67f..d63726e 100644 --- a/type_tests/slice_test.go +++ b/type_tests/slice_test.go @@ -74,7 +74,7 @@ func init() { (*[]jsonMarshaler)(nil), (*[]jsonMarshalerMap)(nil), (*[]textMarshaler)(nil), - selectedSymmetricCase{(*[]textMarshalerMap)(nil)}, + (*[]textMarshalerMap)(nil), ) }