Skip to content

Commit

Permalink
Improve Float*
Browse files Browse the repository at this point in the history
* improve performance for direct type
* support time.Duration
* support json.Number
  • Loading branch information
shockerli committed Sep 9, 2022
1 parent 203a963 commit 253983d
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 3 deletions.
6 changes: 4 additions & 2 deletions cvte_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ var (
aliasTypeUint0 AliasTypeUint = 0
aliasTypeUint1 AliasTypeUint = 1

aliasTypeFloat0 AliasTypeFloat64 = 0
aliasTypeFloat1 AliasTypeFloat64 = 1
aliasTypeFloat0 AliasTypeFloat64 = 0
aliasTypeFloat1 AliasTypeFloat64 = 1
aliasTypeFloat8d15 AliasTypeFloat64 = 8.15

aliasTypeString0 AliasTypeString = "0"
aliasTypeString1 AliasTypeString = "1"
Expand All @@ -62,6 +63,7 @@ var (
pointerIntNil *AliasTypeInt
aliasTypeBytesNil AliasTypeBytes
aliasTypeBytesTrue AliasTypeBytes = []byte("true")
aliasTypeBytes8d15 AliasTypeBytes = []byte("8.15")
)

// custom type
Expand Down
57 changes: 56 additions & 1 deletion float.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package cvt

import (
"encoding/json"
"fmt"
"math"
"strconv"
"time"
)

// Float64 convert an interface to a float64 type, with default value
Expand All @@ -27,6 +29,59 @@ func Float64P(v interface{}, def ...float64) *float64 {

// Float64E convert an interface to a float64 type
func Float64E(val interface{}) (float64, error) {
v, e := convFloat64E(val)
if e := catch("float64", val, e); e != nil {
return 0, e
}
return v, nil
}

func convFloat64E(val interface{}) (float64, error) {
// direct type(for improve performance)
switch vv := val.(type) {
case nil:
return 0, nil
case bool:
if vv {
return 1, nil
}
return 0, nil
case string:
vvv, err := strconv.ParseFloat(vv, 64)
if err == nil {
return vvv, nil
}
return 0, errConvFail
case []byte:
vvv, err := strconv.ParseFloat(string(vv), 64)
if err == nil {
return vvv, nil
}
return 0, errConvFail
case uint, uint8, uint16, uint32, uint64, uintptr:
return float64(Uint64(vv)), nil
case int, int8, int16, int32, int64:
return float64(Int(vv)), nil
case float32:
// use fmt to fix float32 -> float64 precision loss
// eg: cvt.Float64E(float32(8.31))
vvv, err := strconv.ParseFloat(fmt.Sprintf("%f", vv), 64)
if err == nil {
return vvv, nil
}
case float64:
return vv, nil
case json.Number:
vvv, err := vv.Float64()
if err == nil {
return vvv, nil
}
return 0, errConvFail
case time.Duration:
return float64(vv), nil
}

// indirect type
v, rv := indirect(val)

switch vv := v.(type) {
Expand Down Expand Up @@ -86,7 +141,7 @@ func Float32P(v interface{}, def ...float32) *float32 {

// Float32E convert an interface to a float32 type
func Float32E(val interface{}) (float32, error) {
v, e := Float64E(val)
v, e := convFloat64E(val)
if e := catch("float32", val, e); e != nil {
return 0, e
}
Expand Down
20 changes: 20 additions & 0 deletions float_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package cvt_test

import (
"encoding/json"
"fmt"
"math"
"testing"
"time"

"github.com/shockerli/cvt"
)
Expand Down Expand Up @@ -278,6 +280,8 @@ func TestFloat64E(t *testing.T) {
{&aliasTypeInt0, 0, false},
{aliasTypeInt1, 1, false},
{&aliasTypeInt1, 1, false},
{aliasTypeUint1, 1, false},
{&aliasTypeUint0, 0, false},
{aliasTypeString0, 0, false},
{&aliasTypeString0, 0, false},
{aliasTypeString1, 1, false},
Expand All @@ -296,13 +300,24 @@ func TestFloat64E(t *testing.T) {
{&pointerIntNil, 0, false},
{(*AliasTypeInt)(nil), 0, false},
{(*PointerTypeInt)(nil), 0, false},
{json.Number("-.1"), -.1, false},
{json.Number("12"), 12, false},
{aliasTypeBytes8d15, 8.15, false},
{aliasTypeUint1, 1, false},
{aliasTypeFloat8d15, 8.15, false},
{&aliasTypeFloat8d15, 8.15, false},
{time.Duration(1), 1, false},

// errors
{"10a", 0, true},
{"a10a", 0, true},
{"8.01a", 0, true},
{"8.01 ", 0, true},
{"hello", 0, true},
{[]byte("hello"), 0, true},
{json.Number("hello"), 0, true},
{aliasTypeBytesTrue, 0, true},
{aliasTypeBytesNil, 0, true},
{testing.T{}, 0, true},
{&testing.T{}, 0, true},
{[]int{}, 0, true},
Expand Down Expand Up @@ -390,6 +405,7 @@ func TestFloat32E(t *testing.T) {
{&pointerIntNil, 0, false},
{(*AliasTypeInt)(nil), 0, false},
{(*PointerTypeInt)(nil), 0, false},
{AliasTypeFloat32(8.15), 8.15, false},

// errors
{"10a", 0, true},
Expand All @@ -404,6 +420,10 @@ func TestFloat32E(t *testing.T) {
{[]string{}, 0, true},
{[...]string{}, 0, true},
{map[int]string{}, 0, true},
{[]byte("hello"), 0, true},
{json.Number("hello"), 0, true},
{aliasTypeBytesTrue, 0, true},
{aliasTypeBytesNil, 0, true},
}

for i, tt := range tests {
Expand Down

1 comment on commit 253983d

@vercel
Copy link

@vercel vercel bot commented on 253983d Sep 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.