Files
mapsize/internal/textutil/units.go
T

126 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package textutil
import (
"fmt"
"strconv"
"time"
)
// SI selects decimal units (kB, MB, …). The default is IEC (KiB, MiB, …).
// It is set once at start-up, before any goroutines format sizes.
var SI bool
var (
iecUnits = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
siUnits = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
)
func scaled(n int64) (float64, string) {
base, units := 1024.0, iecUnits
if SI {
base, units = 1000.0, siUnits
}
neg := n < 0
v := float64(n)
if neg {
v = -v
}
i := 0
for v >= base && i < len(units)-1 {
v /= base
i++
}
if neg {
v = -v
}
return v, units[i]
}
func num(v float64, unit string) string {
a := v
if a < 0 {
a = -a
}
switch {
case unit == "B":
return strconv.FormatFloat(v, 'f', 0, 64)
case a < 10:
return strconv.FormatFloat(v, 'f', 2, 64)
case a < 100:
return strconv.FormatFloat(v, 'f', 1, 64)
default:
return strconv.FormatFloat(v, 'f', 0, 64)
}
}
// Size formats a byte count, e.g. "86.4 GiB".
func Size(n int64) string {
v, u := scaled(n)
return num(v, u) + " " + u
}
// SizeCompact formats a byte count in at most ~7 cells, e.g. "86GiB".
func SizeCompact(n int64) string {
v, u := scaled(n)
a := v
if a < 0 {
a = -a
}
if u != "B" && a < 10 {
return strconv.FormatFloat(v, 'f', 1, 64) + u
}
return strconv.FormatFloat(v, 'f', 0, 64) + u
}
// SignedSize formats a delta with an explicit sign.
func SignedSize(n int64) string {
if n > 0 {
return "+" + Size(n)
}
if n < 0 {
return "-" + Size(-n)
}
return "±0 B"
}
// Count formats an integer with thousands separators.
func Count(n int64) string {
s := strconv.FormatInt(n, 10)
neg := false
if n < 0 {
neg, s = true, s[1:]
}
out := make([]byte, 0, len(s)+len(s)/3)
for i := range len(s) {
if i > 0 && (len(s)-i)%3 == 0 {
out = append(out, ',')
}
out = append(out, s[i])
}
if neg {
return "-" + string(out)
}
return string(out)
}
// Duration formats an elapsed time as mm:ss or h:mm:ss.
func Duration(d time.Duration) string {
s := int64(d.Seconds())
if s >= 3600 {
return fmt.Sprintf("%d:%02d:%02d", s/3600, s/60%60, s%60)
}
return fmt.Sprintf("%02d:%02d", s/60, s%60)
}
// Percent formats part/whole as a percentage.
func Percent(part, whole int64) string {
if whole <= 0 {
return "–"
}
p := float64(part) * 100 / float64(whole)
if p < 10 {
return strconv.FormatFloat(p, 'f', 1, 64) + "%"
}
return strconv.FormatFloat(p, 'f', 0, 64) + "%"
}