github.com/hairyhenderson/gomplate/v3@v3.11.7/funcs/math.go (about)

     1  package funcs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	gmath "math"
     7  	"strconv"
     8  
     9  	"github.com/hairyhenderson/gomplate/v3/conv"
    10  
    11  	"github.com/hairyhenderson/gomplate/v3/math"
    12  )
    13  
    14  // MathNS - the math namespace
    15  // Deprecated: don't use
    16  func MathNS() *MathFuncs {
    17  	return &MathFuncs{}
    18  }
    19  
    20  // AddMathFuncs -
    21  // Deprecated: use CreateMathFuncs instead
    22  func AddMathFuncs(f map[string]interface{}) {
    23  	for k, v := range CreateMathFuncs(context.Background()) {
    24  		f[k] = v
    25  	}
    26  }
    27  
    28  // CreateMathFuncs -
    29  func CreateMathFuncs(ctx context.Context) map[string]interface{} {
    30  	f := map[string]interface{}{}
    31  
    32  	ns := &MathFuncs{ctx}
    33  	f["math"] = func() interface{} { return ns }
    34  
    35  	f["add"] = ns.Add
    36  	f["sub"] = ns.Sub
    37  	f["mul"] = ns.Mul
    38  	f["div"] = ns.Div
    39  	f["rem"] = ns.Rem
    40  	f["pow"] = ns.Pow
    41  	f["seq"] = ns.Seq
    42  	return f
    43  }
    44  
    45  // MathFuncs -
    46  type MathFuncs struct {
    47  	ctx context.Context
    48  }
    49  
    50  // IsInt -
    51  func (f MathFuncs) IsInt(n interface{}) bool {
    52  	switch i := n.(type) {
    53  	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
    54  		return true
    55  	case string:
    56  		_, err := strconv.ParseInt(i, 0, 64)
    57  		return err == nil
    58  	}
    59  	return false
    60  }
    61  
    62  // IsFloat -
    63  func (f MathFuncs) IsFloat(n interface{}) bool {
    64  	switch i := n.(type) {
    65  	case float32, float64:
    66  		return true
    67  	case string:
    68  		_, err := strconv.ParseFloat(i, 64)
    69  		if err != nil {
    70  			return false
    71  		}
    72  		if f.IsInt(i) {
    73  			return false
    74  		}
    75  		return true
    76  	}
    77  	return false
    78  }
    79  
    80  func (f MathFuncs) containsFloat(n ...interface{}) bool {
    81  	c := false
    82  	for _, v := range n {
    83  		if f.IsFloat(v) {
    84  			return true
    85  		}
    86  	}
    87  	return c
    88  }
    89  
    90  // IsNum -
    91  func (f MathFuncs) IsNum(n interface{}) bool {
    92  	return f.IsInt(n) || f.IsFloat(n)
    93  }
    94  
    95  // Abs -
    96  func (f MathFuncs) Abs(n interface{}) interface{} {
    97  	m := gmath.Abs(conv.ToFloat64(n))
    98  	if f.IsInt(n) {
    99  		return conv.ToInt64(m)
   100  	}
   101  	return m
   102  }
   103  
   104  // Add -
   105  func (f MathFuncs) Add(n ...interface{}) interface{} {
   106  	if f.containsFloat(n...) {
   107  		nums := conv.ToFloat64s(n...)
   108  		var x float64
   109  		for _, v := range nums {
   110  			x += v
   111  		}
   112  		return x
   113  	}
   114  	nums := conv.ToInt64s(n...)
   115  	var x int64
   116  	for _, v := range nums {
   117  		x += v
   118  	}
   119  	return x
   120  }
   121  
   122  // Mul -
   123  func (f MathFuncs) Mul(n ...interface{}) interface{} {
   124  	if f.containsFloat(n...) {
   125  		nums := conv.ToFloat64s(n...)
   126  		x := 1.
   127  		for _, v := range nums {
   128  			x *= v
   129  		}
   130  		return x
   131  	}
   132  	nums := conv.ToInt64s(n...)
   133  	x := int64(1)
   134  	for _, v := range nums {
   135  		x *= v
   136  	}
   137  	return x
   138  }
   139  
   140  // Sub -
   141  func (f MathFuncs) Sub(a, b interface{}) interface{} {
   142  	if f.containsFloat(a, b) {
   143  		return conv.ToFloat64(a) - conv.ToFloat64(b)
   144  	}
   145  	return conv.ToInt64(a) - conv.ToInt64(b)
   146  }
   147  
   148  // Div -
   149  func (f MathFuncs) Div(a, b interface{}) (interface{}, error) {
   150  	divisor := conv.ToFloat64(a)
   151  	dividend := conv.ToFloat64(b)
   152  	if dividend == 0 {
   153  		return 0, fmt.Errorf("error: division by 0")
   154  	}
   155  	return divisor / dividend, nil
   156  }
   157  
   158  // Rem -
   159  func (f MathFuncs) Rem(a, b interface{}) interface{} {
   160  	return conv.ToInt64(a) % conv.ToInt64(b)
   161  }
   162  
   163  // Pow -
   164  func (f MathFuncs) Pow(a, b interface{}) interface{} {
   165  	r := gmath.Pow(conv.ToFloat64(a), conv.ToFloat64(b))
   166  	if f.IsFloat(a) {
   167  		return r
   168  	}
   169  	return conv.ToInt64(r)
   170  }
   171  
   172  // Seq - return a sequence from `start` to `end`, in steps of `step`
   173  // start and step are optional, and default to 1.
   174  func (f MathFuncs) Seq(n ...interface{}) ([]int64, error) {
   175  	start := int64(1)
   176  	end := int64(0)
   177  	step := int64(1)
   178  	if len(n) == 0 {
   179  		return nil, fmt.Errorf("math.Seq must be given at least an 'end' value")
   180  	}
   181  	if len(n) == 1 {
   182  		end = conv.ToInt64(n[0])
   183  	}
   184  	if len(n) == 2 {
   185  		start = conv.ToInt64(n[0])
   186  		end = conv.ToInt64(n[1])
   187  	}
   188  	if len(n) == 3 {
   189  		start = conv.ToInt64(n[0])
   190  		end = conv.ToInt64(n[1])
   191  		step = conv.ToInt64(n[2])
   192  	}
   193  	return math.Seq(conv.ToInt64(start), conv.ToInt64(end), conv.ToInt64(step)), nil
   194  }
   195  
   196  // Max -
   197  func (f MathFuncs) Max(a interface{}, b ...interface{}) (interface{}, error) {
   198  	if f.IsFloat(a) || f.containsFloat(b...) {
   199  		m := conv.ToFloat64(a)
   200  		for _, n := range conv.ToFloat64s(b...) {
   201  			m = gmath.Max(m, n)
   202  		}
   203  		return m, nil
   204  	}
   205  	m := conv.ToInt64(a)
   206  	for _, n := range conv.ToInt64s(b...) {
   207  		if n > m {
   208  			m = n
   209  		}
   210  	}
   211  	return m, nil
   212  }
   213  
   214  // Min -
   215  func (f MathFuncs) Min(a interface{}, b ...interface{}) (interface{}, error) {
   216  	if f.IsFloat(a) || f.containsFloat(b...) {
   217  		m := conv.ToFloat64(a)
   218  		for _, n := range conv.ToFloat64s(b...) {
   219  			m = gmath.Min(m, n)
   220  		}
   221  		return m, nil
   222  	}
   223  	m := conv.ToInt64(a)
   224  	for _, n := range conv.ToInt64s(b...) {
   225  		if n < m {
   226  			m = n
   227  		}
   228  	}
   229  	return m, nil
   230  }
   231  
   232  // Ceil -
   233  func (f MathFuncs) Ceil(n interface{}) interface{} {
   234  	return gmath.Ceil(conv.ToFloat64(n))
   235  }
   236  
   237  // Floor -
   238  func (f MathFuncs) Floor(n interface{}) interface{} {
   239  	return gmath.Floor(conv.ToFloat64(n))
   240  }
   241  
   242  // Round -
   243  func (f MathFuncs) Round(n interface{}) interface{} {
   244  	return gmath.Round(conv.ToFloat64(n))
   245  }