bitbucket.org/ai69/amoy@v0.2.3/humanize_bytes.go (about) 1 package amoy 2 3 // Migrate from https://github.com/dustin/go-humanize/blob/master/bytes.go 4 5 import ( 6 "fmt" 7 "math" 8 "strconv" 9 "strings" 10 "unicode" 11 ) 12 13 // IEC Sizes. 14 // kibis of bits 15 const ( 16 Byte = 1 << (iota * 10) 17 KiByte 18 MiByte 19 GiByte 20 TiByte 21 PiByte 22 EiByte 23 ) 24 25 // SI Sizes. 26 const ( 27 IByte = 1 28 KByte = IByte * 1000 29 MByte = KByte * 1000 30 GByte = MByte * 1000 31 TByte = GByte * 1000 32 PByte = TByte * 1000 33 EByte = PByte * 1000 34 ) 35 36 var bytesSizeTable = map[string]uint64{ 37 "b": Byte, 38 "kib": KiByte, 39 "kb": KByte, 40 "mib": MiByte, 41 "mb": MByte, 42 "gib": GiByte, 43 "gb": GByte, 44 "tib": TiByte, 45 "tb": TByte, 46 "pib": PiByte, 47 "pb": PByte, 48 "eib": EiByte, 49 "eb": EByte, 50 // Without suffix 51 "": Byte, 52 "ki": KiByte, 53 "k": KByte, 54 "mi": MiByte, 55 "m": MByte, 56 "gi": GiByte, 57 "g": GByte, 58 "ti": TiByte, 59 "t": TByte, 60 "pi": PiByte, 61 "p": PByte, 62 "ei": EiByte, 63 "e": EByte, 64 } 65 66 func logn(n, b float64) float64 { 67 return math.Log(n) / math.Log(b) 68 } 69 70 func humanateBytes(s uint64, base float64, sizes []string) string { 71 if s < 10 { 72 return fmt.Sprintf("%d B", s) 73 } 74 e := math.Floor(logn(float64(s), base)) 75 suffix := sizes[int(e)] 76 val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10 77 f := "%.0f %s" 78 if val < 10 { 79 f = "%.1f %s" 80 } 81 82 return fmt.Sprintf(f, val, suffix) 83 } 84 85 // HumanizeBytes produces a human readable representation of an SI size. 86 // 87 // HumanizeBytes(82854982) -> 83 MB 88 func HumanizeBytes(s uint64) string { 89 sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"} 90 return humanateBytes(s, 1000, sizes) 91 } 92 93 // HumanizeIBytes produces a human readable representation of an IEC size. 94 // 95 // HumanizeIBytes(82854982) -> 79 MiB 96 func HumanizeIBytes(s uint64) string { 97 sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} 98 return humanateBytes(s, 1024, sizes) 99 } 100 101 // ParseHumanizedBytes parses a string representation of bytes into the number 102 // of bytes it represents. 103 // 104 // ParseHumanizedBytes("42 MB") -> 42000000, nil 105 // ParseHumanizedBytes("42 mib") -> 44040192, nil 106 func ParseHumanizedBytes(s string) (uint64, error) { 107 lastDigit := 0 108 hasComma := false 109 for _, r := range s { 110 if !(unicode.IsDigit(r) || r == '.' || r == ',') { 111 break 112 } 113 if r == ',' { 114 hasComma = true 115 } 116 lastDigit++ 117 } 118 119 num := s[:lastDigit] 120 if hasComma { 121 num = strings.Replace(num, ",", "", -1) 122 } 123 124 f, err := strconv.ParseFloat(num, 64) 125 if err != nil { 126 return 0, err 127 } 128 129 extra := strings.ToLower(strings.TrimSpace(s[lastDigit:])) 130 if m, ok := bytesSizeTable[extra]; ok { 131 f *= float64(m) 132 if f >= math.MaxUint64 { 133 return 0, fmt.Errorf("too large: %v", s) 134 } 135 return uint64(f), nil 136 } 137 138 return 0, fmt.Errorf("unhandled size name: %v", extra) 139 }