123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- package 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)
- }
|