forked from mongodb/mongo-tools-common
-
Notifications
You must be signed in to change notification settings - Fork 0
/
units.go
74 lines (64 loc) · 2.41 KB
/
units.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
// Copyright (C) MongoDB, Inc. 2014-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package text
import (
"fmt"
"math"
)
const (
decimal = 1000
binary = 1024
)
var (
longByteUnits = []string{"B", "KB", "MB", "GB"}
shortByteUnits = []string{"B", "K", "M", "G"}
shortBitUnits = []string{"b", "k", "m", "g"}
)
// FormatByteAmount takes an int64 representing a size in bytes and
// returns a formatted string of a minimum amount of significant figures.
// e.g. 12.4 GB, 0.0 B, 124.5 KB
func FormatByteAmount(size int64) string {
return formatUnitAmount(binary, size, 3, longByteUnits)
}
// FormatMegabyteAmount is equivalent to FormatByteAmount but expects
// an amount of MB instead of bytes.
func FormatMegabyteAmount(size int64) string {
return formatUnitAmount(binary, size*1024*1024, 3, shortByteUnits)
}
// FormatBits takes in a bit (not byte) count and returns a formatted string
// including units with three total digits (except if it is less than 1k)
// e.g. 12.0g, 0b, 124k
func FormatBits(size int64) string {
return formatUnitAmount(decimal, size, 3, shortBitUnits)
}
// formatUnitAmount formats the size using the units and at least minDigits
// numbers, unless the number is already less than the base, where no decimal
// will be added
func formatUnitAmount(base, size int64, minDigits int, units []string) string {
result := float64(size)
divisor := float64(base)
var shifts int
// keep dividing by base and incrementing our unit until
// we hit the right unit or run out of unit strings
for ; result >= divisor && shifts < len(units)-1; shifts++ {
result /= divisor
}
result = round(result, minDigits)
var precision int // Number of digits to show after the decimal
len := 1 + int(math.Log10(result)) // Number of pre-decimal digits in result
if shifts != 0 && len < minDigits {
// Add as many decimal digits as we can
precision = minDigits - len
}
format := fmt.Sprintf("%%.%df%%s", precision)
return fmt.Sprintf(format, result, units[shifts])
}
// round applies the gradeschool method to round to the nth place
func round(result float64, precision int) float64 {
divisor := float64(math.Pow(10.0, float64(precision-1)))
// round(x) == floor(x + 0.5)
return math.Floor(result*divisor+0.5) / divisor
}