forked from sourcegraph/sourcegraph-public-snapshot
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbytesize.go
More file actions
98 lines (84 loc) · 1.91 KB
/
bytesize.go
File metadata and controls
98 lines (84 loc) · 1.91 KB
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// package bytesize provides utilities to work with bytes in human-readable
// form.
package bytesize
import (
"strconv"
"strings"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
// Bytes represents an amount of bytes.
type Bytes int64
const (
maxSize Bytes = 1<<63 - 1
)
const (
B Bytes = 1
KB = 1_000 * B
KiB = 1_024 * B
MB = 1_000 * KB
MiB = 1_024 * KiB
GB = 1_000 * MB
GiB = 1_024 * MiB
)
// Parse parses string that represents an amount of bytes and returns the
// amount in Bytes.
//
// Only positive amounts are supported.
//
// Bytes are represented as int64. If the value overflows, an error is
// returned.
//
// Example inputs: "3 MB", "4 GiB", "172 KiB". See the tests for more examples.
func Parse(str string) (Bytes, error) {
str = strings.TrimSpace(str)
num, unitIndex, err := readNumber(str)
if err != nil {
return 0, errors.Newf("failed to parse %q into number: %s", str[:unitIndex], err)
}
if unitIndex == 0 {
return 0, errors.Newf("missing number at start of string: %s", str)
}
unit, err := parseUnit(str[unitIndex:])
if err != nil {
return 0, err
}
result := Bytes(num) * unit
if result < 0 {
return 0, errors.Newf("value overflows max size of %d bytes", maxSize)
}
return result, nil
}
func readNumber(str string) (int, int, error) {
for i, c := range str {
if isDigit(c) {
continue
}
if i == 0 {
return 0, 0, nil
}
number, err := strconv.Atoi(str[0:i])
return number, i, err
}
return 0, 0, nil
}
func isDigit(ch rune) bool { return '0' <= ch && ch <= '9' }
func parseUnit(unit string) (Bytes, error) {
switch strings.TrimSpace(unit) {
case "B", "b":
return B, nil
case "kB", "KB":
return KB, nil
case "kiB", "KiB":
return KiB, nil
case "MiB":
return MiB, nil
case "MB":
return MB, nil
case "GiB":
return GiB, nil
case "GB":
return GB, nil
default:
return 0, errors.Newf("unknown unit: %s", unit)
}
}