summaryrefslogtreecommitdiff
path: root/internal/funcs/math.go
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2024-01-25 20:11:31 -0500
committerGitHub <noreply@github.com>2024-01-25 20:11:31 -0500
commitebb97fb7367fb983cffc1935a8fb57e4b80f5249 (patch)
tree43ef6cd01f629f60f59efe1e5b003f7c8e3a1257 /internal/funcs/math.go
parentf1d9158ea99abbe556251c1ff2fe970f3b460ee9 (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.go247
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))
+}