bigbytes.go raw

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