numeric.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. package sprig
  2. import (
  3. "fmt"
  4. "math"
  5. "math/rand"
  6. "reflect"
  7. "strconv"
  8. "strings"
  9. )
  10. // toFloat64 converts 64-bit floats
  11. func toFloat64(v any) float64 {
  12. if str, ok := v.(string); ok {
  13. iv, err := strconv.ParseFloat(str, 64)
  14. if err != nil {
  15. return 0
  16. }
  17. return iv
  18. }
  19. val := reflect.Indirect(reflect.ValueOf(v))
  20. switch val.Kind() {
  21. case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
  22. return float64(val.Int())
  23. case reflect.Uint8, reflect.Uint16, reflect.Uint32:
  24. return float64(val.Uint())
  25. case reflect.Uint, reflect.Uint64:
  26. return float64(val.Uint())
  27. case reflect.Float32, reflect.Float64:
  28. return val.Float()
  29. case reflect.Bool:
  30. if val.Bool() {
  31. return 1
  32. }
  33. return 0
  34. default:
  35. return 0
  36. }
  37. }
  38. func toInt(v any) int {
  39. // It's not optimal. But I don't want duplicate toInt64 code.
  40. return int(toInt64(v))
  41. }
  42. // toInt64 converts integer types to 64-bit integers
  43. func toInt64(v any) int64 {
  44. if str, ok := v.(string); ok {
  45. iv, err := strconv.ParseInt(str, 10, 64)
  46. if err != nil {
  47. return 0
  48. }
  49. return iv
  50. }
  51. val := reflect.Indirect(reflect.ValueOf(v))
  52. switch val.Kind() {
  53. case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
  54. return val.Int()
  55. case reflect.Uint8, reflect.Uint16, reflect.Uint32:
  56. return int64(val.Uint())
  57. case reflect.Uint, reflect.Uint64:
  58. tv := val.Uint()
  59. if tv <= math.MaxInt64 {
  60. return int64(tv)
  61. }
  62. // TODO: What is the sensible thing to do here?
  63. return math.MaxInt64
  64. case reflect.Float32, reflect.Float64:
  65. return int64(val.Float())
  66. case reflect.Bool:
  67. if val.Bool() {
  68. return 1
  69. }
  70. return 0
  71. default:
  72. return 0
  73. }
  74. }
  75. func add1(i any) int64 {
  76. return toInt64(i) + 1
  77. }
  78. func add(i ...any) int64 {
  79. var a int64
  80. for _, b := range i {
  81. a += toInt64(b)
  82. }
  83. return a
  84. }
  85. func sub(a, b any) int64 {
  86. return toInt64(a) - toInt64(b)
  87. }
  88. func div(a, b any) int64 {
  89. return toInt64(a) / toInt64(b)
  90. }
  91. func mod(a, b any) int64 {
  92. return toInt64(a) % toInt64(b)
  93. }
  94. func mul(a any, v ...any) int64 {
  95. val := toInt64(a)
  96. for _, b := range v {
  97. val = val * toInt64(b)
  98. }
  99. return val
  100. }
  101. func randInt(min, max int) int {
  102. return rand.Intn(max-min) + min
  103. }
  104. func maxAsInt64(a any, i ...any) int64 {
  105. aa := toInt64(a)
  106. for _, b := range i {
  107. bb := toInt64(b)
  108. if bb > aa {
  109. aa = bb
  110. }
  111. }
  112. return aa
  113. }
  114. func maxAsFloat64(a any, i ...any) float64 {
  115. m := toFloat64(a)
  116. for _, b := range i {
  117. m = math.Max(m, toFloat64(b))
  118. }
  119. return m
  120. }
  121. func minAsInt64(a any, i ...any) int64 {
  122. aa := toInt64(a)
  123. for _, b := range i {
  124. bb := toInt64(b)
  125. if bb < aa {
  126. aa = bb
  127. }
  128. }
  129. return aa
  130. }
  131. func minAsFloat64(a any, i ...any) float64 {
  132. m := toFloat64(a)
  133. for _, b := range i {
  134. m = math.Min(m, toFloat64(b))
  135. }
  136. return m
  137. }
  138. func until(count int) []int {
  139. step := 1
  140. if count < 0 {
  141. step = -1
  142. }
  143. return untilStep(0, count, step)
  144. }
  145. func untilStep(start, stop, step int) []int {
  146. var v []int
  147. if step == 0 {
  148. return v
  149. }
  150. iterations := math.Abs(float64(stop)-float64(start)) / float64(step)
  151. if iterations > loopExecutionLimit {
  152. panic(fmt.Sprintf("too many iterations in untilStep; max allowed is %d, got %f", loopExecutionLimit, iterations))
  153. }
  154. if stop < start {
  155. if step >= 0 {
  156. return v
  157. }
  158. for i := start; i > stop; i += step {
  159. v = append(v, i)
  160. }
  161. return v
  162. }
  163. if step <= 0 {
  164. return v
  165. }
  166. for i := start; i < stop; i += step {
  167. v = append(v, i)
  168. }
  169. return v
  170. }
  171. func floor(a any) float64 {
  172. return math.Floor(toFloat64(a))
  173. }
  174. func ceil(a any) float64 {
  175. return math.Ceil(toFloat64(a))
  176. }
  177. func round(a any, p int, rOpt ...float64) float64 {
  178. roundOn := .5
  179. if len(rOpt) > 0 {
  180. roundOn = rOpt[0]
  181. }
  182. val := toFloat64(a)
  183. places := toFloat64(p)
  184. var round float64
  185. pow := math.Pow(10, places)
  186. digit := pow * val
  187. _, div := math.Modf(digit)
  188. if div >= roundOn {
  189. round = math.Ceil(digit)
  190. } else {
  191. round = math.Floor(digit)
  192. }
  193. return round / pow
  194. }
  195. // converts unix octal to decimal
  196. func toDecimal(v any) int64 {
  197. result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64)
  198. if err != nil {
  199. return 0
  200. }
  201. return result
  202. }
  203. func atoi(a string) int {
  204. i, _ := strconv.Atoi(a)
  205. return i
  206. }
  207. func seq(params ...int) string {
  208. increment := 1
  209. switch len(params) {
  210. case 0:
  211. return ""
  212. case 1:
  213. start := 1
  214. end := params[0]
  215. if end < start {
  216. increment = -1
  217. }
  218. return intArrayToString(untilStep(start, end+increment, increment), " ")
  219. case 3:
  220. start := params[0]
  221. end := params[2]
  222. step := params[1]
  223. if end < start {
  224. increment = -1
  225. if step > 0 {
  226. return ""
  227. }
  228. }
  229. return intArrayToString(untilStep(start, end+increment, step), " ")
  230. case 2:
  231. start := params[0]
  232. end := params[1]
  233. step := 1
  234. if end < start {
  235. step = -1
  236. }
  237. return intArrayToString(untilStep(start, end+step, step), " ")
  238. default:
  239. return ""
  240. }
  241. }
  242. func intArrayToString(slice []int, delimiter string) string {
  243. return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(slice)), delimiter), "[]")
  244. }