| package sprig |
| |
| import ( |
| "fmt" |
| "math" |
| "reflect" |
| "strconv" |
| "strings" |
| ) |
| |
| // 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() { |
| 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() { |
| 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 maxf(a interface{}, i ...interface{}) float64 { |
| aa := toFloat64(a) |
| for _, b := range i { |
| bb := toFloat64(b) |
| aa = math.Max(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 minf(a interface{}, i ...interface{}) float64 { |
| aa := toFloat64(a) |
| for _, b := range i { |
| bb := toFloat64(b) |
| aa = math.Min(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 |
| } |
| |
| 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, rOpt ...float64) float64 { |
| roundOn := .5 |
| if len(rOpt) > 0 { |
| roundOn = rOpt[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 |
| } |
| |
| // converts unix octal to decimal |
| func toDecimal(v interface{}) int64 { |
| result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64) |
| if err != nil { |
| return 0 |
| } |
| return result |
| } |
| |
| func seq(params ...int) string { |
| increment := 1 |
| switch len(params) { |
| case 0: |
| return "" |
| case 1: |
| start := 1 |
| end := params[0] |
| if end < start { |
| increment = -1 |
| } |
| return intArrayToString(untilStep(start, end+increment, increment), " ") |
| case 3: |
| start := params[0] |
| end := params[2] |
| step := params[1] |
| if end < start { |
| increment = -1 |
| if step > 0 { |
| return "" |
| } |
| } |
| return intArrayToString(untilStep(start, end+increment, step), " ") |
| case 2: |
| start := params[0] |
| end := params[1] |
| step := 1 |
| if end < start { |
| step = -1 |
| } |
| return intArrayToString(untilStep(start, end+step, step), " ") |
| default: |
| return "" |
| } |
| } |
| |
| func intArrayToString(slice []int, delimeter string) string { |
| return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(slice)), delimeter), "[]") |
| } |