-
Notifications
You must be signed in to change notification settings - Fork 89
/
size.go
78 lines (68 loc) · 1.91 KB
/
size.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package utils
import (
"math"
"strconv"
"strings"
"unicode"
"github.com/juju/errors"
)
// ParseSize parses the string as a size, in mebibytes.
//
// The string must be a is a non-negative number with
// an optional multiplier suffix (M, G, T, P, E, Z, or Y).
// If the suffix is not specified, "M" is implied.
func ParseSize(str string) (MB uint64, err error) {
// Find the first non-digit/period:
i := strings.IndexFunc(str, func(r rune) bool {
return r != '.' && !unicode.IsDigit(r)
})
var multiplier float64 = 1
if i > 0 {
suffix := str[i:]
multiplier = 0
for j := 0; j < len(sizeSuffixes); j++ {
base := string(sizeSuffixes[j])
// M, MB, or MiB are all valid.
switch suffix {
case base, base + "B", base + "iB":
multiplier = float64(sizeSuffixMultiplier(j))
break
}
}
if multiplier == 0 {
return 0, errors.Errorf("invalid multiplier suffix %q, expected one of %s", suffix, []byte(sizeSuffixes))
}
str = str[:i]
}
val, err := strconv.ParseFloat(str, 64)
if err != nil || val < 0 {
return 0, errors.Errorf("expected a non-negative number, got %q", str)
}
val *= multiplier
return uint64(math.Ceil(val)), nil
}
var sizeSuffixes = "MGTPEZY"
func sizeSuffixMultiplier(i int) int {
return 1 << uint(i*10)
}
// SizeTracker tracks the number of bytes passing through
// its Write method (which is otherwise a no-op).
//
// Use SizeTracker with io.MultiWriter() to track number of bytes
// written. Use with io.TeeReader() to track number of bytes read.
type SizeTracker struct {
// size is the number of bytes written so far.
size int64
}
// Size returns the number of bytes written so far.
func (st SizeTracker) Size() int64 {
return st.size
}
// Write implements io.Writer.
func (st *SizeTracker) Write(data []byte) (n int, err error) {
n = len(data)
st.size += int64(n)
return n, nil
}