mirror of
https://github.com/restic/restic.git
synced 2024-08-30 16:17:23 +02:00
174 lines
4.2 KiB
Go
174 lines
4.2 KiB
Go
|
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)
|
||
|
}
|