bigbytes.go 4.7 KB

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