diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2024-01-25 20:11:31 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-25 20:11:31 -0500 |
| commit | ebb97fb7367fb983cffc1935a8fb57e4b80f5249 (patch) | |
| tree | 43ef6cd01f629f60f59efe1e5b003f7c8e3a1257 /internal/funcs/math.go | |
| parent | f1d9158ea99abbe556251c1ff2fe970f3b460ee9 (diff) | |
Move funcs package to internal (#1977)
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'internal/funcs/math.go')
| -rw-r--r-- | internal/funcs/math.go | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/internal/funcs/math.go b/internal/funcs/math.go new file mode 100644 index 00000000..68316101 --- /dev/null +++ b/internal/funcs/math.go @@ -0,0 +1,247 @@ +package funcs + +import ( + "context" + "fmt" + gmath "math" + "strconv" + + "github.com/hairyhenderson/gomplate/v4/conv" + + "github.com/hairyhenderson/gomplate/v4/math" +) + +// MathNS - the math namespace +// +// Deprecated: don't use +func MathNS() *MathFuncs { + return &MathFuncs{} +} + +// AddMathFuncs - +// +// Deprecated: use [CreateMathFuncs] instead +func AddMathFuncs(f map[string]interface{}) { + for k, v := range CreateMathFuncs(context.Background()) { + f[k] = v + } +} + +// CreateMathFuncs - +func CreateMathFuncs(ctx context.Context) map[string]interface{} { + f := map[string]interface{}{} + + ns := &MathFuncs{ctx} + f["math"] = func() interface{} { return ns } + + f["add"] = ns.Add + f["sub"] = ns.Sub + f["mul"] = ns.Mul + f["div"] = ns.Div + f["rem"] = ns.Rem + f["pow"] = ns.Pow + f["seq"] = ns.Seq + return f +} + +// MathFuncs - +type MathFuncs struct { + ctx context.Context +} + +// IsInt - +func (f MathFuncs) IsInt(n interface{}) bool { + switch i := n.(type) { + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + return true + case string: + _, err := strconv.ParseInt(i, 0, 64) + return err == nil + } + return false +} + +// IsFloat - +func (f MathFuncs) IsFloat(n interface{}) bool { + switch i := n.(type) { + case float32, float64: + return true + case string: + _, err := strconv.ParseFloat(i, 64) + if err != nil { + return false + } + if f.IsInt(i) { + return false + } + return true + } + return false +} + +func (f MathFuncs) containsFloat(n ...interface{}) bool { + c := false + for _, v := range n { + if f.IsFloat(v) { + return true + } + } + return c +} + +// IsNum - +func (f MathFuncs) IsNum(n interface{}) bool { + return f.IsInt(n) || f.IsFloat(n) +} + +// Abs - +func (f MathFuncs) Abs(n interface{}) interface{} { + m := gmath.Abs(conv.ToFloat64(n)) + if f.IsInt(n) { + return conv.ToInt64(m) + } + return m +} + +// Add - +func (f MathFuncs) Add(n ...interface{}) interface{} { + if f.containsFloat(n...) { + nums := conv.ToFloat64s(n...) + var x float64 + for _, v := range nums { + x += v + } + return x + } + nums := conv.ToInt64s(n...) + var x int64 + for _, v := range nums { + x += v + } + return x +} + +// Mul - +func (f MathFuncs) Mul(n ...interface{}) interface{} { + if f.containsFloat(n...) { + nums := conv.ToFloat64s(n...) + x := 1. + for _, v := range nums { + x *= v + } + return x + } + nums := conv.ToInt64s(n...) + x := int64(1) + for _, v := range nums { + x *= v + } + return x +} + +// Sub - +func (f MathFuncs) Sub(a, b interface{}) interface{} { + if f.containsFloat(a, b) { + return conv.ToFloat64(a) - conv.ToFloat64(b) + } + return conv.ToInt64(a) - conv.ToInt64(b) +} + +// Div - +func (f MathFuncs) Div(a, b interface{}) (interface{}, error) { + divisor := conv.ToFloat64(a) + dividend := conv.ToFloat64(b) + if dividend == 0 { + return 0, fmt.Errorf("error: division by 0") + } + return divisor / dividend, nil +} + +// Rem - +func (f MathFuncs) Rem(a, b interface{}) interface{} { + return conv.ToInt64(a) % conv.ToInt64(b) +} + +// Pow - +func (f MathFuncs) Pow(a, b interface{}) interface{} { + r := gmath.Pow(conv.ToFloat64(a), conv.ToFloat64(b)) + if f.IsFloat(a) { + return r + } + return conv.ToInt64(r) +} + +// Seq - return a sequence from `start` to `end`, in steps of `step` +// start and step are optional, and default to 1. +func (f MathFuncs) Seq(n ...interface{}) ([]int64, error) { + start := int64(1) + end := int64(0) + step := int64(1) + if len(n) == 0 { + return nil, fmt.Errorf("math.Seq must be given at least an 'end' value") + } + if len(n) == 1 { + end = conv.ToInt64(n[0]) + } + if len(n) == 2 { + start = conv.ToInt64(n[0]) + end = conv.ToInt64(n[1]) + } + if len(n) == 3 { + start = conv.ToInt64(n[0]) + end = conv.ToInt64(n[1]) + step = conv.ToInt64(n[2]) + } + return math.Seq(conv.ToInt64(start), conv.ToInt64(end), conv.ToInt64(step)), nil +} + +// Max - +func (f MathFuncs) Max(a interface{}, b ...interface{}) (interface{}, error) { + if f.IsFloat(a) || f.containsFloat(b...) { + m := conv.ToFloat64(a) + for _, n := range conv.ToFloat64s(b...) { + m = gmath.Max(m, n) + } + return m, nil + } + m := conv.ToInt64(a) + for _, n := range conv.ToInt64s(b...) { + if n > m { + m = n + } + } + return m, nil +} + +// Min - +func (f MathFuncs) Min(a interface{}, b ...interface{}) (interface{}, error) { + if f.IsFloat(a) || f.containsFloat(b...) { + m := conv.ToFloat64(a) + for _, n := range conv.ToFloat64s(b...) { + m = gmath.Min(m, n) + } + return m, nil + } + m := conv.ToInt64(a) + for _, n := range conv.ToInt64s(b...) { + if n < m { + m = n + } + } + return m, nil +} + +// Ceil - +func (f MathFuncs) Ceil(n interface{}) interface{} { + return gmath.Ceil(conv.ToFloat64(n)) +} + +// Floor - +func (f MathFuncs) Floor(n interface{}) interface{} { + return gmath.Floor(conv.ToFloat64(n)) +} + +// Round - +func (f MathFuncs) Round(n interface{}) interface{} { + return gmath.Round(conv.ToFloat64(n)) +} |
