github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/utils/datasize/datasize.go (about)

     1  package datasize
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  )
     9  
    10  type ByteSize uint64
    11  
    12  const (
    13  	B  ByteSize = 1
    14  	KB          = B << 10
    15  	MB          = KB << 10
    16  	GB          = MB << 10
    17  	TB          = GB << 10
    18  	PB          = TB << 10
    19  	EB          = PB << 10
    20  
    21  	fnUnmarshalText string = "UnmarshalText"
    22  	maxUint64       uint64 = (1 << 64) - 1
    23  	cutoff          uint64 = maxUint64 / 10
    24  )
    25  
    26  var ErrBits = errors.New("unit with capital unit prefix and lower case unit (b) - bits, not bytes ")
    27  
    28  var defaultDatasize ByteSize
    29  
    30  func Parse(s string) (bytes uint64, err error) {
    31  	err = defaultDatasize.UnmarshalText([]byte(s))
    32  	if err != nil {
    33  		return
    34  	}
    35  	bytes = defaultDatasize.Bytes()
    36  	return
    37  }
    38  func HumanSize(bytes uint64) (s string, err error) {
    39  	err = defaultDatasize.UnmarshalText([]byte(fmt.Sprintf("%d", bytes)))
    40  	if err != nil {
    41  		return
    42  	}
    43  	s = defaultDatasize.HumanReadable()
    44  	return
    45  }
    46  func (b ByteSize) Bytes() uint64 {
    47  	return uint64(b)
    48  }
    49  
    50  func (b ByteSize) KBytes() float64 {
    51  	v := b / KB
    52  	r := b % KB
    53  	return float64(v) + float64(r)/float64(KB)
    54  }
    55  
    56  func (b ByteSize) MBytes() float64 {
    57  	v := b / MB
    58  	r := b % MB
    59  	return float64(v) + float64(r)/float64(MB)
    60  }
    61  
    62  func (b ByteSize) GBytes() float64 {
    63  	v := b / GB
    64  	r := b % GB
    65  	return float64(v) + float64(r)/float64(GB)
    66  }
    67  
    68  func (b ByteSize) TBytes() float64 {
    69  	v := b / TB
    70  	r := b % TB
    71  	return float64(v) + float64(r)/float64(TB)
    72  }
    73  
    74  func (b ByteSize) PBytes() float64 {
    75  	v := b / PB
    76  	r := b % PB
    77  	return float64(v) + float64(r)/float64(PB)
    78  }
    79  
    80  func (b ByteSize) EBytes() float64 {
    81  	v := b / EB
    82  	r := b % EB
    83  	return float64(v) + float64(r)/float64(EB)
    84  }
    85  
    86  func (b ByteSize) String() string {
    87  	switch {
    88  	case b == 0:
    89  		return fmt.Sprint("0B")
    90  	case b%EB == 0:
    91  		return fmt.Sprintf("%dEB", b/EB)
    92  	case b%PB == 0:
    93  		return fmt.Sprintf("%dPB", b/PB)
    94  	case b%TB == 0:
    95  		return fmt.Sprintf("%dTB", b/TB)
    96  	case b%GB == 0:
    97  		return fmt.Sprintf("%dGB", b/GB)
    98  	case b%MB == 0:
    99  		return fmt.Sprintf("%dMB", b/MB)
   100  	case b%KB == 0:
   101  		return fmt.Sprintf("%dKB", b/KB)
   102  	default:
   103  		return fmt.Sprintf("%dB", b)
   104  	}
   105  }
   106  
   107  func (b ByteSize) HR() string {
   108  	return b.HumanReadable()
   109  }
   110  
   111  func (b ByteSize) HumanReadable() string {
   112  	switch {
   113  	case b > EB:
   114  		return fmt.Sprintf("%.1f EB", b.EBytes())
   115  	case b > PB:
   116  		return fmt.Sprintf("%.1f PB", b.PBytes())
   117  	case b > TB:
   118  		return fmt.Sprintf("%.1f TB", b.TBytes())
   119  	case b > GB:
   120  		return fmt.Sprintf("%.1f GB", b.GBytes())
   121  	case b > MB:
   122  		return fmt.Sprintf("%.1f MB", b.MBytes())
   123  	case b > KB:
   124  		return fmt.Sprintf("%.1f KB", b.KBytes())
   125  	default:
   126  		return fmt.Sprintf("%d B", b)
   127  	}
   128  }
   129  
   130  func (b ByteSize) MarshalText() ([]byte, error) {
   131  	return []byte(b.String()), nil
   132  }
   133  
   134  func (b *ByteSize) UnmarshalText(t []byte) error {
   135  	var val uint64
   136  	var unit string
   137  
   138  	// copy for error message
   139  	t0 := t
   140  
   141  	var c byte
   142  	var i int
   143  
   144  ParseLoop:
   145  	for i < len(t) {
   146  		c = t[i]
   147  		switch {
   148  		case '0' <= c && c <= '9':
   149  			if val > cutoff {
   150  				goto Overflow
   151  			}
   152  
   153  			c = c - '0'
   154  			val *= 10
   155  
   156  			if val > val+uint64(c) {
   157  				// val+v overflows
   158  				goto Overflow
   159  			}
   160  			val += uint64(c)
   161  			i++
   162  
   163  		default:
   164  			if i == 0 {
   165  				goto SyntaxError
   166  			}
   167  			break ParseLoop
   168  		}
   169  	}
   170  
   171  	unit = strings.TrimSpace(string(t[i:]))
   172  	switch unit {
   173  	case "Kb", "Mb", "Gb", "Tb", "Pb", "Eb":
   174  		goto BitsError
   175  	}
   176  	unit = strings.ToLower(unit)
   177  	switch unit {
   178  	case "", "b", "byte":
   179  		// do nothing - already in bytes
   180  
   181  	case "k", "kb", "kilo", "kilobyte", "kilobytes":
   182  		if val > maxUint64/uint64(KB) {
   183  			goto Overflow
   184  		}
   185  		val *= uint64(KB)
   186  
   187  	case "m", "mb", "mega", "megabyte", "megabytes":
   188  		if val > maxUint64/uint64(MB) {
   189  			goto Overflow
   190  		}
   191  		val *= uint64(MB)
   192  
   193  	case "g", "gb", "giga", "gigabyte", "gigabytes":
   194  		if val > maxUint64/uint64(GB) {
   195  			goto Overflow
   196  		}
   197  		val *= uint64(GB)
   198  
   199  	case "t", "tb", "tera", "terabyte", "terabytes":
   200  		if val > maxUint64/uint64(TB) {
   201  			goto Overflow
   202  		}
   203  		val *= uint64(TB)
   204  
   205  	case "p", "pb", "peta", "petabyte", "petabytes":
   206  		if val > maxUint64/uint64(PB) {
   207  			goto Overflow
   208  		}
   209  		val *= uint64(PB)
   210  
   211  	case "E", "EB", "e", "eb", "eB":
   212  		if val > maxUint64/uint64(EB) {
   213  			goto Overflow
   214  		}
   215  		val *= uint64(EB)
   216  
   217  	default:
   218  		goto SyntaxError
   219  	}
   220  
   221  	*b = ByteSize(val)
   222  	return nil
   223  
   224  Overflow:
   225  	*b = ByteSize(maxUint64)
   226  	return &strconv.NumError{fnUnmarshalText, string(t0), strconv.ErrRange}
   227  
   228  SyntaxError:
   229  	*b = 0
   230  	return &strconv.NumError{fnUnmarshalText, string(t0), strconv.ErrSyntax}
   231  
   232  BitsError:
   233  	*b = 0
   234  	return &strconv.NumError{fnUnmarshalText, string(t0), ErrBits}
   235  }