~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/dustin/go-humanize/bytes.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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("%dB", 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) -> 83MB
 
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) -> 79MiB
 
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("42MB") -> 42000000, nil
 
109
// ParseBytes("42mib") -> 44040192, nil
 
110
func ParseBytes(s string) (uint64, error) {
 
111
        lastDigit := 0
 
112
        for _, r := range s {
 
113
                if !(unicode.IsDigit(r) || r == '.') {
 
114
                        break
 
115
                }
 
116
                lastDigit++
 
117
        }
 
118
 
 
119
        f, err := strconv.ParseFloat(s[:lastDigit], 64)
 
120
        if err != nil {
 
121
                return 0, err
 
122
        }
 
123
 
 
124
        extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
 
125
        if m, ok := bytesSizeTable[extra]; ok {
 
126
                f *= float64(m)
 
127
                if f >= math.MaxUint64 {
 
128
                        return 0, fmt.Errorf("too large: %v", s)
 
129
                }
 
130
                return uint64(f), nil
 
131
        }
 
132
 
 
133
        return 0, fmt.Errorf("unhandled size name: %v", extra)
 
134
}