2017-03-31 19:01:58 +03:00
|
|
|
package sprig
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// toFloat64 converts 64-bit floats
|
|
|
|
func toFloat64(v interface{}) float64 {
|
|
|
|
if str, ok := v.(string); ok {
|
|
|
|
iv, err := strconv.ParseFloat(str, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return iv
|
|
|
|
}
|
|
|
|
|
|
|
|
val := reflect.Indirect(reflect.ValueOf(v))
|
|
|
|
switch val.Kind() {
|
|
|
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
|
|
|
return float64(val.Int())
|
|
|
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
|
|
|
return float64(val.Uint())
|
|
|
|
case reflect.Uint, reflect.Uint64:
|
|
|
|
return float64(val.Uint())
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
return val.Float()
|
|
|
|
case reflect.Bool:
|
|
|
|
if val.Bool() == true {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
default:
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func toInt(v interface{}) int {
|
|
|
|
//It's not optimal. Bud I don't want duplicate toInt64 code.
|
|
|
|
return int(toInt64(v))
|
|
|
|
}
|
|
|
|
|
|
|
|
// toInt64 converts integer types to 64-bit integers
|
|
|
|
func toInt64(v interface{}) int64 {
|
|
|
|
if str, ok := v.(string); ok {
|
|
|
|
iv, err := strconv.ParseInt(str, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return iv
|
|
|
|
}
|
|
|
|
|
|
|
|
val := reflect.Indirect(reflect.ValueOf(v))
|
|
|
|
switch val.Kind() {
|
|
|
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
|
|
|
return val.Int()
|
|
|
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
|
|
|
return int64(val.Uint())
|
|
|
|
case reflect.Uint, reflect.Uint64:
|
|
|
|
tv := val.Uint()
|
|
|
|
if tv <= math.MaxInt64 {
|
|
|
|
return int64(tv)
|
|
|
|
}
|
|
|
|
// TODO: What is the sensible thing to do here?
|
|
|
|
return math.MaxInt64
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
return int64(val.Float())
|
|
|
|
case reflect.Bool:
|
|
|
|
if val.Bool() == true {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
default:
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func max(a interface{}, i ...interface{}) int64 {
|
|
|
|
aa := toInt64(a)
|
|
|
|
for _, b := range i {
|
|
|
|
bb := toInt64(b)
|
|
|
|
if bb > aa {
|
|
|
|
aa = bb
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return aa
|
|
|
|
}
|
|
|
|
|
|
|
|
func min(a interface{}, i ...interface{}) int64 {
|
|
|
|
aa := toInt64(a)
|
|
|
|
for _, b := range i {
|
|
|
|
bb := toInt64(b)
|
|
|
|
if bb < aa {
|
|
|
|
aa = bb
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return aa
|
|
|
|
}
|
|
|
|
|
|
|
|
func until(count int) []int {
|
|
|
|
step := 1
|
|
|
|
if count < 0 {
|
|
|
|
step = -1
|
|
|
|
}
|
|
|
|
return untilStep(0, count, step)
|
|
|
|
}
|
|
|
|
|
|
|
|
func untilStep(start, stop, step int) []int {
|
|
|
|
v := []int{}
|
|
|
|
|
|
|
|
if stop < start {
|
|
|
|
if step >= 0 {
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
for i := start; i > stop; i += step {
|
|
|
|
v = append(v, i)
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
if step <= 0 {
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
for i := start; i < stop; i += step {
|
|
|
|
v = append(v, i)
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
2017-12-19 16:00:29 +03:00
|
|
|
|
|
|
|
func floor(a interface{}) float64 {
|
|
|
|
aa := toFloat64(a)
|
|
|
|
return math.Floor(aa)
|
|
|
|
}
|
|
|
|
|
|
|
|
func ceil(a interface{}) float64 {
|
|
|
|
aa := toFloat64(a)
|
|
|
|
return math.Ceil(aa)
|
|
|
|
}
|
|
|
|
|
|
|
|
func round(a interface{}, p int, r_opt ...float64) float64 {
|
|
|
|
roundOn := .5
|
|
|
|
if len(r_opt) > 0 {
|
|
|
|
roundOn = r_opt[0]
|
|
|
|
}
|
|
|
|
val := toFloat64(a)
|
|
|
|
places := toFloat64(p)
|
|
|
|
|
|
|
|
var round float64
|
|
|
|
pow := math.Pow(10, places)
|
|
|
|
digit := pow * val
|
|
|
|
_, div := math.Modf(digit)
|
|
|
|
if div >= roundOn {
|
|
|
|
round = math.Ceil(digit)
|
|
|
|
} else {
|
|
|
|
round = math.Floor(digit)
|
|
|
|
}
|
|
|
|
return round / pow
|
|
|
|
}
|