...

Source file src/github.com/dustin/go-humanize/bytes.go

Documentation: github.com/dustin/go-humanize

     1  package humanize
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strconv"
     7  	"strings"
     8  	"unicode"
     9  )
    10  
    11  // IEC Sizes.
    12  // kibis of bits
    13  const (
    14  	Byte = 1 << (iota * 10)
    15  	KiByte
    16  	MiByte
    17  	GiByte
    18  	TiByte
    19  	PiByte
    20  	EiByte
    21  )
    22  
    23  // SI Sizes.
    24  const (
    25  	IByte = 1
    26  	KByte = IByte * 1000
    27  	MByte = KByte * 1000
    28  	GByte = MByte * 1000
    29  	TByte = GByte * 1000
    30  	PByte = TByte * 1000
    31  	EByte = PByte * 1000
    32  )
    33  
    34  var bytesSizeTable = map[string]uint64{
    35  	"b":   Byte,
    36  	"kib": KiByte,
    37  	"kb":  KByte,
    38  	"mib": MiByte,
    39  	"mb":  MByte,
    40  	"gib": GiByte,
    41  	"gb":  GByte,
    42  	"tib": TiByte,
    43  	"tb":  TByte,
    44  	"pib": PiByte,
    45  	"pb":  PByte,
    46  	"eib": EiByte,
    47  	"eb":  EByte,
    48  	// Without suffix
    49  	"":   Byte,
    50  	"ki": KiByte,
    51  	"k":  KByte,
    52  	"mi": MiByte,
    53  	"m":  MByte,
    54  	"gi": GiByte,
    55  	"g":  GByte,
    56  	"ti": TiByte,
    57  	"t":  TByte,
    58  	"pi": PiByte,
    59  	"p":  PByte,
    60  	"ei": EiByte,
    61  	"e":  EByte,
    62  }
    63  
    64  func logn(n, b float64) float64 {
    65  	return math.Log(n) / math.Log(b)
    66  }
    67  
    68  func humanateBytes(s uint64, base float64, sizes []string) string {
    69  	if s < 10 {
    70  		return fmt.Sprintf("%d B", s)
    71  	}
    72  	e := math.Floor(logn(float64(s), base))
    73  	suffix := sizes[int(e)]
    74  	val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
    75  	f := "%.0f %s"
    76  	if val < 10 {
    77  		f = "%.1f %s"
    78  	}
    79  
    80  	return fmt.Sprintf(f, val, suffix)
    81  }
    82  
    83  // Bytes produces a human readable representation of an SI size.
    84  //
    85  // See also: ParseBytes.
    86  //
    87  // Bytes(82854982) -> 83 MB
    88  func Bytes(s uint64) string {
    89  	sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
    90  	return humanateBytes(s, 1000, sizes)
    91  }
    92  
    93  // IBytes produces a human readable representation of an IEC size.
    94  //
    95  // See also: ParseBytes.
    96  //
    97  // IBytes(82854982) -> 79 MiB
    98  func IBytes(s uint64) string {
    99  	sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
   100  	return humanateBytes(s, 1024, sizes)
   101  }
   102  
   103  // ParseBytes parses a string representation of bytes into the number
   104  // of bytes it represents.
   105  //
   106  // See Also: Bytes, IBytes.
   107  //
   108  // ParseBytes("42 MB") -> 42000000, nil
   109  // ParseBytes("42 mib") -> 44040192, nil
   110  func ParseBytes(s string) (uint64, error) {
   111  	lastDigit := 0
   112  	hasComma := false
   113  	for _, r := range s {
   114  		if !(unicode.IsDigit(r) || r == '.' || r == ',') {
   115  			break
   116  		}
   117  		if r == ',' {
   118  			hasComma = true
   119  		}
   120  		lastDigit++
   121  	}
   122  
   123  	num := s[:lastDigit]
   124  	if hasComma {
   125  		num = strings.Replace(num, ",", "", -1)
   126  	}
   127  
   128  	f, err := strconv.ParseFloat(num, 64)
   129  	if err != nil {
   130  		return 0, err
   131  	}
   132  
   133  	extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
   134  	if m, ok := bytesSizeTable[extra]; ok {
   135  		f *= float64(m)
   136  		if f >= math.MaxUint64 {
   137  			return 0, fmt.Errorf("too large: %v", s)
   138  		}
   139  		return uint64(f), nil
   140  	}
   141  
   142  	return 0, fmt.Errorf("unhandled size name: %v", extra)
   143  }
   144  

View as plain text