diff --git a/net/ghttp/ghttp_server_router_serve.go b/net/ghttp/ghttp_server_router_serve.go index 6fb39c5ca..efd6c3bdc 100644 --- a/net/ghttp/ghttp_server_router_serve.go +++ b/net/ghttp/ghttp_server_router_serve.go @@ -175,8 +175,8 @@ func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*han parsedItemList.PushBack(parsedItem) // The middleware is inserted before the serving handler. - // If there're multiple middlewares, they're inserted into the result list by their registering order. - // The middlewares are also executed by their registering order. + // If there're multiple middleware, they're inserted into the result list by their registering order. + // The middleware are also executed by their registered order. case gHANDLER_TYPE_MIDDLEWARE: if lastMiddlewareElem == nil { lastMiddlewareElem = parsedItemList.PushFront(parsedItem) diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 44df0d092..83a20a800 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -50,6 +50,11 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str if pointer == nil { return gerror.New("object pointer cannot be nil") } + + if doStructByDirectReflectSet(params, pointer) { + return nil + } + defer func() { // Catch the panic, especially the reflect operation panics. if e := recover(); e != nil { @@ -255,6 +260,20 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str return nil } +// doStructByDirectReflectSet do the converting directly using reflect Set. +// It returns true if success, or else false. +func doStructByDirectReflectSet(params interface{}, pointer interface{}) (ok bool) { + v1 := reflect.ValueOf(pointer) + v2 := reflect.ValueOf(params) + if v1.Kind() == reflect.Ptr { + if elem := v1.Elem(); elem.IsValid() && elem.Type() == v2.Type() { + elem.Set(v2) + ok = true + } + } + return ok +} + // bindVarToStructAttr sets value to struct object attribute by name. func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping ...map[string]string) (err error) { structFieldValue := elem.FieldByName(name) diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index 0fea84f54..3f02b9311 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -38,6 +38,11 @@ func doStructs(params interface{}, pointer interface{}, mapping ...map[string]st if pointer == nil { return gerror.New("object pointer cannot be nil") } + + if doStructsByDirectReflectSet(params, pointer) { + return nil + } + defer func() { // Catch the panic, especially the reflect operation panics. if e := recover(); e != nil { @@ -104,5 +109,18 @@ func doStructs(params interface{}, pointer interface{}, mapping ...map[string]st } pointerRv.Elem().Set(array) return nil - +} + +// doStructsByDirectReflectSet do the converting directly using reflect Set. +// It returns true if success, or else false. +func doStructsByDirectReflectSet(params interface{}, pointer interface{}) (ok bool) { + v1 := reflect.ValueOf(pointer) + v2 := reflect.ValueOf(params) + if v1.Kind() == reflect.Ptr { + if elem := v1.Elem(); elem.IsValid() && elem.Type() == v2.Type() { + elem.Set(v2) + ok = true + } + } + return ok } diff --git a/util/gconv/gconv_z_bench_struct_test.go b/util/gconv/gconv_z_bench_struct_test.go index 459aa1abe..4373bdf9f 100644 --- a/util/gconv/gconv_z_bench_struct_test.go +++ b/util/gconv/gconv_z_bench_struct_test.go @@ -9,6 +9,7 @@ package gconv import ( + "reflect" "testing" ) @@ -22,7 +23,27 @@ var ( "name": "gf", "score": 100, } - structPointer = new(structType) + structObj = structType{ + Name: "john", + Score: 60, + } + structPointer = &structType{ + Name: "john", + Score: 60, + } + structPointerNil *structType + // struct slice + structSliceNil []structType + structSlice = []structType{ + {Name: "john", Score: 60}, + {Name: "smith", Score: 100}, + } + // struct pointer slice + structPointerSliceNil []*structType + structPointerSlice = []*structType{ + {Name: "john", Score: 60}, + {Name: "smith", Score: 100}, + } ) func Benchmark_Struct_Basic(b *testing.B) { @@ -30,3 +51,83 @@ func Benchmark_Struct_Basic(b *testing.B) { Struct(structMap, structPointer) } } + +// *struct -> **struct +func Benchmark_Reflect_PPStruct_PStruct(b *testing.B) { + for i := 0; i < b.N; i++ { + v1 := reflect.ValueOf(&structPointerNil) + v2 := reflect.ValueOf(structPointer) + //if v1.Kind() == reflect.Ptr { + // if elem := v1.Elem(); elem.Type() == v2.Type() { + // elem.Set(v2) + // } + //} + v1.Elem().Set(v2) + } +} + +func Benchmark_Struct_PPStruct_PStruct(b *testing.B) { + for i := 0; i < b.N; i++ { + Struct(structPointer, &structPointerNil) + } +} + +// struct -> *struct +func Benchmark_Reflect_PStruct_Struct(b *testing.B) { + for i := 0; i < b.N; i++ { + v1 := reflect.ValueOf(structPointer) + v2 := reflect.ValueOf(structObj) + //if v1.Kind() == reflect.Ptr { + // if elem := v1.Elem(); elem.Type() == v2.Type() { + // elem.Set(v2) + // } + //} + v1.Elem().Set(v2) + } +} + +func Benchmark_Struct_PStruct_Struct(b *testing.B) { + for i := 0; i < b.N; i++ { + Struct(structObj, structPointer) + } +} + +// []struct -> *[]struct +func Benchmark_Reflect_PStructs_Structs(b *testing.B) { + for i := 0; i < b.N; i++ { + v1 := reflect.ValueOf(&structSliceNil) + v2 := reflect.ValueOf(structSlice) + //if v1.Kind() == reflect.Ptr { + // if elem := v1.Elem(); elem.Type() == v2.Type() { + // elem.Set(v2) + // } + //} + v1.Elem().Set(v2) + } +} + +func Benchmark_Structs_PStructs_Structs(b *testing.B) { + for i := 0; i < b.N; i++ { + Structs(structSlice, &structSliceNil) + } +} + +// []*struct -> *[]*struct +func Benchmark_Reflect_PPStructs_PStructs(b *testing.B) { + for i := 0; i < b.N; i++ { + v1 := reflect.ValueOf(&structPointerSliceNil) + v2 := reflect.ValueOf(structPointerSlice) + //if v1.Kind() == reflect.Ptr { + // if elem := v1.Elem(); elem.Type() == v2.Type() { + // elem.Set(v2) + // } + //} + v1.Elem().Set(v2) + } +} + +func Benchmark_Structs_PPStructs_PStructs(b *testing.B) { + for i := 0; i < b.N; i++ { + Structs(structPointerSlice, &structPointerSliceNil) + } +} diff --git a/util/gconv/gconv_z_unit_struct_slice_test.go b/util/gconv/gconv_z_unit_struct_slice_test.go index ade38daf0..4fd4d9da9 100644 --- a/util/gconv/gconv_z_unit_struct_slice_test.go +++ b/util/gconv/gconv_z_unit_struct_slice_test.go @@ -143,3 +143,34 @@ func Test_Struct_SliceWithTag(t *testing.T) { t.Assert(users[1].NickName, "name2") }) } + +func Test_Structs_DirectReflectSet(t *testing.T) { + type A struct { + Id int + Name string + } + gtest.C(t, func(t *gtest.T) { + var ( + a = []*A{ + {Id: 1, Name: "john"}, + {Id: 2, Name: "smith"}, + } + b []*A + ) + err := gconv.Structs(a, &b) + t.Assert(err, nil) + t.AssertEQ(a, b) + }) + gtest.C(t, func(t *gtest.T) { + var ( + a = []A{ + {Id: 1, Name: "john"}, + {Id: 2, Name: "smith"}, + } + b []A + ) + err := gconv.Structs(a, &b) + t.Assert(err, nil) + t.AssertEQ(a, b) + }) +} diff --git a/util/gconv/gconv_z_unit_struct_test.go b/util/gconv/gconv_z_unit_struct_test.go index caf7e13d6..fb7146a14 100644 --- a/util/gconv/gconv_z_unit_struct_test.go +++ b/util/gconv/gconv_z_unit_struct_test.go @@ -1003,3 +1003,35 @@ func Test_Struct_AttrStructHasTheSameTag(t *testing.T) { t.Assert(order.Product.UpdatedAtFormat, "") }) } + +func Test_Struct_DirectReflectSet(t *testing.T) { + type A struct { + Id int + Name string + } + + gtest.C(t, func(t *gtest.T) { + var ( + a = &A{ + Id: 1, + Name: "john", + } + b *A + ) + err := gconv.Struct(a, &b) + t.Assert(err, nil) + t.AssertEQ(a, b) + }) + gtest.C(t, func(t *gtest.T) { + var ( + a = A{ + Id: 1, + Name: "john", + } + b A + ) + err := gconv.Struct(a, &b) + t.Assert(err, nil) + t.AssertEQ(a, b) + }) +}