gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

bytes.go (2610B)


      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 }