dip/vendor/github.com/labstack/gommon/bytes/bytes.go

217 lines
4.7 KiB
Go
Raw Normal View History

2020-02-11 19:33:19 +01:00
package bytes
import (
"fmt"
"regexp"
"strconv"
"strings"
)
type (
// Bytes struct
Bytes struct{}
)
2022-11-02 17:50:56 +01:00
// binary units (IEC 60027)
2020-02-11 19:33:19 +01:00
const (
_ = 1.0 << (10 * iota) // ignore first value by assigning to blank identifier
2022-11-02 17:50:56 +01:00
KiB
MiB
GiB
TiB
PiB
EiB
)
// decimal units (SI international system of units)
const (
KB = 1000
MB = KB * 1000
GB = MB * 1000
TB = GB * 1000
PB = TB * 1000
EB = PB * 1000
2020-02-11 19:33:19 +01:00
)
var (
2022-11-02 17:50:56 +01:00
patternBinary = regexp.MustCompile(`(?i)^(-?\d+(?:\.\d+)?)\s?([KMGTPE]iB?)$`)
patternDecimal = regexp.MustCompile(`(?i)^(-?\d+(?:\.\d+)?)\s?([KMGTPE]B?|B?)$`)
global = New()
2020-02-11 19:33:19 +01:00
)
// New creates a Bytes instance.
func New() *Bytes {
return &Bytes{}
}
2022-11-02 17:50:56 +01:00
// Format formats bytes integer to human readable string according to IEC 60027.
// For example, 31323 bytes will return 30.59KB.
func (b *Bytes) Format(value int64) string {
return b.FormatBinary(value)
}
// FormatBinary formats bytes integer to human readable string according to IEC 60027.
2020-02-11 19:33:19 +01:00
// For example, 31323 bytes will return 30.59KB.
2022-11-02 17:50:56 +01:00
func (*Bytes) FormatBinary(value int64) string {
multiple := ""
val := float64(value)
switch {
case value >= EiB:
val /= EiB
multiple = "EiB"
case value >= PiB:
val /= PiB
multiple = "PiB"
case value >= TiB:
val /= TiB
multiple = "TiB"
case value >= GiB:
val /= GiB
multiple = "GiB"
case value >= MiB:
val /= MiB
multiple = "MiB"
case value >= KiB:
val /= KiB
multiple = "KiB"
case value == 0:
return "0"
default:
return strconv.FormatInt(value, 10) + "B"
}
return fmt.Sprintf("%.2f%s", val, multiple)
}
// FormatDecimal formats bytes integer to human readable string according to SI international system of units.
// For example, 31323 bytes will return 31.32KB.
func (*Bytes) FormatDecimal(value int64) string {
2020-02-11 19:33:19 +01:00
multiple := ""
2022-11-02 17:50:56 +01:00
val := float64(value)
2020-02-11 19:33:19 +01:00
switch {
2022-11-02 17:50:56 +01:00
case value >= EB:
val /= EB
2020-02-11 19:33:19 +01:00
multiple = "EB"
2022-11-02 17:50:56 +01:00
case value >= PB:
val /= PB
2020-02-11 19:33:19 +01:00
multiple = "PB"
2022-11-02 17:50:56 +01:00
case value >= TB:
val /= TB
2020-02-11 19:33:19 +01:00
multiple = "TB"
2022-11-02 17:50:56 +01:00
case value >= GB:
val /= GB
2020-02-11 19:33:19 +01:00
multiple = "GB"
2022-11-02 17:50:56 +01:00
case value >= MB:
val /= MB
2020-02-11 19:33:19 +01:00
multiple = "MB"
2022-11-02 17:50:56 +01:00
case value >= KB:
val /= KB
2020-02-11 19:33:19 +01:00
multiple = "KB"
2022-11-02 17:50:56 +01:00
case value == 0:
2020-02-11 19:33:19 +01:00
return "0"
default:
2022-11-02 17:50:56 +01:00
return strconv.FormatInt(value, 10) + "B"
2020-02-11 19:33:19 +01:00
}
2022-11-02 17:50:56 +01:00
return fmt.Sprintf("%.2f%s", val, multiple)
2020-02-11 19:33:19 +01:00
}
// Parse parses human readable bytes string to bytes integer.
2022-11-02 17:50:56 +01:00
// For example, 6GiB (6Gi is also valid) will return 6442450944, and
// 6GB (6G is also valid) will return 6000000000.
func (b *Bytes) Parse(value string) (int64, error) {
i, err := b.ParseBinary(value)
if err == nil {
return i, err
}
return b.ParseDecimal(value)
}
// ParseBinary parses human readable bytes string to bytes integer.
// For example, 6GiB (6Gi is also valid) will return 6442450944.
func (*Bytes) ParseBinary(value string) (i int64, err error) {
parts := patternBinary.FindStringSubmatch(value)
2020-02-11 19:33:19 +01:00
if len(parts) < 3 {
return 0, fmt.Errorf("error parsing value=%s", value)
}
bytesString := parts[1]
multiple := strings.ToUpper(parts[2])
bytes, err := strconv.ParseFloat(bytesString, 64)
if err != nil {
return
}
switch multiple {
2022-11-02 17:50:56 +01:00
case "KI", "KIB":
return int64(bytes * KiB), nil
case "MI", "MIB":
return int64(bytes * MiB), nil
case "GI", "GIB":
return int64(bytes * GiB), nil
case "TI", "TIB":
return int64(bytes * TiB), nil
case "PI", "PIB":
return int64(bytes * PiB), nil
case "EI", "EIB":
return int64(bytes * EiB), nil
2020-02-11 19:33:19 +01:00
default:
return int64(bytes), nil
2022-11-02 17:50:56 +01:00
}
}
// ParseDecimal parses human readable bytes string to bytes integer.
// For example, 6GB (6G is also valid) will return 6000000000.
func (*Bytes) ParseDecimal(value string) (i int64, err error) {
parts := patternDecimal.FindStringSubmatch(value)
if len(parts) < 3 {
return 0, fmt.Errorf("error parsing value=%s", value)
}
bytesString := parts[1]
multiple := strings.ToUpper(parts[2])
bytes, err := strconv.ParseFloat(bytesString, 64)
if err != nil {
return
}
switch multiple {
2020-02-11 19:33:19 +01:00
case "K", "KB":
return int64(bytes * KB), nil
case "M", "MB":
return int64(bytes * MB), nil
case "G", "GB":
return int64(bytes * GB), nil
case "T", "TB":
return int64(bytes * TB), nil
case "P", "PB":
return int64(bytes * PB), nil
case "E", "EB":
return int64(bytes * EB), nil
2022-11-02 17:50:56 +01:00
default:
return int64(bytes), nil
2020-02-11 19:33:19 +01:00
}
}
// Format wraps global Bytes's Format function.
2022-11-02 17:50:56 +01:00
func Format(value int64) string {
return global.Format(value)
}
// FormatBinary wraps global Bytes's FormatBinary function.
func FormatBinary(value int64) string {
return global.FormatBinary(value)
}
// FormatDecimal wraps global Bytes's FormatDecimal function.
func FormatDecimal(value int64) string {
return global.FormatDecimal(value)
2020-02-11 19:33:19 +01:00
}
// Parse wraps global Bytes's Parse function.
2022-11-02 17:50:56 +01:00
func Parse(value string) (int64, error) {
return global.Parse(value)
2020-02-11 19:33:19 +01:00
}