Browse Source

codec: add optimized versions of copy AND bytes array<-->slice conversion

Ugorji Nwoke 6 years ago
parent
commit
9577d195b1
4 changed files with 62 additions and 19 deletions
  1. 4 6
      codec/decode.go
  2. 1 13
      codec/encode.go
  3. 27 0
      codec/helper_not_unsafe.go
  4. 30 0
      codec/helper_unsafe.go

+ 4 - 6
codec/decode.go

@@ -465,9 +465,7 @@ func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
 			d.decode(&v2)
 			d.decode(&v2)
 			rvn = rv4i(&v2).Elem()
 			rvn = rv4i(&v2).Elem()
 			if reflectArrayOfSupported && d.stid == 0 && d.h.PreferArrayOverSlice {
 			if reflectArrayOfSupported && d.stid == 0 && d.h.PreferArrayOverSlice {
-				rvn2 := rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rvn), intfTyp), reflect.Array)
-				reflect.Copy(rvn2, rvn)
-				rvn = rvn2
+				rvn = rvGetArray4Slice(rvn)
 			}
 			}
 		} else {
 		} else {
 			if d.str {
 			if d.str {
@@ -808,7 +806,7 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 				d.errorf("cannot decode into non-settable slice")
 				d.errorf("cannot decode into non-settable slice")
 			}
 			}
 			if rvChanged && oldRvlenGtZero && rtelem0Mut { // !isImmutableKind(rtelem0.Kind()) {
 			if rvChanged && oldRvlenGtZero && rtelem0Mut { // !isImmutableKind(rtelem0.Kind()) {
-				reflect.Copy(rv, rv0) // only copy up to length NOT cap i.e. rv0.Slice(0, rvcap)
+				rvCopySlice(rv, rv0) // only copy up to length NOT cap i.e. rv0.Slice(0, rvcap)
 			}
 			}
 		} else if containerLenS != rvlen {
 		} else if containerLenS != rvlen {
 			rvlen = containerLenS
 			rvlen = containerLenS
@@ -888,7 +886,7 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 				// rvcap = growCap(rvcap, rtelem0Size, rvcap+1+(rvcap*1/3))
 				// rvcap = growCap(rvcap, rtelem0Size, rvcap+1+(rvcap*1/3))
 				rv9 = reflect.MakeSlice(f.ti.rt, rvcap, rvcap)
 				rv9 = reflect.MakeSlice(f.ti.rt, rvcap, rvcap)
 				// xdebugf("else: rv9.Len: %d, rvcap: %d", rv9.Len(), rvcap)
 				// xdebugf("else: rv9.Len: %d, rvcap: %d", rv9.Len(), rvcap)
-				reflect.Copy(rv9, rv)
+				rvCopySlice(rv9, rv)
 				rv = rv9
 				rv = rv9
 				rvChanged = true
 				rvChanged = true
 				rvlen = rvcap
 				rvlen = rvcap
@@ -2306,7 +2304,7 @@ func decInferLen(clen, maxlen, unit int) (rvlen int) {
 // 	scap2 = growCap(scap, stElemSize, num)
 // 	scap2 = growCap(scap, stElemSize, num)
 // 	s2 = reflect.MakeSlice(st, l1, scap2)
 // 	s2 = reflect.MakeSlice(st, l1, scap2)
 // 	changed = true
 // 	changed = true
-// 	reflect.Copy(s2, s)
+// 	rvCopySlice(s2, s)
 // 	return
 // 	return
 // }
 // }
 
 

+ 1 - 13
codec/encode.go

@@ -361,19 +361,7 @@ func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 		case seqTypeSlice:
 		case seqTypeSlice:
 			e.e.EncodeStringBytesRaw(rvGetBytes(rv))
 			e.e.EncodeStringBytesRaw(rvGetBytes(rv))
 		case seqTypeArray:
 		case seqTypeArray:
-			l = rv.Len()
-			if rv.CanAddr() {
-				e.e.EncodeStringBytesRaw(rvGetBytes(rv.Slice(0, l)))
-			} else {
-				var bs []byte
-				if l <= cap(e.b) {
-					bs = e.b[:l]
-				} else {
-					bs = make([]byte, l)
-				}
-				reflect.Copy(rv4i(bs), rv)
-				e.e.EncodeStringBytesRaw(bs)
-			}
+			e.e.EncodeStringBytesRaw(rvGetArrayBytesRO(rv, e.b[:]))
 		case seqTypeChan:
 		case seqTypeChan:
 			e.kSliceBytesChan(rv)
 			e.kSliceBytesChan(rv)
 		}
 		}

+ 27 - 0
codec/helper_not_unsafe.go

@@ -292,6 +292,33 @@ func rvGetSliceCap(rv reflect.Value) int {
 	return rv.Cap()
 	return rv.Cap()
 }
 }
 
 
+func rvGetArrayBytesRO(rv reflect.Value, scratch []byte) (bs []byte) {
+	l := rv.Len()
+	if rv.CanAddr() {
+		return rvGetBytes(rv.Slice(0, l))
+	}
+
+	if l <= cap(scratch) {
+		bs = scratch[:l]
+	} else {
+		bs = make([]byte, l)
+	}
+	reflect.Copy(rv4i(bs), rv)
+	return
+}
+
+func rvGetArray4Slice(rv reflect.Value) (v reflect.Value) {
+	v = rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rv), intfTyp), reflect.Array)
+	reflect.Copy(v, rv)
+	return
+}
+
+func rvCopySlice(dest, src reflect.Value) {
+	reflect.Copy(dest, src)
+}
+
+// ------------
+
 func rvGetBool(rv reflect.Value) bool {
 func rvGetBool(rv reflect.Value) bool {
 	return rv.Bool()
 	return rv.Bool()
 }
 }

+ 30 - 0
codec/helper_unsafe.go

@@ -525,6 +525,32 @@ func rvGetSliceCap(rv reflect.Value) int {
 	return (*unsafeSlice)(urv.ptr).Cap
 	return (*unsafeSlice)(urv.ptr).Cap
 }
 }
 
 
+func rvGetArrayBytesRO(rv reflect.Value, scratch []byte) (bs []byte) {
+	l := rv.Len()
+	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
+	bx := (*unsafeSlice)(unsafe.Pointer(&bs))
+	bx.Data = urv.ptr
+	bx.Len, bx.Cap = l, l
+	return
+}
+
+func rvGetArray4Slice(rv reflect.Value) (v reflect.Value) {
+	v = rvZeroAddrK(reflectArrayOf(rvGetSliceLen(rv), intfTyp), reflect.Array)
+	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
+	uv := (*unsafeReflectValue)(unsafe.Pointer(&v))
+	uv.ptr = *(*unsafe.Pointer)(urv.ptr) // slice rv has a ptr to the slice.
+	return
+}
+
+func rvCopySlice(dest, src reflect.Value) {
+	var i interface{} = dest.Type().Elem()
+	ui := (*unsafeIntf)(unsafe.Pointer(&i))
+	urv := (*unsafeReflectValue)(unsafe.Pointer(&dest))
+	destPtr := urv.ptr
+	urv = (*unsafeReflectValue)(unsafe.Pointer(&src))
+	typedslicecopy(ui.word, *(*unsafeSlice)(destPtr), *(*unsafeSlice)(urv.ptr))
+}
+
 // ------------
 // ------------
 
 
 func rvGetBool(rv reflect.Value) bool {
 func rvGetBool(rv reflect.Value) bool {
@@ -819,3 +845,7 @@ func typedmemmove(typ unsafe.Pointer, dst, src unsafe.Pointer)
 //go:linkname unsafe_New reflect.unsafe_New
 //go:linkname unsafe_New reflect.unsafe_New
 //go:noescape
 //go:noescape
 func unsafe_New(typ unsafe.Pointer) unsafe.Pointer
 func unsafe_New(typ unsafe.Pointer) unsafe.Pointer
+
+//go:linkname typedslicecopy reflect.typedslicecopy
+//go:noescape
+func typedslicecopy(elemType unsafe.Pointer, dst, src unsafeSlice) int