| package humanize |
| |
| import ( |
| "fmt" |
| "math" |
| "strconv" |
| "strings" |
| "unicode" |
| ) |
| |
| // IEC Sizes. |
| // kibis of bits |
| const ( |
| Byte = 1 |
| KiByte = Byte * 1024 |
| MiByte = KiByte * 1024 |
| GiByte = MiByte * 1024 |
| TiByte = GiByte * 1024 |
| PiByte = TiByte * 1024 |
| EiByte = PiByte * 1024 |
| ) |
| |
| // SI Sizes. |
| const ( |
| IByte = 1 |
| KByte = IByte * 1000 |
| MByte = KByte * 1000 |
| GByte = MByte * 1000 |
| TByte = GByte * 1000 |
| PByte = TByte * 1000 |
| EByte = PByte * 1000 |
| ) |
| |
| var bytesSizeTable = map[string]uint64{ |
| "b": Byte, |
| "kib": KiByte, |
| "kb": KByte, |
| "mib": MiByte, |
| "mb": MByte, |
| "gib": GiByte, |
| "gb": GByte, |
| "tib": TiByte, |
| "tb": TByte, |
| "pib": PiByte, |
| "pb": PByte, |
| "eib": EiByte, |
| "eb": EByte, |
| // Without suffix |
| "": Byte, |
| "ki": KiByte, |
| "k": KByte, |
| "mi": MiByte, |
| "m": MByte, |
| "gi": GiByte, |
| "g": GByte, |
| "ti": TiByte, |
| "t": TByte, |
| "pi": PiByte, |
| "p": PByte, |
| "ei": EiByte, |
| "e": EByte, |
| } |
| |
| func logn(n, b float64) float64 { |
| return math.Log(n) / math.Log(b) |
| } |
| |
| func humanateBytes(s uint64, base float64, sizes []string) string { |
| if s < 10 { |
| return fmt.Sprintf("%dB", s) |
| } |
| e := math.Floor(logn(float64(s), base)) |
| suffix := sizes[int(e)] |
| val := float64(s) / math.Pow(base, math.Floor(e)) |
| f := "%.0f" |
| if val < 10 { |
| f = "%.1f" |
| } |
| |
| return fmt.Sprintf(f+"%s", val, suffix) |
| |
| } |
| |
| // Bytes produces a human readable representation of an SI size. |
| // Bytes(82854982) -> 83MB |
| func Bytes(s uint64) string { |
| sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"} |
| return humanateBytes(uint64(s), 1000, sizes) |
| } |
| |
| // IBytes produces a human readable representation of an IEC size. |
| // IBytes(82854982) -> 79MiB |
| func IBytes(s uint64) string { |
| sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} |
| return humanateBytes(uint64(s), 1024, sizes) |
| } |
| |
| // ParseBytes parses a string representation of bytes into the number |
| // of bytes it represents. |
| // ParseBytes("42MB") -> 42000000, nil |
| // ParseBytes("42mib") -> 44040192, nil |
| func ParseBytes(s string) (uint64, error) { |
| lastDigit := 0 |
| for _, r := range s { |
| if !(unicode.IsDigit(r) || r == '.') { |
| break |
| } |
| lastDigit++ |
| } |
| |
| f, err := strconv.ParseFloat(s[:lastDigit], 64) |
| if err != nil { |
| return 0, err |
| } |
| |
| extra := strings.ToLower(strings.TrimSpace(s[lastDigit:])) |
| if m, ok := bytesSizeTable[extra]; ok { |
| return uint64(f * float64(m)), nil |
| } |
| |
| return 0, fmt.Errorf("Unhandled size name: %v", extra) |
| } |