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 }