Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(util/gconv): add cache logic to enhance performance #3673

Merged
merged 28 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d9dec54
只解析结构体时递归,赋值时不递归
wln32 May 3, 2024
967af6c
更新注释
wln32 May 3, 2024
0bb4b84
Merge branch 'gogf:master' into Improve/gconv-struct
wln32 Jun 30, 2024
9dfdbc5
暂时实现,除了嵌套结构体的重名字段之外
wln32 Jun 30, 2024
3fdb6bf
支持嵌套结构体的重名字段
wln32 Jul 1, 2024
2c97fc7
所有功能都已完善
wln32 Jul 1, 2024
791ffbe
1.增加缓存usedParamsKey
wln32 Jul 1, 2024
443ec50
为缓存特性设置一个开关,由用户自定决定,默认开启
wln32 Jul 1, 2024
686a4e6
优化指针类型的字段转换函数逻辑
wln32 Jul 1, 2024
cc3c3ef
ci
wln32 Jul 1, 2024
d35bb83
1.修改或添加一些注释
wln32 Jul 1, 2024
4a568a1
使用sync.Map存储结构体信息
wln32 Jul 1, 2024
6bd3926
Merge branch 'master' into Improve/cache-gconv-struct
wln32 Jul 1, 2024
34931bc
1.不再使用额外的map来关联convertFieldInfo和paramValue
wln32 Jul 2, 2024
26c14b3
1.增加自定义转换类型的快速判断
wln32 Jul 2, 2024
d0d3f94
Merge remote-tracking branch 'origin/Improve/cache-gconv-struct' into…
wln32 Jul 2, 2024
bdc4939
对于匿名不带tag的结构体字段,不缓存
wln32 Jul 2, 2024
b149151
1.更新for循环时赋值的逻辑
wln32 Jul 3, 2024
88cbb41
1.根据paramsMap的长度来选择不同的赋值方法
wln32 Jul 3, 2024
66ec047
Merge branch 'master' into Improve/cache-gconv-struct
wln32 Jul 3, 2024
1e20748
ci
wln32 Jul 3, 2024
b944600
Merge remote-tracking branch 'origin/Improve/cache-gconv-struct' into…
wln32 Jul 3, 2024
330b53e
1.修改convertFieldInfo的每个字段的注释为中文
wln32 Jul 19, 2024
b5b6bcd
1.增加int8,int16等常见的数字类型转换
wln32 Jul 19, 2024
0c3a588
perf(util/gconv): add struct&field cache to improve performance for s…
gqcn Aug 14, 2024
586d824
Merge branch 'master' into Improve/cache-gconv-struct
wln32 Aug 14, 2024
98b70cb
修复了同名字段或tag的*cachedFieldInfoBase不一致
wln32 Aug 18, 2024
fe868a6
up
wln32 Sep 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions util/gconv/gconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

// Package gconv implements powerful and convenient converting functionality for any types of variables.
//
// This package should keep much less dependencies with other packages.
// This package should keep much fewer dependencies with other packages.
package gconv

import (
Expand All @@ -23,7 +23,8 @@ import (
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gtag"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
)

var (
Expand All @@ -35,13 +36,23 @@ var (
"off": {},
"false": {},
}

// StructTagPriority defines the default priority tags for Map*/Struct* functions.
// Note that, the `gconv/param` tags are used by old version of package.
// It is strongly recommended using short tag `c/p` instead in the future.
StructTagPriority = gtag.StructTagPriority
)

func init() {
// register common converters for internal usage.
structcache.RegisterCommonConverter(structcache.CommonConverter{
Int64: Int64,
Uint64: Uint64,
String: String,
Float32: Float32,
Float64: Float64,
Time: Time,
GTime: GTime,
Bytes: Bytes,
Bool: Bool,
})
}

// Byte converts `any` to byte.
func Byte(any interface{}) byte {
if v, ok := any.(byte); ok {
Expand All @@ -63,7 +74,7 @@ func Bytes(any interface{}) []byte {
return value

default:
if f, ok := value.(iBytes); ok {
if f, ok := value.(localinterface.IBytes); ok {
return f.Bytes()
}
originValueAndKind := reflection.OriginValueAndKind(any)
Expand Down Expand Up @@ -174,12 +185,12 @@ func String(any interface{}) string {
if value == nil {
return ""
}
if f, ok := value.(iString); ok {
if f, ok := value.(localinterface.IString); ok {
// If the variable implements the String() interface,
// then use that interface to perform the conversion
return f.String()
}
if f, ok := value.(iError); ok {
if f, ok := value.(localinterface.IError); ok {
// If the variable implements the Error() interface,
// then use that interface to perform the conversion
return f.Error()
Expand Down Expand Up @@ -235,7 +246,7 @@ func Bool(any interface{}) bool {
}
return true
default:
if f, ok := value.(iBool); ok {
if f, ok := value.(localinterface.IBool); ok {
return f.Bool()
}
rv := reflect.ValueOf(any)
Expand Down
2 changes: 2 additions & 0 deletions util/gconv/gconv_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
)

type (
Expand Down Expand Up @@ -82,6 +83,7 @@ func RegisterConverter(fn interface{}) (err error) {
return
}
registeredOutTypeMap[outType] = reflect.ValueOf(fn)
structcache.RegisterCustomConvertType(outType)
return
}

Expand Down
5 changes: 3 additions & 2 deletions util/gconv/gconv_float.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strconv"

"github.com/gogf/gf/v2/encoding/gbinary"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)

// Float32 converts `any` to float32.
Expand All @@ -25,7 +26,7 @@ func Float32(any interface{}) float32 {
case []byte:
return gbinary.DecodeToFloat32(value)
default:
if f, ok := value.(iFloat32); ok {
if f, ok := value.(localinterface.IFloat32); ok {
return f.Float32()
}
v, _ := strconv.ParseFloat(String(any), 64)
Expand All @@ -46,7 +47,7 @@ func Float64(any interface{}) float64 {
case []byte:
return gbinary.DecodeToFloat64(value)
default:
if f, ok := value.(iFloat64); ok {
if f, ok := value.(localinterface.IFloat64); ok {
return f.Float64()
}
v, _ := strconv.ParseFloat(String(any), 64)
Expand Down
3 changes: 2 additions & 1 deletion util/gconv/gconv_int.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strconv"

"github.com/gogf/gf/v2/encoding/gbinary"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)

// Int converts `any` to int.
Expand Down Expand Up @@ -95,7 +96,7 @@ func Int64(any interface{}) int64 {
case []byte:
return gbinary.DecodeToInt64(value)
default:
if f, ok := value.(iInt64); ok {
if f, ok := value.(localinterface.IInt64); ok {
return f.Int64()
}
var (
Expand Down
117 changes: 0 additions & 117 deletions util/gconv/gconv_interface.go

This file was deleted.

10 changes: 5 additions & 5 deletions util/gconv/gconv_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
"github.com/gogf/gf/v2/util/gtag"
)

Expand Down Expand Up @@ -40,8 +41,8 @@ type MapOption struct {
// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
// map/struct/*struct type, then the conversion will fail and returns nil.
//
// If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
// tags that will be detected, otherwise it detects the tags in order of:
// If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority
// priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of:
// gconv, json, field name.
func Map(value interface{}, option ...MapOption) map[string]interface{} {
return doMapConvert(value, recursiveTypeAuto, false, option...)
Expand All @@ -67,10 +68,9 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
return nil
}
// It redirects to its underlying value if it has implemented interface iVal.
if v, ok := value.(iVal); ok {
if v, ok := value.(localinterface.IVal); ok {
value = v.Val()
}

var (
usedOption = getUsedMapOption(option...)
newTags = gtag.StructTagPriority
Expand Down Expand Up @@ -334,7 +334,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
case reflect.Struct:
var dataMap = make(map[string]interface{})
// Map converting interface check.
if v, ok := in.Value.(iMapStrAny); ok {
if v, ok := in.Value.(localinterface.IMapStrAny); ok {
// Value copy, in case of concurrent safety.
for mapK, mapV := range v.MapStrAny() {
if in.RecursiveOption {
Expand Down
3 changes: 2 additions & 1 deletion util/gconv/gconv_scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)

// Scan automatically checks the type of `pointer` and converts `params` to `pointer`.
Expand Down Expand Up @@ -197,7 +198,7 @@ func doConvertWithJsonCheck(srcValue interface{}, dstPointer interface{}) (ok bo

default:
// The `params` might be struct that implements interface function Interface, eg: gvar.Var.
if v, ok := srcValue.(iInterface); ok {
if v, ok := srcValue.(localinterface.IInterface); ok {
return doConvertWithJsonCheck(v.Interface(), dstPointer)
}
}
Expand Down
3 changes: 2 additions & 1 deletion util/gconv/gconv_slice_any.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)

// SliceAny is alias of Interfaces.
Expand Down Expand Up @@ -104,7 +105,7 @@ func Interfaces(any interface{}) []interface{} {
if array != nil {
return array
}
if v, ok := any.(iInterfaces); ok {
if v, ok := any.(localinterface.IInterfaces); ok {
return v.Interfaces()
}
// JSON format string value converting.
Expand Down
9 changes: 5 additions & 4 deletions util/gconv/gconv_slice_float.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)

// SliceFloat is alias of Floats.
Expand Down Expand Up @@ -126,10 +127,10 @@ func Float32s(any interface{}) []float32 {
if array != nil {
return array
}
if v, ok := any.(iFloats); ok {
if v, ok := any.(localinterface.IFloats); ok {
return Float32s(v.Floats())
}
if v, ok := any.(iInterfaces); ok {
if v, ok := any.(localinterface.IInterfaces); ok {
return Float32s(v.Interfaces())
}
// JSON format string value converting.
Expand Down Expand Up @@ -250,10 +251,10 @@ func Float64s(any interface{}) []float64 {
if array != nil {
return array
}
if v, ok := any.(iFloats); ok {
if v, ok := any.(localinterface.IFloats); ok {
return v.Floats()
}
if v, ok := any.(iInterfaces); ok {
if v, ok := any.(localinterface.IInterfaces); ok {
return Floats(v.Interfaces())
}
// JSON format string value converting.
Expand Down
Loading