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

fix(util/gconv): #3764 fix bool converting issue #3765

Merged
merged 10 commits into from
Sep 12, 2024
Merged

Conversation

wln32
Copy link
Member

@wln32 wln32 commented Sep 9, 2024

1.修复bool指针类型转换bug #3764
2.修复bool转float测试错误
3.增加bool,int,uint,float的指针转换测试
3.对于转换到string,bool,float,int,uint等基础类型增加反射判断

2.修复bool转float测试错误
3.增加bool,int,uint,float的指针转换测试
3.对于转换到string,bool,float,int,uint等基础类型增加反射判断
@wln32 wln32 changed the title fix(util/gconv): 修复bool指针类型转换bug fix(util/gconv): 修复bool指针类型转换bug #3764 Sep 9, 2024
@wln32 wln32 requested a review from gqcn September 9, 2024 13:33
@wln32 wln32 linked an issue Sep 9, 2024 that may be closed by this pull request
util/gconv/gconv.go Outdated Show resolved Hide resolved
util/gconv/gconv_z_unit_float_test.go Outdated Show resolved Hide resolved
util/gconv/gconv.go Outdated Show resolved Hide resolved
@gqcn gqcn changed the title fix(util/gconv): 修复bool指针类型转换bug #3764 fix(util/gconv): #3764 fix bool converting issue Sep 10, 2024
@wln32
Copy link
Member Author

wln32 commented Sep 10, 2024

int

func reflectInt64(any interface{}) int64 {
	if any == nil {
		return 0
	}
	rv := reflect.ValueOf(any)

	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return int64(rv.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return int64(rv.Uint())
	case reflect.Uintptr:
		return int64(rv.Uint())
	case reflect.Float32, reflect.Float64:
		return int64(rv.Float())
	case reflect.Bool:
		if rv.Bool() {
			return 1
		}
		return 0
	case reflect.Ptr:
		if rv.IsNil() {
			return 0
		}
		if f, ok := any.(interface{ Int64() int64 }); ok {
			return f.Int64()
		}
		// TODO: reflectInt64(rv.Elem()) 减少来回反射的开销
		return reflectInt64(rv.Elem().Interface())

	case reflect.Slice:
		if rv.Type().Elem().Kind() == reflect.Uint8 {
			return gbinary.DecodeToInt64(rv.Bytes())
		}
	case reflect.String:
		var (
			s       = rv.String()
			isMinus = false
		)
		if len(s) > 0 {
			if s[0] == '-' {
				isMinus = true
				s = s[1:]
			} else if s[0] == '+' {
				s = s[1:]
			}
		}
		// Hexadecimal
		if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
			if v, e := strconv.ParseInt(s[2:], 16, 64); e == nil {
				if isMinus {
					return -v
				}
				return v
			}
		}
		// Decimal
		if v, e := strconv.ParseInt(s, 10, 64); e == nil {
			if isMinus {
				return -v
			}
			return v
		}
		// Float64
		if valueInt64, err := strconv.ParseFloat(s, 64); err != nil || math.IsNaN(valueInt64) {
			return 0
		} else {
			return int64(valueInt64)
		}
	default:

	}
	if f, ok := any.(interface{ Int64() int64 }); ok {
		return f.Int64()
	}
	return 0
}

intTests数据在单测文件里面util/gconv/gconv_z_unit_int_test.go

func Benchmark_Reflect_Int(b *testing.B) {
	for range b.N {
		for _, test := range intTests {
			reflectInt64(test.value)
		}
	}
}
func Benchmark_TypeAssert_Int(b *testing.B) {
	for range b.N {
		for _, test := range intTests {
			gconv.Int64(test.value)
		}
	}
}

go.exe test -benchmem -run='^$ -bench ^(Benchmark_Reflect_Int|Benchmark_TypeAssert_Int)$' 要测试的文件名
goos: windows
goarch: amd64
pkg: issue3764
cpu: AMD Ryzen 5 1400 Quad-Core Processor           
Benchmark_Reflect_Int-8      	  397916	      2826 ns/op	     664 B/op	      30 allocs/op
Benchmark_TypeAssert_Int-8   	   72208	     15998 ns/op	    2314 B/op	     113 allocs/op
PASS
ok  	issue3764	2.885s

uint

func reflectUint64(any interface{}) uint64 {
	if any == nil {
		return 0
	}
	rv := reflect.ValueOf(any)

	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return uint64(rv.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return uint64(rv.Uint())
	case reflect.Uintptr:
		return uint64(rv.Uint())
	case reflect.Float32, reflect.Float64:
		return uint64(rv.Float())
	case reflect.Bool:
		if rv.Bool() {
			return 1
		}
		return 0
	case reflect.Ptr:
		if rv.IsNil() {
			return 0
		}
		switch f := any.(type) {
		case (interface{ Int64() int64 }):
			return uint64(f.Int64())
		case (interface{ Uint64() uint64 }):
			return f.Uint64()
		case (interface{ Float64() float64 }):
			return uint64(f.Float64())
		}

		// TODO: reflectUint64(rv.Elem()) 减少来回反射的开销
		return reflectUint64(rv.Elem().Interface())

	case reflect.Slice:
		if rv.Type().Elem().Kind() == reflect.Uint8 {
			return gbinary.DecodeToUint64(rv.Bytes())
		}
	case reflect.String:
		var (
			s = rv.String()
		)

		// Hexadecimal
		if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
			if v, e := strconv.ParseUint(s[2:], 16, 64); e == nil {
				return v
			}
		}
		// Decimal
		if v, e := strconv.ParseUint(s, 10, 64); e == nil {
			return v
		}
		// Float64
		if valueFloat64 := gconv.Float64(any); math.IsNaN(valueFloat64) {
			return 0
		} else {
			return uint64(valueFloat64)
		}

	default:

	}
	switch f := any.(type) {
	case (interface{ Int64() int64 }):
		return uint64(f.Int64())
	case (interface{ Uint64() uint64 }):
		return f.Uint64()
	case (interface{ Float64() float64 }):
		return uint64(f.Float64())
	}

	return 0
}

func Benchmark_Reflect_Uint(b *testing.B) {
	for range b.N {
		for _, test := range uintTests {
			reflectUint64(test.value)
		}
	}
}
func Benchmark_TypeAssert_Uint(b *testing.B) {
	for range b.N {
		for _, test := range intTests {
			gconv.Uint64(test.value)
		}
	}
}

go test -benchmem -run='^$ -bench ^(Benchmark_Reflect_Uint|Benchmark_TypeAssert_Uint)$' 要测试的文件名

goos: windows
goarch: amd64
pkg: issue3764
cpu: AMD Ryzen 5 1400 Quad-Core Processor           
Benchmark_Reflect_Uint-8      	  541568	      2247 ns/op	     688 B/op	      26 allocs/op
Benchmark_TypeAssert_Uint-8   	   81062	     14867 ns/op	    2514 B/op	     112 allocs/op
PASS

float

func Benchmark_Reflect_Float(b *testing.B) {
	for range b.N {
		for _, test := range floatTests {
			reflectFloat64(test.value)
		}
	}
}
func Benchmark_TypeAssert_Float(b *testing.B) {
	for range b.N {
		for _, test := range floatTests {
			gconv.Float64(test.value)
		}
	}
}
func reflectFloat64(any interface{}) float64 {
	if any == nil {
		return 0
	}
	rv := reflect.ValueOf(any)

	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(rv.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return float64(rv.Uint())
	case reflect.Uintptr:
		return float64(rv.Uint())
	case reflect.Float32, reflect.Float64:
		return float64(rv.Float())
	case reflect.Bool:
		if rv.Bool() {
			return 1
		}
		return 0
	case reflect.Ptr:
		if rv.IsNil() {
			return 0
		}
		if f, ok := any.(interface{ Float64() float64 }); ok {
			return float64(f.Float64())
		}
		// TODO: reflectFloat64(rv.Elem()) 减少来回反射的开销
		return reflectFloat64(rv.Elem().Interface())

	case reflect.Slice:
		if rv.Type().Elem().Kind() == reflect.Uint8 {
			return gbinary.DecodeToFloat64(rv.Bytes())
		}
	case reflect.String:
		f, _ := strconv.ParseFloat(rv.String(), 64)
		return f
	default:

	}
	if f, ok := any.(interface{ Float64() float64 }); ok {
		return f.Float64()
	}
	return 0
}

go.exe test -benchmem -run='^$ -bench ^(Benchmark_Reflect_Float|Benchmark_TypeAssert_Float)$' 被测试的文件名

goos: windows
goarch: amd64
pkg: issue3764
cpu: AMD Ryzen 5 1400 Quad-Core Processor           
Benchmark_Reflect_Float-8      	  859450	      1345 ns/op	     280 B/op	      12 allocs/op
Benchmark_TypeAssert_Float-8   	  116479	     10000 ns/op	    1249 B/op	      67 allocs/op
PASS
ok  	issue3764	2.846s

string的暂时没有,提升一般

wln32 and others added 8 commits September 10, 2024 16:50
2.对float,int,uint类型等使用反射判断
2.对于(map,slice,array,struct)类型转换到bool标记TODO
2.增加自定义基础类型的测试
* feat(database/gdb): add `time` field type for value converting for/from field (gogf#3712)

* fix(net/goai): fix openapi miss `required` tag of `BizRequest` when set `CommonRequest` (gogf#3724)

* perf(database/gdb): performance improvement for struct scanning when with feature disabled (gogf#3677)

* up

---------

Co-authored-by: CyJaySong <29367599+cyjaysong@users.noreply.github.com>
Co-authored-by: Zwei <zwei.elen@outlook.com>
Co-authored-by: wln32 <49137144+wln32@users.noreply.github.com>
2.增加各种基础类型指针强转nil的测试
Copy link

sonarcloud bot commented Sep 12, 2024

@gqcn gqcn merged commit 0e471ea into gogf:master Sep 12, 2024
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

util/gconv: compatibility for bool pointer
2 participants