mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-03-25 21:40:52 +00:00
86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
|
|
package obiutils
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
"unicode"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ParseMemSize parses a human-readable memory size string and returns the
|
||
|
|
// equivalent number of bytes. The value is a number optionally followed by a
|
||
|
|
// unit suffix (case-insensitive):
|
||
|
|
//
|
||
|
|
// B or (no suffix) — bytes
|
||
|
|
// K or KB — kibibytes (1 024)
|
||
|
|
// M or MB — mebibytes (1 048 576)
|
||
|
|
// G or GB — gibibytes (1 073 741 824)
|
||
|
|
// T or TB — tebibytes (1 099 511 627 776)
|
||
|
|
//
|
||
|
|
// Examples: "512", "128K", "128k", "64M", "1G", "2GB"
|
||
|
|
func ParseMemSize(s string) (int, error) {
|
||
|
|
s = strings.TrimSpace(s)
|
||
|
|
if s == "" {
|
||
|
|
return 0, fmt.Errorf("empty memory size string")
|
||
|
|
}
|
||
|
|
|
||
|
|
// split numeric prefix from unit suffix
|
||
|
|
i := 0
|
||
|
|
for i < len(s) && (unicode.IsDigit(rune(s[i])) || s[i] == '.') {
|
||
|
|
i++
|
||
|
|
}
|
||
|
|
numStr := s[:i]
|
||
|
|
unit := strings.ToUpper(strings.TrimSpace(s[i:]))
|
||
|
|
// strip trailing 'B' from two-letter units (KB→K, MB→M …)
|
||
|
|
if len(unit) == 2 && unit[1] == 'B' {
|
||
|
|
unit = unit[:1]
|
||
|
|
}
|
||
|
|
|
||
|
|
val, err := strconv.ParseFloat(numStr, 64)
|
||
|
|
if err != nil {
|
||
|
|
return 0, fmt.Errorf("invalid memory size %q: %w", s, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
var multiplier float64
|
||
|
|
switch unit {
|
||
|
|
case "", "B":
|
||
|
|
multiplier = 1
|
||
|
|
case "K":
|
||
|
|
multiplier = 1024
|
||
|
|
case "M":
|
||
|
|
multiplier = 1024 * 1024
|
||
|
|
case "G":
|
||
|
|
multiplier = 1024 * 1024 * 1024
|
||
|
|
case "T":
|
||
|
|
multiplier = 1024 * 1024 * 1024 * 1024
|
||
|
|
default:
|
||
|
|
return 0, fmt.Errorf("unknown memory unit %q in %q", unit, s)
|
||
|
|
}
|
||
|
|
|
||
|
|
return int(val * multiplier), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// FormatMemSize formats a byte count as a human-readable string with the
|
||
|
|
// largest unit that produces a value ≥ 1 (e.g. 1536 → "1.5K").
|
||
|
|
func FormatMemSize(n int) string {
|
||
|
|
units := []struct {
|
||
|
|
suffix string
|
||
|
|
size int
|
||
|
|
}{
|
||
|
|
{"T", 1024 * 1024 * 1024 * 1024},
|
||
|
|
{"G", 1024 * 1024 * 1024},
|
||
|
|
{"M", 1024 * 1024},
|
||
|
|
{"K", 1024},
|
||
|
|
}
|
||
|
|
for _, u := range units {
|
||
|
|
if n >= u.size {
|
||
|
|
v := float64(n) / float64(u.size)
|
||
|
|
if v == float64(int(v)) {
|
||
|
|
return fmt.Sprintf("%d%s", int(v), u.suffix)
|
||
|
|
}
|
||
|
|
return fmt.Sprintf("%.1f%s", v, u.suffix)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return fmt.Sprintf("%dB", n)
|
||
|
|
}
|