improve converting performance for equal type converting

This commit is contained in:
John Guo
2021-10-03 00:58:57 +08:00
parent 322f5933ad
commit 71189c8fb0
4 changed files with 94 additions and 12 deletions

View File

@ -0,0 +1,19 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gvar
import (
"github.com/gogf/gf/util/gconv"
)
// Scan automatically checks the type of `pointer` and converts `params` to `pointer`. It supports `pointer`
// with type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting.
//
// See gconv.Scan.
func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error {
return gconv.Scan(v.Val(), pointer, mapping...)
}

View File

@ -21,12 +21,3 @@ func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) error {
return gconv.Structs(v.Val(), pointer, mapping...)
}
// Scan automatically calls Struct or Structs function according to the type of parameter
// `pointer` to implement the converting.
//
// It calls function Struct if `pointer` is type of *struct/**struct to do the converting.
// It calls function Structs if `pointer` is type of *[]struct/*[]*struct to do the converting.
func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error {
return gconv.Scan(v.Val(), pointer, mapping...)
}

View File

@ -21,14 +21,18 @@ import (
// It calls function `doStructs` internally if `pointer` is type of *[]struct/*[]*struct for converting.
func Scan(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
var (
pointerType reflect.Type
pointerKind reflect.Kind
pointerType reflect.Type
pointerKind reflect.Kind
pointerValue reflect.Value
)
if v, ok := pointer.(reflect.Value); ok {
pointerValue = v
pointerType = v.Type()
} else {
pointerType = reflect.TypeOf(pointer)
pointerValue = reflect.ValueOf(pointer)
pointerType = reflect.TypeOf(pointer) // Do not use pointerValue.Type() as pointerValue might be zero.
}
if pointerType == nil {
return gerror.NewCode(gcode.CodeInvalidParameter, "parameter pointer should not be nil")
}
@ -36,6 +40,30 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
if pointerKind != reflect.Ptr {
return gerror.NewCodef(gcode.CodeInvalidParameter, "params should be type of pointer, but got type: %v", pointerKind)
}
// Direct assignment checks!
var (
paramsType reflect.Type
paramsValue reflect.Value
)
if v, ok := params.(reflect.Value); ok {
paramsValue = v
paramsType = paramsValue.Type()
} else {
paramsValue = reflect.ValueOf(params)
paramsType = reflect.TypeOf(params) // Do not use paramsValue.Type() as paramsValue might be zero.
}
// If `params` and `pointer` are the same type, the do directly assignment.
// For performance enhancement purpose.
var (
pointerValueElem = pointerValue.Elem()
)
if pointerValueElem.CanSet() && paramsType == pointerValueElem.Type() {
pointerValueElem.Set(paramsValue)
return nil
}
// Converting.
var (
pointerElem = pointerType.Elem()
pointerElemKind = pointerElem.Kind()

View File

@ -7,6 +7,7 @@
package gconv_test
import (
"fmt"
"github.com/gogf/gf/container/gvar"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/test/gtest"
@ -275,3 +276,46 @@ func Test_Scan_JsonAttributes_StringArray(t *testing.T) {
t.Assert(len(s.Array), 0)
})
}
func Test_Scan_SameType_Just_Assign(t *testing.T) {
// Struct.
gtest.C(t, func(t *gtest.T) {
type User struct {
Uid int
Name string
Pass1 string
Pass2 string
Pointer *int
}
var (
int1 = 1
int2 = 1
user1 = new(User)
user2 *User
)
user1.Pointer = &int1
err := gconv.Scan(user1, &user2)
t.AssertNil(err)
t.Assert(fmt.Sprintf(`%p`, user1), fmt.Sprintf(`%p`, user2))
t.Assert(*user1.Pointer, *user2.Pointer)
user1.Pointer = &int2
t.Assert(*user1.Pointer, *user2.Pointer)
})
// Map.
gtest.C(t, func(t *gtest.T) {
var (
int1 = 1
int2 = 1
m1 = map[string]*int{
"int": &int1,
}
m2 map[string]*int
)
err := gconv.Scan(m1, &m2)
t.AssertNil(err)
t.Assert(fmt.Sprintf(`%p`, m1), fmt.Sprintf(`%p`, m2))
t.Assert(*m1["int"], *m2["int"])
m1["int"] = &int2
t.Assert(*m1["int"], *m2["int"])
})
}