Browse Source

use reflect2 decode slice

Tao Wen 7 years ago
parent
commit
29604bf5c3
4 changed files with 33 additions and 61 deletions
  1. 1 1
      feature_any.go
  2. 1 1
      feature_any_string.go
  3. 30 58
      feature_reflect_slice.go
  4. 1 1
      type_tests/slice_test.go

+ 1 - 1
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 {

+ 1 - 1
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 {

+ 30 - 58
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
-			}
-		}
+	c = iter.nextToken()
+	if c == ']' {
+		sliceType.Set(ptr, sliceType.UnsafeNew())
+		return
 	}
-	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 {
+	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
 }

+ 1 - 1
type_tests/slice_test.go

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