diff options
Diffstat (limited to 'vendor/github.com/dustin/go-humanize/si.go')
| -rw-r--r-- | vendor/github.com/dustin/go-humanize/si.go | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/vendor/github.com/dustin/go-humanize/si.go b/vendor/github.com/dustin/go-humanize/si.go new file mode 100644 index 0000000..8b85019 --- /dev/null +++ b/vendor/github.com/dustin/go-humanize/si.go | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | package humanize | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "errors" | ||
| 5 | "math" | ||
| 6 | "regexp" | ||
| 7 | "strconv" | ||
| 8 | ) | ||
| 9 | |||
| 10 | var siPrefixTable = map[float64]string{ | ||
| 11 | -30: "q", // quecto | ||
| 12 | -27: "r", // ronto | ||
| 13 | -24: "y", // yocto | ||
| 14 | -21: "z", // zepto | ||
| 15 | -18: "a", // atto | ||
| 16 | -15: "f", // femto | ||
| 17 | -12: "p", // pico | ||
| 18 | -9: "n", // nano | ||
| 19 | -6: "ยต", // micro | ||
| 20 | -3: "m", // milli | ||
| 21 | 0: "", | ||
| 22 | 3: "k", // kilo | ||
| 23 | 6: "M", // mega | ||
| 24 | 9: "G", // giga | ||
| 25 | 12: "T", // tera | ||
| 26 | 15: "P", // peta | ||
| 27 | 18: "E", // exa | ||
| 28 | 21: "Z", // zetta | ||
| 29 | 24: "Y", // yotta | ||
| 30 | 27: "R", // ronna | ||
| 31 | 30: "Q", // quetta | ||
| 32 | } | ||
| 33 | |||
| 34 | var revSIPrefixTable = revfmap(siPrefixTable) | ||
| 35 | |||
| 36 | // revfmap reverses the map and precomputes the power multiplier | ||
| 37 | func revfmap(in map[float64]string) map[string]float64 { | ||
| 38 | rv := map[string]float64{} | ||
| 39 | for k, v := range in { | ||
| 40 | rv[v] = math.Pow(10, k) | ||
| 41 | } | ||
| 42 | return rv | ||
| 43 | } | ||
| 44 | |||
| 45 | var riParseRegex *regexp.Regexp | ||
| 46 | |||
| 47 | func init() { | ||
| 48 | ri := `^([\-0-9.]+)\s?([` | ||
| 49 | for _, v := range siPrefixTable { | ||
| 50 | ri += v | ||
| 51 | } | ||
| 52 | ri += `]?)(.*)` | ||
| 53 | |||
| 54 | riParseRegex = regexp.MustCompile(ri) | ||
| 55 | } | ||
| 56 | |||
| 57 | // ComputeSI finds the most appropriate SI prefix for the given number | ||
| 58 | // and returns the prefix along with the value adjusted to be within | ||
| 59 | // that prefix. | ||
| 60 | // | ||
| 61 | // See also: SI, ParseSI. | ||
| 62 | // | ||
| 63 | // e.g. ComputeSI(2.2345e-12) -> (2.2345, "p") | ||
| 64 | func ComputeSI(input float64) (float64, string) { | ||
| 65 | if input == 0 { | ||
| 66 | return 0, "" | ||
| 67 | } | ||
| 68 | mag := math.Abs(input) | ||
| 69 | exponent := math.Floor(logn(mag, 10)) | ||
| 70 | exponent = math.Floor(exponent/3) * 3 | ||
| 71 | |||
| 72 | value := mag / math.Pow(10, exponent) | ||
| 73 | |||
| 74 | // Handle special case where value is exactly 1000.0 | ||
| 75 | // Should return 1 M instead of 1000 k | ||
| 76 | if value == 1000.0 { | ||
| 77 | exponent += 3 | ||
| 78 | value = mag / math.Pow(10, exponent) | ||
| 79 | } | ||
| 80 | |||
| 81 | value = math.Copysign(value, input) | ||
| 82 | |||
| 83 | prefix := siPrefixTable[exponent] | ||
| 84 | return value, prefix | ||
| 85 | } | ||
| 86 | |||
| 87 | // SI returns a string with default formatting. | ||
| 88 | // | ||
| 89 | // SI uses Ftoa to format float value, removing trailing zeros. | ||
| 90 | // | ||
| 91 | // See also: ComputeSI, ParseSI. | ||
| 92 | // | ||
| 93 | // e.g. SI(1000000, "B") -> 1 MB | ||
| 94 | // e.g. SI(2.2345e-12, "F") -> 2.2345 pF | ||
| 95 | func SI(input float64, unit string) string { | ||
| 96 | value, prefix := ComputeSI(input) | ||
| 97 | return Ftoa(value) + " " + prefix + unit | ||
| 98 | } | ||
| 99 | |||
| 100 | // SIWithDigits works like SI but limits the resulting string to the | ||
| 101 | // given number of decimal places. | ||
| 102 | // | ||
| 103 | // e.g. SIWithDigits(1000000, 0, "B") -> 1 MB | ||
| 104 | // e.g. SIWithDigits(2.2345e-12, 2, "F") -> 2.23 pF | ||
| 105 | func SIWithDigits(input float64, decimals int, unit string) string { | ||
| 106 | value, prefix := ComputeSI(input) | ||
| 107 | return FtoaWithDigits(value, decimals) + " " + prefix + unit | ||
| 108 | } | ||
| 109 | |||
| 110 | var errInvalid = errors.New("invalid input") | ||
| 111 | |||
| 112 | // ParseSI parses an SI string back into the number and unit. | ||
| 113 | // | ||
| 114 | // See also: SI, ComputeSI. | ||
| 115 | // | ||
| 116 | // e.g. ParseSI("2.2345 pF") -> (2.2345e-12, "F", nil) | ||
| 117 | func ParseSI(input string) (float64, string, error) { | ||
| 118 | found := riParseRegex.FindStringSubmatch(input) | ||
| 119 | if len(found) != 4 { | ||
| 120 | return 0, "", errInvalid | ||
| 121 | } | ||
| 122 | mag := revSIPrefixTable[found[2]] | ||
| 123 | unit := found[3] | ||
| 124 | |||
| 125 | base, err := strconv.ParseFloat(found[1], 64) | ||
| 126 | return base * mag, unit, err | ||
| 127 | } | ||