Initial QSfera import
This commit is contained in:
+108
@@ -0,0 +1,108 @@
|
||||
# Math Utils
|
||||
|
||||
- some features
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/gookit/goutil/mathutil
|
||||
```
|
||||
|
||||
## Go docs
|
||||
|
||||
- [Go Docs](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
## Functions
|
||||
|
||||
```go
|
||||
|
||||
func CompFloat[T comdef.Float](first, second T, op string) (ok bool)
|
||||
func CompInt[T comdef.Xint](first, second T, op string) (ok bool)
|
||||
func CompInt64(first, second int64, op string) bool
|
||||
func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool)
|
||||
func Compare(first, second any, op string) (ok bool)
|
||||
func DataSize(size uint64) string
|
||||
func ElapsedTime(startTime time.Time) string
|
||||
func Float(in any) (float64, error)
|
||||
func FloatOr(in any, defVal float64) float64
|
||||
func FloatOrDefault(in any, defVal float64) float64
|
||||
func FloatOrErr(in any) (float64, error)
|
||||
func FloatOrPanic(in any) float64
|
||||
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func HowLongAgo(sec int64) string
|
||||
func InRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func InUintRange[T comdef.Uint](val, min, max T) bool
|
||||
func Int(in any) (int, error)
|
||||
func Int64(in any) (int64, error)
|
||||
func Int64OrErr(in any) (int64, error)
|
||||
func IntOr(in any, defVal int) int
|
||||
func IntOrDefault(in any, defVal int) int
|
||||
func IntOrErr(in any) (iVal int, err error)
|
||||
func IntOrPanic(in any) int
|
||||
func IsNumeric(c byte) bool
|
||||
func LessOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func Max[T comdef.XintOrFloat](x, y T) T
|
||||
func MaxFloat(x, y float64) float64
|
||||
func MaxI64(x, y int64) int64
|
||||
func MaxInt(x, y int) int
|
||||
func Min[T comdef.XintOrFloat](x, y T) T
|
||||
func MustFloat(in any) float64
|
||||
func MustInt(in any) int
|
||||
func MustInt64(in any) int64
|
||||
func MustString(val any) string
|
||||
func MustUint(in any) uint64
|
||||
func OrElse[T comdef.XintOrFloat](val, defVal T) T
|
||||
func OutRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func Percent(val, total int) float64
|
||||
func QuietFloat(in any) float64
|
||||
func QuietInt(in any) int
|
||||
func QuietInt64(in any) int64
|
||||
func QuietString(val any) string
|
||||
func QuietUint(in any) uint64
|
||||
func RandInt(min, max int) int
|
||||
func RandIntWithSeed(min, max int, seed int64) int
|
||||
func RandomInt(min, max int) int
|
||||
func RandomIntWithSeed(min, max int, seed int64) int
|
||||
func SafeFloat(in any) float64
|
||||
func SafeInt(in any) int
|
||||
func SafeInt64(in any) int64
|
||||
func SafeUint(in any) uint64
|
||||
func StrInt(s string) int
|
||||
func StrIntOr(s string, defVal int) int
|
||||
func String(val any) string
|
||||
func StringOrErr(val any) (string, error)
|
||||
func StringOrPanic(val any) string
|
||||
func SwapMax[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func SwapMaxI64(x, y int64) (int64, int64)
|
||||
func SwapMaxInt(x, y int) (int, int)
|
||||
func SwapMin[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func ToFloat(in any) (f64 float64, err error)
|
||||
func ToFloatWithFunc(in any, usrFn func(any) (float64, error)) (f64 float64, err error)
|
||||
func ToInt(in any) (iVal int, err error)
|
||||
func ToInt64(in any) (i64 int64, err error)
|
||||
func ToString(val any) (string, error)
|
||||
func ToUint(in any) (u64 uint64, err error)
|
||||
func ToUintWithFunc(in any, usrFn func(any) (uint64, error)) (u64 uint64, err error)
|
||||
func TryToString(val any, defaultAsErr bool) (str string, err error)
|
||||
func Uint(in any) (uint64, error)
|
||||
func UintOrErr(in any) (uint64, error)
|
||||
func ZeroOr[T comdef.XintOrFloat](val, defVal T) T
|
||||
|
||||
```
|
||||
|
||||
## Testings
|
||||
|
||||
```shell
|
||||
go test -v ./mathutil/...
|
||||
```
|
||||
|
||||
Test limit by regexp:
|
||||
|
||||
```shell
|
||||
go test -v -run ^TestSetByKeys ./mathutil/...
|
||||
```
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package mathutil
|
||||
|
||||
import "github.com/gookit/goutil/comdef"
|
||||
|
||||
// Abs get absolute value of given value
|
||||
func Abs[T comdef.Int](val T) T {
|
||||
if val >= 0 {
|
||||
return val
|
||||
}
|
||||
return -val
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package mathutil
|
||||
|
||||
import "github.com/gookit/goutil/comdef"
|
||||
|
||||
// IsNumeric returns true if the given character is a numeric, otherwise false.
|
||||
func IsNumeric(c byte) bool { return c >= '0' && c <= '9' }
|
||||
|
||||
// IsInteger strict check the given value is an integer(intX,uintX), otherwise false.
|
||||
func IsInteger(val any) bool {
|
||||
switch val.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsFloat returns true if the given character is a float(32/64), otherwise false.
|
||||
func IsFloat(val any) bool {
|
||||
switch val.(type) {
|
||||
case float32, float64:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Compare any intX,floatX value by given op. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// mathutil.Compare(2, 3, ">") // false
|
||||
// mathutil.Compare(2, 1.3, ">") // true
|
||||
// mathutil.Compare(2.2, 1.3, ">") // true
|
||||
// mathutil.Compare(2.1, 2, ">") // true
|
||||
func Compare(first, second any, op string) bool {
|
||||
if first == nil || second == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch fVal := first.(type) {
|
||||
case float64:
|
||||
if sVal, err := ToFloat(second); err == nil {
|
||||
return CompFloat(fVal, sVal, op)
|
||||
}
|
||||
case float32:
|
||||
if sVal, err := ToFloat(second); err == nil {
|
||||
return CompFloat(float64(fVal), sVal, op)
|
||||
}
|
||||
default: // as int64
|
||||
if int1, err := ToInt64(first); err == nil {
|
||||
if int2, err := ToInt64(second); err == nil {
|
||||
return CompInt64(int1, int2, op)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// CompInt compare all intX,uintX type value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompInt[T comdef.Xint](first, second T, op string) (ok bool) {
|
||||
return CompValue(first, second, op)
|
||||
}
|
||||
|
||||
// CompInt64 compare int64 value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompInt64(first, second int64, op string) bool {
|
||||
return CompValue(first, second, op)
|
||||
}
|
||||
|
||||
// CompFloat compare float64,float32 value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompFloat[T comdef.Float](first, second T, op string) (ok bool) {
|
||||
return CompValue(first, second, op)
|
||||
}
|
||||
|
||||
// CompValue compare intX,uintX,floatX value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompValue[T comdef.Number](first, second T, op string) (ok bool) {
|
||||
switch op {
|
||||
case "<", "lt":
|
||||
ok = first < second
|
||||
case "<=", "lte":
|
||||
ok = first <= second
|
||||
case ">", "gt":
|
||||
ok = first > second
|
||||
case ">=", "gte":
|
||||
ok = first >= second
|
||||
case "=", "eq":
|
||||
ok = first == second
|
||||
case "!=", "ne", "neq":
|
||||
ok = first != second
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// InRange check if val in int/float range [min, max]
|
||||
func InRange[T comdef.Number](val, min, max T) bool {
|
||||
return val >= min && val <= max
|
||||
}
|
||||
|
||||
// OutRange check if val not in int/float range [min, max]
|
||||
func OutRange[T comdef.Number](val, min, max T) bool {
|
||||
return val < min || val > max
|
||||
}
|
||||
|
||||
// InUintRange check if val in unit range [min, max]
|
||||
func InUintRange[T comdef.Uint](val, min, max T) bool {
|
||||
if max == 0 {
|
||||
return val >= min
|
||||
}
|
||||
return val >= min && val <= max
|
||||
}
|
||||
|
||||
// InDelta Check whether two floating-point numbers are equal within a specified margin of error
|
||||
//
|
||||
// Params:
|
||||
// want - 期望的浮点数值
|
||||
// give - 实际给定的浮点数值
|
||||
// delta - 允许的误差范围
|
||||
func InDelta[T comdef.Float](want, give T, delta float64) bool {
|
||||
diff := float64(want) - float64(give)
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
}
|
||||
return diff <= delta
|
||||
}
|
||||
|
||||
// InDeltaAny Check whether two floating-point numbers are equal within a specified margin of error
|
||||
func InDeltaAny(want, give any, delta float64) bool {
|
||||
wantVal, err := ToFloat(want)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
giveVal, err := ToFloat(give)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return InDelta(wantVal, giveVal, delta)
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// Min compare two value and return max value
|
||||
func Min[T comdef.Number](x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// Max compare two value and return max value
|
||||
func Max[T comdef.Number](x, y T) T {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// SwapMin compare and always return [min, max] value
|
||||
func SwapMin[T comdef.Number](x, y T) (T, T) {
|
||||
if x < y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// SwapMax compare and always return [max, min] value
|
||||
func SwapMax[T comdef.Number](x, y T) (T, T) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxInt compare and return max value
|
||||
func MaxInt(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// SwapMaxInt compare and return max, min value
|
||||
func SwapMaxInt(x, y int) (int, int) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxI64 compare and return max value
|
||||
func MaxI64(x, y int64) int64 {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// SwapMaxI64 compare and return max, min value
|
||||
func SwapMaxI64(x, y int64) (int64, int64) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxFloat compare and return max value
|
||||
func MaxFloat(x, y float64) float64 {
|
||||
return math.Max(x, y)
|
||||
}
|
||||
|
||||
// OrElse return default value on val is zero, else return val
|
||||
func OrElse[T comdef.Number](val, defVal T) T {
|
||||
return ZeroOr(val, defVal)
|
||||
}
|
||||
|
||||
// ZeroOr return default value on val is zero, else return val
|
||||
func ZeroOr[T comdef.Number](val, defVal T) T {
|
||||
if val != 0 {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// LessOr return val on val < max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// LessOr(11, 10, 1) // 1
|
||||
// LessOr(2, 10, 1) // 2
|
||||
// LessOr(10, 10, 1) // 1
|
||||
func LessOr[T comdef.Number](val, max, devVal T) T {
|
||||
if val < max {
|
||||
return val
|
||||
}
|
||||
return devVal
|
||||
}
|
||||
|
||||
// LteOr return val on val <= max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// LteOr(11, 10, 1) // 11
|
||||
// LteOr(2, 10, 1) // 2
|
||||
// LteOr(10, 10, 1) // 10
|
||||
func LteOr[T comdef.Number](val, max, devVal T) T {
|
||||
if val <= max {
|
||||
return val
|
||||
}
|
||||
return devVal
|
||||
}
|
||||
|
||||
// GreaterOr return val on val > max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// GreaterOr(23, 0, 2) // 23
|
||||
// GreaterOr(0, 0, 2) // 2
|
||||
func GreaterOr[T comdef.Number](val, min, defVal T) T {
|
||||
if val > min {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// GteOr return val on val >= max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// GteOr(23, 0, 2) // 23
|
||||
// GteOr(0, 0, 2) // 0
|
||||
func GteOr[T comdef.Number](val, min, defVal T) T {
|
||||
if val >= min {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
+648
@@ -0,0 +1,648 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* region convert to int
|
||||
*************************************************************/
|
||||
|
||||
// Int convert value to int
|
||||
func Int(in any) (int, error) { return ToInt(in) }
|
||||
|
||||
// SafeInt convert value to int, will ignore error
|
||||
func SafeInt(in any) int {
|
||||
val, _ := ToInt(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// QuietInt convert value to int, will ignore error
|
||||
func QuietInt(in any) int { return SafeInt(in) }
|
||||
|
||||
// IntOrPanic convert value to int, will panic on error
|
||||
func IntOrPanic(in any) int {
|
||||
val, err := ToInt(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// MustInt convert value to int, will panic on error
|
||||
func MustInt(in any) int { return IntOrPanic(in) }
|
||||
|
||||
// IntOrDefault convert value to int, return defaultVal on failed
|
||||
func IntOrDefault(in any, defVal int) int { return IntOr(in, defVal) }
|
||||
|
||||
// IntOr convert value to int, return defaultVal on failed
|
||||
func IntOr(in any, defVal int) int {
|
||||
val, err := ToIntWith(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// IntOrErr convert value to int, return error on failed
|
||||
func IntOrErr(in any) (int, error) { return ToIntWith(in) }
|
||||
|
||||
// ToInt convert value to int, return error on failed
|
||||
func ToInt(in any) (int, error) { return ToIntWith(in) }
|
||||
|
||||
// ToIntWith convert value to int, can with some option func.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ToIntWithFunc(val, mathutil.WithNilAsFail, mathutil.WithUserConvFn(func(in any) (int, error) {
|
||||
// })
|
||||
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[int]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
// try convert to int
|
||||
iVal, err = TryStrInt(tVal)
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
iVal = tVal
|
||||
case *int: // default support int ptr type
|
||||
iVal = *tVal
|
||||
case int8:
|
||||
iVal = int(tVal)
|
||||
case int16:
|
||||
iVal = int(tVal)
|
||||
case int32:
|
||||
iVal = int(tVal)
|
||||
case int64:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint8:
|
||||
iVal = int(tVal)
|
||||
case uint16:
|
||||
iVal = int(tVal)
|
||||
case uint32:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint64:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case float32:
|
||||
iVal = int(tVal)
|
||||
case float64:
|
||||
iVal = int(tVal)
|
||||
case time.Duration:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
if i64, err = tVal.Int64(); err == nil {
|
||||
if i64 > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(i64)
|
||||
}
|
||||
}
|
||||
default:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
iVal, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToIntWith(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region convert to int64
|
||||
*************************************************************/
|
||||
|
||||
// Int64 convert value to int64, return error on failed
|
||||
func Int64(in any) (int64, error) { return ToInt64(in) }
|
||||
|
||||
// SafeInt64 convert value to int64, will ignore error
|
||||
func SafeInt64(in any) int64 {
|
||||
i64, _ := ToInt64With(in)
|
||||
return i64
|
||||
}
|
||||
|
||||
// QuietInt64 convert value to int64, will ignore error
|
||||
func QuietInt64(in any) int64 { return SafeInt64(in) }
|
||||
|
||||
// MustInt64 convert value to int64, will panic on error
|
||||
func MustInt64(in any) int64 {
|
||||
i64, err := ToInt64With(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// Int64OrDefault convert value to int64, return default val on failed
|
||||
func Int64OrDefault(in any, defVal int64) int64 { return Int64Or(in, defVal) }
|
||||
|
||||
// Int64Or convert value to int64, return default val on failed
|
||||
func Int64Or(in any, defVal int64) int64 {
|
||||
i64, err := ToInt64With(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// ToInt64 convert value to int64, return error on failed
|
||||
func ToInt64(in any) (int64, error) { return ToInt64With(in) }
|
||||
|
||||
// Int64OrErr convert value to int64, return error on failed
|
||||
func Int64OrErr(in any) (int64, error) { return ToInt64With(in) }
|
||||
|
||||
// ToInt64With try to convert value to int64. can with some option func, more see ConvOption.
|
||||
func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[int64]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
// try convert to int64
|
||||
i64, err = TryStrInt64(tVal)
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
i64 = int64(tVal)
|
||||
case int8:
|
||||
i64 = int64(tVal)
|
||||
case int16:
|
||||
i64 = int64(tVal)
|
||||
case int32:
|
||||
i64 = int64(tVal)
|
||||
case int64:
|
||||
i64 = tVal
|
||||
case *int64: // default support int64 ptr type
|
||||
i64 = *tVal
|
||||
case uint:
|
||||
i64 = int64(tVal)
|
||||
case uint8:
|
||||
i64 = int64(tVal)
|
||||
case uint16:
|
||||
i64 = int64(tVal)
|
||||
case uint32:
|
||||
i64 = int64(tVal)
|
||||
case uint64:
|
||||
i64 = int64(tVal)
|
||||
case float32:
|
||||
// in strict mode, cannot convert float to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
i64 = int64(tVal)
|
||||
case float64:
|
||||
// in strict mode, cannot convert float to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
if tVal > math.MaxInt64 {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
i64 = int64(tVal)
|
||||
case time.Duration:
|
||||
i64 = int64(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
i64, err = tVal.Int64()
|
||||
default:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
i64, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToInt64With(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region convert to uint
|
||||
*************************************************************/
|
||||
|
||||
// Uint convert any to uint, return error on failed
|
||||
func Uint(in any) (uint, error) { return ToUint(in) }
|
||||
|
||||
// SafeUint convert any to uint, will ignore error
|
||||
func SafeUint(in any) uint {
|
||||
val, _ := ToUint(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// QuietUint convert any to uint, will ignore error
|
||||
func QuietUint(in any) uint { return SafeUint(in) }
|
||||
|
||||
// MustUint convert any to uint, will panic on error
|
||||
func MustUint(in any) uint {
|
||||
val, err := ToUintWith(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrDefault convert any to uint, return default val on failed
|
||||
func UintOrDefault(in any, defVal uint) uint { return UintOr(in, defVal) }
|
||||
|
||||
// UintOr convert any to uint, return default val on failed
|
||||
func UintOr(in any, defVal uint) uint {
|
||||
val, err := ToUintWith(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrErr convert value to uint, return error on failed
|
||||
func UintOrErr(in any) (uint, error) { return ToUintWith(in) }
|
||||
|
||||
// ToUint convert value to uint, return error on failed
|
||||
func ToUint(in any) (u64 uint, err error) { return ToUintWith(in) }
|
||||
|
||||
// ToUintWith try to convert value to uint. can with some option func, more see ConvOption.
|
||||
func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[uint]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
// try convert to uint64
|
||||
var u64 uint64
|
||||
if u64, err = TryStrUint64(tVal); err == nil {
|
||||
uVal = uint(u64)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
uVal = uint(tVal)
|
||||
case int8:
|
||||
uVal = uint(tVal)
|
||||
case int16:
|
||||
uVal = uint(tVal)
|
||||
case int32:
|
||||
uVal = uint(tVal)
|
||||
case int64:
|
||||
uVal = uint(tVal)
|
||||
case uint:
|
||||
uVal = tVal
|
||||
case *uint: // default support uint ptr type
|
||||
uVal = *tVal
|
||||
case uint8:
|
||||
uVal = uint(tVal)
|
||||
case uint16:
|
||||
uVal = uint(tVal)
|
||||
case uint32:
|
||||
uVal = uint(tVal)
|
||||
case uint64:
|
||||
uVal = uint(tVal)
|
||||
case float32:
|
||||
uVal = uint(tVal)
|
||||
case float64:
|
||||
uVal = uint(tVal)
|
||||
case time.Duration:
|
||||
uVal = uint(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
i64, err = tVal.Int64()
|
||||
uVal = uint(i64)
|
||||
default:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
uVal, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToUintWith(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region convert to uint64
|
||||
*************************************************************/
|
||||
|
||||
// Uint64 convert any to uint64, return error on failed
|
||||
func Uint64(in any) (uint64, error) { return ToUint64(in) }
|
||||
|
||||
// QuietUint64 convert any to uint64, will ignore error
|
||||
func QuietUint64(in any) uint64 { return SafeUint64(in) }
|
||||
|
||||
// SafeUint64 convert any to uint64, will ignore error
|
||||
func SafeUint64(in any) uint64 {
|
||||
val, _ := ToUint64(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// MustUint64 convert any to uint64, will panic on error
|
||||
func MustUint64(in any) uint64 {
|
||||
val, err := ToUint64With(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Uint64OrDefault convert any to uint64, return default val on failed
|
||||
func Uint64OrDefault(in any, defVal uint64) uint64 { return Uint64Or(in, defVal) }
|
||||
|
||||
// Uint64Or convert any to uint64, return default val on failed
|
||||
func Uint64Or(in any, defVal uint64) uint64 {
|
||||
val, err := ToUint64With(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Uint64OrErr convert value to uint64, return error on failed
|
||||
func Uint64OrErr(in any) (uint64, error) { return ToUint64With(in) }
|
||||
|
||||
// ToUint64 convert value to uint64, return error on failed
|
||||
func ToUint64(in any) (uint64, error) { return ToUint64With(in) }
|
||||
|
||||
// ToUint64With try to convert value to uint64. can with some option func, more see ConvOption.
|
||||
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[uint64]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
// try convert to uint64
|
||||
u64, err = TryStrUint64(tVal)
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
u64 = uint64(tVal)
|
||||
case int8:
|
||||
u64 = uint64(tVal)
|
||||
case int16:
|
||||
u64 = uint64(tVal)
|
||||
case int32:
|
||||
u64 = uint64(tVal)
|
||||
case int64:
|
||||
u64 = uint64(tVal)
|
||||
case uint:
|
||||
u64 = uint64(tVal)
|
||||
case uint8:
|
||||
u64 = uint64(tVal)
|
||||
case uint16:
|
||||
u64 = uint64(tVal)
|
||||
case uint32:
|
||||
u64 = uint64(tVal)
|
||||
case uint64:
|
||||
u64 = tVal
|
||||
case *uint64: // default support uint64 ptr type
|
||||
u64 = *tVal
|
||||
case float32:
|
||||
u64 = uint64(tVal)
|
||||
case float64:
|
||||
u64 = uint64(tVal)
|
||||
case time.Duration:
|
||||
u64 = uint64(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
i64, err = tVal.Int64()
|
||||
u64 = uint64(i64)
|
||||
default:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
u64, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToUint64With(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region string to intX/uintX
|
||||
*************************************************************/
|
||||
|
||||
// StrInt convert string to int, ignore error
|
||||
func StrInt(s string) int {
|
||||
iVal, _ := strconv.Atoi(strings.TrimSpace(s))
|
||||
return iVal
|
||||
}
|
||||
|
||||
// StrIntOr convert string to int, return default val on failed
|
||||
func StrIntOr(s string, defVal int) int {
|
||||
iVal, err := strconv.Atoi(strings.TrimSpace(s))
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return iVal
|
||||
}
|
||||
|
||||
// TryStrInt convert string to int, return error on failed.
|
||||
//
|
||||
// - empty string will return 0.
|
||||
// - allow float string.
|
||||
func TryStrInt(s string) (int, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// try convert to int
|
||||
iVal, err := strconv.Atoi(s)
|
||||
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsNumeric(s) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
|
||||
iVal = int(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return iVal, err
|
||||
}
|
||||
|
||||
// TryStrInt64 convert string to int64, return error on failed.
|
||||
//
|
||||
// - empty string will return 0.
|
||||
// - allow float string.
|
||||
func TryStrInt64(s string) (int64, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return 0, nil
|
||||
}
|
||||
i64, err := strconv.ParseInt(s, 10, 0)
|
||||
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsNumeric(s) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
|
||||
i64 = int64(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return i64, err
|
||||
}
|
||||
|
||||
// TryStrUint64 try to convert string to uint64, return error on failed
|
||||
//
|
||||
// - empty string will return 0.
|
||||
// - allow float string.
|
||||
func TryStrUint64(s string) (uint64, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// try convert to int64
|
||||
u64, err := strconv.ParseUint(s, 10, 0)
|
||||
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsPositiveNum(s) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
|
||||
u64 = uint64(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return u64, err
|
||||
}
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// ConvOption convert options
|
||||
type ConvOption[T any] struct {
|
||||
// if ture: value is nil, will return convert error;
|
||||
// if false(default): value is nil, will convert to zero value
|
||||
NilAsFail bool
|
||||
// HandlePtr auto convert ptr type(int,float,string) value. eg: *int to int
|
||||
// - if true: will use real type try convert. default is false
|
||||
// - NOTE: current T type's ptr is default support.
|
||||
HandlePtr bool
|
||||
// StrictMode for convert value. default is false
|
||||
//
|
||||
// TRUE:
|
||||
// - to int: string, float will return error
|
||||
StrictMode bool
|
||||
// set custom fallback convert func for not supported type.
|
||||
UserConvFn ToTypeFunc[T]
|
||||
}
|
||||
|
||||
// NewConvOption create a new ConvOption
|
||||
func NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T] {
|
||||
opt := &ConvOption[T]{}
|
||||
opt.WithOption(optFns...)
|
||||
return opt
|
||||
}
|
||||
|
||||
// WithOption set convert option
|
||||
func (opt *ConvOption[T]) WithOption(optFns ...ConvOptionFn[T]) {
|
||||
for _, fn := range optFns {
|
||||
if fn != nil {
|
||||
fn(opt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConvOptionFn convert option func
|
||||
type ConvOptionFn[T any] func(opt *ConvOption[T])
|
||||
|
||||
// WithNilAsFail set ConvOption.NilAsFail option
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ToIntWithFunc(val, mathutil.WithNilAsFail[int])
|
||||
func WithNilAsFail[T any](opt *ConvOption[T]) { opt.NilAsFail = true }
|
||||
|
||||
// WithHandlePtr set ConvOption.HandlePtr option
|
||||
func WithHandlePtr[T any](opt *ConvOption[T]) { opt.HandlePtr = true }
|
||||
|
||||
// WithStrictMode set ConvOption.StrictMode option
|
||||
func WithStrictMode[T any](opt *ConvOption[T]) { opt.StrictMode = true }
|
||||
|
||||
// WithUserConvFn set ConvOption.UserConvFn option
|
||||
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T] {
|
||||
return func(opt *ConvOption[T]) {
|
||||
opt.UserConvFn = fn
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region Strict to int/uint
|
||||
*************************************************************/
|
||||
|
||||
// StrictInt check the given value is an integer(intX,uintX), return the int64 value and true if success
|
||||
func StrictInt(val any) (int64, bool) {
|
||||
switch tVal := val.(type) {
|
||||
case int:
|
||||
return int64(tVal), true
|
||||
case int8:
|
||||
return int64(tVal), true
|
||||
case int16:
|
||||
return int64(tVal), true
|
||||
case int32:
|
||||
return int64(tVal), true
|
||||
case int64:
|
||||
return tVal, true
|
||||
case uint:
|
||||
return int64(tVal), true
|
||||
case uint8:
|
||||
return int64(tVal), true
|
||||
case uint16:
|
||||
return int64(tVal), true
|
||||
case uint32:
|
||||
return int64(tVal), true
|
||||
case uint64:
|
||||
return int64(tVal), true
|
||||
case uintptr:
|
||||
return int64(tVal), true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// StrictUint strict check value is integer(intX,uintX) and convert to uint64.
|
||||
func StrictUint(val any) (uint64, bool) {
|
||||
switch tVal := val.(type) {
|
||||
case int:
|
||||
return uint64(tVal), true
|
||||
case int8:
|
||||
return uint64(tVal), true
|
||||
case int16:
|
||||
return uint64(tVal), true
|
||||
case int32:
|
||||
return uint64(tVal), true
|
||||
case int64:
|
||||
return uint64(tVal), true
|
||||
case uint:
|
||||
return uint64(tVal), true
|
||||
case uint8:
|
||||
return uint64(tVal), true
|
||||
case uint16:
|
||||
return uint64(tVal), true
|
||||
case uint32:
|
||||
return uint64(tVal), true
|
||||
case uint64:
|
||||
return tVal, true
|
||||
case uintptr:
|
||||
return uint64(tVal), true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region convert to float64
|
||||
*************************************************************/
|
||||
|
||||
// QuietFloat convert value to float64, will ignore error. alias of SafeFloat
|
||||
func QuietFloat(in any) float64 { return SafeFloat(in) }
|
||||
|
||||
// SafeFloat convert value to float64, will ignore error
|
||||
func SafeFloat(in any) float64 {
|
||||
val, _ := ToFloatWith(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// FloatOrPanic convert value to float64, will panic on error
|
||||
func FloatOrPanic(in any) float64 { return MustFloat(in) }
|
||||
|
||||
// MustFloat convert value to float64, will panic on error
|
||||
func MustFloat(in any) float64 {
|
||||
val, err := ToFloatWith(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// FloatOrDefault convert value to float64, will return default value on error
|
||||
func FloatOrDefault(in any, defVal float64) float64 { return FloatOr(in, defVal) }
|
||||
|
||||
// FloatOr convert value to float64, will return default value on error
|
||||
func FloatOr(in any, defVal float64) float64 {
|
||||
val, err := ToFloatWith(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Float convert value to float64, return error on failed
|
||||
func Float(in any) (float64, error) { return ToFloatWith(in) }
|
||||
|
||||
// FloatOrErr convert value to float64, return error on failed
|
||||
func FloatOrErr(in any) (float64, error) { return ToFloatWith(in) }
|
||||
|
||||
// ToFloat convert value to float64, return error on failed
|
||||
func ToFloat(in any) (float64, error) { return ToFloatWith(in) }
|
||||
|
||||
// ToFloatWith try to convert value to float64. can with some option func, more see ConvOption.
|
||||
func ToFloatWith(in any, optFns ...ConvOptionFn[float64]) (f64 float64, err error) {
|
||||
opt := NewConvOption(optFns...)
|
||||
if !opt.NilAsFail && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case string:
|
||||
f64, err = strconv.ParseFloat(strings.TrimSpace(tVal), 64)
|
||||
case int:
|
||||
f64 = float64(tVal)
|
||||
case int8:
|
||||
f64 = float64(tVal)
|
||||
case int16:
|
||||
f64 = float64(tVal)
|
||||
case int32:
|
||||
f64 = float64(tVal)
|
||||
case int64:
|
||||
f64 = float64(tVal)
|
||||
case uint:
|
||||
f64 = float64(tVal)
|
||||
case uint8:
|
||||
f64 = float64(tVal)
|
||||
case uint16:
|
||||
f64 = float64(tVal)
|
||||
case uint32:
|
||||
f64 = float64(tVal)
|
||||
case uint64:
|
||||
f64 = float64(tVal)
|
||||
case float32:
|
||||
f64 = float64(tVal)
|
||||
case float64:
|
||||
f64 = tVal
|
||||
case *float64: // default support float64 ptr type
|
||||
f64 = *tVal
|
||||
case time.Duration:
|
||||
f64 = float64(tVal)
|
||||
case comdef.Float64able: // eg: json.Number
|
||||
f64, err = tVal.Float64()
|
||||
default:
|
||||
if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToFloatWith(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
f64, err = opt.UserConvFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region intX/floatX to string
|
||||
*************************************************************/
|
||||
|
||||
// MustString convert intX/floatX value to string, will panic on error
|
||||
func MustString(val any) string {
|
||||
str, err := ToStringWith(val)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// StringOrPanic convert intX/floatX value to string, will panic on error
|
||||
func StringOrPanic(val any) string { return MustString(val) }
|
||||
|
||||
// StringOrDefault convert intX/floatX value to string, will return default value on error
|
||||
func StringOrDefault(val any, defVal string) string { return StringOr(val, defVal) }
|
||||
|
||||
// StringOr convert intX/floatX value to string, will return default value on error
|
||||
func StringOr(val any, defVal string) string {
|
||||
str, err := ToStringWith(val)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// ToString convert intX/floatX value to string, return error on failed
|
||||
func ToString(val any) (string, error) { return ToStringWith(val) }
|
||||
|
||||
// StringOrErr convert intX/floatX value to string, return error on failed
|
||||
func StringOrErr(val any) (string, error) { return ToStringWith(val) }
|
||||
|
||||
// QuietString convert intX/floatX value to string, other type convert by fmt.Sprint
|
||||
func QuietString(val any) string { return SafeString(val) }
|
||||
|
||||
// String convert intX/floatX value to string, other type convert by fmt.Sprint
|
||||
func String(val any) string {
|
||||
str, _ := TryToString(val, false)
|
||||
return str
|
||||
}
|
||||
|
||||
// SafeString convert intX/floatX value to string, other type convert by fmt.Sprint
|
||||
func SafeString(val any) string {
|
||||
str, _ := TryToString(val, false)
|
||||
return str
|
||||
}
|
||||
|
||||
// TryToString try convert intX/floatX value to string
|
||||
//
|
||||
// if defaultAsErr is False, will use fmt.Sprint convert other type
|
||||
func TryToString(val any, defaultAsErr bool) (string, error) {
|
||||
var optFn comfunc.ConvOptionFn
|
||||
if !defaultAsErr {
|
||||
optFn = comfunc.WithUserConvFn(comfunc.StrBySprintFn)
|
||||
}
|
||||
return ToStringWith(val, optFn)
|
||||
}
|
||||
|
||||
// ToStringWith try to convert value to string. can with some option func, more see comfunc.ConvOption.
|
||||
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error) {
|
||||
return comfunc.ToStringWith(in, optFns...)
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package mathutil
|
||||
|
||||
import "fmt"
|
||||
|
||||
// DataSize format bytes number friendly. eg: 1024 => 1KB, 1024*1024 => 1MB
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// file, err := os.Open(path)
|
||||
// fl, err := file.Stat()
|
||||
// fmtSize := DataSize(fl.Size())
|
||||
func DataSize(size uint64) string {
|
||||
switch {
|
||||
case size < 1024:
|
||||
return fmt.Sprintf("%dB", size)
|
||||
case size < 1024*1024:
|
||||
return fmt.Sprintf("%.2fK", float64(size)/1024)
|
||||
case size < 1024*1024*1024:
|
||||
return fmt.Sprintf("%.2fM", float64(size)/1024/1024)
|
||||
default:
|
||||
return fmt.Sprintf("%.2fG", float64(size)/1024/1024/1024)
|
||||
}
|
||||
}
|
||||
|
||||
// FormatBytes Format the byte size to be a readable string. eg: 1024 => 1 KB
|
||||
func FormatBytes(bytes int) string {
|
||||
const unit = 1024
|
||||
if bytes < unit {
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
}
|
||||
|
||||
div, exp := int64(unit), 0
|
||||
for n := bytes / unit; n >= unit; n /= unit {
|
||||
div *= unit
|
||||
exp++
|
||||
}
|
||||
return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
|
||||
}
|
||||
|
||||
var timeFormats = [][]int{
|
||||
{0},
|
||||
{1},
|
||||
{2, 1},
|
||||
{60},
|
||||
{120, 60},
|
||||
{3600},
|
||||
{7200, 3600},
|
||||
{86400},
|
||||
{172800, 86400}, // second elem is unit.
|
||||
{2592000},
|
||||
{2592000 * 2, 2592000},
|
||||
}
|
||||
|
||||
var timeMessages = []string{
|
||||
"< 1 sec", "1 sec", "secs", "1 min", "mins", "1 hr", "hrs", "1 day", "days", "1 month", "months",
|
||||
}
|
||||
|
||||
// HowLongAgo format a seconds, get how lang ago. eg: 1 day, 1 week
|
||||
func HowLongAgo(sec int64) string {
|
||||
intVal := int(sec)
|
||||
length := len(timeFormats)
|
||||
|
||||
for i, item := range timeFormats {
|
||||
if intVal >= item[0] {
|
||||
ni := i + 1
|
||||
match := false
|
||||
|
||||
if ni < length { // next exists
|
||||
next := timeFormats[ni]
|
||||
if intVal < next[0] { // current <= intVal < next
|
||||
match = true
|
||||
}
|
||||
} else if ni == length { // current is last
|
||||
match = true
|
||||
}
|
||||
|
||||
if match { // match success
|
||||
if len(item) == 1 {
|
||||
return timeMessages[i]
|
||||
}
|
||||
return fmt.Sprintf("%d %s", intVal/item[1], timeMessages[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "unknown" // He should never happen
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
// Package mathutil provide math(int, number) util functions. eg: convert, math calc, random
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
)
|
||||
|
||||
// Mul computes the `a*b` value, rounding the result.
|
||||
func Mul[T1, T2 comdef.Number](a T1, b T2) float64 {
|
||||
return math.Round(SafeFloat(a) * SafeFloat(b))
|
||||
}
|
||||
|
||||
// MulF2i computes the float64 type a * b value, rounding the result to an integer.
|
||||
func MulF2i(a, b float64) int {
|
||||
return int(math.Round(a * b))
|
||||
}
|
||||
|
||||
// Div computes the `a/b` value, result uses a round handle.
|
||||
func Div[T1, T2 comdef.Number](a T1, b T2) float64 {
|
||||
return math.Round(SafeFloat(a) / SafeFloat(b))
|
||||
}
|
||||
|
||||
// DivInt computes the int type a / b value, rounding the result to an integer.
|
||||
func DivInt[T comdef.Integer](a, b T) int {
|
||||
fv := math.Round(float64(a) / float64(b))
|
||||
return int(fv)
|
||||
}
|
||||
|
||||
// DivF2i computes the float64 type a / b value, rounding the result to an integer.
|
||||
func DivF2i(a, b float64) int {
|
||||
return int(math.Round(a / b))
|
||||
}
|
||||
|
||||
// Percent returns a value percentage of the total. eg: 1/100 = 1.0%
|
||||
func Percent(val, total int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
return (float64(val) / float64(total)) * 100
|
||||
}
|
||||
|
||||
// Range a number range expression, and handle each value. eg: "1-100,123,124"
|
||||
func Range(expr string, handle func(val int)) error {
|
||||
for _, item := range strings.Split(expr, ",") {
|
||||
item = strings.TrimSpace(item)
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// is range, eg: "1-100", "-20-2"
|
||||
if idx := checkfn.IndexByteAfter(item, '-', 1); idx > 0 {
|
||||
start, end, err := parseIntRange(item, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// range number
|
||||
for i := start; i <= end; i++ {
|
||||
handle(i)
|
||||
}
|
||||
} else {
|
||||
iVal, err := strconv.Atoi(item)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid integer value: %q", item)
|
||||
}
|
||||
handle(iVal)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Expand a number range expression to int[]. eg: "1-100,123,124"
|
||||
func Expand(expr string) ([]int, error) {
|
||||
var nums []int
|
||||
for _, item := range strings.Split(expr, ",") {
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// is range, eg: "1-100", "-20-2"
|
||||
if idx := checkfn.IndexByteAfter(item, '-', 1); idx > 0 {
|
||||
ints, err := expandIntRange(item, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nums = append(nums, ints...)
|
||||
} else {
|
||||
iVal, err := strconv.Atoi(item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid integer value: %q", item)
|
||||
}
|
||||
nums = append(nums, iVal)
|
||||
}
|
||||
}
|
||||
return nums, nil
|
||||
}
|
||||
|
||||
// 处理范围格式
|
||||
// eg: "1-30" -> [1, 30], "-20-2" -> [-20, 2]
|
||||
func parseIntRange(value string, sepIdx int) (min int, max int, err error) {
|
||||
start, end := value[:sepIdx], value[sepIdx+1:]
|
||||
|
||||
min, err = strconv.Atoi(start)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid range start value: %q", start)
|
||||
return
|
||||
}
|
||||
|
||||
max, err = strconv.Atoi(end)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid range end value: %q", end)
|
||||
return
|
||||
}
|
||||
|
||||
// swap min and max
|
||||
if min > max {
|
||||
min, max = max, min
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 将 "1-30" 转换为 int 列表
|
||||
func expandIntRange(value string, sepIdx int) ([]int, error) {
|
||||
var ints []int
|
||||
start, end, err := parseIntRange(value, sepIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := start; i <= end; i++ {
|
||||
ints = append(ints, i)
|
||||
}
|
||||
return ints, nil
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RandomInt return a random int at the [min, max)
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// RandomInt(10, 99)
|
||||
// RandomInt(100, 999)
|
||||
// RandomInt(1000, 9999)
|
||||
func RandomInt(min, max int) int {
|
||||
rr := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return min + rr.Intn(max-min)
|
||||
}
|
||||
|
||||
// RandInt alias of RandomInt()
|
||||
func RandInt(min, max int) int { return RandomInt(min, max) }
|
||||
|
||||
// RandIntWithSeed alias of RandomIntWithSeed()
|
||||
func RandIntWithSeed(min, max int, seed int64) int {
|
||||
return RandomIntWithSeed(min, max, seed)
|
||||
}
|
||||
|
||||
// RandomIntWithSeed return a random int at the [min, max)
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// seed := time.Now().UnixNano()
|
||||
// RandomIntWithSeed(1000, 9999, seed)
|
||||
func RandomIntWithSeed(min, max int, seed int64) int {
|
||||
rr := rand.New(rand.NewSource(seed))
|
||||
return min + rr.Intn(max-min)
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package mathutil
|
||||
|
||||
// ToIntFunc convert value to int
|
||||
type ToIntFunc func(any) (int, error)
|
||||
|
||||
// ToInt64Func convert value to int64
|
||||
type ToInt64Func func(any) (int64, error)
|
||||
|
||||
// ToUintFunc convert value to uint
|
||||
type ToUintFunc func(any) (uint, error)
|
||||
|
||||
// ToUint64Func convert value to uint
|
||||
type ToUint64Func func(any) (uint64, error)
|
||||
|
||||
// ToFloatFunc convert value to float
|
||||
type ToFloatFunc func(any) (float64, error)
|
||||
|
||||
// ToTypeFunc convert value to defined type
|
||||
type ToTypeFunc[T any] func(any) (T, error)
|
||||
Reference in New Issue
Block a user