gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

size.go (2996B)


      1 package units
      2 
      3 import (
      4 	"fmt"
      5 	"regexp"
      6 	"strconv"
      7 	"strings"
      8 )
      9 
     10 // See: http://en.wikipedia.org/wiki/Binary_prefix
     11 const (
     12 	// Decimal
     13 
     14 	KB = 1000
     15 	MB = 1000 * KB
     16 	GB = 1000 * MB
     17 	TB = 1000 * GB
     18 	PB = 1000 * TB
     19 
     20 	// Binary
     21 
     22 	KiB = 1024
     23 	MiB = 1024 * KiB
     24 	GiB = 1024 * MiB
     25 	TiB = 1024 * GiB
     26 	PiB = 1024 * TiB
     27 )
     28 
     29 type unitMap map[string]int64
     30 
     31 var (
     32 	decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
     33 	binaryMap  = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
     34 	sizeRegex  = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[iI]?[bB]?$`)
     35 )
     36 
     37 var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
     38 var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
     39 
     40 func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) {
     41 	i := 0
     42 	unitsLimit := len(_map) - 1
     43 	for size >= base && i < unitsLimit {
     44 		size = size / base
     45 		i++
     46 	}
     47 	return size, _map[i]
     48 }
     49 
     50 // CustomSize returns a human-readable approximation of a size
     51 // using custom format.
     52 func CustomSize(format string, size float64, base float64, _map []string) string {
     53 	size, unit := getSizeAndUnit(size, base, _map)
     54 	return fmt.Sprintf(format, size, unit)
     55 }
     56 
     57 // HumanSizeWithPrecision allows the size to be in any precision,
     58 // instead of 4 digit precision used in units.HumanSize.
     59 func HumanSizeWithPrecision(size float64, precision int) string {
     60 	size, unit := getSizeAndUnit(size, 1000.0, decimapAbbrs)
     61 	return fmt.Sprintf("%.*g%s", precision, size, unit)
     62 }
     63 
     64 // HumanSize returns a human-readable approximation of a size
     65 // capped at 4 valid numbers (eg. "2.746 MB", "796 KB").
     66 func HumanSize(size float64) string {
     67 	return HumanSizeWithPrecision(size, 4)
     68 }
     69 
     70 // BytesSize returns a human-readable size in bytes, kibibytes,
     71 // mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB").
     72 func BytesSize(size float64) string {
     73 	return CustomSize("%.4g%s", size, 1024.0, binaryAbbrs)
     74 }
     75 
     76 // FromHumanSize returns an integer from a human-readable specification of a
     77 // size using SI standard (eg. "44kB", "17MB").
     78 func FromHumanSize(size string) (int64, error) {
     79 	return parseSize(size, decimalMap)
     80 }
     81 
     82 // RAMInBytes parses a human-readable string representing an amount of RAM
     83 // in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and
     84 // returns the number of bytes, or -1 if the string is unparseable.
     85 // Units are case-insensitive, and the 'b' suffix is optional.
     86 func RAMInBytes(size string) (int64, error) {
     87 	return parseSize(size, binaryMap)
     88 }
     89 
     90 // Parses the human-readable size string into the amount it represents.
     91 func parseSize(sizeStr string, uMap unitMap) (int64, error) {
     92 	matches := sizeRegex.FindStringSubmatch(sizeStr)
     93 	if len(matches) != 4 {
     94 		return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
     95 	}
     96 
     97 	size, err := strconv.ParseFloat(matches[1], 64)
     98 	if err != nil {
     99 		return -1, err
    100 	}
    101 
    102 	unitPrefix := strings.ToLower(matches[3])
    103 	if mul, ok := uMap[unitPrefix]; ok {
    104 		size *= float64(mul)
    105 	}
    106 
    107 	return int64(size), nil
    108 }