Permalink
Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign uppackage humanize | |
import ( | |
"fmt" | |
"math" | |
"strconv" | |
"strings" | |
"unicode" | |
) | |
// IEC Sizes. | |
// kibis of bits | |
const ( | |
Byte = 1 << (iota * 10) | |
KiByte | |
MiByte | |
GiByte | |
TiByte | |
PiByte | |
EiByte | |
) | |
// 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("%d B", s) | |
} | |
e := math.Floor(logn(float64(s), base)) | |
suffix := sizes[int(e)] | |
val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10 | |
f := "%.0f %s" | |
if val < 10 { | |
f = "%.1f %s" | |
} | |
return fmt.Sprintf(f, val, suffix) | |
} | |
// Bytes produces a human readable representation of an SI size. | |
// | |
// See also: ParseBytes. | |
// | |
// Bytes(82854982) -> 83 MB | |
func Bytes(s uint64) string { | |
sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"} | |
return humanateBytes(s, 1000, sizes) | |
} | |
// IBytes produces a human readable representation of an IEC size. | |
// | |
// See also: ParseBytes. | |
// | |
// IBytes(82854982) -> 79 MiB | |
func IBytes(s uint64) string { | |
sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} | |
return humanateBytes(s, 1024, sizes) | |
} | |
// ParseBytes parses a string representation of bytes into the number | |
// of bytes it represents. | |
// | |
// See Also: Bytes, IBytes. | |
// | |
// ParseBytes("42 MB") -> 42000000, nil | |
// ParseBytes("42 mib") -> 44040192, nil | |
func ParseBytes(s string) (uint64, error) { | |
lastDigit := 0 | |
hasComma := false | |
for _, r := range s { | |
if !(unicode.IsDigit(r) || r == '.' || r == ',') { | |
break | |
} | |
if r == ',' { | |
hasComma = true | |
} | |
lastDigit++ | |
} | |
num := s[:lastDigit] | |
if hasComma { | |
num = strings.Replace(num, ",", "", -1) | |
} | |
f, err := strconv.ParseFloat(num, 64) | |
if err != nil { | |
return 0, err | |
} | |
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:])) | |
if m, ok := bytesSizeTable[extra]; ok { | |
f *= float64(m) | |
if f >= math.MaxUint64 { | |
return 0, fmt.Errorf("too large: %v", s) | |
} | |
return uint64(f), nil | |
} | |
return 0, fmt.Errorf("unhandled size name: %v", extra) | |
} |