Browse code

pkg/units: including suggestions and enhancements

Docker-DCO-1.1-Signed-off-by: fcarriedo <fcarriedo@gmail.com> (github: fcarriedo)

fcarriedo authored on 2014/07/26 01:33:04
Showing 1 changed files
... ...
@@ -7,9 +7,30 @@ import (
7 7
 	"strings"
8 8
 )
9 9
 
10
+type unit int64
11
+
12
+// See: http://en.wikipedia.org/wiki/Binary_prefix
10 13
 const (
11
-	decimalKUnit = 1000
12
-	binaryKUnit  = 1024
14
+	// Decimal
15
+	KB unit = 1000
16
+	MB      = 1000 * KB
17
+	GB      = 1000 * MB
18
+	TB      = 1000 * GB
19
+	PB      = 1000 * TB
20
+
21
+	// Binary
22
+	KiB unit = 1024
23
+	MiB      = 1024 * KiB
24
+	GiB      = 1024 * MiB
25
+	TiB      = 1024 * GiB
26
+	PiB      = 1024 * TiB
27
+)
28
+
29
+type unitMap map[string]unit
30
+
31
+var (
32
+	decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
33
+	binaryMap  = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
13 34
 )
14 35
 
15 36
 var sizeRegex *regexp.Regexp
... ...
@@ -18,7 +39,7 @@ func init() {
18 18
 	sizeRegex = regexp.MustCompile("^(\\d+)([kKmMgGtTpP])?[bB]?$")
19 19
 }
20 20
 
21
-var bytePrefixes = [...]string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
21
+var unitAbbrs = [...]string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
22 22
 
23 23
 // HumanSize returns a human-readable approximation of a size
24 24
 // using SI standard (eg. "44kB", "17MB")
... ...
@@ -29,13 +50,13 @@ func HumanSize(size int64) string {
29 29
 		sizef = sizef / 1000.0
30 30
 		i++
31 31
 	}
32
-	return fmt.Sprintf("%.4g %s", sizef, bytePrefixes[i])
32
+	return fmt.Sprintf("%.4g %s", sizef, unitAbbrs[i])
33 33
 }
34 34
 
35 35
 // FromHumanSize returns an integer from a human-readable specification of a
36 36
 // size using SI standard (eg. "44kB", "17MB")
37 37
 func FromHumanSize(size string) (int64, error) {
38
-	return parseSize(size, decimalKUnit)
38
+	return parseSize(size, decimalMap)
39 39
 }
40 40
 
41 41
 // Parses a human-readable string representing an amount of RAM
... ...
@@ -43,37 +64,25 @@ func FromHumanSize(size string) (int64, error) {
43 43
 // returns the number of bytes, or -1 if the string is unparseable.
44 44
 // Units are case-insensitive, and the 'b' suffix is optional.
45 45
 func RAMInBytes(size string) (int64, error) {
46
-	return parseSize(size, binaryKUnit)
46
+	return parseSize(size, binaryMap)
47 47
 }
48 48
 
49
-// Parses the human-readable size string into the amount it represents given
50
-// the desired kilo unit [decimalKiloUnit=1000|binaryKiloUnit=1024]
51
-func parseSize(size string, kUnit int64) (int64, error) {
52
-	matches := sizeRegex.FindStringSubmatch(size)
53
-
49
+// Parses the human-readable size string into the amount it represents
50
+func parseSize(sizeStr string, uMap unitMap) (int64, error) {
51
+	matches := sizeRegex.FindStringSubmatch(sizeStr)
54 52
 	if len(matches) != 3 {
55
-		return -1, fmt.Errorf("Invalid size: '%s'", size)
53
+		return -1, fmt.Errorf("Invalid size: '%s'", sizeStr)
56 54
 	}
57 55
 
58
-	theSize, err := strconv.ParseInt(matches[1], 10, 0)
56
+	size, err := strconv.ParseInt(matches[1], 10, 0)
59 57
 	if err != nil {
60 58
 		return -1, err
61 59
 	}
62 60
 
63 61
 	unitPrefix := strings.ToLower(matches[2])
64
-
65
-	switch unitPrefix {
66
-	case "k":
67
-		theSize *= kUnit
68
-	case "m":
69
-		theSize *= kUnit * kUnit
70
-	case "g":
71
-		theSize *= kUnit * kUnit * kUnit
72
-	case "t":
73
-		theSize *= kUnit * kUnit * kUnit * kUnit
74
-	case "p":
75
-		theSize *= kUnit * kUnit * kUnit * kUnit * kUnit
62
+	if mul, ok := uMap[unitPrefix]; ok {
63
+		size *= int64(mul)
76 64
 	}
77 65
 
78
-	return theSize, nil
66
+	return size, nil
79 67
 }