improve performance for gconv.Struct

This commit is contained in:
John 2020-11-08 00:06:05 +08:00
parent 1edc1f35fb
commit e1dd5cce7d
6 changed files with 84 additions and 21 deletions

View File

@ -24,6 +24,7 @@ func TagFields(pointer interface{}, priority []string) []*Field {
// doTagFields retrieves the tag and corresponding attribute name from <pointer>. It also filters repeated
// tag internally.
// The parameter <pointer> should be type of struct/*struct.
// TODO remove third-party package "structs" by reducing the reflect usage to improve the performance.
func doTagFields(pointer interface{}, priority []string, tagMap map[string]struct{}) []*Field {
// If <pointer> points to an invalid address, for example a nil variable,
// it here creates an empty struct using reflect feature.

View File

@ -7,16 +7,10 @@
package utils
import (
"regexp"
"bytes"
"strings"
)
var (
// replaceCharReg is the regular expression object for replacing chars in key.
// It is used for function EqualFoldWithoutChars.
replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
)
// IsLetterUpper checks whether the given byte b is in upper case.
func IsLetterUpper(b byte) bool {
if b >= byte('A') && b <= byte('Z') {
@ -83,11 +77,19 @@ func ReplaceByMap(origin string, replaces map[string]string) string {
return origin
}
// RemoveSymbols removes all symbols from string and lefts only numbers and letters.
func RemoveSymbols(s string) string {
buffer := bytes.NewBuffer(nil)
for _, c := range s {
if (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') {
buffer.WriteByte(byte(c))
}
}
return buffer.String()
}
// EqualFoldWithoutChars checks string <s1> and <s2> equal case-insensitively,
// with/without chars '-'/'_'/'.'/' '.
func EqualFoldWithoutChars(s1, s2 string) bool {
return strings.EqualFold(
replaceCharReg.ReplaceAllString(s1, ""),
replaceCharReg.ReplaceAllString(s2, ""),
)
return strings.EqualFold(RemoveSymbols(s1), RemoveSymbols(s2))
}

View File

@ -0,0 +1,29 @@
// Copyright 2020 gf Author(https://github.com/gogf/gf). 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 utils_test
import (
"github.com/gogf/gf/internal/utils"
"regexp"
"testing"
)
var (
replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
)
func Benchmark_RemoveSymbols(b *testing.B) {
for i := 0; i < b.N; i++ {
utils.RemoveSymbols(`-a-b._a c1!@#$%^&*()_+:";'.,'01`)
}
}
func Benchmark_RegularReplaceChars(b *testing.B) {
for i := 0; i < b.N; i++ {
replaceCharReg.ReplaceAllString(`-a-b._a c1!@#$%^&*()_+:";'.,'01`, "")
}
}

View File

@ -63,3 +63,9 @@ func Test_ReadCloser(t *testing.T) {
t.Assert(r, []byte{1, 2, 3, 4})
})
}
func Test_RemoveSymbols(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(utils.RemoveSymbols(`-a-b._a c1!@#$%^&*()_+:";'.,'01`), `abac101`)
})
}

View File

@ -12,19 +12,12 @@ import (
"github.com/gogf/gf/internal/empty"
"github.com/gogf/gf/internal/json"
"reflect"
"regexp"
"strings"
"github.com/gogf/gf/internal/structs"
"github.com/gogf/gf/internal/utils"
)
var (
// replaceCharReg is the regular expression object for replacing chars
// in map keys and attribute names.
replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
)
// Struct maps the params key-value pairs to the corresponding struct object's attributes.
// The third parameter <mapping> is unnecessary, indicating the mapping rules between the
// custom key name and the attribute name(case sensitive).
@ -193,7 +186,7 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
}
} else {
tempName = elemFieldType.Name
attrMap[tempName] = replaceCharReg.ReplaceAllString(tempName, "")
attrMap[tempName] = utils.RemoveSymbols(tempName)
}
}
if len(attrMap) == 0 {
@ -204,7 +197,7 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
// and the value is its replaced tag name for later comparison to improve performance.
tagMap := make(map[string]string)
for k, v := range structs.TagMapName(pointer, StructTagPriority) {
tagMap[v] = replaceCharReg.ReplaceAllString(k, "")
tagMap[v] = utils.RemoveSymbols(k)
}
var (
@ -213,7 +206,7 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
)
for mapK, mapV := range paramsMap {
attrName = ""
checkName = replaceCharReg.ReplaceAllString(mapK, "")
checkName = utils.RemoveSymbols(mapK)
// Loop to find the matched attribute name with or without
// string cases and chars like '-'/'_'/'.'/' '.

View File

@ -0,0 +1,32 @@
// Copyright 2017-2018 gf Author(https://github.com/gogf/gf). 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.
// go test *.go -bench=".*" -benchmem
package gconv
import (
"testing"
)
type structType struct {
Name string
Score int
}
var (
structMap = map[string]interface{}{
"name": "gf",
"score": 100,
}
structPointer = new(structType)
)
func Benchmark_Struct_Basic(b *testing.B) {
for i := 0; i < b.N; i++ {
Struct(structMap, structPointer)
}
}