bitbucket.org/ai69/amoy@v0.2.3/humanize_bytes.go (about)

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