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 }