github.com/wuhuizuo/gomplate@v3.5.0+incompatible/funcs/math.go (about)

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