Skip to content

Commit

Permalink
perf(util/gconv): add cache logic to enhance performance (#3673)
Browse files Browse the repository at this point in the history
  • Loading branch information
wln32 authored Sep 9, 2024
1 parent 803cb5a commit 1b4ebc0
Show file tree
Hide file tree
Showing 22 changed files with 998 additions and 358 deletions.
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

0 comments on commit 1b4ebc0

Please sign in to comment.