| package humanize |
| |
| import ( |
| "fmt" |
| "math/big" |
| "strings" |
| "unicode" |
| ) |
| |
| var ( |
| bigIECExp = big.NewInt(1024) |
| |
| // BigByte is one byte in bit.Ints |
| BigByte = big.NewInt(1) |
| // BigKiByte is 1,024 bytes in bit.Ints |
| BigKiByte = (&big.Int{}).Mul(BigByte, bigIECExp) |
| // BigMiByte is 1,024 k bytes in bit.Ints |
| BigMiByte = (&big.Int{}).Mul(BigKiByte, bigIECExp) |
| // BigGiByte is 1,024 m bytes in bit.Ints |
| BigGiByte = (&big.Int{}).Mul(BigMiByte, bigIECExp) |
| // BigTiByte is 1,024 g bytes in bit.Ints |
| BigTiByte = (&big.Int{}).Mul(BigGiByte, bigIECExp) |
| // BigPiByte is 1,024 t bytes in bit.Ints |
| BigPiByte = (&big.Int{}).Mul(BigTiByte, bigIECExp) |
| // BigEiByte is 1,024 p bytes in bit.Ints |
| BigEiByte = (&big.Int{}).Mul(BigPiByte, bigIECExp) |
| // BigZiByte is 1,024 e bytes in bit.Ints |
| BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp) |
| // BigYiByte is 1,024 z bytes in bit.Ints |
| BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp) |
| ) |
| |
| var ( |
| bigSIExp = big.NewInt(1000) |
| |
| // BigSIByte is one SI byte in big.Ints |
| BigSIByte = big.NewInt(1) |
| // BigKByte is 1,000 SI bytes in big.Ints |
| BigKByte = (&big.Int{}).Mul(BigSIByte, bigSIExp) |
| // BigMByte is 1,000 SI k bytes in big.Ints |
| BigMByte = (&big.Int{}).Mul(BigKByte, bigSIExp) |
| // BigGByte is 1,000 SI m bytes in big.Ints |
| BigGByte = (&big.Int{}).Mul(BigMByte, bigSIExp) |
| // BigTByte is 1,000 SI g bytes in big.Ints |
| BigTByte = (&big.Int{}).Mul(BigGByte, bigSIExp) |
| // BigPByte is 1,000 SI t bytes in big.Ints |
| BigPByte = (&big.Int{}).Mul(BigTByte, bigSIExp) |
| // BigEByte is 1,000 SI p bytes in big.Ints |
| BigEByte = (&big.Int{}).Mul(BigPByte, bigSIExp) |
| // BigZByte is 1,000 SI e bytes in big.Ints |
| BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp) |
| // BigYByte is 1,000 SI z bytes in big.Ints |
| BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp) |
| ) |
| |
| var bigBytesSizeTable = map[string]*big.Int{ |
| "b": BigByte, |
| "kib": BigKiByte, |
| "kb": BigKByte, |
| "mib": BigMiByte, |
| "mb": BigMByte, |
| "gib": BigGiByte, |
| "gb": BigGByte, |
| "tib": BigTiByte, |
| "tb": BigTByte, |
| "pib": BigPiByte, |
| "pb": BigPByte, |
| "eib": BigEiByte, |
| "eb": BigEByte, |
| "zib": BigZiByte, |
| "zb": BigZByte, |
| "yib": BigYiByte, |
| "yb": BigYByte, |
| // Without suffix |
| "": BigByte, |
| "ki": BigKiByte, |
| "k": BigKByte, |
| "mi": BigMiByte, |
| "m": BigMByte, |
| "gi": BigGiByte, |
| "g": BigGByte, |
| "ti": BigTiByte, |
| "t": BigTByte, |
| "pi": BigPiByte, |
| "p": BigPByte, |
| "ei": BigEiByte, |
| "e": BigEByte, |
| "z": BigZByte, |
| "zi": BigZiByte, |
| "y": BigYByte, |
| "yi": BigYiByte, |
| } |
| |
| var ten = big.NewInt(10) |
| |
| func humanateBigBytes(s, base *big.Int, sizes []string) string { |
| if s.Cmp(ten) < 0 { |
| return fmt.Sprintf("%d B", s) |
| } |
| c := (&big.Int{}).Set(s) |
| val, mag := oomm(c, base, len(sizes)-1) |
| suffix := sizes[mag] |
| f := "%.0f %s" |
| if val < 10 { |
| f = "%.1f %s" |
| } |
| |
| return fmt.Sprintf(f, val, suffix) |
| |
| } |
| |
| // BigBytes produces a human readable representation of an SI size. |
| // |
| // See also: ParseBigBytes. |
| // |
| // BigBytes(82854982) -> 83 MB |
| func BigBytes(s *big.Int) string { |
| sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} |
| return humanateBigBytes(s, bigSIExp, sizes) |
| } |
| |
| // BigIBytes produces a human readable representation of an IEC size. |
| // |
| // See also: ParseBigBytes. |
| // |
| // BigIBytes(82854982) -> 79 MiB |
| func BigIBytes(s *big.Int) string { |
| sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"} |
| return humanateBigBytes(s, bigIECExp, sizes) |
| } |
| |
| // ParseBigBytes parses a string representation of bytes into the number |
| // of bytes it represents. |
| // |
| // See also: BigBytes, BigIBytes. |
| // |
| // ParseBigBytes("42 MB") -> 42000000, nil |
| // ParseBigBytes("42 mib") -> 44040192, nil |
| func ParseBigBytes(s string) (*big.Int, 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) |
| } |
| |
| val := &big.Rat{} |
| _, err := fmt.Sscanf(num, "%f", val) |
| if err != nil { |
| return nil, err |
| } |
| |
| extra := strings.ToLower(strings.TrimSpace(s[lastDigit:])) |
| if m, ok := bigBytesSizeTable[extra]; ok { |
| mv := (&big.Rat{}).SetInt(m) |
| val.Mul(val, mv) |
| rv := &big.Int{} |
| rv.Div(val.Num(), val.Denom()) |
| return rv, nil |
| } |
| |
| return nil, fmt.Errorf("unhandled size name: %v", extra) |
| } |