mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package humanize
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"unicode"
 | 
						|
)
 | 
						|
 | 
						|
// IEC Sizes.
 | 
						|
// kibis of bits
 | 
						|
const (
 | 
						|
	Byte = 1 << (iota * 10)
 | 
						|
	KiByte
 | 
						|
	MiByte
 | 
						|
	GiByte
 | 
						|
	TiByte
 | 
						|
	PiByte
 | 
						|
	EiByte
 | 
						|
)
 | 
						|
 | 
						|
// SI Sizes.
 | 
						|
const (
 | 
						|
	IByte = 1
 | 
						|
	KByte = IByte * 1000
 | 
						|
	MByte = KByte * 1000
 | 
						|
	GByte = MByte * 1000
 | 
						|
	TByte = GByte * 1000
 | 
						|
	PByte = TByte * 1000
 | 
						|
	EByte = PByte * 1000
 | 
						|
)
 | 
						|
 | 
						|
var bytesSizeTable = map[string]uint64{
 | 
						|
	"b":   Byte,
 | 
						|
	"kib": KiByte,
 | 
						|
	"kb":  KByte,
 | 
						|
	"mib": MiByte,
 | 
						|
	"mb":  MByte,
 | 
						|
	"gib": GiByte,
 | 
						|
	"gb":  GByte,
 | 
						|
	"tib": TiByte,
 | 
						|
	"tb":  TByte,
 | 
						|
	"pib": PiByte,
 | 
						|
	"pb":  PByte,
 | 
						|
	"eib": EiByte,
 | 
						|
	"eb":  EByte,
 | 
						|
	// Without suffix
 | 
						|
	"":   Byte,
 | 
						|
	"ki": KiByte,
 | 
						|
	"k":  KByte,
 | 
						|
	"mi": MiByte,
 | 
						|
	"m":  MByte,
 | 
						|
	"gi": GiByte,
 | 
						|
	"g":  GByte,
 | 
						|
	"ti": TiByte,
 | 
						|
	"t":  TByte,
 | 
						|
	"pi": PiByte,
 | 
						|
	"p":  PByte,
 | 
						|
	"ei": EiByte,
 | 
						|
	"e":  EByte,
 | 
						|
}
 | 
						|
 | 
						|
func logn(n, b float64) float64 {
 | 
						|
	return math.Log(n) / math.Log(b)
 | 
						|
}
 | 
						|
 | 
						|
func humanateBytes(s uint64, base float64, sizes []string) string {
 | 
						|
	if s < 10 {
 | 
						|
		return fmt.Sprintf("%d B", s)
 | 
						|
	}
 | 
						|
	e := math.Floor(logn(float64(s), base))
 | 
						|
	suffix := sizes[int(e)]
 | 
						|
	val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
 | 
						|
	f := "%.0f %s"
 | 
						|
	if val < 10 {
 | 
						|
		f = "%.1f %s"
 | 
						|
	}
 | 
						|
 | 
						|
	return fmt.Sprintf(f, val, suffix)
 | 
						|
}
 | 
						|
 | 
						|
// Bytes produces a human readable representation of an SI size.
 | 
						|
//
 | 
						|
// See also: ParseBytes.
 | 
						|
//
 | 
						|
// Bytes(82854982) -> 83 MB
 | 
						|
func Bytes(s uint64) string {
 | 
						|
	sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
 | 
						|
	return humanateBytes(s, 1000, sizes)
 | 
						|
}
 | 
						|
 | 
						|
// IBytes produces a human readable representation of an IEC size.
 | 
						|
//
 | 
						|
// See also: ParseBytes.
 | 
						|
//
 | 
						|
// IBytes(82854982) -> 79 MiB
 | 
						|
func IBytes(s uint64) string {
 | 
						|
	sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
 | 
						|
	return humanateBytes(s, 1024, sizes)
 | 
						|
}
 | 
						|
 | 
						|
// ParseBytes parses a string representation of bytes into the number
 | 
						|
// of bytes it represents.
 | 
						|
//
 | 
						|
// See Also: Bytes, IBytes.
 | 
						|
//
 | 
						|
// ParseBytes("42 MB") -> 42000000, nil
 | 
						|
// ParseBytes("42 mib") -> 44040192, nil
 | 
						|
func ParseBytes(s string) (uint64, error) {
 | 
						|
	lastDigit := 0
 | 
						|
	hasComma := false
 | 
						|
	for _, r := range s {
 | 
						|
		if !(unicode.IsDigit(r) || r == '.' || r == ',') {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		if r == ',' {
 | 
						|
			hasComma = true
 | 
						|
		}
 | 
						|
		lastDigit++
 | 
						|
	}
 | 
						|
 | 
						|
	num := s[:lastDigit]
 | 
						|
	if hasComma {
 | 
						|
		num = strings.Replace(num, ",", "", -1)
 | 
						|
	}
 | 
						|
 | 
						|
	f, err := strconv.ParseFloat(num, 64)
 | 
						|
	if err != nil {
 | 
						|
		return 0, err
 | 
						|
	}
 | 
						|
 | 
						|
	extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
 | 
						|
	if m, ok := bytesSizeTable[extra]; ok {
 | 
						|
		f *= float64(m)
 | 
						|
		if f >= math.MaxUint64 {
 | 
						|
			return 0, fmt.Errorf("too large: %v", s)
 | 
						|
		}
 | 
						|
		return uint64(f), nil
 | 
						|
	}
 | 
						|
 | 
						|
	return 0, fmt.Errorf("unhandled size name: %v", extra)
 | 
						|
}
 |