blob: 1a2bf61723922c0a199af8c6134be7e801b7edad [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001package humanize
2
3import (
4 "fmt"
5 "math/big"
6 "strings"
7 "unicode"
8)
9
10var (
11 bigIECExp = big.NewInt(1024)
12
13 // BigByte is one byte in bit.Ints
14 BigByte = big.NewInt(1)
15 // BigKiByte is 1,024 bytes in bit.Ints
16 BigKiByte = (&big.Int{}).Mul(BigByte, bigIECExp)
17 // BigMiByte is 1,024 k bytes in bit.Ints
18 BigMiByte = (&big.Int{}).Mul(BigKiByte, bigIECExp)
19 // BigGiByte is 1,024 m bytes in bit.Ints
20 BigGiByte = (&big.Int{}).Mul(BigMiByte, bigIECExp)
21 // BigTiByte is 1,024 g bytes in bit.Ints
22 BigTiByte = (&big.Int{}).Mul(BigGiByte, bigIECExp)
23 // BigPiByte is 1,024 t bytes in bit.Ints
24 BigPiByte = (&big.Int{}).Mul(BigTiByte, bigIECExp)
25 // BigEiByte is 1,024 p bytes in bit.Ints
26 BigEiByte = (&big.Int{}).Mul(BigPiByte, bigIECExp)
27 // BigZiByte is 1,024 e bytes in bit.Ints
28 BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp)
29 // BigYiByte is 1,024 z bytes in bit.Ints
30 BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp)
31)
32
33var (
34 bigSIExp = big.NewInt(1000)
35
36 // BigSIByte is one SI byte in big.Ints
37 BigSIByte = big.NewInt(1)
38 // BigKByte is 1,000 SI bytes in big.Ints
39 BigKByte = (&big.Int{}).Mul(BigSIByte, bigSIExp)
40 // BigMByte is 1,000 SI k bytes in big.Ints
41 BigMByte = (&big.Int{}).Mul(BigKByte, bigSIExp)
42 // BigGByte is 1,000 SI m bytes in big.Ints
43 BigGByte = (&big.Int{}).Mul(BigMByte, bigSIExp)
44 // BigTByte is 1,000 SI g bytes in big.Ints
45 BigTByte = (&big.Int{}).Mul(BigGByte, bigSIExp)
46 // BigPByte is 1,000 SI t bytes in big.Ints
47 BigPByte = (&big.Int{}).Mul(BigTByte, bigSIExp)
48 // BigEByte is 1,000 SI p bytes in big.Ints
49 BigEByte = (&big.Int{}).Mul(BigPByte, bigSIExp)
50 // BigZByte is 1,000 SI e bytes in big.Ints
51 BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp)
52 // BigYByte is 1,000 SI z bytes in big.Ints
53 BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp)
54)
55
56var bigBytesSizeTable = map[string]*big.Int{
57 "b": BigByte,
58 "kib": BigKiByte,
59 "kb": BigKByte,
60 "mib": BigMiByte,
61 "mb": BigMByte,
62 "gib": BigGiByte,
63 "gb": BigGByte,
64 "tib": BigTiByte,
65 "tb": BigTByte,
66 "pib": BigPiByte,
67 "pb": BigPByte,
68 "eib": BigEiByte,
69 "eb": BigEByte,
70 "zib": BigZiByte,
71 "zb": BigZByte,
72 "yib": BigYiByte,
73 "yb": BigYByte,
74 // Without suffix
75 "": BigByte,
76 "ki": BigKiByte,
77 "k": BigKByte,
78 "mi": BigMiByte,
79 "m": BigMByte,
80 "gi": BigGiByte,
81 "g": BigGByte,
82 "ti": BigTiByte,
83 "t": BigTByte,
84 "pi": BigPiByte,
85 "p": BigPByte,
86 "ei": BigEiByte,
87 "e": BigEByte,
88 "z": BigZByte,
89 "zi": BigZiByte,
90 "y": BigYByte,
91 "yi": BigYiByte,
92}
93
94var ten = big.NewInt(10)
95
96func humanateBigBytes(s, base *big.Int, sizes []string) string {
97 if s.Cmp(ten) < 0 {
98 return fmt.Sprintf("%d B", s)
99 }
100 c := (&big.Int{}).Set(s)
101 val, mag := oomm(c, base, len(sizes)-1)
102 suffix := sizes[mag]
103 f := "%.0f %s"
104 if val < 10 {
105 f = "%.1f %s"
106 }
107
108 return fmt.Sprintf(f, val, suffix)
109
110}
111
112// BigBytes produces a human readable representation of an SI size.
113//
114// See also: ParseBigBytes.
115//
116// BigBytes(82854982) -> 83 MB
117func BigBytes(s *big.Int) string {
118 sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
119 return humanateBigBytes(s, bigSIExp, sizes)
120}
121
122// BigIBytes produces a human readable representation of an IEC size.
123//
124// See also: ParseBigBytes.
125//
126// BigIBytes(82854982) -> 79 MiB
127func BigIBytes(s *big.Int) string {
128 sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
129 return humanateBigBytes(s, bigIECExp, sizes)
130}
131
132// ParseBigBytes parses a string representation of bytes into the number
133// of bytes it represents.
134//
135// See also: BigBytes, BigIBytes.
136//
137// ParseBigBytes("42 MB") -> 42000000, nil
138// ParseBigBytes("42 mib") -> 44040192, nil
139func ParseBigBytes(s string) (*big.Int, error) {
140 lastDigit := 0
141 hasComma := false
142 for _, r := range s {
143 if !(unicode.IsDigit(r) || r == '.' || r == ',') {
144 break
145 }
146 if r == ',' {
147 hasComma = true
148 }
149 lastDigit++
150 }
151
152 num := s[:lastDigit]
153 if hasComma {
154 num = strings.Replace(num, ",", "", -1)
155 }
156
157 val := &big.Rat{}
158 _, err := fmt.Sscanf(num, "%f", val)
159 if err != nil {
160 return nil, err
161 }
162
163 extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
164 if m, ok := bigBytesSizeTable[extra]; ok {
165 mv := (&big.Rat{}).SetInt(m)
166 val.Mul(val, mv)
167 rv := &big.Int{}
168 rv.Div(val.Num(), val.Denom())
169 return rv, nil
170 }
171
172 return nil, fmt.Errorf("unhandled size name: %v", extra)
173}