mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			126 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| 	Simple byte size formatting.
 | |
| 
 | |
| 	This package implements types that can be used in stdlib formatting functions
 | |
| 	like `fmt.Printf` to control the output of the expected printed string.
 | |
| 
 | |
| 
 | |
| 	Floating point flags %f and %g print the value in using the correct unit
 | |
| 	suffix. Decimal units are default, # switches to binary units. If a value is
 | |
| 	best represented as full bytes, integer bytes are printed instead.
 | |
| 
 | |
| 		Examples:
 | |
| 			fmt.Printf("%.2f", 123 * B)   => "123B"
 | |
| 			fmt.Printf("%.2f", 1234 * B)  => "1.23kB"
 | |
| 			fmt.Printf("%g", 1200 * B)    => "1.2kB"
 | |
| 			fmt.Printf("%#g", 1024 * B)   => "1KiB"
 | |
| 
 | |
| 
 | |
| 	Integer flag %d always prints the value in bytes. # flag adds an unit prefix.
 | |
| 
 | |
| 		Examples:
 | |
| 			fmt.Printf("%d", 1234 * B)    => "1234"
 | |
| 			fmt.Printf("%#d", 1234 * B)   => "1234B"
 | |
| 
 | |
| 	%v is equal to %g
 | |
| 
 | |
| */
 | |
| package units
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"math"
 | |
| 	"math/big"
 | |
| )
 | |
| 
 | |
| type Bytes int64
 | |
| 
 | |
| const (
 | |
| 	B Bytes = 1 << (10 * iota)
 | |
| 	KiB
 | |
| 	MiB
 | |
| 	GiB
 | |
| 	TiB
 | |
| 	PiB
 | |
| 	EiB
 | |
| 
 | |
| 	KB = 1e3 * B
 | |
| 	MB = 1e3 * KB
 | |
| 	GB = 1e3 * MB
 | |
| 	TB = 1e3 * GB
 | |
| 	PB = 1e3 * TB
 | |
| 	EB = 1e3 * PB
 | |
| )
 | |
| 
 | |
| var units = map[bool][]string{
 | |
| 	false: []string{
 | |
| 		"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB",
 | |
| 	},
 | |
| 	true: []string{
 | |
| 		"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB",
 | |
| 	},
 | |
| }
 | |
| 
 | |
| func (b Bytes) Format(f fmt.State, c rune) {
 | |
| 	switch c {
 | |
| 	case 'f', 'g':
 | |
| 		fv, unit, ok := b.floatValue(f.Flag('#'))
 | |
| 		if !ok {
 | |
| 			b.formatInt(&noPrecision{f}, 'd', true)
 | |
| 			return
 | |
| 		}
 | |
| 		big.NewFloat(fv).Format(f, c)
 | |
| 		io.WriteString(f, unit)
 | |
| 	case 'd':
 | |
| 		b.formatInt(f, c, f.Flag('#'))
 | |
| 	default:
 | |
| 		if f.Flag('#') {
 | |
| 			fmt.Fprintf(f, "bytes(%d)", int64(b))
 | |
| 		} else {
 | |
| 			fmt.Fprintf(f, "%g", b)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (b Bytes) formatInt(f fmt.State, c rune, withUnit bool) {
 | |
| 	big.NewInt(int64(b)).Format(f, c)
 | |
| 	if withUnit {
 | |
| 		io.WriteString(f, "B")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (b Bytes) floatValue(binary bool) (float64, string, bool) {
 | |
| 	i := 0
 | |
| 	var baseUnit Bytes = 1
 | |
| 	if b < 0 {
 | |
| 		baseUnit *= -1
 | |
| 	}
 | |
| 	for {
 | |
| 		next := baseUnit
 | |
| 		if binary {
 | |
| 			next *= 1 << 10
 | |
| 		} else {
 | |
| 			next *= 1e3
 | |
| 		}
 | |
| 		if (baseUnit > 0 && b >= next) || (baseUnit < 0 && b <= next) {
 | |
| 			i++
 | |
| 			baseUnit = next
 | |
| 			continue
 | |
| 		}
 | |
| 		if i == 0 {
 | |
| 			return 0, "", false
 | |
| 		}
 | |
| 
 | |
| 		return float64(b) / math.Abs(float64(baseUnit)), units[binary][i], true
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type noPrecision struct {
 | |
| 	fmt.State
 | |
| }
 | |
| 
 | |
| func (*noPrecision) Precision() (prec int, ok bool) {
 | |
| 	return 0, false
 | |
| }
 | 
