File: units.go

package info (click to toggle)
incus 6.0.4-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 23,864 kB
  • sloc: sh: 16,015; ansic: 3,121; python: 456; makefile: 321; ruby: 51; sql: 50; lisp: 6
file content (194 lines) | stat: -rw-r--r-- 4,616 bytes parent folder | download | duplicates (8)
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package units

import (
	"fmt"
	"strconv"
)

func handleOverflow(val int64, mult int64) (int64, error) {
	result := val * mult
	if val == 0 || mult == 0 || val == 1 || mult == 1 {
		return result, nil
	}

	if val != 0 && (result/val) != mult {
		return -1, fmt.Errorf("Overflow multiplying %d with %d", val, mult)
	}

	return result, nil
}

// ParseByteSizeString parses a human representation of an amount of
// data into a number of bytes.
func ParseByteSizeString(input string) (int64, error) {
	// Empty input
	if input == "" {
		return 0, nil
	}

	// Find where the suffix begins
	suffixLen := 0
	for i, chr := range []byte(input) {
		_, err := strconv.Atoi(string([]byte{chr}))
		if err != nil {
			suffixLen = len(input) - i
			break
		}
	}

	if suffixLen == len(input) {
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	// Extract the suffix
	suffix := input[len(input)-suffixLen:]

	// Extract the value
	value := input[0 : len(input)-suffixLen]
	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return -1, fmt.Errorf("Invalid integer: %s", input)
	}

	// Figure out the multiplicator
	multiplicator := int64(0)
	switch suffix {
	case "", "B", " bytes":
		multiplicator = 1
	case "kB":
		multiplicator = 1000
	case "MB":
		multiplicator = 1000 * 1000
	case "GB":
		multiplicator = 1000 * 1000 * 1000
	case "TB":
		multiplicator = 1000 * 1000 * 1000 * 1000
	case "PB":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000
	case "EB":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000 * 1000
	case "KiB":
		multiplicator = 1024
	case "MiB":
		multiplicator = 1024 * 1024
	case "GiB":
		multiplicator = 1024 * 1024 * 1024
	case "TiB":
		multiplicator = 1024 * 1024 * 1024 * 1024
	case "PiB":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024
	case "EiB":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024 * 1024
	default:
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	return handleOverflow(valueInt, multiplicator)
}

// ParseBitSizeString parses a human representation of an amount of
// data into a number of bits.
func ParseBitSizeString(input string) (int64, error) {
	// Empty input
	if input == "" {
		return 0, nil
	}

	// Find where the suffix begins
	suffixLen := 0
	for i, chr := range []byte(input) {
		_, err := strconv.Atoi(string([]byte{chr}))
		if err != nil {
			suffixLen = len(input) - i
			break
		}
	}

	if suffixLen == len(input) {
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	// Extract the suffix
	suffix := input[len(input)-suffixLen:]

	// Extract the value
	value := input[0 : len(input)-suffixLen]
	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return -1, fmt.Errorf("Invalid integer: %s", input)
	}

	// Figure out the multiplicator
	multiplicator := int64(0)
	switch suffix {
	case "", "bit":
		multiplicator = 1
	case "kbit":
		multiplicator = 1000
	case "Mbit":
		multiplicator = 1000 * 1000
	case "Gbit":
		multiplicator = 1000 * 1000 * 1000
	case "Tbit":
		multiplicator = 1000 * 1000 * 1000 * 1000
	case "Pbit":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000
	case "Ebit":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000 * 1000
	case "Kibit":
		multiplicator = 1024
	case "Mibit":
		multiplicator = 1024 * 1024
	case "Gibit":
		multiplicator = 1024 * 1024 * 1024
	case "Tibit":
		multiplicator = 1024 * 1024 * 1024 * 1024
	case "Pibit":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024
	case "Eibit":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024 * 1024

	default:
		return -1, fmt.Errorf("Unsupported suffix: %s", suffix)
	}

	return handleOverflow(valueInt, multiplicator)
}

// GetByteSizeString takes a number of bytes and precision and returns a
// human representation of the amount of data.
func GetByteSizeString(input int64, precision uint) string {
	if input < 1000 {
		return fmt.Sprintf("%dB", input)
	}

	value := float64(input)

	for _, unit := range []string{"kB", "MB", "GB", "TB", "PB", "EB"} {
		value = value / 1000
		if value < 1000 {
			return fmt.Sprintf("%.*f%s", precision, value, unit)
		}
	}

	return fmt.Sprintf("%.*fEB", precision, value)
}

// GetByteSizeStringIEC takes a number of bytes and precision and returns a
// human representation of the amount of data using IEC units.
func GetByteSizeStringIEC(input int64, precision uint) string {
	if input < 1024 {
		return fmt.Sprintf("%dB", input)
	}

	value := float64(input)

	for _, unit := range []string{"KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} {
		value = value / 1024
		if value < 1024 {
			return fmt.Sprintf("%.*f%s", precision, value, unit)
		}
	}

	return fmt.Sprintf("%.*fEB", precision, value)
}